import * as assert from "assert" ; import { parseError } from "vscode-azureextensionui" ; import { stringify } from "./stringify" ; export namespace assertEx { type keyedObject = { [ key ] : unknown ; } ; export interface IEqualExOptions { /** If true, will only match against the properties in the expected object */ ignorePropertiesNotInExpected ? : boolean ; } export function strictEqual < T > ( actual , expected , options , message ? ) { if ( typeof actual === 'string' && typeof expected === 'string' ) { const actualNoWitespace = actual . replace ( /\s+/g , ' ' ) ; const expectedNoWhitespace = expected . replace ( /\s+/g , ' ' ) ; if ( expectedNoWhitespace === actualNoWitespace ) { assert . strictEqual ( actual , expected , `${ message ?? 'String match failed' }\n*** STRINGS DIFFER ONLY IN WHITESPACE ***` ) ; return ; } else if ( actual . toLowerCase ( ) === expected . toLowerCase ( ) ) { assert . strictEqual ( actual , expected , `${ message ?? 'String match failed' }\n*** STRINGS DIFFER ONLY IN CASING ***` ) ; return ; } } else if ( typeof actual === 'string' && expected instanceof RegExp ) { const match = expected . test ( actual ) ; if ( ! match ) { assert . fail ( `${ message }: String failed regex match` ) ; } return ; } assert . strictEqual ( actual , expected , message ) ; } export function arraysEqual < T > ( actual , expected , options , message ) { try { assert . equal ( actual . length , expected . length , `${ message }: Number of diagnostics does not match expected` ) ; for ( let i = 0 ; i < actual . length ; ++ i ) { strictEqual ( actual [ i ] , expected [ i ] , { } , `${ message }: Line ${ i + 1 } mismatch` ) ; } } catch ( error ) { const compare = 'EXPECTED:\n' + stringify ( expected . map ( s => ( < { } > s ) . toString ( ) ) ) + '\nACTUAL:\n' + stringify ( actual ) ; throw new Error ( parseError ( error ) . message + '\n' + compare ) ; } } export function deepEqual < T > ( actual , expected , options ) { let partial = actual ; if ( options . ignorePropertiesNotInExpected ) { partial = < Partial < T > > deepPartialClone ( actual , expected ) ; } assert . deepStrictEqual ( partial , expected ) ; } /**
     * Creates a deep clone of 'o' that includes only the (deep) properties of 'shape'
     */ function deepPartialClone ( o , shape ) { if ( Array . isArray ( o ) || Array . isArray ( shape ) ) { if ( ! ( Array . isArray ( o ) || Array . isArray ( shape ) ) ) { return o ; } const a = < unknown [ ] > o ; const arrayShape = < unknown [ ] > shape ; const newArray = [ ] ; for ( let i = 0 ; i < Math . max ( a . length , arrayShape . length ) ; ++ i ) { newArray [ i ] = deepPartialClone ( a [ i ] , arrayShape [ i ] ) ; } return newArray ; } else if ( shape instanceof Object && o instanceof Object ) { const clonedObject = < keyedObject > { } ; for ( const propName of Object . getOwnPropertyNames ( shape ) ) { clonedObject [ propName ] = deepPartialClone ( ( < keyedObject > o ) [ propName ] , ( < keyedObject > shape ) [ propName ] ) ; } return clonedObject ; } else { return o ; } } }