// // Utility functions // function shouldThrow(func, expected, msg) { var err; try { func(); } catch (e) { err = e; } finally { ok(err instanceof expected, msg); } } function recursiveArrayCompare(actual, expected) { is( Array.isArray(actual), Array.isArray(expected), "Both should either be arrays, or not" ); if (Array.isArray(actual) && Array.isArray(expected)) { var diff = actual.length !== expected.length; for (var i = 0, n = actual.length; !diff && i < n; ++i) { diff = recursiveArrayCompare(actual[i], expected[i]); } return diff; } else { return actual !== expected; } } function arrayEquals(actual, expected, msg) { if (actual === expected) { return; } var diff = recursiveArrayCompare(actual, expected); ok(!diff, msg); if (diff) { is(actual, expected, msg); } } function checkHas(headers, name, msg) { function doCheckHas(n) { return headers.has(n); } return _checkHas(doCheckHas, headers, name, msg); } function checkNotHas(headers, name, msg) { function doCheckNotHas(n) { return !headers.has(n); } return _checkHas(doCheckNotHas, headers, name, msg); } function _checkHas(func, headers, name, msg) { ok(func(name), msg); ok(func(name.toLowerCase()), msg); ok(func(name.toUpperCase()), msg); } function checkGet(headers, name, expected, msg) { is(headers.get(name), expected, msg); is(headers.get(name.toLowerCase()), expected, msg); is(headers.get(name.toUpperCase()), expected, msg); } // // Test Cases // function TestCoreBehavior(headers, name) { var start = headers.get(name); headers.append(name, "bar"); checkHas(headers, name, "Has the header"); var expected = start ? start.concat(", bar") : "bar"; checkGet(headers, name, expected, "Retrieve all headers for name"); headers.append(name, "baz"); checkHas(headers, name, "Has the header"); expected = start ? start.concat(", bar, baz") : "bar, baz"; checkGet(headers, name, expected, "Retrieve all headers for name"); headers.set(name, "snafu"); checkHas(headers, name, "Has the header after set"); checkGet(headers, name, "snafu", "Retrieve all headers after set"); const value_bam = "boom"; let testHTTPWhitespace = ["\t", "\n", "\r", " "]; while (testHTTPWhitespace.length) { headers.delete(name); let char = testHTTPWhitespace.shift(); headers.set(name, char); checkGet( headers, name, "", "Header value " + char + " should be normalized before checking and throwing" ); headers.delete(name); let valueFront = char + value_bam; headers.set(name, valueFront); checkGet( headers, name, value_bam, "Header value " + valueFront + " should be normalized before checking and throwing" ); headers.delete(name); let valueBack = value_bam + char; headers.set(name, valueBack); checkGet( headers, name, value_bam, "Header value " + valueBack + " should be normalized before checking and throwing" ); } headers.delete(name.toUpperCase()); checkNotHas(headers, name, "Does not have the header after delete"); checkGet(headers, name, null, "Retrieve all headers after delete"); // should be ok to delete non-existent name headers.delete(name); shouldThrow( function () { headers.append("foo,", "bam"); }, TypeError, "Append invalid header name should throw TypeError." ); shouldThrow( function () { headers.append(name, "ba\nm"); }, TypeError, "Append invalid header value should throw TypeError." ); shouldThrow( function () { headers.append(name, "ba\rm"); }, TypeError, "Append invalid header value should throw TypeError." ); ok(!headers.guard, "guard should be undefined in content"); } function TestEmptyHeaders() { is(typeof Headers, "function", "Headers global constructor exists."); var headers = new Headers(); ok(headers, "Constructed empty Headers object"); TestCoreBehavior(headers, "foo"); } function TestFilledHeaders() { var source = new Headers(); var filled = new Headers(source); ok(filled, "Fill header from empty header"); TestCoreBehavior(filled, "foo"); source = new Headers(); source.append("abc", "123"); source.append("def", "456"); source.append("def", "789"); filled = new Headers(source); checkGet( filled, "abc", source.get("abc"), "Single value header list matches" ); checkGet( filled, "def", source.get("def"), "Multiple value header list matches" ); TestCoreBehavior(filled, "def"); filled = new Headers({ zxy: "987", xwv: "654", uts: "321", }); checkGet(filled, "zxy", "987", "Has first object filled key"); checkGet(filled, "xwv", "654", "Has second object filled key"); checkGet(filled, "uts", "321", "Has third object filled key"); TestCoreBehavior(filled, "xwv"); filled = new Headers([ ["zxy", "987"], ["xwv", "654"], ["xwv", "abc"], ["uts", "321"], ]); checkGet(filled, "zxy", "987", "Has first sequence filled key"); checkGet(filled, "xwv", "654, abc", "Has second sequence filled key"); checkGet(filled, "uts", "321", "Has third sequence filled key"); TestCoreBehavior(filled, "xwv"); shouldThrow( function () { filled = new Headers([ ["zxy", "987", "654"], ["uts", "321"], ]); }, TypeError, "Fill with non-tuple sequence should throw TypeError." ); shouldThrow( function () { filled = new Headers([["zxy"], ["uts", "321"]]); }, TypeError, "Fill with non-tuple sequence should throw TypeError." ); } function iterate(iter) { var result = []; for (var val = iter.next(); !val.done; ) { result.push(val.value); val = iter.next(); } return result; } function iterateForOf(iter) { var result = []; for (var value of iter) { result.push(value); } return result; } function byteInflate(str) { var encoder = new TextEncoder(); var encoded = encoder.encode(str); var result = ""; for (var i = 0; i < encoded.length; ++i) { result += String.fromCharCode(encoded[i]); } return result; } function TestHeadersIterator() { var ehsanInflated = byteInflate("احسان"); var headers = new Headers(); headers.set("foo0", "bar0"); headers.append("foo", "bar"); headers.append("foo", ehsanInflated); headers.append("Foo2", "bar2"); headers.set("Foo2", "baz2"); headers.set("foo3", "bar3"); headers.delete("foo0"); headers.delete("foo3"); var key_iter = headers.keys(); var value_iter = headers.values(); var entries_iter = headers.entries(); arrayEquals(iterate(key_iter), ["foo", "foo2"], "Correct key iterator"); arrayEquals( iterate(value_iter), ["bar, " + ehsanInflated, "baz2"], "Correct value iterator" ); arrayEquals( iterate(entries_iter), [ ["foo", "bar, " + ehsanInflated], ["foo2", "baz2"], ], "Correct entries iterator" ); arrayEquals( iterateForOf(headers), [ ["foo", "bar, " + ehsanInflated], ["foo2", "baz2"], ], "Correct entries iterator" ); arrayEquals( iterateForOf(new Headers(headers)), [ ["foo", "bar, " + ehsanInflated], ["foo2", "baz2"], ], "Correct entries iterator" ); } function runTest() { TestEmptyHeaders(); TestFilledHeaders(); TestHeadersIterator(); return Promise.resolve(); }