| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489 | 
							- "use strict";
 
- const promisify = require("util.promisify");
 
- const gensync = require("../");
 
- const TEST_ERROR = new Error("TEST_ERROR");
 
- const DID_ERROR = new Error("DID_ERROR");
 
- const doSuccess = gensync({
 
-   sync: () => 42,
 
-   async: () => Promise.resolve(42),
 
- });
 
- const doError = gensync({
 
-   sync: () => {
 
-     throw DID_ERROR;
 
-   },
 
-   async: () => Promise.reject(DID_ERROR),
 
- });
 
- function throwTestError() {
 
-   throw TEST_ERROR;
 
- }
 
- async function expectResult(
 
-   fn,
 
-   arg,
 
-   { error, value, expectSync = false, syncErrback = expectSync }
 
- ) {
 
-   if (!expectSync) {
 
-     expect(() => fn.sync(arg)).toThrow(TEST_ERROR);
 
-   } else if (error) {
 
-     expect(() => fn.sync(arg)).toThrow(error);
 
-   } else {
 
-     expect(fn.sync(arg)).toBe(value);
 
-   }
 
-   if (error) {
 
-     await expect(fn.async(arg)).rejects.toBe(error);
 
-   } else {
 
-     await expect(fn.async(arg)).resolves.toBe(value);
 
-   }
 
-   await new Promise((resolve, reject) => {
 
-     let sync = true;
 
-     fn.errback(arg, (err, val) => {
 
-       try {
 
-         expect(err).toBe(error);
 
-         expect(val).toBe(value);
 
-         expect(sync).toBe(syncErrback);
 
-         resolve();
 
-       } catch (e) {
 
-         reject(e);
 
-       }
 
-     });
 
-     sync = false;
 
-   });
 
- }
 
- describe("gensync({})", () => {
 
-   describe("option validation", () => {
 
-     test("disallow async and errback handler together", () => {
 
-       try {
 
-         gensync({
 
-           sync: throwTestError,
 
-           async: throwTestError,
 
-           errback: throwTestError,
 
-         });
 
-         throwTestError();
 
-       } catch (err) {
 
-         expect(err.message).toMatch(
 
-           /Expected one of either opts.async or opts.errback, but got _both_\./
 
-         );
 
-         expect(err.code).toBe("GENSYNC_OPTIONS_ERROR");
 
-       }
 
-     });
 
-     test("disallow missing sync handler", () => {
 
-       try {
 
-         gensync({
 
-           async: throwTestError,
 
-         });
 
-         throwTestError();
 
-       } catch (err) {
 
-         expect(err.message).toMatch(/Expected opts.sync to be a function./);
 
-         expect(err.code).toBe("GENSYNC_OPTIONS_ERROR");
 
-       }
 
-     });
 
-     test("errback callback required", () => {
 
-       const fn = gensync({
 
-         sync: throwTestError,
 
-         async: throwTestError,
 
-       });
 
-       try {
 
-         fn.errback();
 
-         throwTestError();
 
-       } catch (err) {
 
-         expect(err.message).toMatch(/function called without callback/);
 
-         expect(err.code).toBe("GENSYNC_ERRBACK_NO_CALLBACK");
 
-       }
 
-     });
 
-   });
 
-   describe("generator function metadata", () => {
 
-     test("automatic naming", () => {
 
-       expect(
 
-         gensync({
 
-           sync: function readFileSync() {},
 
-           async: () => {},
 
-         }).name
 
-       ).toBe("readFile");
 
-       expect(
 
-         gensync({
 
-           sync: function readFile() {},
 
-           async: () => {},
 
-         }).name
 
-       ).toBe("readFile");
 
-       expect(
 
-         gensync({
 
-           sync: function readFileAsync() {},
 
-           async: () => {},
 
-         }).name
 
-       ).toBe("readFileAsync");
 
-       expect(
 
-         gensync({
 
-           sync: () => {},
 
-           async: function readFileSync() {},
 
-         }).name
 
-       ).toBe("readFileSync");
 
-       expect(
 
-         gensync({
 
-           sync: () => {},
 
-           async: function readFile() {},
 
-         }).name
 
-       ).toBe("readFile");
 
-       expect(
 
-         gensync({
 
-           sync: () => {},
 
-           async: function readFileAsync() {},
 
-         }).name
 
-       ).toBe("readFile");
 
-       expect(
 
-         gensync({
 
-           sync: () => {},
 
-           errback: function readFileSync() {},
 
-         }).name
 
-       ).toBe("readFileSync");
 
-       expect(
 
-         gensync({
 
-           sync: () => {},
 
-           errback: function readFile() {},
 
-         }).name
 
-       ).toBe("readFile");
 
-       expect(
 
-         gensync({
 
-           sync: () => {},
 
-           errback: function readFileAsync() {},
 
-         }).name
 
-       ).toBe("readFileAsync");
 
-     });
 
-     test("explicit naming", () => {
 
-       expect(
 
-         gensync({
 
-           name: "readFile",
 
-           sync: () => {},
 
-           async: () => {},
 
-         }).name
 
-       ).toBe("readFile");
 
-     });
 
-     test("default arity", () => {
 
-       expect(
 
-         gensync({
 
-           sync: function(a, b, c, d, e, f, g) {
 
-             throwTestError();
 
-           },
 
-           async: throwTestError,
 
-         }).length
 
-       ).toBe(7);
 
-     });
 
-     test("explicit arity", () => {
 
-       expect(
 
-         gensync({
 
-           arity: 3,
 
-           sync: throwTestError,
 
-           async: throwTestError,
 
-         }).length
 
-       ).toBe(3);
 
-     });
 
-   });
 
-   describe("'sync' handler", async () => {
 
-     test("success", async () => {
 
-       const fn = gensync({
 
-         sync: (...args) => JSON.stringify(args),
 
-       });
 
-       await expectResult(fn, 42, { value: "[42]", expectSync: true });
 
-     });
 
-     test("failure", async () => {
 
-       const fn = gensync({
 
-         sync: (...args) => {
 
-           throw JSON.stringify(args);
 
-         },
 
-       });
 
-       await expectResult(fn, 42, { error: "[42]", expectSync: true });
 
-     });
 
-   });
 
-   describe("'async' handler", async () => {
 
-     test("success", async () => {
 
-       const fn = gensync({
 
-         sync: throwTestError,
 
-         async: (...args) => Promise.resolve(JSON.stringify(args)),
 
-       });
 
-       await expectResult(fn, 42, { value: "[42]" });
 
-     });
 
-     test("failure", async () => {
 
-       const fn = gensync({
 
-         sync: throwTestError,
 
-         async: (...args) => Promise.reject(JSON.stringify(args)),
 
-       });
 
-       await expectResult(fn, 42, { error: "[42]" });
 
-     });
 
-   });
 
-   describe("'errback' sync handler", async () => {
 
-     test("success", async () => {
 
-       const fn = gensync({
 
-         sync: throwTestError,
 
-         errback: (...args) => args.pop()(null, JSON.stringify(args)),
 
-       });
 
-       await expectResult(fn, 42, { value: "[42]", syncErrback: true });
 
-     });
 
-     test("failure", async () => {
 
-       const fn = gensync({
 
-         sync: throwTestError,
 
-         errback: (...args) => args.pop()(JSON.stringify(args)),
 
-       });
 
-       await expectResult(fn, 42, { error: "[42]", syncErrback: true });
 
-     });
 
-   });
 
-   describe("'errback' async handler", async () => {
 
-     test("success", async () => {
 
-       const fn = gensync({
 
-         sync: throwTestError,
 
-         errback: (...args) =>
 
-           process.nextTick(() => args.pop()(null, JSON.stringify(args))),
 
-       });
 
-       await expectResult(fn, 42, { value: "[42]" });
 
-     });
 
-     test("failure", async () => {
 
-       const fn = gensync({
 
-         sync: throwTestError,
 
-         errback: (...args) =>
 
-           process.nextTick(() => args.pop()(JSON.stringify(args))),
 
-       });
 
-       await expectResult(fn, 42, { error: "[42]" });
 
-     });
 
-   });
 
- });
 
- describe("gensync(function* () {})", () => {
 
-   test("sync throw before body", async () => {
 
-     const fn = gensync(function*(arg = throwTestError()) {});
 
-     await expectResult(fn, undefined, {
 
-       error: TEST_ERROR,
 
-       syncErrback: true,
 
-     });
 
-   });
 
-   test("sync throw inside body", async () => {
 
-     const fn = gensync(function*() {
 
-       throwTestError();
 
-     });
 
-     await expectResult(fn, undefined, {
 
-       error: TEST_ERROR,
 
-       syncErrback: true,
 
-     });
 
-   });
 
-   test("async throw inside body", async () => {
 
-     const fn = gensync(function*() {
 
-       const val = yield* doSuccess();
 
-       throwTestError();
 
-     });
 
-     await expectResult(fn, undefined, {
 
-       error: TEST_ERROR,
 
-     });
 
-   });
 
-   test("error inside body", async () => {
 
-     const fn = gensync(function*() {
 
-       yield* doError();
 
-     });
 
-     await expectResult(fn, undefined, {
 
-       error: DID_ERROR,
 
-       expectSync: true,
 
-       syncErrback: false,
 
-     });
 
-   });
 
-   test("successful return value", async () => {
 
-     const fn = gensync(function*() {
 
-       const value = yield* doSuccess();
 
-       expect(value).toBe(42);
 
-       return 84;
 
-     });
 
-     await expectResult(fn, undefined, {
 
-       value: 84,
 
-       expectSync: true,
 
-       syncErrback: false,
 
-     });
 
-   });
 
-   test("successful final value", async () => {
 
-     const fn = gensync(function*() {
 
-       return 42;
 
-     });
 
-     await expectResult(fn, undefined, {
 
-       value: 42,
 
-       expectSync: true,
 
-     });
 
-   });
 
-   test("yield unexpected object", async () => {
 
-     const fn = gensync(function*() {
 
-       yield {};
 
-     });
 
-     try {
 
-       await fn.async();
 
-       throwTestError();
 
-     } catch (err) {
 
-       expect(err.message).toMatch(
 
-         /Got unexpected yielded value in gensync generator/
 
-       );
 
-       expect(err.code).toBe("GENSYNC_EXPECTED_START");
 
-     }
 
-   });
 
-   test("yield suspend yield", async () => {
 
-     const fn = gensync(function*() {
 
-       yield Symbol.for("gensync:v1:start");
 
-       // Should be "yield*" for no error.
 
-       yield {};
 
-     });
 
-     try {
 
-       await fn.async();
 
-       throwTestError();
 
-     } catch (err) {
 
-       expect(err.message).toMatch(/Expected GENSYNC_SUSPEND, got {}/);
 
-       expect(err.code).toBe("GENSYNC_EXPECTED_SUSPEND");
 
-     }
 
-   });
 
-   test("yield suspend return", async () => {
 
-     const fn = gensync(function*() {
 
-       yield Symbol.for("gensync:v1:start");
 
-       // Should be "yield*" for no error.
 
-       return {};
 
-     });
 
-     try {
 
-       await fn.async();
 
-       throwTestError();
 
-     } catch (err) {
 
-       expect(err.message).toMatch(/Unexpected generator completion/);
 
-       expect(err.code).toBe("GENSYNC_EXPECTED_SUSPEND");
 
-     }
 
-   });
 
- });
 
- describe("gensync.all()", () => {
 
-   test("success", async () => {
 
-     const fn = gensync(function*() {
 
-       const result = yield* gensync.all([doSuccess(), doSuccess()]);
 
-       expect(result).toEqual([42, 42]);
 
-     });
 
-     await expectResult(fn, undefined, {
 
-       value: undefined,
 
-       expectSync: true,
 
-       syncErrback: false,
 
-     });
 
-   });
 
-   test("error first", async () => {
 
-     const fn = gensync(function*() {
 
-       yield* gensync.all([doError(), doSuccess()]);
 
-     });
 
-     await expectResult(fn, undefined, {
 
-       error: DID_ERROR,
 
-       expectSync: true,
 
-       syncErrback: false,
 
-     });
 
-   });
 
-   test("error last", async () => {
 
-     const fn = gensync(function*() {
 
-       yield* gensync.all([doSuccess(), doError()]);
 
-     });
 
-     await expectResult(fn, undefined, {
 
-       error: DID_ERROR,
 
-       expectSync: true,
 
-       syncErrback: false,
 
-     });
 
-   });
 
-   test("empty list", async () => {
 
-     const fn = gensync(function*() {
 
-       yield* gensync.all([]);
 
-     });
 
-     await expectResult(fn, undefined, {
 
-       value: undefined,
 
-       expectSync: true,
 
-       syncErrback: false,
 
-     });
 
-   });
 
- });
 
- describe("gensync.race()", () => {
 
-   test("success", async () => {
 
-     const fn = gensync(function*() {
 
-       const result = yield* gensync.race([doSuccess(), doError()]);
 
-       expect(result).toEqual(42);
 
-     });
 
-     await expectResult(fn, undefined, {
 
-       value: undefined,
 
-       expectSync: true,
 
-       syncErrback: false,
 
-     });
 
-   });
 
-   test("error", async () => {
 
-     const fn = gensync(function*() {
 
-       yield* gensync.race([doError(), doSuccess()]);
 
-     });
 
-     await expectResult(fn, undefined, {
 
-       error: DID_ERROR,
 
-       expectSync: true,
 
-       syncErrback: false,
 
-     });
 
-   });
 
- });
 
 
  |