-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.test.ts
200 lines (173 loc) · 7.23 KB
/
index.test.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
import { expect } from 'chai';
import compare, { Comparator } from './index';
// tslint:disable:only-arrow-functions
describe('creating comparators', function () {
describe('simple comparisons', function () {
it('can compare numbers', function () {
const f = compare();
expect(f(10, 10)).to.equal(0);
expect(f(20, 10)).to.equal(1);
expect(f(10, 20)).to.equal(-1);
});
it('can compare strings', function () {
const f = compare();
expect(f('a', 'b')).to.equal(-1);
expect(f('a', 'a')).to.equal(0);
expect(f('b', 'a')).to.equal(1);
});
it('uses valueOf for custom objects', function () {
class ValueOf {
constructor(private value: number) { }
public valueOf(): number {
return this.value;
}
}
const f = compare();
expect(f(new ValueOf(5), new ValueOf(-10))).to.equal(1);
});
});
describe('custom comparator', function () {
it('calls a custom comparator if given', function () {
interface Named {
name: string;
}
function compareName(a: Named, b: Named): number {
return a.name.localeCompare(b.name);
}
const f = compare(compareName);
expect(f({ name: 'Alice' }, { name: 'Bob' })).to.equal(-1);
});
});
});
describe('modifiers', function () {
describe('#reverse', function () {
it('works', function () {
const f = compare().reverse();
expect(f(10, 20)).to.equal(1);
expect(f(10, 10)).to.equal(0);
expect(f(20, 10)).to.equal(-1);
});
});
describe('#from', function () {
it('works', function () {
const f: Comparator<number> = compare().from((x) => x.toString());
expect(f(16, 9)).to.equal(-1);
});
});
describe('#append', function () {
describe('with type predicates', function () {
const f: Comparator<number | string> = compare<number>().append(isString);
it('uses the underlying comparator when the predicate matches neither', function () {
expect(f(1, 1)).to.equal(0);
expect(f(16, 9)).to.equal(1);
});
it('orders T before U', function () {
expect(f(1, '1')).to.equal(-1);
expect(f('1', 1)).to.equal(1);
});
it('uses the auxiliary comparator when the predicate matches both', function () {
expect(f('1', '1')).to.equal(0);
expect(f('16', '9')).to.equal(-1);
});
});
describe('with normal predicates', function () {
const f = compare<string>().append((x: string) => x.length === 1, compare().reverse());
it('uses the underlying comparator when the predicate matches neither', function () {
expect(f('aa', 'aa')).to.equal(0);
expect(f('aa', 'bb')).to.equal(-1);
});
it('orders falsy before truthy', function () {
expect(f('zzzzz', 'a')).to.equal(-1);
expect(f('a', 'zzzzz')).to.equal(1);
});
it('uses the auxiliary comparator when the predicate matches both', function () {
expect(f('z', 'a')).to.equal(-1);
});
});
});
describe('#prepend', function () {
describe('with type predicates', function () {
const f: Comparator<number | string> = compare<number>().prepend(isString);
it('uses the underlying comparator when the predicate matches neither', function () {
expect(f(1, 1)).to.equal(0);
expect(f(16, 9)).to.equal(1);
});
it('orders T after U', function () {
expect(f(1, '1')).to.equal(1);
expect(f('1', 1)).to.equal(-1);
});
it('uses the auxiliary comparator when the predicate matches both', function () {
expect(f('1', '1')).to.equal(0);
expect(f('16', '9')).to.equal(-1);
});
});
describe('with normal predicates', function () {
const f = compare<string>().prepend((x: string) => x.length === 1, compare().reverse());
it('uses the underlying comparator when the predicate matches neither', function () {
expect(f('aa', 'aa')).to.equal(0);
expect(f('aa', 'bb')).to.equal(-1);
});
it('orders truthy before falsy', function () {
expect(f('z', 'aaaaa')).to.equal(-1);
expect(f('aaaaa', 'z')).to.equal(1);
});
it('uses the auxiliary comparator when the predicate matches both', function () {
expect(f('z', 'a')).to.equal(-1);
});
});
});
describe('#then', function () {
interface Person {
name: string;
age: number;
}
const anna = { name: 'Anna', age: 32 };
const khalid = { name: 'Khalid', age: 16 };
const yuukoTheElder = { name: 'Yuuko', age: 64 };
const yuukoTheYounger = { name: 'Yuuko', age: 8 };
const f = compare<string>().from((x: Person) => x.name)
.then(compare<number>().from((x: Person) => x.age).reverse());
it('returns the first result if non-zero', function () {
expect(f(anna, khalid)).to.equal(-1);
expect(f(yuukoTheYounger, khalid)).to.equal(1);
});
it('uses the second comparator if the first compares equal', function () {
expect(f(yuukoTheElder, yuukoTheYounger)).to.equal(-1);
expect(f(yuukoTheYounger, yuukoTheElder)).to.equal(1);
});
it('returns zero if both comparators compare equal', function () {
expect(f(khalid, khalid)).to.equal(0);
});
it('uses the default comparator if none given', function () {
const g = compare<string>().from((s: string) => s[1]).then<string>();
expect(g('za', 'yb')).to.equal(-1);
expect(g('za', 'ya')).to.equal(1);
});
});
});
describe('prefabs', function () {
describe('#on', function () {
it('accepts callbacks', function () {
const f: Comparator<string> = compare.on((s) => s.toLowerCase());
expect(f('ZZZ', 'aaa')).to.equal(1);
});
});
describe('#locale', function () {
it('works', function () {
const f = compare.locale('en', { sensitivity: 'base' });
expect(f('AAA', 'aaa')).to.equal(0);
expect(f('aaa', 'BBB')).to.equal(-1);
});
it('exposes a collator property', function () {
const f = compare.locale('en', { sensitivity: 'base' });
expect(f.collator).is.instanceOf(Intl.Collator);
});
it('marks the collator property as read-only', function () {
const f = compare.locale('en', { sensitivity: 'base' });
expect(() => (f as any).collator = 42).to.throw(TypeError);
});
});
});
function isString<T>(value: T | string): value is string {
return typeof value === 'string';
}