<!DOCTYPE html>
<meta charset="utf-8">
<title>Sequence conversion</title>
<link rel="help" href="https://webidl.spec.whatwg.org/#es-sequence">
<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me">

<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>

<canvas></canvas>

<script>
"use strict";

const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");

test(() => {
  ctx.setLineDash([1, 2]);
  assert_array_equals(ctx.getLineDash(), [1, 2]);
}, "An array");

test(() => {
  function* generatorFunc() {
    yield 4;
    yield 5;
  }
  const generator = generatorFunc();

  ctx.setLineDash(generator);
  assert_array_equals(ctx.getLineDash(), [4, 5]);
}, "A generator");

test(() => {
  function* generatorFunc() {
    yield 6;
    yield 7;
  }

  let callCount = 0;
  const array = [1, 2];
  Object.defineProperty(array, Symbol.iterator, {
    get() {
      ++callCount;
      return generatorFunc;
    }
  });

  ctx.setLineDash(array);
  assert_array_equals(ctx.getLineDash(), [6, 7]);
  assert_equals(callCount, 1, "@@iterator must only have been gotten once");
}, "An array with an overridden Symbol.iterator");

test(t => {
  function* generatorFunc() {
    yield ["foo", "bar"];
    yield ["baz", "quux"];
  }

  let callCount = 0;
  const obj = {};
  Object.defineProperty(obj, Symbol.iterator, {
    get() {
      ++callCount;
      return generatorFunc;
    }
  });

  const searchParams = new URLSearchParams(obj);
  assert_equals(searchParams.get("foo"), "bar");
  assert_equals(searchParams.get("baz"), "quux");
  assert_equals(callCount, 1, "@@iterator must only have been gotten once");
}, "An object with an overriden Symbol.iterator");

test(t => {
  const originalIterator = Object.getOwnPropertyDescriptor(Array.prototype, Symbol.iterator);
  t.add_cleanup(() => {
    Object.defineProperty(Array.prototype, Symbol.iterator, originalIterator);
  });

  function* generatorFunc() {
    yield 11;
    yield 12;
  }

  let callCount = 0;
  const array = [1, 2];
  Object.defineProperty(Array.prototype, Symbol.iterator, {
    get() {
      ++callCount;
      return generatorFunc;
    }
  });

  ctx.setLineDash(array);
  assert_array_equals(ctx.getLineDash(), [11, 12]);
  assert_equals(callCount, 1, "@@iterator must only have been gotten once");
}, "An array with an overridden Symbol.iterator on the prototype");

test(t => {
  const arrayIteratorPrototype = Object.getPrototypeOf(Array.prototype[Symbol.iterator]());
  const nextBefore = arrayIteratorPrototype.next;
  t.add_cleanup(() => {
    arrayIteratorPrototype.next = nextBefore;
  });

  let callCount = 0;
  arrayIteratorPrototype.next = () => {
    switch (callCount) {
      case 0: {
        ++callCount;
        return { done: false, value: 8 };
      }
      case 1: {
        ++callCount;
        return { done: false, value: 9 };
      }
      case 2: {
        ++callCount;
        return { done: true, value: 10 }; // value should be ignored this time
      }
      default: {
        assert_unreached("next() should be called three times exactly");
      }
    }
  };

  const array = [1, 2];
  ctx.setLineDash(array);
  assert_array_equals(ctx.getLineDash(), [8, 9]);
  assert_equals(callCount, 3, "next() must have been called thrice");
}, "An array with an overridden %ArrayIterator%.prototype.next");

test(t => {
  t.add_cleanup(() => {
    delete Array.prototype[1];
  });

  Object.defineProperty(Array.prototype, "1", {
    configurable: true,
    enumerable: true,
    get() {
      return 14;
    }
  });

  const array = [13, , 15, 16];
  ctx.setLineDash(array);
  assert_array_equals(ctx.getLineDash(), [13, 14, 15, 16]);
}, "A holey array with fallback to an accessor on the prototype");

test(t => {
  // Should fail rather than falling back to record
  assert_throws_js(TypeError, function() { new URLSearchParams(["key", "value"]); });
}, "A string array in sequence<sequence> or record");

</script>
