@@ -221,6 +221,21 @@ describe("search methods", async () => {
221221 ) . toEqual ( hexToBytes ( searchEntry . contentHash ) ) ;
222222 }
223223 } ) ;
224+
225+ it ( "returns false for non-existent paths" , async ( ) => {
226+ const { manifest } = await makeManifestOfLength ( 10 ) ;
227+ for ( const searchEntry of [
228+ new Uint8Array ( PATH_HASH_SIZE ) ,
229+ new Uint8Array ( PATH_HASH_SIZE ) . fill ( 127 ) ,
230+ new Uint8Array ( PATH_HASH_SIZE ) . fill ( 255 ) ,
231+ ] ) {
232+ const foundEntry = binarySearch (
233+ new Uint8Array ( manifest , HEADER_SIZE ) ,
234+ searchEntry
235+ ) ;
236+ expect ( foundEntry ) . toBe ( false ) ;
237+ }
238+ } ) ;
224239 } ) ;
225240
226241 describe ( "interpolation search" , ( ) => {
@@ -308,5 +323,88 @@ describe("search methods", async () => {
308323 ) . toEqual ( hexToBytes ( searchEntry . contentHash ) ) ;
309324 }
310325 } ) ;
326+
327+ it ( "returns false for non-existent paths" , async ( ) => {
328+ const { manifest } = await makeManifestOfLength ( 10 ) ;
329+ for ( const searchEntry of [
330+ new Uint8Array ( PATH_HASH_SIZE ) ,
331+ new Uint8Array ( PATH_HASH_SIZE ) . fill ( 127 ) ,
332+ new Uint8Array ( PATH_HASH_SIZE ) . fill ( 255 ) ,
333+ ] ) {
334+ const foundEntry = interpolationSearch (
335+ new Uint8Array ( manifest , HEADER_SIZE ) ,
336+ searchEntry
337+ ) ;
338+ expect ( foundEntry ) . toBe ( false ) ;
339+ }
340+ } ) ;
341+
342+ it ( "doesn't throw 'RangeError: Division by zero' with extreme manifests" , async ( ) => {
343+ const smallEntry = {
344+ path : "/small" ,
345+ pathHashBytes : new Uint8Array ( PATH_HASH_SIZE ) ,
346+ contentHash : "00000000000000000000000000000000" ,
347+ } ;
348+ const largeEntry = {
349+ path : "/large" ,
350+ pathHashBytes : new Uint8Array ( PATH_HASH_SIZE ) . fill ( 255 ) ,
351+ contentHash : "ffffffffffffffffffffffffffffffff" ,
352+ } ;
353+ const entries = [ smallEntry , largeEntry ] ;
354+ entries . sort ( ( a , b ) => compare ( a . pathHashBytes , b . pathHashBytes ) ) ;
355+
356+ const assetManifestBytes = new Uint8Array (
357+ HEADER_SIZE + entries . length * ENTRY_SIZE
358+ ) ;
359+
360+ for ( const [ i , { pathHashBytes, contentHash } ] of entries . entries ( ) ) {
361+ const contentHashBytes = hexToBytes ( contentHash ) ;
362+ const entryOffset = HEADER_SIZE + i * ENTRY_SIZE ;
363+
364+ assetManifestBytes . set ( pathHashBytes , entryOffset + PATH_HASH_OFFSET ) ;
365+ assetManifestBytes . set (
366+ contentHashBytes ,
367+ entryOffset + CONTENT_HASH_OFFSET
368+ ) ;
369+ }
370+
371+ const foundSmallEntry = interpolationSearch (
372+ new Uint8Array ( assetManifestBytes . buffer , HEADER_SIZE ) ,
373+ smallEntry . pathHashBytes
374+ ) as Uint8Array ;
375+ expect ( foundSmallEntry ) . not . toBe ( false ) ;
376+ expect (
377+ new Uint8Array (
378+ foundSmallEntry . buffer ,
379+ CONTENT_HASH_OFFSET + foundSmallEntry . byteOffset ,
380+ CONTENT_HASH_SIZE
381+ )
382+ ) . toEqual ( hexToBytes ( smallEntry . contentHash ) ) ;
383+
384+ const foundLargeEntry = interpolationSearch (
385+ new Uint8Array ( assetManifestBytes . buffer , HEADER_SIZE ) ,
386+ largeEntry . pathHashBytes
387+ ) as Uint8Array ;
388+ expect ( foundLargeEntry ) . not . toBe ( false ) ;
389+ expect (
390+ new Uint8Array (
391+ foundLargeEntry . buffer ,
392+ CONTENT_HASH_OFFSET + foundLargeEntry . byteOffset ,
393+ CONTENT_HASH_SIZE
394+ )
395+ ) . toEqual ( hexToBytes ( largeEntry . contentHash ) ) ;
396+
397+ for ( const searchEntry of [
398+ new Uint8Array ( PATH_HASH_SIZE ) . fill ( 1 ) ,
399+ new Uint8Array ( PATH_HASH_SIZE ) . fill ( 127 ) ,
400+ new Uint8Array ( PATH_HASH_SIZE ) . fill ( 254 ) ,
401+ ] ) {
402+ const foundEntry = interpolationSearch (
403+ new Uint8Array ( assetManifestBytes . buffer , HEADER_SIZE ) ,
404+ searchEntry
405+ ) ;
406+ expect ( foundEntry ) . toBe ( false ) ;
407+ }
408+ } ) ;
311409 } ) ;
312410} ) ;
0 commit comments