11cb0ef41Sopenharmony_ci// META: global=window,worker 21cb0ef41Sopenharmony_ci// META: script=resources/readable-stream-from-array.js 31cb0ef41Sopenharmony_ci// META: script=resources/readable-stream-to-array.js 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ci'use strict'; 61cb0ef41Sopenharmony_ciconst inputString = 'I \u{1F499} streams'; 71cb0ef41Sopenharmony_ciconst expectedOutputBytes = [0x49, 0x20, 0xf0, 0x9f, 0x92, 0x99, 0x20, 0x73, 81cb0ef41Sopenharmony_ci 0x74, 0x72, 0x65, 0x61, 0x6d, 0x73]; 91cb0ef41Sopenharmony_ci// This is a character that must be represented in two code units in a string, 101cb0ef41Sopenharmony_ci// ie. it is not in the Basic Multilingual Plane. 111cb0ef41Sopenharmony_ciconst astralCharacter = '\u{1F499}'; // BLUE HEART 121cb0ef41Sopenharmony_ciconst astralCharacterEncoded = [0xf0, 0x9f, 0x92, 0x99]; 131cb0ef41Sopenharmony_ciconst leading = astralCharacter[0]; 141cb0ef41Sopenharmony_ciconst trailing = astralCharacter[1]; 151cb0ef41Sopenharmony_ciconst replacementEncoded = [0xef, 0xbf, 0xbd]; 161cb0ef41Sopenharmony_ci 171cb0ef41Sopenharmony_ci// These tests assume that the implementation correctly classifies leading and 181cb0ef41Sopenharmony_ci// trailing surrogates and treats all the code units in each set equivalently. 191cb0ef41Sopenharmony_ci 201cb0ef41Sopenharmony_ciconst testCases = [ 211cb0ef41Sopenharmony_ci { 221cb0ef41Sopenharmony_ci input: [inputString], 231cb0ef41Sopenharmony_ci output: [expectedOutputBytes], 241cb0ef41Sopenharmony_ci description: 'encoding one string of UTF-8 should give one complete chunk' 251cb0ef41Sopenharmony_ci }, 261cb0ef41Sopenharmony_ci { 271cb0ef41Sopenharmony_ci input: [leading, trailing], 281cb0ef41Sopenharmony_ci output: [astralCharacterEncoded], 291cb0ef41Sopenharmony_ci description: 'a character split between chunks should be correctly encoded' 301cb0ef41Sopenharmony_ci }, 311cb0ef41Sopenharmony_ci { 321cb0ef41Sopenharmony_ci input: [leading, trailing + astralCharacter], 331cb0ef41Sopenharmony_ci output: [astralCharacterEncoded.concat(astralCharacterEncoded)], 341cb0ef41Sopenharmony_ci description: 'a character following one split between chunks should be ' + 351cb0ef41Sopenharmony_ci 'correctly encoded' 361cb0ef41Sopenharmony_ci }, 371cb0ef41Sopenharmony_ci { 381cb0ef41Sopenharmony_ci input: [leading, trailing + leading, trailing], 391cb0ef41Sopenharmony_ci output: [astralCharacterEncoded, astralCharacterEncoded], 401cb0ef41Sopenharmony_ci description: 'two consecutive astral characters each split down the ' + 411cb0ef41Sopenharmony_ci 'middle should be correctly reassembled' 421cb0ef41Sopenharmony_ci }, 431cb0ef41Sopenharmony_ci { 441cb0ef41Sopenharmony_ci input: [leading, trailing + leading + leading, trailing], 451cb0ef41Sopenharmony_ci output: [astralCharacterEncoded.concat(replacementEncoded), astralCharacterEncoded], 461cb0ef41Sopenharmony_ci description: 'two consecutive astral characters each split down the ' + 471cb0ef41Sopenharmony_ci 'middle with an invalid surrogate in the middle should be correctly ' + 481cb0ef41Sopenharmony_ci 'encoded' 491cb0ef41Sopenharmony_ci }, 501cb0ef41Sopenharmony_ci { 511cb0ef41Sopenharmony_ci input: [leading], 521cb0ef41Sopenharmony_ci output: [replacementEncoded], 531cb0ef41Sopenharmony_ci description: 'a stream ending in a leading surrogate should emit a ' + 541cb0ef41Sopenharmony_ci 'replacement character as a final chunk' 551cb0ef41Sopenharmony_ci }, 561cb0ef41Sopenharmony_ci { 571cb0ef41Sopenharmony_ci input: [leading, astralCharacter], 581cb0ef41Sopenharmony_ci output: [replacementEncoded.concat(astralCharacterEncoded)], 591cb0ef41Sopenharmony_ci description: 'an unmatched surrogate at the end of a chunk followed by ' + 601cb0ef41Sopenharmony_ci 'an astral character in the next chunk should be replaced with ' + 611cb0ef41Sopenharmony_ci 'the replacement character at the start of the next output chunk' 621cb0ef41Sopenharmony_ci }, 631cb0ef41Sopenharmony_ci { 641cb0ef41Sopenharmony_ci input: [leading, 'A'], 651cb0ef41Sopenharmony_ci output: [replacementEncoded.concat([65])], 661cb0ef41Sopenharmony_ci description: 'an unmatched surrogate at the end of a chunk followed by ' + 671cb0ef41Sopenharmony_ci 'an ascii character in the next chunk should be replaced with ' + 681cb0ef41Sopenharmony_ci 'the replacement character at the start of the next output chunk' 691cb0ef41Sopenharmony_ci }, 701cb0ef41Sopenharmony_ci { 711cb0ef41Sopenharmony_ci input: [leading, leading, trailing], 721cb0ef41Sopenharmony_ci output: [replacementEncoded, astralCharacterEncoded], 731cb0ef41Sopenharmony_ci description: 'an unmatched surrogate at the end of a chunk followed by ' + 741cb0ef41Sopenharmony_ci 'a plane 1 character split into two chunks should result in ' + 751cb0ef41Sopenharmony_ci 'the encoded plane 1 character appearing in the last output chunk' 761cb0ef41Sopenharmony_ci }, 771cb0ef41Sopenharmony_ci { 781cb0ef41Sopenharmony_ci input: [leading, leading], 791cb0ef41Sopenharmony_ci output: [replacementEncoded, replacementEncoded], 801cb0ef41Sopenharmony_ci description: 'two leading chunks should result in two replacement ' + 811cb0ef41Sopenharmony_ci 'characters' 821cb0ef41Sopenharmony_ci }, 831cb0ef41Sopenharmony_ci { 841cb0ef41Sopenharmony_ci input: [leading + leading, trailing], 851cb0ef41Sopenharmony_ci output: [replacementEncoded, astralCharacterEncoded], 861cb0ef41Sopenharmony_ci description: 'a non-terminal unpaired leading surrogate should ' + 871cb0ef41Sopenharmony_ci 'immediately be replaced' 881cb0ef41Sopenharmony_ci }, 891cb0ef41Sopenharmony_ci { 901cb0ef41Sopenharmony_ci input: [trailing, astralCharacter], 911cb0ef41Sopenharmony_ci output: [replacementEncoded, astralCharacterEncoded], 921cb0ef41Sopenharmony_ci description: 'a terminal unpaired trailing surrogate should ' + 931cb0ef41Sopenharmony_ci 'immediately be replaced' 941cb0ef41Sopenharmony_ci }, 951cb0ef41Sopenharmony_ci { 961cb0ef41Sopenharmony_ci input: [leading, '', trailing], 971cb0ef41Sopenharmony_ci output: [astralCharacterEncoded], 981cb0ef41Sopenharmony_ci description: 'a leading surrogate chunk should be carried past empty chunks' 991cb0ef41Sopenharmony_ci }, 1001cb0ef41Sopenharmony_ci { 1011cb0ef41Sopenharmony_ci input: [leading, ''], 1021cb0ef41Sopenharmony_ci output: [replacementEncoded], 1031cb0ef41Sopenharmony_ci description: 'a leading surrogate chunk should error when it is clear ' + 1041cb0ef41Sopenharmony_ci 'it didn\'t form a pair' 1051cb0ef41Sopenharmony_ci }, 1061cb0ef41Sopenharmony_ci { 1071cb0ef41Sopenharmony_ci input: [''], 1081cb0ef41Sopenharmony_ci output: [], 1091cb0ef41Sopenharmony_ci description: 'an empty string should result in no output chunk' 1101cb0ef41Sopenharmony_ci }, 1111cb0ef41Sopenharmony_ci { 1121cb0ef41Sopenharmony_ci input: ['', inputString], 1131cb0ef41Sopenharmony_ci output: [expectedOutputBytes], 1141cb0ef41Sopenharmony_ci description: 'a leading empty chunk should be ignored' 1151cb0ef41Sopenharmony_ci }, 1161cb0ef41Sopenharmony_ci { 1171cb0ef41Sopenharmony_ci input: [inputString, ''], 1181cb0ef41Sopenharmony_ci output: [expectedOutputBytes], 1191cb0ef41Sopenharmony_ci description: 'a trailing empty chunk should be ignored' 1201cb0ef41Sopenharmony_ci }, 1211cb0ef41Sopenharmony_ci { 1221cb0ef41Sopenharmony_ci input: ['A'], 1231cb0ef41Sopenharmony_ci output: [[65]], 1241cb0ef41Sopenharmony_ci description: 'a plain ASCII chunk should be converted' 1251cb0ef41Sopenharmony_ci }, 1261cb0ef41Sopenharmony_ci { 1271cb0ef41Sopenharmony_ci input: ['\xff'], 1281cb0ef41Sopenharmony_ci output: [[195, 191]], 1291cb0ef41Sopenharmony_ci description: 'characters in the ISO-8859-1 range should be encoded correctly' 1301cb0ef41Sopenharmony_ci }, 1311cb0ef41Sopenharmony_ci]; 1321cb0ef41Sopenharmony_ci 1331cb0ef41Sopenharmony_cifor (const {input, output, description} of testCases) { 1341cb0ef41Sopenharmony_ci promise_test(async () => { 1351cb0ef41Sopenharmony_ci const inputStream = readableStreamFromArray(input); 1361cb0ef41Sopenharmony_ci const outputStream = inputStream.pipeThrough(new TextEncoderStream()); 1371cb0ef41Sopenharmony_ci const chunkArray = await readableStreamToArray(outputStream); 1381cb0ef41Sopenharmony_ci assert_equals(chunkArray.length, output.length, 1391cb0ef41Sopenharmony_ci 'number of chunks should match'); 1401cb0ef41Sopenharmony_ci for (let i = 0; i < output.length; ++i) { 1411cb0ef41Sopenharmony_ci assert_array_equals(chunkArray[i], output[i], `chunk ${i} should match`); 1421cb0ef41Sopenharmony_ci } 1431cb0ef41Sopenharmony_ci }, description); 1441cb0ef41Sopenharmony_ci} 145