@@ -20,7 +20,7 @@ describe('InternPoolStore', () => {
2020 let store : InternPoolStore ;
2121
2222 beforeEach ( ( ) => {
23- store = new InternPoolStore ( ) ;
23+ store = InternPoolStore . create ( ) ;
2424 } ) ;
2525
2626 it ( 'should add and get strings from the pool' , ( ) => {
@@ -62,4 +62,151 @@ describe('InternPoolStore', () => {
6262 'FieldPathSet ID 999 not found in pool' ,
6363 ) ;
6464 } ) ;
65+
66+ it ( 'should split buffer if the string size exceeds maxBufferSize' , ( ) => {
67+ const smallStore = InternPoolStore . create ( 10 ) ;
68+ smallStore . addStrings ( [
69+ { id : 1 , value : 'abcdefgh' } , // 8 bytes -> fits in 1st buffer
70+ { id : 2 , value : 'ijklmnop' } , // 8 bytes -> exceeds remaining 2 bytes, goes to 2nd buffer
71+ { id : 3 , value : 'qrstuvwxyz12345' } , // 15 bytes -> exceeds 10 bytes maxBufferSize, allocated standalone
72+ { id : 4 , value : 'abc' } , // 3 bytes -> fits in next buffer
73+ ] ) ;
74+
75+ expect ( smallStore . getString ( 1 ) ) . toBe ( 'abcdefgh' ) ;
76+ expect ( smallStore . getString ( 2 ) ) . toBe ( 'ijklmnop' ) ;
77+ expect ( smallStore . getString ( 3 ) ) . toBe ( 'qrstuvwxyz12345' ) ;
78+ expect ( smallStore . getString ( 4 ) ) . toBe ( 'abc' ) ;
79+ } ) ;
80+
81+ it ( 'should resize metadata TypedArrays when string ID is large' , ( ) => {
82+ store . addStrings ( [ { id : 2000 , value : 'large-id-string' } ] ) ;
83+
84+ expect ( store . getString ( 2000 ) ) . toBe ( 'large-id-string' ) ;
85+ } ) ;
86+
87+ it ( 'should allow reconstructing string values from getSharedData() buffers' , ( ) => {
88+ store . addStrings ( [
89+ { id : 10 , value : 'shared-string-1' } ,
90+ { id : 20 , value : 'shared-string-2' } ,
91+ ] ) ;
92+
93+ const sharedData = store . getSharedData ( ) ;
94+
95+ const localIndices = new Uint16Array (
96+ sharedData . metadataSab ,
97+ 0 ,
98+ sharedData . capacity ,
99+ ) ;
100+ const localOffsets = new Uint32Array (
101+ sharedData . metadataSab ,
102+ sharedData . capacity * 2 ,
103+ sharedData . capacity ,
104+ ) ;
105+ const localLengths = new Uint32Array (
106+ sharedData . metadataSab ,
107+ sharedData . capacity * 6 ,
108+ sharedData . capacity ,
109+ ) ;
110+
111+ const index10 = localIndices [ 10 ] - 1 ;
112+ const offset10 = localOffsets [ 10 ] ;
113+ const length10 = localLengths [ 10 ] ;
114+
115+ const buffer10 = new Uint8Array ( sharedData . bufferSabs [ index10 ] ) ;
116+ const bytes10 = buffer10 . subarray ( offset10 , offset10 + length10 ) ;
117+ const nonSharedBytes10 = new Uint8Array ( length10 ) ;
118+ nonSharedBytes10 . set ( bytes10 ) ;
119+ const decoder = new TextDecoder ( ) ;
120+
121+ expect ( decoder . decode ( nonSharedBytes10 ) ) . toBe ( 'shared-string-1' ) ;
122+
123+ const index20 = localIndices [ 20 ] - 1 ;
124+ const offset20 = localOffsets [ 20 ] ;
125+ const length20 = localLengths [ 20 ] ;
126+
127+ const buffer20 = new Uint8Array ( sharedData . bufferSabs [ index20 ] ) ;
128+ const bytes20 = buffer20 . subarray ( offset20 , offset20 + length20 ) ;
129+ const nonSharedBytes20 = new Uint8Array ( length20 ) ;
130+ nonSharedBytes20 . set ( bytes20 ) ;
131+
132+ expect ( decoder . decode ( nonSharedBytes20 ) ) . toBe ( 'shared-string-2' ) ;
133+ } ) ;
134+
135+ it ( 'should be transmissible via postMessage and decodable inside a WebWorker' , ( done ) => {
136+ store . addStrings ( [ { id : 10 , value : 'worker-shared-string' } ] ) ;
137+
138+ const sharedData = store . getSharedData ( ) ;
139+
140+ const workerCode = `
141+ self.onmessage = function(e) {
142+ try {
143+ const sharedData = e.data;
144+ const localIndices = new Uint16Array(sharedData.metadataSab, 0, sharedData.capacity);
145+ const localOffsets = new Uint32Array(sharedData.metadataSab, sharedData.capacity * 2, sharedData.capacity);
146+ const localLengths = new Uint32Array(sharedData.metadataSab, sharedData.capacity * 6, sharedData.capacity);
147+
148+ const index = localIndices[10] - 1;
149+ const offset = localOffsets[10];
150+ const length = localLengths[10];
151+
152+ const buffer = new Uint8Array(sharedData.bufferSabs[index]);
153+ const bytes = buffer.subarray(offset, offset + length);
154+ const nonSharedBytes = new Uint8Array(length);
155+ nonSharedBytes.set(bytes);
156+ const decoded = new TextDecoder().decode(nonSharedBytes);
157+
158+ self.postMessage({ success: true, decoded });
159+ } catch (err) {
160+ self.postMessage({ success: false, error: err.toString() });
161+ }
162+ };
163+ ` ;
164+ const blob = new Blob ( [ workerCode ] , { type : 'application/javascript' } ) ;
165+ const worker = new Worker ( URL . createObjectURL ( blob ) ) ;
166+
167+ worker . onmessage = ( e ) => {
168+ const result = e . data ;
169+ if ( result . success ) {
170+ expect ( result . decoded ) . toBe ( 'worker-shared-string' ) ;
171+ } else {
172+ fail ( 'Worker failed with error: ' + result . error ) ;
173+ }
174+ worker . terminate ( ) ;
175+ done ( ) ;
176+ } ;
177+
178+ worker . postMessage ( sharedData ) ;
179+ } ) ;
180+
181+ it ( 'should initialize successfully from sharedData using fromSharedData()' , ( ) => {
182+ store . addStrings ( [
183+ { id : 10 , value : 'shared-string-1' } ,
184+ { id : 20 , value : 'shared-string-2' } ,
185+ ] ) ;
186+ store . addFieldPathSets ( [ { id : 100 , fieldPathStringIds : [ 10 , 20 ] } ] ) ;
187+
188+ const sharedData = store . getSharedData ( ) ;
189+ const sharedStore = InternPoolStore . fromSharedData ( sharedData ) ;
190+
191+ expect ( sharedStore . getString ( 10 ) ) . toBe ( 'shared-string-1' ) ;
192+ expect ( sharedStore . getString ( 20 ) ) . toBe ( 'shared-string-2' ) ;
193+ expect ( sharedStore . getFieldPathSet ( 100 ) ) . toEqual ( [
194+ 'shared-string-1' ,
195+ 'shared-string-2' ,
196+ ] ) ;
197+ } ) ;
198+
199+ it ( 'should throw an error on write attempts on a read-only instance created from sharedData' , ( ) => {
200+ store . addStrings ( [ { id : 10 , value : 'shared-string' } ] ) ;
201+ const sharedData = store . getSharedData ( ) ;
202+ const sharedStore = InternPoolStore . fromSharedData ( sharedData ) ;
203+
204+ expect ( ( ) => {
205+ sharedStore . addStrings ( [ { id : 11 , value : 'fail' } ] ) ;
206+ } ) . toThrowError ( 'Cannot write to a shared read-only InternPoolStore' ) ;
207+
208+ expect ( ( ) => {
209+ sharedStore . addFieldPathSets ( [ { id : 200 , fieldPathStringIds : [ 10 ] } ] ) ;
210+ } ) . toThrowError ( 'Cannot write to a shared read-only InternPoolStore' ) ;
211+ } ) ;
65212} ) ;
0 commit comments