From da40b220d9a8e1d1fb63ac9f0a9ab198c182b1a8 Mon Sep 17 00:00:00 2001 From: Guido Scialfa Date: Thu, 29 Feb 2024 23:37:19 +0100 Subject: [PATCH] Set content is not completely unique We do not want to have duplicate in our Set, therefore whenever we create a new instance of a Set we do not include in the collection existing elements. Fix #29 --- sources/client/src/models/set.ts | 19 +++++++++++++++++-- tests/client/unit/models/set.test.ts | 9 ++++++++- .../unit/utils/unique-control-options.test.ts | 2 +- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/sources/client/src/models/set.ts b/sources/client/src/models/set.ts index d6a2ca7..0469762 100644 --- a/sources/client/src/models/set.ts +++ b/sources/client/src/models/set.ts @@ -7,7 +7,7 @@ export class Set< T > { readonly #data: ReadonlyArray< T >; public constructor( data: ReadonlyArray< T > = [] ) { - this.#data = data; + this.#data = this.ensureUniqueness( data ); } public add( value: T ): Set< T > { @@ -29,7 +29,7 @@ export class Set< T > { } public has( value: T ): boolean { - return this.#data.some( ( current ) => this.isEqual( current, value ) ); + return this._has( value, this.#data ); } public map< R = T >( fn: ( value: T ) => R ): Set< R > { @@ -99,4 +99,19 @@ export class Set< T > { private isEqual( a: unknown, b: unknown ): boolean { return _isEqual( a, b ); } + + private _has( value: T, data: ReadonlyArray< T > ): boolean { + return data.some( ( current ) => this.isEqual( current, value ) ); + } + + private ensureUniqueness( data: ReadonlyArray< T > ): ReadonlyArray< T > { + const accumulator: Array< T > = []; + return data.reduce( ( acc, value ) => { + if ( ! this._has( value, acc ) ) { + acc.push( value ); + } + + return acc; + }, accumulator ); + } } diff --git a/tests/client/unit/models/set.test.ts b/tests/client/unit/models/set.test.ts index a0e77c6..2419d4c 100644 --- a/tests/client/unit/models/set.test.ts +++ b/tests/client/unit/models/set.test.ts @@ -37,7 +37,7 @@ describe( 'Set', () => { const set1 = set.add( 1 ).add( 2 ).add( 3 ); const set2 = set.add( 2 ).add( 3 ).add( 4 ); const concat = set1.concat( set2 ); - expect( concat.length() ).toBe( 6 ); + expect( concat.length() ).toBe( 4 ); expect( concat.has( 1 ) ).toBe( true ); expect( concat.has( 2 ) ).toBe( true ); expect( concat.has( 3 ) ).toBe( true ); @@ -202,4 +202,11 @@ describe( 'Set', () => { .add( 6 ); expect( set.equals( set2 ) ).toBe( false ); } ); + + it( 'Should ensure concatenating two sets keep uniqueness', () => { + const set1 = new Set< any >().add( { a: { a1: 1 } } ).add( { b: 2 } ); + const set2 = new Set< any >().add( { a: { a1: 1 } } ).add( { b: 2 } ); + const concat = set1.concat( set2 ); + expect( concat.length() ).toBe( 2 ); + } ); } ); diff --git a/tests/client/unit/utils/unique-control-options.test.ts b/tests/client/unit/utils/unique-control-options.test.ts index 8d2ee40..02eb93a 100644 --- a/tests/client/unit/utils/unique-control-options.test.ts +++ b/tests/client/unit/utils/unique-control-options.test.ts @@ -20,7 +20,7 @@ describe( 'Unique Control Options', () => { { label: 'bar', value: 'bar' }, ] ); - expect( set.length() ).toBe( 4 ); + expect( set.length() ).toBe( 2 ); const uniqueSet = uniqueControlOptions( set ); expect( uniqueSet.length() ).toBe( 2 ); expect( uniqueSet.first()?.value ).toBe( 'foo' );