<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Headers structure</title>
    <meta name="help" href="https://fetch.spec.whatwg.org/#headers">
    <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr">
    <script src="/resources/testharness.js"></script>
    <script src="/resources/testharnessreport.js"></script>
  </head>
  <body>
    <script>
      test(function() {
        new Headers();
      }, "Create headers from no parameter");

      test(function() {
        new Headers(undefined);
      }, "Create headers from undefined parameter");

      test(function() {
        new Headers({});
      }, "Create headers from empty object");

      var parameters = [null, 1];
      parameters.forEach(function(parameter) {
        test(function() {
          assert_throws(new TypeError(), function() { new Headers(parameter) });
        }, "Create headers with " + parameter + " should throw");
      });

      var headerDict = {"name1": "value1",
                        "name2": "value2",
                        "name3": "value3",
                        "name4": null,
                        "name5": undefined,
                        "name6": 1,
                        "Content-Type": "value4"
      };

      var headerSeq = [];
      for (var name in headerDict)
        headerSeq.push([name, headerDict[name]]);

      test(function() {
        var headers = new Headers(headerSeq);
        for (name in headerDict) {
          assert_equals(headers.get(name), String(headerDict[name]),
            "name: " + name + " has value: " + headerDict[name]);
        }
        assert_equals(headers.get("length"), null, "init should be treated as a sequence, not as a dictionary");
      }, "Create headers with sequence");

      test(function() {
        var headers = new Headers(headerDict);
        for (name in headerDict) {
          assert_equals(headers.get(name), String(headerDict[name]),
            "name: " + name + " has value: " + headerDict[name]);
        }
      }, "Create headers with OpenEndedDictionary");

      test(function() {
        var headers = new Headers(headerDict);
        var headers2 = new Headers(headers);
        for (name in headerDict) {
          assert_equals(headers2.get(name), String(headerDict[name]),
            "name: " + name + " has value: " + headerDict[name]);
        }
      }, "Create headers with existing headers");

      test(function() {
        var headers = new Headers();
        for (name in headerDict) {
          headers.append(name, headerDict[name]);
          assert_equals(headers.get(name), String(headerDict[name]),
            "name: " + name + " has value: " + headerDict[name]);
        }
      }, "Check append method");

      test(function() {
        var headers = new Headers();
        for (name in headerDict) {
          headers.set(name, headerDict[name]);
          assert_equals(headers.get(name), String(headerDict[name]),
            "name: " + name + " has value: " + headerDict[name]);
        }
      }, "Check set method");

      test(function() {
        var headers = new Headers(headerDict);
        for (name in headerDict)
          assert_true(headers.has(name),"headers has name " + name);

        assert_false(headers.has("nameNotInHeaders"),"headers do not have header: nameNotInHeaders");
      }, "Check has method");

      test(function() {
        var headers = new Headers(headerDict);
        for (name in headerDict) {
          assert_true(headers.has(name),"headers have a header: " + name);
          headers.delete(name)
          assert_true(!headers.has(name),"headers do not have anymore a header: " + name);
        }
      }, "Check delete method");

      test(function() {
        var headers = new Headers(headerDict);
        for (name in headerDict)
          assert_equals(headers.get(name), String(headerDict[name]),
            "name: " + name + " has value: " + headerDict[name]);

        assert_equals(headers.get("nameNotInHeaders"), null, "header: nameNotInHeaders has no value");
      }, "Check get method");

      var headerEntriesDict = {"name1": "value1",
                               "Name2": "value2",
                               "name": "value3",
                               "content-Type": "value4",
                               "Content-Typ": "value5",
                               "Content-Types": "value6"
      };
      var sortedHeaderDict = {};
      var headerValues = [];
      var sortedHeaderKeys = Object.keys(headerEntriesDict).map(function(value) {
        sortedHeaderDict[value.toLowerCase()] = headerEntriesDict[value];
        headerValues.push(headerEntriesDict[value]);
        return value.toLowerCase();
      }).sort();

      var iteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]()));
      function checkIteratorProperties(iterator) {
        var prototype = Object.getPrototypeOf(iterator);
        assert_equals(Object.getPrototypeOf(prototype), iteratorPrototype);

        var descriptor = Object.getOwnPropertyDescriptor(prototype, "next");
        assert_true(descriptor.configurable, "configurable");
        assert_true(descriptor.enumerable, "enumerable");
        assert_true(descriptor.writable, "writable");
      }

      test(function() {
        var headers = new Headers(headerEntriesDict);
        var actual = headers.keys();
        checkIteratorProperties(actual);

        sortedHeaderKeys.forEach(function(key) {
            entry = actual.next();
            assert_false(entry.done);
            assert_equals(entry.value, key);
        });
        assert_true(actual.next().done);
        assert_true(actual.next().done);

        for (key of headers.keys())
            assert_true(sortedHeaderKeys.indexOf(key) != -1);
      }, "Check keys method");

      test(function() {
        var headers = new Headers(headerEntriesDict);
        var actual = headers.values();
        checkIteratorProperties(actual);

        sortedHeaderKeys.forEach(function(key) {
            entry = actual.next();
            assert_false(entry.done);
            assert_equals(entry.value, sortedHeaderDict[key]);
        });
        assert_true(actual.next().done);
        assert_true(actual.next().done);

        for (value of headers.values())
            assert_true(headerValues.indexOf(value) != -1);
      }, "Check values method");

      test(function() {
        var headers = new Headers(headerEntriesDict);
        var actual = headers.entries();
        checkIteratorProperties(actual);

        sortedHeaderKeys.forEach(function(key) {
            entry = actual.next();
            assert_false(entry.done);
            assert_equals(entry.value[0], key);
            assert_equals(entry.value[1], sortedHeaderDict[key]);
        });
        assert_true(actual.next().done);
        assert_true(actual.next().done);

        for (entry of headers.entries())
            assert_equals(entry[1], sortedHeaderDict[entry[0]]);
      }, "Check entries method");

      test(function() {
        var headers = new Headers(headerEntriesDict);
        var actual = headers[Symbol.iterator]();

        sortedHeaderKeys.forEach(function(key) {
            entry = actual.next();
            assert_false(entry.done);
            assert_equals(entry.value[0], key);
            assert_equals(entry.value[1], sortedHeaderDict[key]);
        });
        assert_true(actual.next().done);
        assert_true(actual.next().done);
      }, "Check Symbol.iterator method");

      test(function() {
        var headers = new Headers(headerEntriesDict);
        var reference = sortedHeaderKeys[Symbol.iterator]();
        headers.forEach(function(value, key, container) {
            assert_equals(headers, container);
            entry = reference.next();
            assert_false(entry.done);
            assert_equals(key, entry.value);
            assert_equals(value, sortedHeaderDict[entry.value]);
        });
        assert_true(reference.next().done);
      }, "Check forEach method");
   </script>
  </body>
</html>