<!DOCTYPE html>
<html>
<head>
    <script src="../../resources/testharness.js"></script>
    <script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<script>
    // To test a named property setter with [OverrideBuiltins] specified, we use DOMStringMap via element.dataset.
    test(() => {
        let element = document.createElement("div");
        element.dataset["a"] = "value1";
        element.dataset["b"] = "value2";
        
        Object.defineProperty(element.dataset, "c", { value: "value3" });
        assert_equals(element.dataset["c"], "value3");
        assert_equals(element.getAttribute("data-c"), "value3")
    }, "Test that the setting a non-existing named property with Object.defineProperty creates the property ([OverrideBuiltins] specified).");

    test(() => {
        let element = document.createElement("div");
        element.dataset[1] = "value1";
        element.dataset[2] = "value2";
        
        Object.defineProperty(element.dataset, 3, { value: "value3" });
        assert_equals(element.dataset[3], "value3");
        assert_equals(element.getAttribute("data-3"), "value3")
    }, "Test that the setting a non-existing indexed property with Object.defineProperty creates the property ([OverrideBuiltins] specified).");

    test(() => {
        let element = document.createElement("div");
        element.dataset["a"] = "value1";
        element.dataset["b"] = "value2";
        
        Object.defineProperty(element.dataset, "a", { value: "value3" });
        assert_equals(element.dataset["a"], "value3");
        assert_equals(element.getAttribute("data-a"), "value3")
    }, "Test that the setting an existing named property with Object.defineProperty replaces the value ([OverrideBuiltins] specified).");

    test(() => {
        let element = document.createElement("div");
        element.dataset[1] = "value1";
        element.dataset[2] = "value2";
        
        Object.defineProperty(element.dataset, 1, { value: "value3" });
        assert_equals(element.dataset[1], "value3");
        assert_equals(element.getAttribute("data-1"), "value3")
    }, "Test that the setting an existing indexed property with Object.defineProperty replaces the value ([OverrideBuiltins] specified).");

    test(() => {
        let element = document.createElement("div");
        element.dataset["a"] = "value1";
        element.dataset["b"] = "value2";
        
        assert_throws_dom("SyntaxError", () => {
            Object.defineProperty(element.dataset, "-invalid", { value: "value3" });            
        });
        assert_not_equals(element.dataset["-invalid"], 'value3');
        assert_not_equals(element.getAttribute("data--invalid"), "value3")
    }, "Test that the setting a non-existing but invalid named property with Object.defineProperty throws ([OverrideBuiltins] specified).");

    test(() => {
        let element = document.createElement("div");
        element.dataset["a"] = "value1";
        element.dataset["b"] = "value2";
        
        assert_equals(element.dataset["c"], undefined);
        try {
            Object.defineProperty(element.dataset, "c", { 
                get: function() { return 1; },
                set: function(newValue) { }
            });
        } catch (e) { }
        assert_equals(element.dataset["c"], undefined);
    }, "Test that the setting a non-data descriptor property with Object.defineProperty does not set anything ([OverrideBuiltins] specified).");

    test((t) => {
        t.add_cleanup(() => {
          delete DOMStringMap.prototype["c"];
        });
    
        let element = document.createElement("div");
    
        DOMStringMap.prototype["c"] = 'prototype-value';
        Object.defineProperty(element.dataset, "c", { value: "map-value" });
        
        assert_equals(element.dataset["c"], "map-value");
        assert_equals(element.getAttribute("data-c"), "map-value")
        assert_equals(DOMStringMap.prototype["c"], "prototype-value")
    }, "Test that the setting a named property with Object.defineProperty that shadows an existing prototype value still creates the item ([OverrideBuiltins] specified).");


    // To test a named property setter without [OverrideBuiltins] specified, we use Storage via window.sessionStorage.
    test((t) => {
        t.add_cleanup(() => {
          window.sessionStorage.clear();
        });
        
        window.sessionStorage.clear();
        assert_equals(window.sessionStorage.length, 0);
    
        window.sessionStorage["a"] = "value1";
        window.sessionStorage["b"] = "value2";
        
        Object.defineProperty(window.sessionStorage, "c", { value: "value3" });
        assert_equals(window.sessionStorage["c"], "value3");
        assert_equals(window.sessionStorage.getItem("c"), "value3")
    }, "Test that the setting a non-existing named property with Object.defineProperty creates the property ([OverrideBuiltins] not specified).");

    test((t) => {
        t.add_cleanup(() => {
          window.sessionStorage.clear();
        });
        
        window.sessionStorage.clear();
        assert_equals(window.sessionStorage.length, 0);
    
        window.sessionStorage["a"] = "value1";
        window.sessionStorage["b"] = "value2";
            
        Object.defineProperty(window.sessionStorage, 3, { value: "value3" });
        assert_equals(window.sessionStorage[3], "value3");
        assert_equals(window.sessionStorage.getItem("3"), "value3")
    }, "Test that the setting a non-existing indexed property with Object.defineProperty creates the property ([OverrideBuiltins] not specified).");

    test((t) => {
        t.add_cleanup(() => {
          window.sessionStorage.clear();
        });
        
        window.sessionStorage.clear();
        assert_equals(window.sessionStorage.length, 0);
    
        window.sessionStorage["a"] = "value1";
        window.sessionStorage["b"] = "value2";
        
        Object.defineProperty(window.sessionStorage, "a", { value: "value3" });
        assert_equals(window.sessionStorage["a"], "value3");
        assert_equals(window.sessionStorage.getItem("a"), "value3")
    }, "Test that the setting an existing named property with Object.defineProperty replaces the value ([OverrideBuiltins] not specified).");

    test((t) => {
        t.add_cleanup(() => {
          window.sessionStorage.clear();
        });
        
        window.sessionStorage.clear();
        assert_equals(window.sessionStorage.length, 0);
    
        window.sessionStorage["a"] = "value1";
        window.sessionStorage["b"] = "value2";
            
        Object.defineProperty(window.sessionStorage, 1, { value: "value3" });
        assert_equals(window.sessionStorage[1], "value3");
        assert_equals(window.sessionStorage.getItem("1"), "value3")
    }, "Test that the setting an existing indexed property with Object.defineProperty replaces the value ([OverrideBuiltins] not specified).");

    test((t) => {
        t.add_cleanup(() => {
          window.sessionStorage.clear();
        });
        
        window.sessionStorage.clear();
        assert_equals(window.sessionStorage.length, 0);
    
        window.sessionStorage["a"] = "value1";
        window.sessionStorage["b"] = "value2";
        
        assert_equals(window.sessionStorage["c"], undefined);
        try {
            Object.defineProperty(window.sessionStorage, "c", { 
                get: function() { return 1; },
                set: function(newValue) { }
            });
        } catch (e) { }
        assert_equals(window.sessionStorage["c"], undefined);
    }, "Test that the setting a non-data descriptor property with Object.defineProperty does not set anything ([OverrideBuiltins] not specified).");

    test((t) => {
        t.add_cleanup(() => {
            window.sessionStorage.clear();
            delete Storage.prototype["c"];
        });
        
        Storage.prototype["c"] = 'prototype-value';
        Object.defineProperty(window.sessionStorage, "c", { value: "map-value" });
        
        assert_equals(window.sessionStorage["c"], "prototype-value");
        assert_equals(window.sessionStorage.getItem("c"), "map-value")
        assert_equals(Storage.prototype["c"], "prototype-value")
    }, "Test that the setting a named property with Object.defineProperty that shadows an existing prototype value still creates the item ([OverrideBuiltins] not specified).");


    test((t) => {
        t.add_cleanup(() => {
          window.sessionStorage.clear();
        });
        
        window.sessionStorage.clear();
        assert_equals(window.sessionStorage.length, 0);
    
        window.sessionStorage["a"] = "value1";
        window.sessionStorage["b"] = "value2";

        let currentLength = window.sessionStorage.length;
        
        Object.defineProperty(window.sessionStorage, "length", { value: "value3" });
        assert_equals(window.sessionStorage['length'], currentLength + 1);
        assert_equals(window.sessionStorage.getItem("length"), "value3")
    }, "Test that the trying to set a named property, matching a builtin property name, with Object.defineProperty does nothing ([OverrideBuiltins] not specified).");
</script>
</body>
</html>
