import { IFluidHandle } from '@fluidframework/core-interfaces' ; import { FluidSerializer } from '@fluidframework/shared-object-base' ; import { MockFluidDataStoreRuntime } from '@fluidframework/test-runtime-utils' ; import { expect } from 'chai' ; import { comparePayloads } from '../Common' ; import { Payload } from '../generic' ; describe ( 'SnapshotUtilities' , ( ) => { describe ( 'comparePayloads' , ( ) => { const serializer = new FluidSerializer ( new MockFluidDataStoreRuntime ( ) . IFluidHandleContext , ( ) => { } ) ; const binder = { bind : ( ) => void { } } as unknown as IFluidHandle ; enum Equality { Equal , Unequal , Unspecified } function checkEquality ( equal , equality ) { if ( equality !== Equality . Unspecified ) { expect ( equal ) . equals ( equality === Equality . Equal ) ; } } function check ( a , b , flags ) { expect ( comparePayloads ( a , a ) ) . equal ( true ) ; expect ( comparePayloads ( b , b ) ) . equal ( true ) ; checkEquality ( comparePayloads ( a , b ) , flags . initial ) ; checkEquality ( comparePayloads ( b , a ) , flags . initial ) ; const [ aString , aDeserialized ] = checkSerialization ( a , flags . roundtrip ) ; const [ bString , bDeserialized ] = checkSerialization ( b , flags . roundtrip ) ; checkEquality ( aString === bString , flags . serialized ) ; checkEquality ( comparePayloads ( aDeserialized , bDeserialized ) , flags . deserialized ) ; checkEquality ( comparePayloads ( bDeserialized , aDeserialized ) , flags . deserialized ) ; } function checkSerialization ( a , roundtrip ) { const aString = serializer . stringify ( a , binder ) ; const a2 = serializer . parse ( aString ) ; const aString2 = serializer . stringify ( a2 , binder ) ; expect ( aString2 ) . equal ( aString ) ; checkEquality ( comparePayloads ( a , a2 ) , roundtrip ) ; const a3 = serializer . parse ( aString2 ) ; expect ( comparePayloads ( a3 , a2 ) ) . true ; return [ aString , a2 ] ; } const allEqual = { initial : Equality . Equal , serialized : Equality . Equal , deserialized : Equality . Equal , roundtrip : Equality . Equal } ; const allEqualUnstable = { initial : Equality . Equal , serialized : Equality . Unspecified , deserialized : Equality . Equal , roundtrip : Equality . Equal } ; const allUnequal = { initial : Equality . Unequal , serialized : Equality . Unequal , deserialized : Equality . Unequal , roundtrip : Equality . Equal } ; it ( 'compares numbers correctly' , ( ) => { check ( 0 , 0 , allEqual ) ; check ( 1 , 1 , allEqual ) ; check ( 0 , 1 , allUnequal ) ; check ( - 1 , 1 , allUnequal ) ; check ( 5.2 , 5.200000001 , allUnequal ) ; } ) ; it ( 'compares strings' , ( ) => { check ( '' , '' , allEqual ) ; check ( ' ' , '' , allUnequal ) ; check ( '1' , '+1' , allUnequal ) ; check ( '𤭢' , '𤭢' , allEqual ) ; check ( '𤭢' , '' , allUnequal ) ; check ( 'several characters' , 'several characters' , allEqual ) ; check ( 'several characters' , 'several_characters' , allUnequal ) ; } ) ; it ( 'compares arrays' , ( ) => { check ( [ ] , [ ] , allEqual ) ; check ( [ 1 ] , [ 1 ] , allEqual ) ; check ( [ [ 1 ] ] , [ [ 1 ] ] , allEqual ) ; check ( [ [ 1 ] ] , [ [ 2 ] ] , allUnequal ) ; check ( [ ] , [ 1 ] , allUnequal ) ; check ( [ 1 , 2 ] , [ 2 , 1 ] , allUnequal ) ; } ) ; it ( 'compares objects' , ( ) => { check ( { 1 : 'x' } , { 1 : 'x' } , allEqual ) ; check ( { x : 'x' } , { y : 'x' } , allUnequal ) ; check ( { x : 'x' } , { x : { } } , allUnequal ) ; check ( { x : { } } , { x : { } } , allEqual ) ; check ( { x : [ 1 , 2 , 3 , 5 ] } , { x : [ 1 , 2 , 3 , 4 ] } , allUnequal ) ; check ( { 1 : 'x' } , { } , allUnequal ) ; check ( { x : 'x' } , { x : 'x' , y : 'x' } , allUnequal ) ; check ( { field : 'a' } , { field : 'b' } , allUnequal ) ; check ( { y : 'a' , x : 'b' } , { x : 'b' , y : 'a' } , allEqualUnstable ) ; } ) ; it ( 'compares mixed types' , ( ) => { check ( { 0 : 1 } , [ 1 ] , allUnequal ) ; check ( null , 'null' , allUnequal ) ; check ( null , 'null' , allUnequal ) ; check ( 1 , '1' , allUnequal ) ; check ( null , 0 , allUnequal ) ; check ( '' , 0 , allUnequal ) ; } ) ; const sameAfter = { initial : Equality . Unspecified , serialized : Equality . Unspecified , deserialized : Equality . Equal , roundtrip : Equality . Unspecified } ; const differentAfter = { initial : Equality . Unequal , serialized : Equality . Unequal , deserialized : Equality . Unequal , roundtrip : Equality . Unspecified } ; it ( 'lossy cases' , ( ) => { check ( { x : undefined } , { y : undefined } , sameAfter ) ; check ( { x : undefined } , { } , sameAfter ) ; check ( NaN , NaN , sameAfter ) ; check ( NaN , 7 , differentAfter ) ; check ( Infinity , Infinity , sameAfter ) ; check ( - Infinity , Infinity , sameAfter ) ; check ( NaN , 'NaN' , differentAfter ) ; check ( - 0 , - 0 , sameAfter ) ; } ) ; it ( 'compares handles' , ( ) => { function makeMockHandle ( data ) { const handleObject = { absolutePath : data , IFluidHandle : undefined as unknown } ; handleObject . IFluidHandle = handleObject ; const handle = handleObject as IFluidHandle ; const serialized = serializer . stringify ( handle , binder ) ; const finalHandle = serializer . parse ( serialized ) ; return finalHandle ; } check ( makeMockHandle ( 'x' ) , makeMockHandle ( 'x' ) , allEqualUnstable ) ; check ( makeMockHandle ( 'x' ) , makeMockHandle ( 'y' ) , allUnequal ) ; check ( { x : makeMockHandle ( 'x' ) } , makeMockHandle ( 'x' ) , allUnequal ) ; } ) ; it . skip ( 'strange cases' , ( ) => { check ( undefined , null , sameAfter ) ; } ) ; } ) ; } ) ;