diff --git a/.gitignore b/.gitignore index c6f9a44..3258af1 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ .vscode/settings.json +lib/unit-tests/cache/ diff --git a/lib/unit-tests/__tests__/basic.test.ts b/lib/unit-tests/__tests__/basic.test.ts index 041516f..f59aad3 100644 --- a/lib/unit-tests/__tests__/basic.test.ts +++ b/lib/unit-tests/__tests__/basic.test.ts @@ -10,7 +10,7 @@ describe('Schema - Basic types', () => { 30 * 1000 ) test('Basic', async () => { - const validateSchema = await setupValidator() + const validateSchema = (await setupValidator()).validate // Basic expect( @@ -102,7 +102,7 @@ describe('Schema - Basic types', () => { ).toBe(null) }) test('Bad property', async () => { - const validateSchema = await setupValidator() + const validateSchema = (await setupValidator()).validate expect( validateSchema({ @@ -121,7 +121,7 @@ describe('Schema - Basic types', () => { // "object" test('Property: boolean', async () => { - const validateSchema = await setupValidator() + const validateSchema = (await setupValidator()).validate expect( validateSchema({ @@ -147,7 +147,7 @@ describe('Schema - Basic types', () => { ).toMatch(/not.*boolean/) }) test('Property: string', async () => { - const validateSchema = await setupValidator() + const validateSchema = (await setupValidator()).validate expect( validateSchema({ @@ -177,7 +177,7 @@ describe('Schema - Basic types', () => { // "pattern": Regular Expression, }) test('Property: number', async () => { - const validateSchema = await setupValidator() + const validateSchema = (await setupValidator()).validate expect( validateSchema({ @@ -209,7 +209,7 @@ describe('Schema - Basic types', () => { // "exclusiveMinimum": number, }) test('Property: integer', async () => { - const validateSchema = await setupValidator() + const validateSchema = (await setupValidator()).validate expect( validateSchema({ @@ -241,7 +241,7 @@ describe('Schema - Basic types', () => { // "exclusiveMinimum": number, }) test('Property: array', async () => { - const validateSchema = await setupValidator() + const validateSchema = (await setupValidator()).validate expect( validateSchema({ @@ -320,7 +320,7 @@ describe('Schema - Basic types', () => { // "minContains": number }) test('Property: object', async () => { - const validateSchema = await setupValidator() + const validateSchema = (await setupValidator()).validate expect( validateSchema({ diff --git a/lib/unit-tests/__tests__/gddTypes/_ensure-all-gddTypes.test.ts b/lib/unit-tests/__tests__/gddTypes/_ensure-all-gddTypes.test.ts new file mode 100644 index 0000000..e3e5d0e --- /dev/null +++ b/lib/unit-tests/__tests__/gddTypes/_ensure-all-gddTypes.test.ts @@ -0,0 +1,99 @@ +import { promises as fs } from 'fs' +import { setupValidator } from '../lib/validator' + +test('Ensure that all GDDTypes in README exist and passes validation', async () => { + let validatedTypeCount = 0 + let validatedExampleCount = 0 + + // Gather all GDDTypes from README: + const readme = await fs.readFile('../../README.md', 'utf8') + + const iStart = readme.indexOf('## GDD Types') + if (iStart === -1) throw new Error('Could not find "## GDD Types" in README.md') + const iEnd = readme.indexOf('\n## ', iStart + 1) + if (iEnd === -1) throw new Error('Could not find next heading after "## GDD Types" in README.md') + + /** String containing the GDD Types */ + const readmeGDDTypes = readme.slice(iStart + 13, iEnd) + + /** Array of headers */ + const mentionedGDDTypes = readmeGDDTypes.match(/\n### (.*)\n/g) + if (!mentionedGDDTypes) throw new Error('Could not find any GDDTypes in README.md') + + const definitions: { name: string; index: number; ignore: boolean }[] = [] + for (const mentionedGDDType of mentionedGDDTypes) { + const m = mentionedGDDType.match(/\n### (.*)\n/) + if (!m) throw new Error(`Error regexing "${mentionedGDDType}"`) + + const name = m[1] + let ignore = false + + if (name.includes('Private GDD Types')) ignore = true + + const iType = readmeGDDTypes.indexOf(mentionedGDDType) + if (iType === -1) throw new Error(`Error finding "${mentionedGDDType}"`) + + definitions.push({ name, index: iType, ignore }) + } + + const { validate: validateSchema, cache } = await setupValidator() + if (!cache) throw new Error('cache object is null') + const cacheStr = JSON.stringify(cache) + + for (let i = 0; i < definitions.length; i++) { + const definition = definitions[i] + + if (definition.ignore) continue + + const iType = definition.index + const iNext = definitions[i + 1]?.index || readmeGDDTypes.length + + const typeStr = readmeGDDTypes.slice(iType, iNext) + + // Gather schema examples: + const typeExamples = typeStr.match(/```(typescript|json)([\w\W]*?)```/gm) + if (!typeExamples) throw new Error(`Could not find any examples for "${definition.name}"`) + + let hasExamples = false + for (const typeExample of typeExamples) { + let str = typeExample.replace(/^.+?\n/, '') // remove first line "```typescript" + str = str.replace(/```$/, '') // remove last line "```" + str = str.replace(/[Optional] \/\/.*/g, '') // Remove inline comments + str = str.replace(/\/\/.*/g, '') // Remove inline comments + + const gddTypeNameMatch = str.match(/"gddType": "(.*)"/) + if (!gddTypeNameMatch) throw new Error(`Could not find "gddType" in "${str}"`) + const gddTypeName = gddTypeNameMatch[1] + + // Ensure that gddTypeName exists in schema: + if (!cacheStr.includes(`{"gddType":{"const":"${gddTypeName}"}}`)) { + throw new Error(`Could not find "${gddTypeName}" in schema`) + } + + try { + const json = JSON.parse(str) + + expect( + validateSchema({ + type: 'object', + properties: { + f0: json, + }, + }) + ).toBe(null) + validatedExampleCount++ + hasExamples = true + } catch (e) { + if (e instanceof Error) { + e.message = `Error parsing example for "${str}": ${e.message}` + } + console.log(typeStr) + throw e + } + } + if (hasExamples) validatedTypeCount++ + } + + expect(validatedExampleCount).toBeGreaterThanOrEqual(10) + expect(validatedTypeCount).toBeGreaterThanOrEqual(8) +}) diff --git a/lib/unit-tests/__tests__/gddTypes/_private-gddTypes.test.ts b/lib/unit-tests/__tests__/gddTypes/_private-gddTypes.test.ts index 935cc20..92444b6 100644 --- a/lib/unit-tests/__tests__/gddTypes/_private-gddTypes.test.ts +++ b/lib/unit-tests/__tests__/gddTypes/_private-gddTypes.test.ts @@ -1,7 +1,7 @@ import { setupValidator } from '../lib/validator' test('gddType: non-standard', async () => { - const validateSchema = await setupValidator() + const validateSchema = (await setupValidator()).validate expect( validateSchema({ diff --git a/lib/unit-tests/__tests__/gddTypes/color-rrggbb.test.ts b/lib/unit-tests/__tests__/gddTypes/color-rrggbb.test.ts index ffa94e3..a9a75b7 100644 --- a/lib/unit-tests/__tests__/gddTypes/color-rrggbb.test.ts +++ b/lib/unit-tests/__tests__/gddTypes/color-rrggbb.test.ts @@ -1,7 +1,7 @@ import { setupValidator } from '../lib/validator' test('gddType: color-rrggbb', async () => { - const validateSchema = await setupValidator() + const validateSchema = (await setupValidator()).validate expect( validateSchema({ diff --git a/lib/unit-tests/__tests__/gddTypes/duration-ms.test.ts b/lib/unit-tests/__tests__/gddTypes/duration-ms.test.ts index 85eacb3..817f385 100644 --- a/lib/unit-tests/__tests__/gddTypes/duration-ms.test.ts +++ b/lib/unit-tests/__tests__/gddTypes/duration-ms.test.ts @@ -1,7 +1,7 @@ import { setupValidator } from '../lib/validator' test('gddType: duration-ms', async () => { - const validateSchema = await setupValidator() + const validateSchema = (await setupValidator()).validate expect( validateSchema({ diff --git a/lib/unit-tests/__tests__/gddTypes/file-path.test.ts b/lib/unit-tests/__tests__/gddTypes/file-path.test.ts index 2a1c386..eca8f33 100644 --- a/lib/unit-tests/__tests__/gddTypes/file-path.test.ts +++ b/lib/unit-tests/__tests__/gddTypes/file-path.test.ts @@ -1,7 +1,7 @@ import { setupValidator } from '../lib/validator' test('gddType: file-path', async () => { - const validateSchema = await setupValidator() + const validateSchema = (await setupValidator()).validate expect( validateSchema({ diff --git a/lib/unit-tests/__tests__/gddTypes/image-path.test.ts b/lib/unit-tests/__tests__/gddTypes/image-path.test.ts index 3710e48..84799ab 100644 --- a/lib/unit-tests/__tests__/gddTypes/image-path.test.ts +++ b/lib/unit-tests/__tests__/gddTypes/image-path.test.ts @@ -1,7 +1,7 @@ import { setupValidator } from '../lib/validator' test('gddType: image-file-path', async () => { - const validateSchema = await setupValidator() + const validateSchema = (await setupValidator()).validate expect( validateSchema({ diff --git a/lib/unit-tests/__tests__/gddTypes/multi-line.test.ts b/lib/unit-tests/__tests__/gddTypes/multi-line.test.ts index 787844d..a85774b 100644 --- a/lib/unit-tests/__tests__/gddTypes/multi-line.test.ts +++ b/lib/unit-tests/__tests__/gddTypes/multi-line.test.ts @@ -1,7 +1,7 @@ import { setupValidator } from '../lib/validator' test('gddType: multi-line', async () => { - const validateSchema = await setupValidator() + const validateSchema = (await setupValidator()).validate expect( validateSchema({ diff --git a/lib/unit-tests/__tests__/gddTypes/percentage.test.ts b/lib/unit-tests/__tests__/gddTypes/percentage.test.ts index 7c74270..b69ff66 100644 --- a/lib/unit-tests/__tests__/gddTypes/percentage.test.ts +++ b/lib/unit-tests/__tests__/gddTypes/percentage.test.ts @@ -1,7 +1,7 @@ import { setupValidator } from '../lib/validator' test('gddType: percentage', async () => { - const validateSchema = await setupValidator() + const validateSchema = (await setupValidator()).validate expect( validateSchema({ diff --git a/lib/unit-tests/__tests__/gddTypes/select.test.ts b/lib/unit-tests/__tests__/gddTypes/select.test.ts index c5ba45e..298e670 100644 --- a/lib/unit-tests/__tests__/gddTypes/select.test.ts +++ b/lib/unit-tests/__tests__/gddTypes/select.test.ts @@ -1,7 +1,7 @@ import { setupValidator } from '../lib/validator' test('gddType: select', async () => { - const validateSchema = await setupValidator() + const validateSchema = (await setupValidator()).validate expect( validateSchema({ diff --git a/lib/unit-tests/__tests__/gddTypes/single-line.test.ts b/lib/unit-tests/__tests__/gddTypes/single-line.test.ts index ae5780e..9cd810d 100644 --- a/lib/unit-tests/__tests__/gddTypes/single-line.test.ts +++ b/lib/unit-tests/__tests__/gddTypes/single-line.test.ts @@ -1,7 +1,7 @@ import { setupValidator } from '../lib/validator' test('gddType: single-line', async () => { - const validateSchema = await setupValidator() + const validateSchema = (await setupValidator()).validate expect( validateSchema({ diff --git a/lib/unit-tests/__tests__/lib/validator.ts b/lib/unit-tests/__tests__/lib/validator.ts index 69929e4..28d846c 100644 --- a/lib/unit-tests/__tests__/lib/validator.ts +++ b/lib/unit-tests/__tests__/lib/validator.ts @@ -2,11 +2,10 @@ import * as path from 'path' import * as fs from 'fs' import fetch from 'node-fetch' /* eslint-disable node/no-unpublished-import */ -import { SchemaValidator, setupSchemaValidator } from '../../../javascript-library' - -export async function setupValidator(): Promise { - const cachePath = path.resolve('./__cache.json') +import { SchemaValidator, ValidatorCache, setupSchemaValidator } from '../../../javascript-library' +export async function setupValidator(): Promise<{ validate: SchemaValidator; cache: ValidatorCache | null }> { + const cachePath = getCachePath() const { validate, cache } = await setupSchemaValidator({ getCache: async () => { if (await fileExists(cachePath)) { @@ -39,7 +38,15 @@ export async function setupValidator(): Promise { await fs.promises.writeFile(cachePath, JSON.stringify(cache), 'utf-8') } - return validate + return { validate, cache } +} + +export async function clearValidatorCache(): Promise { + await fs.promises.unlink(getCachePath()) +} + +function getCachePath(): string { + return path.resolve('./__cache.json') } async function fileExists(filePath: string): Promise { diff --git a/lib/unit-tests/__tests__/playout-options.test.ts b/lib/unit-tests/__tests__/playout-options.test.ts index 7c1e37c..ad2caa5 100644 --- a/lib/unit-tests/__tests__/playout-options.test.ts +++ b/lib/unit-tests/__tests__/playout-options.test.ts @@ -1,7 +1,7 @@ import { setupValidator } from './lib/validator' test('gddPlayoutOptions.client', async () => { - const validateSchema = await setupValidator() + const validateSchema = (await setupValidator()).validate // Minimal object: expect( @@ -110,7 +110,7 @@ test('gddPlayoutOptions.client', async () => { ).toMatch(/is not.*json/) }) test('gddPlayoutOptions.playout', async () => { - const validateSchema = await setupValidator() + const validateSchema = (await setupValidator()).validate // Minimal object: expect(