11cb0ef41Sopenharmony_ci// META: global=window,worker 21cb0ef41Sopenharmony_ci'use strict'; 31cb0ef41Sopenharmony_ci 41cb0ef41Sopenharmony_ciclass LipFuzzTransformer { 51cb0ef41Sopenharmony_ci constructor(substitutions) { 61cb0ef41Sopenharmony_ci this.substitutions = substitutions; 71cb0ef41Sopenharmony_ci this.partialChunk = ''; 81cb0ef41Sopenharmony_ci this.lastIndex = undefined; 91cb0ef41Sopenharmony_ci } 101cb0ef41Sopenharmony_ci 111cb0ef41Sopenharmony_ci transform(chunk, controller) { 121cb0ef41Sopenharmony_ci chunk = this.partialChunk + chunk; 131cb0ef41Sopenharmony_ci this.partialChunk = ''; 141cb0ef41Sopenharmony_ci // lastIndex is the index of the first character after the last substitution. 151cb0ef41Sopenharmony_ci this.lastIndex = 0; 161cb0ef41Sopenharmony_ci chunk = chunk.replace(/\{\{([a-zA-Z0-9_-]+)\}\}/g, this.replaceTag.bind(this)); 171cb0ef41Sopenharmony_ci // Regular expression for an incomplete template at the end of a string. 181cb0ef41Sopenharmony_ci const partialAtEndRegexp = /\{(\{([a-zA-Z0-9_-]+(\})?)?)?$/g; 191cb0ef41Sopenharmony_ci // Avoid looking at any characters that have already been substituted. 201cb0ef41Sopenharmony_ci partialAtEndRegexp.lastIndex = this.lastIndex; 211cb0ef41Sopenharmony_ci this.lastIndex = undefined; 221cb0ef41Sopenharmony_ci const match = partialAtEndRegexp.exec(chunk); 231cb0ef41Sopenharmony_ci if (match) { 241cb0ef41Sopenharmony_ci this.partialChunk = chunk.substring(match.index); 251cb0ef41Sopenharmony_ci chunk = chunk.substring(0, match.index); 261cb0ef41Sopenharmony_ci } 271cb0ef41Sopenharmony_ci controller.enqueue(chunk); 281cb0ef41Sopenharmony_ci } 291cb0ef41Sopenharmony_ci 301cb0ef41Sopenharmony_ci flush(controller) { 311cb0ef41Sopenharmony_ci if (this.partialChunk.length > 0) { 321cb0ef41Sopenharmony_ci controller.enqueue(this.partialChunk); 331cb0ef41Sopenharmony_ci } 341cb0ef41Sopenharmony_ci } 351cb0ef41Sopenharmony_ci 361cb0ef41Sopenharmony_ci replaceTag(match, p1, offset) { 371cb0ef41Sopenharmony_ci let replacement = this.substitutions[p1]; 381cb0ef41Sopenharmony_ci if (replacement === undefined) { 391cb0ef41Sopenharmony_ci replacement = ''; 401cb0ef41Sopenharmony_ci } 411cb0ef41Sopenharmony_ci this.lastIndex = offset + replacement.length; 421cb0ef41Sopenharmony_ci return replacement; 431cb0ef41Sopenharmony_ci } 441cb0ef41Sopenharmony_ci} 451cb0ef41Sopenharmony_ci 461cb0ef41Sopenharmony_ciconst substitutions = { 471cb0ef41Sopenharmony_ci in1: 'out1', 481cb0ef41Sopenharmony_ci in2: 'out2', 491cb0ef41Sopenharmony_ci quine: '{{quine}}', 501cb0ef41Sopenharmony_ci bogusPartial: '{{incompleteResult}' 511cb0ef41Sopenharmony_ci}; 521cb0ef41Sopenharmony_ci 531cb0ef41Sopenharmony_ciconst cases = [ 541cb0ef41Sopenharmony_ci { 551cb0ef41Sopenharmony_ci input: [''], 561cb0ef41Sopenharmony_ci output: [''] 571cb0ef41Sopenharmony_ci }, 581cb0ef41Sopenharmony_ci { 591cb0ef41Sopenharmony_ci input: [], 601cb0ef41Sopenharmony_ci output: [] 611cb0ef41Sopenharmony_ci }, 621cb0ef41Sopenharmony_ci { 631cb0ef41Sopenharmony_ci input: ['{{in1}}'], 641cb0ef41Sopenharmony_ci output: ['out1'] 651cb0ef41Sopenharmony_ci }, 661cb0ef41Sopenharmony_ci { 671cb0ef41Sopenharmony_ci input: ['z{{in1}}'], 681cb0ef41Sopenharmony_ci output: ['zout1'] 691cb0ef41Sopenharmony_ci }, 701cb0ef41Sopenharmony_ci { 711cb0ef41Sopenharmony_ci input: ['{{in1}}q'], 721cb0ef41Sopenharmony_ci output: ['out1q'] 731cb0ef41Sopenharmony_ci }, 741cb0ef41Sopenharmony_ci { 751cb0ef41Sopenharmony_ci input: ['{{in1}}{{in1}'], 761cb0ef41Sopenharmony_ci output: ['out1', '{{in1}'] 771cb0ef41Sopenharmony_ci }, 781cb0ef41Sopenharmony_ci { 791cb0ef41Sopenharmony_ci input: ['{{in1}}{{in1}', '}'], 801cb0ef41Sopenharmony_ci output: ['out1', 'out1'] 811cb0ef41Sopenharmony_ci }, 821cb0ef41Sopenharmony_ci { 831cb0ef41Sopenharmony_ci input: ['{{in1', '}}'], 841cb0ef41Sopenharmony_ci output: ['', 'out1'] 851cb0ef41Sopenharmony_ci }, 861cb0ef41Sopenharmony_ci { 871cb0ef41Sopenharmony_ci input: ['{{', 'in1}}'], 881cb0ef41Sopenharmony_ci output: ['', 'out1'] 891cb0ef41Sopenharmony_ci }, 901cb0ef41Sopenharmony_ci { 911cb0ef41Sopenharmony_ci input: ['{', '{in1}}'], 921cb0ef41Sopenharmony_ci output: ['', 'out1'] 931cb0ef41Sopenharmony_ci }, 941cb0ef41Sopenharmony_ci { 951cb0ef41Sopenharmony_ci input: ['{{', 'in1}'], 961cb0ef41Sopenharmony_ci output: ['', '', '{{in1}'] 971cb0ef41Sopenharmony_ci }, 981cb0ef41Sopenharmony_ci { 991cb0ef41Sopenharmony_ci input: ['{'], 1001cb0ef41Sopenharmony_ci output: ['', '{'] 1011cb0ef41Sopenharmony_ci }, 1021cb0ef41Sopenharmony_ci { 1031cb0ef41Sopenharmony_ci input: ['{', ''], 1041cb0ef41Sopenharmony_ci output: ['', '', '{'] 1051cb0ef41Sopenharmony_ci }, 1061cb0ef41Sopenharmony_ci { 1071cb0ef41Sopenharmony_ci input: ['{', '{', 'i', 'n', '1', '}', '}'], 1081cb0ef41Sopenharmony_ci output: ['', '', '', '', '', '', 'out1'] 1091cb0ef41Sopenharmony_ci }, 1101cb0ef41Sopenharmony_ci { 1111cb0ef41Sopenharmony_ci input: ['{{in1}}{{in2}}{{in1}}'], 1121cb0ef41Sopenharmony_ci output: ['out1out2out1'] 1131cb0ef41Sopenharmony_ci }, 1141cb0ef41Sopenharmony_ci { 1151cb0ef41Sopenharmony_ci input: ['{{wrong}}'], 1161cb0ef41Sopenharmony_ci output: [''] 1171cb0ef41Sopenharmony_ci }, 1181cb0ef41Sopenharmony_ci { 1191cb0ef41Sopenharmony_ci input: ['{{wron', 'g}}'], 1201cb0ef41Sopenharmony_ci output: ['', ''] 1211cb0ef41Sopenharmony_ci }, 1221cb0ef41Sopenharmony_ci { 1231cb0ef41Sopenharmony_ci input: ['{{quine}}'], 1241cb0ef41Sopenharmony_ci output: ['{{quine}}'] 1251cb0ef41Sopenharmony_ci }, 1261cb0ef41Sopenharmony_ci { 1271cb0ef41Sopenharmony_ci input: ['{{bogusPartial}}'], 1281cb0ef41Sopenharmony_ci output: ['{{incompleteResult}'] 1291cb0ef41Sopenharmony_ci }, 1301cb0ef41Sopenharmony_ci { 1311cb0ef41Sopenharmony_ci input: ['{{bogusPartial}}}'], 1321cb0ef41Sopenharmony_ci output: ['{{incompleteResult}}'] 1331cb0ef41Sopenharmony_ci } 1341cb0ef41Sopenharmony_ci]; 1351cb0ef41Sopenharmony_ci 1361cb0ef41Sopenharmony_cifor (const testCase of cases) { 1371cb0ef41Sopenharmony_ci const inputChunks = testCase.input; 1381cb0ef41Sopenharmony_ci const outputChunks = testCase.output; 1391cb0ef41Sopenharmony_ci promise_test(() => { 1401cb0ef41Sopenharmony_ci const lft = new TransformStream(new LipFuzzTransformer(substitutions)); 1411cb0ef41Sopenharmony_ci const writer = lft.writable.getWriter(); 1421cb0ef41Sopenharmony_ci const promises = []; 1431cb0ef41Sopenharmony_ci for (const inputChunk of inputChunks) { 1441cb0ef41Sopenharmony_ci promises.push(writer.write(inputChunk)); 1451cb0ef41Sopenharmony_ci } 1461cb0ef41Sopenharmony_ci promises.push(writer.close()); 1471cb0ef41Sopenharmony_ci const reader = lft.readable.getReader(); 1481cb0ef41Sopenharmony_ci let readerChain = Promise.resolve(); 1491cb0ef41Sopenharmony_ci for (const outputChunk of outputChunks) { 1501cb0ef41Sopenharmony_ci readerChain = readerChain.then(() => { 1511cb0ef41Sopenharmony_ci return reader.read().then(({ value, done }) => { 1521cb0ef41Sopenharmony_ci assert_false(done, `done should be false when reading ${outputChunk}`); 1531cb0ef41Sopenharmony_ci assert_equals(value, outputChunk, `value should match outputChunk`); 1541cb0ef41Sopenharmony_ci }); 1551cb0ef41Sopenharmony_ci }); 1561cb0ef41Sopenharmony_ci } 1571cb0ef41Sopenharmony_ci readerChain = readerChain.then(() => { 1581cb0ef41Sopenharmony_ci return reader.read().then(({ done }) => assert_true(done, `done should be true`)); 1591cb0ef41Sopenharmony_ci }); 1601cb0ef41Sopenharmony_ci promises.push(readerChain); 1611cb0ef41Sopenharmony_ci return Promise.all(promises); 1621cb0ef41Sopenharmony_ci }, `testing "${inputChunks}" (length ${inputChunks.length})`); 1631cb0ef41Sopenharmony_ci} 164