@@ -125,3 +125,49 @@ for (let i = 1; i < 10; i++) {
125125 assert . strictEqual ( Buffer . byteLength ( 'foo' , encoding ) ,
126126 Buffer . byteLength ( 'foo' , 'utf8' ) ) ;
127127}
128+
129+ // byteLength('utf8') must equal the bytes Buffer.from writes, including
130+ // unpaired surrogates (3-byte U+FFFD). Large inputs exercise the SIMD path.
131+ {
132+ const HI = '\uD83D' ; // Unpaired high surrogate
133+ const LO = '\uDE00' ; // Unpaired low surrogate
134+ const PAIR = '\u{1F600}' ; // Valid surrogate pair (4 bytes)
135+ const enc = new TextEncoder ( ) ;
136+
137+ // Independent UTF-8 byte-length oracle with replacement semantics.
138+ const utf8Bytes = ( str ) => {
139+ let n = 0 ;
140+ for ( let i = 0 ; i < str . length ; i ++ ) {
141+ const c = str . charCodeAt ( i ) ;
142+ if ( c < 0x80 ) n += 1 ;
143+ else if ( c < 0x800 ) n += 2 ;
144+ else if ( c >= 0xD800 && c <= 0xDBFF ) {
145+ const next = str . charCodeAt ( i + 1 ) ;
146+ if ( next >= 0xDC00 && next <= 0xDFFF ) { n += 4 ; i ++ ; } else n += 3 ;
147+ } else n += 3 ; // BMP >= 0x800, incl. unpaired low surrogate
148+ }
149+ return n ;
150+ } ;
151+
152+ const cases = [
153+ 'a' . repeat ( 300 ) + HI + 'b' . repeat ( 300 ) , // Unpaired high inside large 2-byte
154+ 'a' . repeat ( 300 ) + LO + 'b' . repeat ( 300 ) , // Unpaired low inside large 2-byte
155+ HI . repeat ( 200 ) , // many unpaired highs
156+ ( HI + LO ) . repeat ( 200 ) , // Reversed order, still unpaired
157+ PAIR . repeat ( 200 ) , // valid pairs, large
158+ '中' . repeat ( 500 ) , // BMP 3-byte, large
159+ 'é' . repeat ( 500 ) , // latin1, large
160+ `a中${ PAIR } ${ HI } é` . repeat ( 100 ) , // mixed, large
161+ `A${ HI } ` , // Tiny, below SIMD threshold
162+ HI , // Single unpaired surrogate
163+ '' ,
164+ ] ;
165+
166+ for ( const s of cases ) {
167+ const ref = enc . encode ( s ) ; // WHATWG ground-truth UTF-8 bytes
168+ const label = JSON . stringify ( s ) . slice ( 0 , 32 ) ;
169+ assert . strictEqual ( utf8Bytes ( s ) , ref . length , `oracle vs TextEncoder: ${ label } ` ) ;
170+ assert . strictEqual ( Buffer . byteLength ( s , 'utf8' ) , ref . length , `byteLength: ${ label } ` ) ;
171+ assert . deepStrictEqual ( new Uint8Array ( Buffer . from ( s , 'utf8' ) ) , ref , `bytes: ${ label } ` ) ;
172+ }
173+ }
0 commit comments