JSlang.dev

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

February 22, 2024
TestsSource
#69 Generators

Source Code

The source code we wrote during the event.

import {strict as assert} from 'assert';

describe('take a string and yield every character', () => {
  it('should yield one character of a string "a"', () => {
    function* myGenerator() {
      yield "a";
    }
    assert.equal(myGenerator().next().value, "a");
  });
  it('call next() twice for "a" returns `value:undefined` in the second call', () => {
    function * myGenerator() {
      yield "a";
    }
    const generator = myGenerator();
    generator.next();
    assert.equal(generator.next().value, undefined);
  });
  it('calling a generator once return done=false', () => {
    function * myGenerator() {
      yield "a";
    }
    assert.equal(myGenerator().next().done, false);
  });
  it('calling a generator with one `yield` twice returns done=true', () => {
    function * myGenerator() {
      yield "a";
    }
    const generator = myGenerator();
    generator.next();
    assert.equal(generator.next().done, true);
  });

  it('a generator without a yield return value=undefined for next() called once', () => {
    function* myGenerator() {}
    assert.equal(myGenerator().next().value, undefined);
  });
  it('a generator with two yield statements return a character for each yield', () => {
    function * myGenerator() {
      yield "a";
      yield "b";
    }
    const generator = myGenerator();
    assert.equal(generator.next().value, 'a');
    assert.equal(generator.next().value, 'b');
  });
  it('a generator taking "the string" returns each charater for one next() call', () => {
    function* characterGenerator(s) {
      for (const char of s) {
        yield char;
      }
    }
    const generator = characterGenerator('the string');
    assert.equal(generator.next().value, 't');
    assert.equal(generator.next().value, 'h');
    assert.equal(generator.next().value, 'e');
    assert.equal(generator.next().value, ' ');
  });
});

describe('Can I return from within a generator?', () => {
  it('the typeof a generator instance without a yield inside is "object"', () => {
    function* gen() {}
    assert.equal(typeof gen(), 'object');
  });
  it('the typeof a generator instance with a yield inside is "object"', () => {
    function* gen() {
      yield 1;
    }
    assert.equal(typeof gen(), 'object');
  });
  it('a generator that has a yield without value returns value=undefined', () => {
    function* gen() {
      yield;
    }
    assert.equal(gen().next().value, undefined);
  });
  it('a generator with `return "r"` statement inside returns value="r"', () => {
    function* gen() {
      return 'r';
    }
    assert.equal(gen().next().value, 'r');
  });
  it('a generator with a return inside return done=true and value=undefined', () => {
    function* gen() {
      return;
    }
    assert.deepEqual(gen().next(), {done: true, value: undefined});
  });
  it('a generator with a yield "a" and then a return "b", returns value="a", done=false on first next()', () => {
    function* gen() {
      yield 'a';
      return 'b';
    }
    assert.deepEqual(gen().next(), {value: 'a', done: false})
  });
  it('a generator with a yield "a" and then a return "b", returns value="b", done=true on second next()', () => {
    function* gen() {
      yield 'a';
      return 'b';
    }
    const generator = gen();
    generator.next();
    assert.deepEqual(generator.next(), {value: 'b', done: true})
  });

  it('calling `next(param)` we use param inside the generator and return param on the next yield', () => {
    function* gen() {
      yield yield 1;
    }
    const generator = gen();
    assert.deepEqual(generator.next(), {done: false, value: 1});
    assert.equal(generator.next(42).value, 42);
  });
});