import { strict as assert } from "assert" ; import { MockFluidDataStoreRuntime } from "@fluidframework/test-runtime-utils" ; import { ISharedMap , SharedMap , MapFactory } from "@fluidframework/map" ; import { IFluidDataStoreContext } from "@fluidframework/runtime-definitions" ; import { createSharedMapWithInterception } from "../map" ; describe ( "Shared Map with Interception" , ( ) => { describe ( "Simple User Attribution" , ( ) => { /**
         * The following tests test simple user attribution in SharedMap with interception.
         * In the callback function of the SharedMap with inteception, it sets the user
         * attribution information in the underlying SharedMap against <key>.attribution.
         */ const userAttributes = { userId : "Fake User" } ; const documentId = "fakeId" ; const attributionKey = ( key ) => `${ key }.attribution` ; let sharedMap ; let dataStoreContext ; function orderSequentially ( callback ) { callback ( ) ; } function interceptionCb ( map , key , value ) { map . set ( attributionKey ( key ) , userAttributes ) ; } beforeEach ( ( ) => { const dataStoreRuntime = new MockFluidDataStoreRuntime ( ) ; sharedMap = new SharedMap ( documentId , dataStoreRuntime , MapFactory . Attributes ) ; dataStoreContext = { containerRuntime : { orderSequentially } } as IFluidDataStoreContext ; } ) ; function verifyMapAttribution ( map , key , value , props ? ) { assert . equal ( map . get ( key ) , value , "The retrieved value should match the value that was set" ) ; if ( props === undefined ) { assert . equal ( map . get ( attributionKey ( key ) ) , undefined , "The user attributes should not exist because there was no interception" ) ; } else { assert . deepEqual ( map . get ( attributionKey ( key ) ) , props , "The user attributes set via the interception callback should exist." ) ; } } it ( "should be able to intercept SharedMap set method in the wrapper" , async ( ) => { const sharedMapWithInterception = createSharedMapWithInterception ( sharedMap , dataStoreContext , interceptionCb ) ; const key = "color" ; const value = "green" ; sharedMapWithInterception . set ( key , value ) ; verifyMapAttribution ( sharedMapWithInterception , key , value , userAttributes ) ; } ) ; it ( "should be able to see changes made by the wrapper from the underlying shared map" , async ( ) => { const sharedMapWithInterception = createSharedMapWithInterception ( sharedMap , dataStoreContext , interceptionCb ) ; const key = "style" ; const value = "bold" ; sharedMapWithInterception . set ( key , value ) ; verifyMapAttribution ( sharedMap , key , value , userAttributes ) ; } ) ; it ( "should be able to see changes made by the underlying shared map from the wrapper" , async ( ) => { const sharedMapWithInterception = createSharedMapWithInterception ( sharedMap , dataStoreContext , interceptionCb ) ; const key = "font" ; const value = "Arial" ; sharedMap . set ( key , value ) ; verifyMapAttribution ( sharedMapWithInterception , key , value ) ; } ) ; /**
         * This test calls set on the wrapper from the interception callback which will cause an infinite
         * recursion. Verify that the wrapper detects this and asserts.
         * Also, verify that the object is not unusable after the assert.
         */ it ( "should assert if set is called on the wrapper from the callback causing infinite recursion" , async ( ) => { let sharedMapWithInterception ; let useWrapper = true ; function recursiveInterceptionCb ( map , key , value ) { const localMap = useWrapper ? sharedMapWithInterception : sharedMap ; localMap . set ( attributionKey ( key ) , userAttributes ) ; } sharedMapWithInterception = createSharedMapWithInterception ( sharedMap , dataStoreContext , recursiveInterceptionCb ) ; let asserted = false ; try { sharedMapWithInterception . set ( "color" , "green" ) ; } catch ( error ) { assert . strictEqual ( error . message , "0x0c0" , "We should have caught an assert in replaceText because it detects an infinite recursion" ) ; asserted = true ; } assert . equal ( asserted , true , "The set call should have asserted because it detects inifinite recursion" ) ; useWrapper = false ; const colorKey = "color" ; const colorValue = "red" ; sharedMapWithInterception . set ( colorKey , colorValue ) ; verifyMapAttribution ( sharedMapWithInterception , colorKey , colorValue , userAttributes ) ; } ) ; } ) ; } ) ;