import type AjvJTD from "../dist/jtd" ; import type { SchemaObject , JTDParser } from "../dist/jtd" ; import _AjvJTD from "./ajv_jtd" ; import getAjvInstances from "./ajv_instances" ; import { withStandalone } from "./ajv_standalone" ; import jtdValidationTests = require ( "./json-typedef-spec/tests/validation.json" ) ; import jtdInvalidSchemasTests = require ( "./json-typedef-spec/tests/invalid_schemas.json" ) ; import jsonParseTests = require ( "./json_parse_tests.json" ) ; import assert = require ( "assert" ) ; import AjvPack from "../dist/standalone/instance" ; interface TestCase { schema : SchemaObject ; instance : unknown ; errors : TestCaseError [ ] ; } interface TestCaseError { instancePath : string [ ] ; schemaPath : string [ ] ; } interface JSONParseTest { name : string ; valid : boolean | null ; json : string ; data ? : unknown ; only ? : boolean ; skip ? : boolean ; } interface JSONParseTestSuite { suite : string ; tests : JSONParseTest [ ] ; } interface JTDError { instancePath : string ; schemaPath : string ; } const ONLY = [ ] ; describe ( "JSON Type Definition" , ( ) => { describe ( "validation" , function ( ) { this . timeout ( 10000 ) ; let ajvs ; before ( ( ) => { ajvs = getAjvInstances ( _AjvJTD , { allErrors : true , inlineRefs : false , code : { es5 : true , lines : true , optimize : false } , } ) as AjvJTD [ ] ; ajvs . forEach ( ( ajv ) => ( ajv . opts . code . source = true ) ) ; } ) ; for ( const testName in jtdValidationTests ) { const { schema , instance , errors } = jtdValidationTests [ testName ] as TestCase ; const valid = errors . length === 0 ; describeOnly ( testName , ( ) => it ( `should be ${ valid ? "valid" : "invalid" }` , ( ) => withStandalone ( ajvs ) . forEach ( ( ajv ) => { assert . strictEqual ( ajv . validate ( schema , instance ) , valid ) ; const opts = ajv instanceof AjvPack ? ajv . ajv . opts : ajv . opts ; if ( opts . allErrors ) { assert . deepStrictEqual ( cleanErrors ( ajv . errors ) , valid ? null : convertErrors ( errors ) ) ; } } ) ) ) ; } function cleanErrors ( errors ? ) { if ( errors ) { return sortErrors ( errors . map ( ( { instancePath , schemaPath } ) => ( { instancePath , schemaPath } ) ) ) ; } return errors ; } function convertErrors ( errors ) { return sortErrors ( errors . map ( ( e ) => ( { instancePath : jsonPointer ( e . instancePath ) , schemaPath : jsonPointer ( e . schemaPath ) , } ) ) ) ; } function sortErrors ( errors ? ) { if ( errors ) { errors . sort ( ( e1 , e2 ) => e1 . schemaPath . localeCompare ( e2 . schemaPath ) || e1 . instancePath . localeCompare ( e2 . instancePath ) ) ; } return errors ; } function jsonPointer ( error ) { return error . map ( ( s ) => `/${ s }` ) . join ( "" ) ; } } ) ; describe ( "invalid schemas" , ( ) => { let ajv ; before ( ( ) => ( ajv = new _AjvJTD ( ) ) ) ; for ( const testName in jtdInvalidSchemasTests ) { const schema = jtdInvalidSchemasTests [ testName ] ; describe ( testName , ( ) => it ( "should be invalid schema" , ( ) => assert . throws ( ( ) => ajv . compile ( schema ) ) ) ) ; } } ) ; describe ( "serialize" , ( ) => { const ajv = new _AjvJTD ( ) ; for ( const testName in jtdValidationTests ) { const { schema , instance , errors } = jtdValidationTests [ testName ] as TestCase ; const valid = errors . length === 0 ; if ( ! valid ) continue ; describe ( testName , ( ) => it ( `should serialize data` , ( ) => { const serialize = ajv . compileSerializer ( schema ) ; assert . deepStrictEqual ( JSON . parse ( serialize ( instance ) ) , instance ) ; } ) ) ; } } ) ; describe ( "parse" , ( ) => { let ajv ; before ( ( ) => ( ajv = new _AjvJTD ( ) ) ) ; for ( const testName in jtdValidationTests ) { const { schema , instance , errors } = jtdValidationTests [ testName ] as TestCase ; const valid = errors . length === 0 ; describeOnly ( testName , ( ) => { if ( valid ) { it ( `should parse valid JSON string` , ( ) => { const parse = ajv . compileParser ( schema ) ; shouldParse ( parse , JSON . stringify ( instance ) , instance ) ; shouldParse ( parse , `  ${ JSON . stringify ( instance , null , 2 ) }  ` , instance ) ; } ) ; } else { it ( `should return undefined on invalid JSON string` , ( ) => { const parse = ajv . compileParser ( schema ) ; shouldFail ( parse , JSON . stringify ( instance ) ) ; shouldFail ( parse , `  ${ JSON . stringify ( instance , null , 2 ) }  ` ) ; } ) ; } } ) ; } } ) ; describe ( "parse tests nst/JSONTestSuite" , ( ) => { const ajv = new _AjvJTD ( ) ; const parseJson = ajv . compileParser ( { } ) ; const parse = { string : ajv . compileParser ( { elements : { type : "string" } } ) , number : ajv . compileParser ( { elements : { type : "float64" } } ) , array : ajv . compileParser ( { elements : { } } ) , object : ajv . compileParser ( { values : { } } ) , } ; for ( const { suite , tests } of jsonParseTests as JSONParseTestSuite [ ] ) { describe ( suite , ( ) => { for ( const test of tests ) { const { valid , name , json , data } = test ; if ( valid ) { it ( `should parse ${ name }` , ( ) => shouldParse ( parseJson , json , data ) ) ; if ( suite in parse ) { _it ( test ) ( `should parse as ${ suite }: ${ name }` , ( ) => shouldParse ( parse [ suite ] , json , data ) ) ; } } else if ( valid === false ) { it ( `should fail parsing ${ name }` , ( ) => shouldFail ( parseJson , json ) ) ; if ( suite in parse ) { _it ( test ) ( `should fail parsing as ${ suite }: ${ name }` , ( ) => shouldFail ( parse [ suite ] , json ) ) ; } } } } ) ; } } ) ; } ) ; type TestFunc = typeof it | typeof it . only | typeof it . skip ; function _it ( { only , skip } ) { return skip ? it . skip : only ? it . only : it ; } function shouldParse ( parse , str , res ) { assert . deepStrictEqual ( parse ( str ) , res ) ; assert . strictEqual ( parse . message , undefined ) ; assert . strictEqual ( parse . position , undefined ) ; } function shouldFail ( parse , str ) { assert . strictEqual ( parse ( str ) , undefined ) ; assert . strictEqual ( typeof parse . message , "string" ) ; assert . strictEqual ( typeof parse . position , "number" ) ; } function describeOnly ( name , func ) { if ( ONLY . length === 0 || ONLY . some ( ( p ) => p . test ( name ) ) ) { describe ( name , func ) ; } else { describe . skip ( name , func ) ; } }