@@ -214,3 +214,171 @@ test("Zero-Copy Performance Test", () => {
214214 const byteResult = stringzilla . findByte ( largeHaystack , 97 ) ; // 'a'
215215 assert . strictEqual ( byteResult , 0n ) ;
216216} ) ;
217+
218+ test ( "Edge Cases - Empty Buffers" , ( ) => {
219+ const haystack = Buffer . from ( "hello world" ) ;
220+ const empty = Buffer . alloc ( 0 ) ;
221+
222+ // Finding empty in non-empty should return 0
223+ assert . strictEqual ( stringzilla . find ( haystack , empty ) , 0n ) ;
224+ assert . strictEqual ( stringzilla . findLast ( haystack , empty ) , BigInt ( haystack . length ) ) ;
225+
226+ // Finding non-empty in empty should return -1
227+ assert . strictEqual ( stringzilla . find ( empty , haystack ) , - 1n ) ;
228+ assert . strictEqual ( stringzilla . findLast ( empty , haystack ) , - 1n ) ;
229+
230+ // Empty in empty
231+ assert . strictEqual ( stringzilla . find ( empty , empty ) , 0n ) ;
232+ assert . strictEqual ( stringzilla . count ( empty , empty ) , 0n ) ;
233+ } ) ;
234+
235+ test ( "Find Byte - Boundary Values" , ( ) => {
236+ const buffer = Buffer . from ( [ 0 , 127 , 128 , 255 ] ) ;
237+
238+ // Test boundary byte values
239+ assert . strictEqual ( stringzilla . findByte ( buffer , 0 ) , 0n ) ;
240+ assert . strictEqual ( stringzilla . findByte ( buffer , 127 ) , 1n ) ;
241+ assert . strictEqual ( stringzilla . findByte ( buffer , 128 ) , 2n ) ;
242+ assert . strictEqual ( stringzilla . findByte ( buffer , 255 ) , 3n ) ;
243+
244+ // Test not found
245+ assert . strictEqual ( stringzilla . findByte ( buffer , 1 ) , - 1n ) ;
246+ } ) ;
247+
248+ test ( "UTF-8 Multi-byte Character Handling" , ( ) => {
249+ const haystack = Buffer . from ( "Hello 世界 World" ) ;
250+ const needle = Buffer . from ( "世界" ) ;
251+
252+ // Should work at byte level, not character level
253+ const result = stringzilla . find ( haystack , needle ) ;
254+ assert ( result > 0n ) ;
255+
256+ // Test with emoji
257+ const emojiBuffer = Buffer . from ( "Hello 👋 World" ) ;
258+ const emoji = Buffer . from ( "👋" ) ;
259+ assert ( stringzilla . find ( emojiBuffer , emoji ) > 0n ) ;
260+ } ) ;
261+
262+ test ( "Pattern at Buffer Boundaries" , ( ) => {
263+ const haystack = Buffer . from ( "abcdefghijk" ) ;
264+
265+ // Pattern at start
266+ assert . strictEqual ( stringzilla . find ( haystack , Buffer . from ( "abc" ) ) , 0n ) ;
267+
268+ // Pattern at end
269+ assert . strictEqual ( stringzilla . find ( haystack , Buffer . from ( "ijk" ) ) , 8n ) ;
270+ assert . strictEqual ( stringzilla . findLast ( haystack , Buffer . from ( "ijk" ) ) , 8n ) ;
271+
272+ // Pattern spans entire buffer
273+ assert . strictEqual ( stringzilla . find ( haystack , haystack ) , 0n ) ;
274+ } ) ;
275+
276+ test ( "Repeated Patterns" , ( ) => {
277+ const haystack = Buffer . from ( "aaaaaaaaaa" ) ;
278+ const needle = Buffer . from ( "aa" ) ;
279+
280+ // Test first and last occurrence
281+ assert . strictEqual ( stringzilla . find ( haystack , needle ) , 0n ) ;
282+ assert . strictEqual ( stringzilla . findLast ( haystack , needle ) , 8n ) ;
283+
284+ // Count with and without overlap
285+ assert . strictEqual ( stringzilla . count ( haystack , needle , false ) , 5n ) ;
286+ assert . strictEqual ( stringzilla . count ( haystack , needle , true ) , 9n ) ;
287+ } ) ;
288+
289+ test ( "Find Byte From - Edge Cases" , ( ) => {
290+ const haystack = Buffer . from ( "1234567890" ) ;
291+
292+ // Empty charset
293+ const emptyCharset = Buffer . alloc ( 0 ) ;
294+ assert . strictEqual ( stringzilla . findByteFrom ( haystack , emptyCharset ) , - 1n ) ;
295+
296+ // Charset with all possible bytes
297+ const allBytes = Buffer . alloc ( 256 ) ;
298+ for ( let i = 0 ; i < 256 ; i ++ ) allBytes [ i ] = i ;
299+ assert . strictEqual ( stringzilla . findByteFrom ( haystack , allBytes ) , 0n ) ;
300+
301+ // Charset with duplicates
302+ const duplicates = Buffer . from ( "1111" ) ;
303+ assert . strictEqual ( stringzilla . findByteFrom ( haystack , duplicates ) , 0n ) ;
304+ } ) ;
305+
306+ test ( "Binary Data Handling" , ( ) => {
307+ // Test with null bytes and binary data
308+ const binaryData = Buffer . from ( [ 0x00 , 0x01 , 0x02 , 0x00 , 0x03 , 0x00 ] ) ;
309+ const nullByte = Buffer . from ( [ 0x00 ] ) ;
310+
311+ assert . strictEqual ( stringzilla . find ( binaryData , nullByte ) , 0n ) ;
312+ assert . strictEqual ( stringzilla . findLast ( binaryData , nullByte ) , 5n ) ;
313+ assert . strictEqual ( stringzilla . count ( binaryData , nullByte ) , 3n ) ;
314+
315+ // Test hash consistency with binary data
316+ const hash1 = stringzilla . hash ( binaryData ) ;
317+ const hash2 = stringzilla . hash ( binaryData ) ;
318+ assert . strictEqual ( hash1 , hash2 ) ;
319+ } ) ;
320+
321+ test ( "Large Buffer Operations" , ( ) => {
322+ const size = 100000 ; // 100KB (smaller than 1MB for faster tests)
323+ const largeBuffer = Buffer . alloc ( size ) ;
324+
325+ // Fill with pattern
326+ for ( let i = 0 ; i < size ; i ++ ) {
327+ largeBuffer [ i ] = i % 256 ;
328+ }
329+
330+ // Test operations on large buffer
331+ const pattern = Buffer . from ( [ 0 , 1 , 2 , 3 ] ) ;
332+ assert ( stringzilla . count ( largeBuffer , pattern ) > 0n ) ;
333+
334+ // Test hash performance
335+ const start = Date . now ( ) ;
336+ const hash = stringzilla . hash ( largeBuffer ) ;
337+ const duration = Date . now ( ) - start ;
338+ assert ( duration < 100 ) ; // Should be fast
339+ assert ( typeof hash === "bigint" ) ;
340+ } ) ;
341+
342+ test ( "Hasher - Incremental vs Single Shot" , ( ) => {
343+ const data = Buffer . from ( "a" . repeat ( 1000 ) ) ;
344+
345+ // Single shot
346+ const hashSingle = stringzilla . hash ( data ) ;
347+
348+ // Progressive hashing with different chunk sizes should be consistent
349+ const hasher1 = new stringzilla . Hasher ( ) ;
350+ hasher1 . update ( data . subarray ( 0 , 100 ) ) ;
351+ hasher1 . update ( data . subarray ( 100 , 500 ) ) ;
352+ hasher1 . update ( data . subarray ( 500 ) ) ;
353+ const hashProgressive1 = hasher1 . digest ( ) ;
354+
355+ const hasher2 = new stringzilla . Hasher ( ) ;
356+ hasher2 . update ( data . subarray ( 0 , 300 ) ) ;
357+ hasher2 . update ( data . subarray ( 300 ) ) ;
358+ const hashProgressive2 = hasher2 . digest ( ) ;
359+
360+ // Progressive hashing with same data should be consistent
361+ assert . strictEqual ( hashProgressive1 , hashProgressive2 ) ;
362+
363+ // Test that single-shot and progressive produce valid hashes
364+ assert . strictEqual ( typeof hashSingle , "bigint" ) ;
365+ assert . strictEqual ( typeof hashProgressive1 , "bigint" ) ;
366+ assert ( hashSingle > 0n ) ;
367+ assert ( hashProgressive1 > 0n ) ;
368+ } ) ;
369+
370+ test ( "Compare - Special Cases" , ( ) => {
371+ // Different lengths
372+ assert ( stringzilla . compare ( Buffer . from ( "a" ) , Buffer . from ( "aa" ) ) < 0 ) ;
373+ assert ( stringzilla . compare ( Buffer . from ( "aa" ) , Buffer . from ( "a" ) ) > 0 ) ;
374+
375+ // Empty buffers
376+ assert . strictEqual ( stringzilla . compare ( Buffer . alloc ( 0 ) , Buffer . alloc ( 0 ) ) , 0 ) ;
377+ assert ( stringzilla . compare ( Buffer . alloc ( 0 ) , Buffer . from ( "a" ) ) < 0 ) ;
378+ assert ( stringzilla . compare ( Buffer . from ( "a" ) , Buffer . alloc ( 0 ) ) > 0 ) ;
379+
380+ // Binary data comparison
381+ const binary1 = Buffer . from ( [ 0x00 , 0x01 , 0x02 ] ) ;
382+ const binary2 = Buffer . from ( [ 0x00 , 0x01 , 0x03 ] ) ;
383+ assert ( stringzilla . compare ( binary1 , binary2 ) < 0 ) ;
384+ } ) ;
0 commit comments