JSlang.dev

JavaScript Deep Dives with Wolfram. Since 2015
Inclusive, Test-Driven, Spec-Focused, Collaborative.

December 19, 2019
TestsSource
Generator - again, again and again

Source Code

The source code we wrote during the event.

import assert from 'assert';

describe('Creating a generator', () => {
    it('has the type of "function"', () => {
        function* generator() {}
        assert.equal(typeof generator, 'function');
    });
    it('order of asterisk does matter', () => {
        function *generator() {}
        assert.equal(typeof generator, 'function');
    });
    it('assigning an unnamed function as a generator is possible', () => {
        assert.doesNotThrow(() => eval('const gen = function* () {}'));
        assert.doesNotThrow(() => eval('const gen = function*() {}'));
        assert.doesNotThrow(() => eval('const gen = function  *() {}'));
        assert.doesNotThrow(() => eval('const gen = function     *      () {}'));
    });
    it('arrow function can not be a generator', () => {
        assert.throws(() => eval('const generator = *() => {};'), SyntaxError);
        assert.throws(() => eval('const generator *= () => {};'), SyntaxError);
        assert.throws(() => eval('const generator = ()* => {};'), SyntaxError);
        assert.throws(() => eval('const generator = () => *{};'), SyntaxError);
        assert.throws(() => eval('const *generator = () => {};'), SyntaxError);
    });
    it('stringified prototype of the generator is "[object Generator]"', () => {
        function* generator() {}
        assert.equal(generator.prototype.toString(), '[object Generator]');
    });
});

describe('Calling a generator', () => {
    it('is of type "object"', () => {
        function* generator() {}
        assert.equal(typeof generator(), 'object');
    });
    it('prototype of a called generator returns undefined', () => {
        function* generator() {}
        assert.equal(generator().prototype, undefined);
    });
    it('prototype of a called generator returns undefined', () => {
        function* generator() {
            yield 1;
        }
        assert.equal(generator().prototype, undefined);
    });
    it('called generator returning a string returns ???', () => {
        function* generator() {
            return "a string";
        }
        assert.notEqual(generator(), "a string");
    });
    it('does not execute the return statement', () => {
        let a = 0;
        function* generator() {
            return a++;
        }
        generator();
        assert.equal(a, 0);
    });
    it('does not execute function body', () => {
        let a = 0;
        function* generator() {
            a++;
        }
        generator();
        assert.equal(a, 0);
    });
});

describe('Using a generator', () => {
    it('increases `a` once when calling next() twice', () => {
        let a = 0;
        function* generator() {
            a++;
        }

        const iterator = generator();
        iterator.next();
        assert.equal(a, 1);
        iterator.next();
        assert.equal(a, 1);
    });
    it('calling `next()` on an iterator DOES not return the original return value', () => {
        function* generator() {
            return 'a string';
        }
        assert.notEqual(generator().next(), 'a string');
    });
    it('return terminates the generator regardless of a yield afterwards', () => {
        function* generator() {
            return 0;
            yield 1;
        }
        assert.deepStrictEqual(generator().next(), {done: true, value: 0});
    });
    it('does not execute things after `return`', () => {
        let a = 0;
        function* generator() {
            return 99;
            a++;
        }
        generator().next();
        assert.strictEqual(a, 0);
    });
    it('yielding two values they can be read via 2x `next()`', () => {
        function*  generator() {
            yield 1;
            yield 2;
            return 3;
        }
        const iterator =  generator();
        assert.deepStrictEqual(iterator.next(), {done: false, value: 1});
        assert.deepStrictEqual(iterator.next(), {done: false, value: 2});
        assert.deepStrictEqual(iterator.next(), {done: true, value: 3});
    });
    it('a `return yield 2` will terminate the iterator', () => {
        function * generator() {
            yield 1;
            return yield 2;
        }
        const iterator = generator();
        iterator.next();
        assert.deepStrictEqual(iterator.next(), {done: false, value: 2});
    });
    it('the return value of a yielded value is undefined', () => {
        function * generator() {
            return yield 1;
        }
        const iterator = generator();
        iterator.next();
        assert.deepStrictEqual(iterator.next(), {done: true, value: undefined});
    });
    it('the return value of a yielded value is the value passed to previous `next()`', () => {
        function * generator() {
            return yield 1;
        }
        const iterator = generator();
        iterator.next();
        assert.deepStrictEqual(iterator.next(2), {done: true, value: 2});
    });
    it('yielding and assigning is fun, learning ...', () => {
        let a = 0;
        function * generator() {
            a = yield 1;
            yield a;
        }
        const iterator = generator();
        assert.deepStrictEqual(iterator.next(), {done: false, value: 1});
        assert.deepStrictEqual(iterator.next(), {done: false, value: undefined});
        assert.deepStrictEqual(iterator.next(), {done: true, value: undefined});
        assert.strictEqual(a, undefined);
    });
    it('yielding and assigning is fun, learning part 2 ...', () => {
        let a = 0;
        const b = 5;
        function * generator(param) {
            a = yield param;
            yield a;
        }
        const iterator = generator(6);
        assert.deepStrictEqual(iterator.next('this parameter is ignored'), {done: false, value: 6});
        assert.deepStrictEqual(iterator.next(3), {done: false, value: 3});
        assert.deepStrictEqual(iterator.next(), {done: true, value: undefined});
        // assert.strictEqual(a, 3);
    });
});