Skip to content

Commit b5d3014

Browse files
committed
Merge branch 'feature/length'
Merges #7 Closes #5
2 parents 6e99435 + d38d9fe commit b5d3014

17 files changed

+506
-6
lines changed

.travis.yml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ before_script:
88
- npm run typings
99
after_success:
1010
- npm run coveralls
11-
before_deploy:
12-
- npm run build
1311
deploy:
1412
- provider: npm
1513
email:
@@ -30,5 +28,3 @@ deploy:
3028
repo: akim-mcmath/chai-iterator
3129
node: "4"
3230
tags: true
33-
after_deploy:
34-
- npm run unbuild

README.md

Lines changed: 119 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@ Chai's `should()` [assertion style][assertion-style], just to be different.
3939
[2, 3, 5].should.iterate.from([2, 3]);
4040
[2, 3, 5].should.iterate.until([3, 5]);
4141

42+
[2, 3, 5].should.iterate.for.lengthOf(3);
43+
[2, 3, 5].should.iterate.for.length.above(2);
44+
[2, 3, 5].should.iterate.for.length.below(4);
45+
[2, 3, 5].should.iterate.for.length.of.at.least(3);
46+
[2, 3, 5].should.iterate.for.length.of.at.most(3);
47+
[2, 3, 5].should.iterate.for.length.within(2, 4);
48+
4249
[2, 3, 5].should.not.iterate.over([1, 2, 3]);
4350
[{n: 2}, {n: 3}].should.deep.iterate.from([{n: 2}]);
4451
```
@@ -70,7 +77,7 @@ class Count {
7077
this.step = step;
7178
}
7279

73-
* [Symbol.iterator]() {
80+
*[Symbol.iterator]() {
7481
for (let n = this.start; true; n += this.step) {
7582
yield n;
7683
}
@@ -104,7 +111,7 @@ Let's generate the [fibonacci sequence][fibonacci-sequence]. A
104111
iterable.
105112

106113
```js
107-
function * fibonacci() {
114+
function* fibonacci() {
108115
for (let [x, y] = [1, 1]; true; [x, y] = [y, x + y]) {
109116
yield x;
110117
}
@@ -229,6 +236,12 @@ chai.use(chaiIterator);
229236
- [`iterate.over()`](#iterateoverexpected)
230237
- [`iterate.from()`](#iteratefromexpected)
231238
- [`iterate.until()`](#iterateuntilexpected)
239+
- [`iterate.for.lengthOf()`](#iterateforlengthofn)
240+
- [`iterate.for.length.above()`](#iterateforlengthaboven)
241+
- [`iterate.for.length.below()`](#iterateforlengthbelown)
242+
- [`iterate.for.length.of.at.least()`](#iterateforlengthofatleastn)
243+
- [`iterate.for.length.of.at.most()`](#iterateforlengthofatmostn)
244+
- [`iterate.for.length.within()`](#iterateforlengthwithinmin-max)
232245

233246
#### `iterable`
234247

@@ -289,6 +302,90 @@ expect([2, 3, 5]).not.to.iterate.until([2, 3]);
289302
expect([{n: 2}, {n: 3}]).to.deep.iterate.until([{n: 3}]);
290303
```
291304

305+
#### `iterate.for.lengthOf(n)`
306+
307+
Asserts that the target yields exactly *n* values.
308+
309+
| Param | Type | Description |
310+
| :----- | :------- | :------------------ |
311+
| n | `number` | A positive integer |
312+
313+
```js
314+
expect([2, 3, 5]).to.iterate.for.lengthOf(3);
315+
expect('abcdefg').to.iterate.for.lengthOf(7);
316+
expect([2, 3, 5]).not.to.iterate.for.lengthOf(7);
317+
```
318+
319+
#### `iterate.for.length.above(n)`
320+
321+
Asserts that the target yields more than *n* values.
322+
323+
| Param | Type | Description |
324+
| :----- | :------- | :------------------ |
325+
| n | `number` | A positive integer |
326+
327+
```js
328+
expect([2, 3, 5]).to.iterate.for.length.above(2);
329+
expect('abcdefg').to.iterate.for.length.above(5);
330+
expect([2, 3, 5]).not.to.iterate.for.length.above(3);
331+
```
332+
333+
#### `iterate.for.length.below(n)`
334+
335+
Asserts that the target yields fewer than *n* values.
336+
337+
| Param | Type | Description |
338+
| :----- | :------- | :------------------ |
339+
| n | `number` | A positive integer |
340+
341+
```js
342+
expect([2, 3, 5]).to.iterate.for.length.below(4);
343+
expect('abcdefg').to.iterate.for.length.below(10);
344+
expect([2, 3, 5]).not.to.iterate.for.length.below(3);
345+
```
346+
347+
#### `iterate.for.length.of.at.least(n)`
348+
349+
Asserts that the target yields at least *n* values.
350+
351+
| Param | Type | Description |
352+
| :----- | :------- | :------------------ |
353+
| n | `number` | A positive integer |
354+
355+
```js
356+
expect([2, 3, 5]).to.iterate.for.length.of.at.least(2);
357+
expect([2, 3, 5]).to.iterate.for.length.of.at.least(3);
358+
expect([2, 3, 5]).not.to.iterate.for.length.of.at.least(4);
359+
```
360+
361+
#### `iterate.for.length.of.at.most(n)`
362+
363+
Asserts that the target yields at most *n* values.
364+
365+
| Param | Type | Description |
366+
| :----- | :------- | :------------------ |
367+
| n | `number` | A positive integer |
368+
369+
```js
370+
expect([2, 3, 5]).to.iterate.for.length.of.at.most(4);
371+
expect([2, 3, 5]).to.iterate.for.length.of.at.most(3);
372+
expect([2, 3, 5]).not.to.iterate.for.length.of.at.most(2);
373+
```
374+
375+
#### `iterate.for.length.within(min, max)`
376+
377+
Asserts that the target yields between *min* and *max* values, inclusive.
378+
379+
| Param | Type | Description |
380+
| :----- | :------- | :------------------ |
381+
| n | `number` | A positive integer |
382+
383+
```js
384+
expect([2, 3, 5]).to.iterate.for.length.within(2, 4);
385+
expect([2, 3, 5]).to.iterate.for.length.within(3, 3);
386+
expect([2, 3, 5]).not.to.iterate.for.length.within(4, 7);
387+
```
388+
292389
## Assert API
293390

294391
#### Assertions
@@ -307,6 +404,7 @@ expect([{n: 2}, {n: 3}]).to.deep.iterate.until([{n: 3}]);
307404
- [`doesNotIterateUntil()`](#doesnotiterateuntilvalue-expected-message)
308405
- [`deepIteratesUntil()`](#deepiteratesuntilvalue-expected-message)
309406
- [`doesNotDeepIterateUntil()`](#doesnotdeepiterateuntilvalue-expected-message)
407+
- [`lengthOf()`](#lengthofvalue-expected-message)
310408

311409
#### Parameters
312410

@@ -316,6 +414,7 @@ The parameters for the assert methods are as follows.
316414
| :------- | :------- | :--------------------------------------- |
317415
| value | `any` | Any value. |
318416
| expected | `object` | An iterable object. |
417+
| n | `number` | A positive integer. |
319418
| message? | `string` | An optional message to display on error. |
320419

321420
#### `isIterable(value, [message])`
@@ -456,6 +555,23 @@ assert.doesNotDeepIterateUntil([{n: 2}, {n: 3}], [{n: 5}]);
456555
assert.doesNotDeepIterateUntil([[0, 2], [1, 3]], [[0, 2]]);
457556
```
458557

558+
#### `lengthOf(value, n, [message])`
559+
560+
Asserts that an iterable yields a given number of values. If *value* is not an
561+
iterable object, or if it has a `'length'` property, Chai's native
562+
[`assert.lengthOf()`][chai-assert-lengthof] will be used.
563+
564+
```js
565+
function* range(min=0, max=Infinity, step=1) {
566+
for (let n = min; n < max; n += step) {
567+
yield n;
568+
}
569+
}
570+
571+
assert.lengthOf(range(0, 10), 10);
572+
assert.lengthOf(range(6, 42), 36);
573+
```
574+
459575
## License
460576

461577
Copyright &copy; 2016 Akim McMath. Licensed under the [MIT License][license].
@@ -496,3 +612,4 @@ Copyright &copy; 2016 Akim McMath. Licensed under the [MIT License][license].
496612
[es6-lib]: https://github.com/Microsoft/TypeScript/blob/master/lib/lib.es6.d.ts
497613
[deep]: http://chaijs.com/api/bdd/#method_deep
498614
[chai-npm]: https://www.npmjs.com/package/chai
615+
[chai-assert-lengthof]: http://chaijs.com/api/assert/#method_lengthof

chai-iterator.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ declare module "~chai/lib/Assertion" {
3030
interface Assertion {
3131
iterable: Assertion;
3232
iterate: {
33+
for: Assertion;
3334
over(values: Iterable<any>): Assertion;
3435
from(values: Iterable<any>): Assertion;
3536
until(values: Iterable<any>): Assertion;

chai-iterator.js

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
var Assertion = chai.Assertion;
1717
var assert = chai.assert;
1818

19+
var noop = function() {};
20+
1921
var ELLIPSIS = unquote('...');
2022

2123
// Expect/should assertions =============================
@@ -59,6 +61,129 @@
5961
return actual;
6062
}));
6163

64+
Assertion.addProperty('for', noop);
65+
66+
Assertion.overwriteMethod('lengthOf', function(_super) {
67+
return function(exp) {
68+
if (utils.flag(this, 'iterate')) {
69+
var len = iterableLength(this._obj, exp);
70+
71+
this.assert(
72+
len === exp,
73+
'expected #{this} to iterate for length above #{exp}, but got #{act}',
74+
'expected #{this} not to iterate for length above #{exp}',
75+
exp,
76+
len
77+
);
78+
79+
} else {
80+
_super.apply(this, arguments);
81+
}
82+
};
83+
});
84+
85+
Assertion.overwriteMethod('above', function(_super) {
86+
return function(exp) {
87+
if (utils.flag(this, 'iterate')) {
88+
var len = iterableLength(this._obj, exp);
89+
90+
this.assert(
91+
len > exp,
92+
'expected #{this} to iterate for length above #{exp}, but got #{act}',
93+
'expected #{this} not to iterate for length above #{exp}',
94+
exp,
95+
len
96+
);
97+
98+
} else {
99+
_super.apply(this, arguments);
100+
}
101+
};
102+
});
103+
104+
Assertion.overwriteMethod('below', function(_super) {
105+
return function(exp) {
106+
if (utils.flag(this, 'iterate')) {
107+
var max = exp + 100;
108+
var len = iterableLength(this._obj, max);
109+
var act = len === Infinity ? unquote('more than ' + max) : len;
110+
111+
this.assert(
112+
len < exp,
113+
'expected #{this} to iterate for length below #{exp}, but got #{act}',
114+
'expected #{this} not to iterate for length below #{exp}',
115+
exp,
116+
act
117+
);
118+
119+
} else {
120+
_super.apply(this, arguments);
121+
}
122+
};
123+
});
124+
125+
Assertion.overwriteMethod('least', function(_super) {
126+
return function(exp) {
127+
if (utils.flag(this, 'iterate')) {
128+
var len = iterableLength(this._obj, exp);
129+
130+
this.assert(
131+
len >= exp,
132+
'expected #{this} to iterate for length of at least #{exp}, but got #{act}',
133+
'expected #{this} not to iterate for length of at least #{exp}',
134+
exp,
135+
len
136+
);
137+
138+
} else {
139+
_super.apply(this, arguments);
140+
}
141+
};
142+
});
143+
144+
Assertion.overwriteMethod('most', function(_super) {
145+
return function(exp) {
146+
if (utils.flag(this, 'iterate')) {
147+
var max = exp + 100;
148+
var len = iterableLength(this._obj, max);
149+
var act = len === Infinity ? unquote('more than ' + max) : len;
150+
151+
this.assert(
152+
len <= exp,
153+
'expected #{this} to iterate for length of at most #{exp}, but got #{act}',
154+
'expected #{this} not to iterate for length of at most #{exp}',
155+
exp,
156+
act
157+
);
158+
159+
} else {
160+
_super.apply(this, arguments);
161+
}
162+
};
163+
});
164+
165+
Assertion.overwriteMethod('within', function(_super) {
166+
return function(min, max) {
167+
if (utils.flag(this, 'iterate')) {
168+
var cutoff = max + 100;
169+
var len = iterableLength(this._obj, cutoff);
170+
var exp = unquote(min + 'and' + max);
171+
var act = len === Infinity ? unquote('more than ' + cutoff) : len;
172+
173+
this.assert(
174+
min <= len && len <= max,
175+
'expected #{this} to iterate for length within #{exp}, but got #{act}',
176+
'expected #{this} not to iterate for length within #{exp}',
177+
exp,
178+
act
179+
);
180+
181+
} else {
182+
_super.apply(this, arguments);
183+
}
184+
};
185+
});
186+
62187
// Assert methods =======================================
63188

64189
assert.isIterable = function(value, msg) {
@@ -117,6 +242,16 @@
117242
new Assertion(value, msg).not.deep.iterate.until(exp);
118243
};
119244

245+
var _lengthOf = assert.lengthOf;
246+
247+
assert.lengthOf = function(value, exp, msg) {
248+
if (isIterable(value) && typeof value.length !== 'number') {
249+
new Assertion(value, msg).iterate.for.lengthOf(exp);
250+
} else {
251+
_lengthOf.apply(assert, arguments);
252+
}
253+
}
254+
120255
// Helpers ==============================================
121256

122257
function iterateMethod(predicate, getActual) {
@@ -144,6 +279,20 @@
144279
return value != null && typeof value[Symbol.iterator] === 'function';
145280
}
146281

282+
function iterableLength(iterable, max) {
283+
max = max == null ? Infinity : max;
284+
285+
var it = iterable[Symbol.iterator]();
286+
287+
for (var i = 0; i <= max; i++) {
288+
if (it.next().done) {
289+
return i;
290+
}
291+
}
292+
293+
return Infinity;
294+
}
295+
147296
function strictEqual(a, b) {
148297
return a === b;
149298
}

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"test:tsc": "tsc",
99
"test:eslint": "eslint chai-iterator.js",
1010
"test:mocha": "mocha",
11+
"test:watch": "mocha -w",
1112
"test:cover": "istanbul cover _mocha",
1213
"test:report": "npm run test:cover && open coverage/lcov-report/index.html",
1314
"test": "npm run test:tsc && npm run test:eslint && npm run test:cover",

0 commit comments

Comments
 (0)