import { toIncludeComparison } from "./comparison/toIncludeComparison" ; import { toIncludeEqualComparison } from "./comparison/toIncludeEqualComparison" ; import { Actual } from "./Actual" ; import { Expected } from "./Expected" ; import { assert } from "./assert" ; @ external ( "__aspect" , "tryCall" ) declare function tryCall ( func ) ; @ global export class Expectation < T > { /**
     * This i32 is set to 1 if the expectation is negated. Using the _not (xor) condition assertion
     * makes assertions very easy to write and understand.
     */ _not : i32 = 0 ; actual : T ; constructor ( actual ) { this . actual = actual ; } public get not ( ) : Expectation < T > { this . _not = 1 ; return this ; } public toBe ( expected , message = "" ) { let actual = this . actual ; let equals = i32 ( actual == expected ) ; let negated = this . _not ; Actual . report ( actual ) ; if ( isReference ( actual ) && ! isFunction ( actual ) ) { if ( ! negated && changetype < usize > ( actual ) !== 0 && changetype < usize > ( expected ) !== 0 && Reflect . equals ( actual , expected ) == Reflect . SUCCESSFUL_MATCH ) { Expected . report ( "Serializes to same value." , 0 ) ; } else { Expected . report ( expected , negated ) ; } } else { Expected . report ( expected , negated ) ; } assert ( equals ^ negated , message ) ; Actual . clear ( ) ; Expected . clear ( ) ; } public toStrictEqual ( expected , message = "" ) { let result = Reflect . FAILED_MATCH ; result = Reflect . equals ( this . actual , expected ) ; let equals = i32 ( result == Reflect . SUCCESSFUL_MATCH ) ; Actual . report ( this . actual ) ; Expected . report ( expected ) ; assert ( equals ^ this . _not , message ) ; Actual . clear ( ) ; Expected . clear ( ) ; } public toBlockEqual ( expected , message = "" ) { WARNING ( "toBlockEqual has been deprecated and results in a toStrictEqual call." ) ; this . toStrictEqual ( expected , message ) ; } public toBeTruthy ( message = "" ) { let actual = this . actual ; Actual . report ( actual ) ; let negated = this . _not ; Expected . reportTruthy ( negated ) ; if ( isReference ( actual ) ) { if ( actual instanceof String ) { let truthy = i32 ( changetype < usize > ( actual ) != 0 && changetype < string > ( actual ) . length > 0 ) ; assert ( truthy ^ negated , message ) ; } else { let truthy = i32 ( changetype < usize > ( actual ) != 0 ) ; assert ( truthy ^ negated , message ) ; } } else { if ( isFloat ( actual ) ) { let truthy = i32 ( ! isNaN ( actual ) && actual != 0.0 ) ; assert ( truthy ^ negated , message ) ; } else if ( isInteger ( actual ) ) { let truthy = i32 ( actual != 0 ) ; assert ( truthy ^ negated , message ) ; } } Actual . clear ( ) ; Expected . clear ( ) ; } public toBeFalsy ( message = "" ) { let actual = this . actual ; Actual . report ( actual ) ; let negated = this . _not ; Expected . reportFalsy ( negated ) ; if ( isReference ( actual ) ) { if ( actual instanceof String ) { let falsy = i32 ( changetype < usize > ( actual ) == 0 || changetype < string > ( actual ) . length == 0 ) ; assert ( falsy ^ negated , message ) ; } else { let falsy = i32 ( changetype < usize > ( actual ) == 0 ) ; assert ( falsy ^ negated , message ) ; } } else { if ( isFloat ( actual ) ) { let falsy = i32 ( isNaN ( actual ) || actual == 0.0 ) ; assert ( falsy ^ negated , message ) ; } else if ( isInteger ( actual ) ) { let falsy = i32 ( actual == 0 ) ; assert ( falsy ^ negated , message ) ; } } Actual . clear ( ) ; Expected . clear ( ) ; } public toThrow ( message = "" ) { let actual = this . actual ; let negated = this . _not ; if ( ! isFunction ( this . actual ) ) ERROR ( "Expectation#toThrow assertion called on actual T where T is not a function reference" ) ; if ( idof < T > ( ) != idof < ( ) => void > ( ) ) ERROR ( "Expectation#toThrow assertion called on actual T where T is not a function reference with signature () => void" ) ; let throws = i32 ( ! tryCall ( actual ) ) ; Actual . report ( throws ? "Throws" : "Not Throws" ) ; Expected . report ( "Throws" , negated ) ; assert ( negated ^ throws , message ) ; Actual . clear ( ) ; Expected . clear ( ) ; } public toBeGreaterThan ( expected , message = "" ) { let actual = this . actual ; let negated = this . _not ; Actual . report ( actual ) ; Expected . report ( expected , negated ) ; if ( ! isDefined ( actual > expected ) ) ERROR ( "Invalid call to toBeGreaterThan. Generic type T must have an operator implemented for the greaterThan (>) operation." ) ; if ( isReference ( actual ) ) { assert ( i32 ( changetype < usize > ( expected ) != 0 ) , "Value comparison fails, expected value is null." ) ; assert ( i32 ( changetype < usize > ( actual ) != 0 ) , "Value comparison fails, actual value is null." ) ; } if ( isFloat ( actual ) ) { assert ( i32 ( ! isNaN ( expected ) ) , "Value comparison fails, expected value is NaN." ) ; assert ( i32 ( ! isNaN ( actual ) ) , "Value comparison fails, actual value is NaN." ) ; } assert ( negated ^ i32 ( actual > expected ) , message ) ; Actual . clear ( ) ; Expected . clear ( ) ; } public toBeGreaterThanOrEqual ( expected , message = "" ) { let actual = this . actual ; let negated = this . _not ; Actual . report ( actual ) ; Expected . report ( expected , negated ) ; if ( ! isDefined ( actual >= expected ) ) ERROR ( "Invalid call to toBeGreaterThanOrEqual. Generic type T must have an operator implemented for the greaterThanOrEqual (>=) operation." ) ; if ( isReference ( actual ) ) { assert ( i32 ( changetype < usize > ( expected ) != 0 ) , "Value comparison fails, expected value is null." ) ; assert ( i32 ( changetype < usize > ( actual ) != 0 ) , "Value comparison fails, actual value is null." ) ; } if ( isFloat ( actual ) ) { assert ( i32 ( ! isNaN ( expected ) ) , "Value comparison fails, expected value is NaN." ) ; assert ( i32 ( ! isNaN ( actual ) ) , "Value comparison fails, actual value is NaN." ) ; } assert ( negated ^ i32 ( actual >= expected ) , message ) ; Actual . clear ( ) ; Expected . clear ( ) ; } public toBeLessThan ( expected , message = "" ) { let actual = this . actual ; let negated = this . _not ; Actual . report ( actual ) ; Expected . report ( expected , negated ) ; if ( ! isDefined ( actual < expected ) ) ERROR ( "Invalid call to toBeLessThan. Generic type T must have an operator implemented for the lessThan (<) operation." ) ; if ( isReference ( actual ) ) { assert ( i32 ( changetype < usize > ( expected ) != 0 ) , "Value comparison fails, expected value is null." ) ; assert ( i32 ( changetype < usize > ( actual ) != 0 ) , "Value comparison fails, actual value is null." ) ; } else if ( isFloat ( actual ) ) { assert ( i32 ( ! isNaN ( expected ) ) , "Value comparison fails, expected value is NaN." ) ; assert ( i32 ( ! isNaN ( actual ) ) , "Value comparison fails, actual value is NaN." ) ; } assert ( negated ^ i32 ( actual < expected ) , message ) ; Actual . clear ( ) ; Expected . clear ( ) ; } public toBeLessThanOrEqual ( expected , message = "" ) { let actual = this . actual ; let negated = this . _not ; Actual . report ( actual ) ; Expected . report ( expected , negated ) ; if ( ! isDefined ( actual > expected ) ) ERROR ( "Invalid call to toBeLessThanOrEqual. Generic type T must have an operator implemented for the lessThanOrEqual (<=) operation." ) ; if ( isReference ( actual ) ) { assert ( i32 ( changetype < usize > ( expected ) != 0 ) , "Value comparison fails, expected value is null." ) ; assert ( i32 ( changetype < usize > ( actual ) != 0 ) , "Value comparison fails, actual value is null." ) ; } if ( isFloat ( actual ) ) { assert ( i32 ( ! isNaN ( expected ) ) , "Value comparison fails, expected value is NaN." ) ; assert ( i32 ( ! isNaN ( actual ) ) , "Value comparison fails, actual value is NaN." ) ; } assert ( negated ^ i32 ( actual <= expected ) , message ) ; Actual . clear ( ) ; Expected . clear ( ) ; } public toBeNull ( message = "" ) { let negated = this . _not ; let actual = this . actual ; if ( actual instanceof usize ) { Actual . report ( actual ) ; Expected . report ( < usize > 0 , negated ) ; assert ( negated ^ i32 ( actual == 0 ) , message ) ; Actual . clear ( ) ; Expected . clear ( ) ; } else if ( isReference ( actual ) ) { Actual . report ( actual ) ; Expected . report ( changetype < T > ( 0 ) , negated ) ; assert ( negated ^ i32 ( changetype < usize > ( actual ) == 0 ) , message ) ; Actual . clear ( ) ; Expected . clear ( ) ; } else { ERROR ( "toBeNull assertion must be called with a reference type T or usize." ) ; } } public toBeCloseTo ( expected , decimalPlaces = 2 , message = "" ) { let actual = this . actual ; let negated = this . _not ; if ( ! isFloat ( actual ) ) ERROR ( "toBeCloseTo must be called with a Float value type T." ) ; Actual . report ( actual ) ; Expected . report ( expected , negated ) ; assert ( i32 ( isFinite ( actual ) ) , "toBeCloseTo assertion fails because a actual value is not finite" ) ; assert ( i32 ( isFinite ( expected ) ) , "toBeCloseTo assertion fails because expected value is not finite." ) ; let isClose = i32 ( abs ( expected - actual ) < Math . pow ( 10 , - decimalPlaces ) ) ; assert ( negated ^ isClose , message ) ; Actual . clear ( ) ; Expected . clear ( ) ; } public toBeNaN ( message = "" ) { let actual = this . actual ; let negated = this . _not ; if ( ! isFloat ( actual ) ) ERROR ( "toBeNaN must be called with a Float value type T." ) ; Actual . report ( actual ) ; Expected . report < T > ( NaN , negated ) ; let isNaNValue = i32 ( isNaN ( actual ) ) ; assert ( isNaNValue ^ negated , message ) ; Actual . clear ( ) ; Expected . clear ( ) ; } public toBeFinite ( message = "" ) { let actual = this . actual ; let negated = this . _not ; if ( ! isFloat ( actual ) ) ERROR ( "toBeNaN must be called with a Float value type T." ) ; Actual . report ( actual ) ; Expected . reportFinite ( negated ) ; let isFiniteValue = i32 ( isFinite ( actual ) ) ; assert ( isFiniteValue ^ negated , message ) ; Actual . clear ( ) ; Expected . clear ( ) ; } public toHaveLength ( expected , message = "" ) { let actual = this . actual ; let negated = this . _not ; let length = 0 ; if ( actual instanceof ArrayBuffer ) { length = actual . byteLength ; } else { if ( ! isDefined ( actual . length ) ) ERROR ( "toHaveLength cannot be called on type T where T.length is not defined." ) ; length = < i32 > actual . length ; } Actual . report ( length ) ; Expected . report ( expected , negated ) ; let lengthsEqual = i32 ( length == expected ) ; assert ( lengthsEqual ^ negated , message ) ; Actual . clear ( ) ; Expected . clear ( ) ; } public toInclude < U > ( expected , message = "" ) { toIncludeComparison < T , U > ( this . actual , expected , this . _not , message ) ; Actual . clear ( ) ; Expected . clear ( ) ; } public toContain ( expected , message = "" ) { this . toInclude ( expected , message ) ; } public toIncludeEqual < U > ( expected , message = "" ) { toIncludeEqualComparison < T , U > ( this . actual , expected , this . _not , message ) ; Actual . clear ( ) ; Expected . clear ( ) ; } public toContainEqual < U > ( expected , message = "" ) { this . toIncludeEqual ( expected , message ) ; } public toMatchSnapshot ( name = null ) { assert ( i32 ( ! this . _not ) , "Snapshots cannot be negated." ) ; Expected . reportSnapshot ( this . actual , name ) ; } } @ global export function expect < T > ( actual ) { return new Expectation ( actual ) ; } @ global export function expectFn ( cb ) { WARNING ( "expectFn() has been deprecated. Use expect() instead." ) ; return new Expectation ( cb ) ; }