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