diff --git a/package.json b/package.json index 2f4d331..b0147bd 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "scripts": { "prepublishOnly": "npm run build", "build": "microbundle -i src/index.ts -f es,cjs", - "test": "typed-test --typeCheck 'src/**/*.test.ts'" + "test": "typed-test --typeCheck 'src/**/*.__test__.ts'" }, "keywords": [ "most", diff --git a/src/index.__test__.ts b/src/index.__test__.ts new file mode 100644 index 0000000..cfe2cb4 --- /dev/null +++ b/src/index.__test__.ts @@ -0,0 +1,164 @@ +import { + count, + index, + indexed, + keepIndex, + withCount, + withIndex, + withIndexStart +} from "./index"; +import { constant, periodic, runEffects, take, tap } from "@most/core"; +import { newDefaultScheduler } from "@most/scheduler"; +import { Stream } from "@most/types"; +import { describe, it, given } from "@typed/test"; + +const TEST_EVENT_VALUE = "test"; + +const collect = async (n: number, s: Stream): Promise => { + const xs: A[] = []; + const sa = tap(x => xs.push(x), s); + await runEffects(take(n, sa), newDefaultScheduler()); + return xs; +}; + +const range = (start: number, n: number): number[] => + Array.from(Array(n), (_, i) => start + i); + +const randomInt = (min: number, max: number) => + min + Math.floor(Math.random() * (max - min)); + +export const indexTests = describe("index", [ + given("a stream", [ + it("replaces events with 0-based index", async ({ equal }) => { + // Fixture setup + const s = periodic(1); + const n = randomInt(10, 20); + const expectedEvents = range(0, n); + // Exercise system + const result = index(s); + // Verify outcome + const actualEvents = await collect(n, result); + equal(expectedEvents, actualEvents); + }) + ]) +]); + +export const withIndexTests = describe("withIndex", [ + given("a stream", [ + it("pairs events with 0-based count", async ({ equal }) => { + // Fixture setup + const s = constant(TEST_EVENT_VALUE, periodic(1)); + const n = randomInt(10, 20); + const expectedEvents = range(0, n).map<[number, string]>(n => [ + n, + TEST_EVENT_VALUE + ]); + // Exercise system + const result = withIndex(s); + // Verify outcome + const actualEvents = await collect(n, result); + equal(expectedEvents, actualEvents); + }) + ]) +]); + +export const countTests = describe("count", [ + given("a stream", [ + it("replaces events with 1-based count", async ({ equal }) => { + // Fixture setup + const s = periodic(1); + const n = randomInt(10, 20); + const expectedEvents = range(1, n); + // Exercise system + const result = count(s); + // Verify outcome + const actualEvents = await collect(n, result); + equal(expectedEvents, actualEvents); + }) + ]) +]); + +export const withCountTests = describe("withCount", [ + given("a stream", [ + it("pairs events with 1-based count", async ({ equal }) => { + // Fixture setup + const s = constant(TEST_EVENT_VALUE, periodic(1)); + const n = randomInt(10, 20); + const expectedEvents = range(1, n).map<[number, string]>(n => [ + n, + TEST_EVENT_VALUE + ]); + // Exercise system + const result = withCount(s); + // Verify outcome + const actualEvents = await collect(n, result); + equal(expectedEvents, actualEvents); + }) + ]) +]); + +export const withIndexStartTests = describe("withIndexStart", [ + given("a start index and a stream", [ + it("pairs events with start-based index", async ({ equal }) => { + // Fixture setup + const idx = randomInt(0, 10000); + const s = constant(TEST_EVENT_VALUE, periodic(1)); + const n = randomInt(10, 20); + const expectedEvents = range(idx, n).map<[number, string]>(n => [ + n, + TEST_EVENT_VALUE + ]); + // Exercise system + const result = withIndexStart(idx, s); + // Verify outcome + const actualEvents = await collect(n, result); + equal(expectedEvents, actualEvents); + }) + ]) +]); + +export const indexedTests = describe("indexed", [ + given("a function, an initial value, and a stream", [ + it("should pair events with computed index", async ({ equal }) => { + // Fixture setup + const n = randomInt(10, 20); + const arbitraryChar = "a"; + const strOfLenN = Array(n) + .fill(arbitraryChar) + .join(""); + const stringIndex = (s: string) => (prev: string): [string, string] => [ + prev, + prev + s + ]; + const f = stringIndex(arbitraryChar); + const init = ""; + const s = constant(TEST_EVENT_VALUE, periodic(1)); + const expectedEvents = range(0, n).map<[string, string]>((_, i) => [ + strOfLenN.slice(0, i), + TEST_EVENT_VALUE + ]); + // Exercise system + const result = indexed(f, init, s); + // Verify outcome + const actualEvents = await collect(n, result); + equal(expectedEvents, actualEvents); + }) + ]) +]); + +export const keepIndexTests = describe("keepIndex", [ + given("a stream of an [index, value] pair", [ + it("should keep index and discard value", async ({ equal }) => { + // Fixture setup + const idx = randomInt(0, 10000); + const s = withIndexStart(idx, constant(TEST_EVENT_VALUE, periodic(1))); + const n = randomInt(10, 20); + const expectedEvents = range(idx, n); + // Exercise system + const result = keepIndex(s); + // Verify outcome + const actualEvents = await collect(n, result); + equal(expectedEvents, actualEvents); + }) + ]) +]); diff --git a/src/index.test.ts b/src/index.test.ts deleted file mode 100644 index 2de9099..0000000 --- a/src/index.test.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { count, index, indexed, keepIndex, withCount, withIndex, withIndexStart } from './index' -import { constant, periodic, runEffects, take, tap } from '@most/core' -import { newDefaultScheduler } from '@most/scheduler' -import { Stream } from '@most/types' -import { describe, it } from '@typed/test' - -const collect = async(n: number, s: Stream): Promise => { - const eventValues: A[] = [] - const collectStream = tap(x => eventValues.push(x), s) - await runEffects(take(n, collectStream), newDefaultScheduler()) - return eventValues -} - -const range = (start: number, n: number): number[] => - Array.from(Array(n), (_, i) => start + i) - -const randomInt = (min: number, max: number) => - min + Math.floor(Math.random() * (max - min)) - -export const indexTests = describe('index', [ - it('replaces events with 0-based index', async ({ equal }) => { - const n = randomInt(10, 20) - const events = await collect(n, index(periodic(1))) - equal(range(0, n), events) - }) -]) - -export const withIndexTests = describe('withIndex', [ - it('pairs events with 0-based count', async ({ equal }) => { - const n = randomInt(10, 20) - const events = await collect(n, withIndex(constant('test', periodic(1)))) - equal(range(0, n).map(x => [x, 'test']), events) - }) -]) - -export const countTests = describe('count', [ - it('replaces events with 1-based count', async ({ equal }) => { - const n = randomInt(10, 20) - const events = await collect(n, count(periodic(1))) - equal(range(1, n), events) - }) -]) - -export const withCountTests = describe('withCount', [ - it('pairs events with 1-based count', async ({ equal }) => { - const n = randomInt(10, 20) - const events = await collect(n, withCount(constant('test', periodic(1)))) - equal(range(1, n).map(x => [x, 'test']), events) - }) -]) - -export const withIndexStartTests = describe('withIndexStart', [ - it('pairs events with start-based index', async ({ equal }) => { - const start = randomInt(0, 10000) - const n = randomInt(10, 20) - const events = await collect(n, withIndexStart(start, constant('test', periodic(1)))) - equal(range(start, n).map(x => [x, 'test']), events) - }) -]) - -export const indexedTests = describe('indexed', [ - it('pairs events with computed index', async ({ equal }) => { - const n = randomInt(10, 20) - - const s = Array(n).fill('a').join('') - const expected = range(0, n).map((_, i) => [s.slice(0, i), 'test']) - - const stringIndex = (s: string) => (prev: string): [string, string] => - [prev, prev + s] - - const events = await collect(n, indexed(stringIndex('a'), '', constant('test', periodic(1)))) - equal(expected, events) - }) -]) - -export const keepIndexTests = describe('keepIndex', [ - it('keeps index and discards value', async ({ equal }) => { - const start = randomInt(0, 10000) - const n = randomInt(10, 20) - const events = await collect(n, keepIndex(withIndexStart(start, constant('test', periodic(1))))) - equal(range(start, n), events) - }) -]) \ No newline at end of file diff --git a/tsconfig.base.json b/tsconfig.base.json new file mode 100644 index 0000000..e80a90b --- /dev/null +++ b/tsconfig.base.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "es2015", + "moduleResolution": "node", + "lib": ["es2015", "es2016", "es2017"], + "declaration": true, + "sourceMap": true, + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitAny": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "allowSyntheticDefaultImports": true, + "esModuleInterop": true + }, + "exclude": ["node_modules", "src/**/*.__test__.ts"] +} diff --git a/tsconfig.json b/tsconfig.json index 7b8b447..8eeb7d6 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,31 +1,7 @@ { + "extends": "./tsconfig.base.json", "compilerOptions": { - "moduleResolution": "node", - "target": "es5", - "module": "es2015", - "lib": [ - "es5", - "es2015", - "es2016", - "es2017" - ], - "incremental": true, - "strict": true, - "sourceMap": true, - "declaration": true, - "declarationDir": "dist", - "outDir": "dist", - "typeRoots": [ - "node_modules/@types" - ] + "outDir": "dist" }, - "exclude": [ - "experiments/**/*.ts", - "examples/**/*.ts", - "node_modules", - "src/**/*.test.ts" - ], - "include": [ - "src" - ] + "include": ["src/**/*.ts"] } diff --git a/tsconfig.test.json b/tsconfig.test.json new file mode 100644 index 0000000..b9c47be --- /dev/null +++ b/tsconfig.test.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.base.json", + "compilerOptions": { + "lib": ["dom", "es2015", "es2016", "es2017"], + "outDir": "__test__" + }, + "include": ["src/**/*.__test__.ts"], + "exclude": ["node_modules"] +}