Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 4 | |
michael@0 | 5 | Components.utils.import("resource://gre/modules/Dict.jsm"); |
michael@0 | 6 | |
michael@0 | 7 | /** |
michael@0 | 8 | * Test that a few basic get, set, has and del operations work. |
michael@0 | 9 | */ |
michael@0 | 10 | function test_get_set_has_del() { |
michael@0 | 11 | let dict = new Dict({foo: "bar"}); |
michael@0 | 12 | dict.set("baz", 200); |
michael@0 | 13 | do_check_eq(dict.get("foo"), "bar"); |
michael@0 | 14 | do_check_eq(dict.get("baz"), 200); |
michael@0 | 15 | do_check_true(dict.has("foo")); |
michael@0 | 16 | do_check_true(dict.has("baz")); |
michael@0 | 17 | // Now delete the entries |
michael@0 | 18 | do_check_true(dict.del("foo")); |
michael@0 | 19 | do_check_true(dict.del("baz")); |
michael@0 | 20 | do_check_false(dict.has("foo")); |
michael@0 | 21 | do_check_false(dict.has("baz")); |
michael@0 | 22 | // and make sure del returns false |
michael@0 | 23 | do_check_false(dict.del("foo")); |
michael@0 | 24 | do_check_false(dict.del("baz")); |
michael@0 | 25 | } |
michael@0 | 26 | |
michael@0 | 27 | /** |
michael@0 | 28 | * Test that the second parameter of get (default value) works. |
michael@0 | 29 | */ |
michael@0 | 30 | function test_get_default() { |
michael@0 | 31 | let dict = new Dict(); |
michael@0 | 32 | do_check_true(dict.get("foo") === undefined); |
michael@0 | 33 | do_check_eq(dict.get("foo", "bar"), "bar"); |
michael@0 | 34 | } |
michael@0 | 35 | |
michael@0 | 36 | /** |
michael@0 | 37 | * Test that there are no collisions with builtins. |
michael@0 | 38 | */ |
michael@0 | 39 | function test_collisions_with_builtins() { |
michael@0 | 40 | let dict = new Dict(); |
michael@0 | 41 | // First check that a new dictionary doesn't already have builtins. |
michael@0 | 42 | do_check_false(dict.has("toString")); |
michael@0 | 43 | do_check_false(dict.has("watch")); |
michael@0 | 44 | do_check_false(dict.has("__proto__")); |
michael@0 | 45 | |
michael@0 | 46 | // Add elements in an attempt to collide with builtins. |
michael@0 | 47 | dict.set("toString", "toString"); |
michael@0 | 48 | dict.set("watch", "watch"); |
michael@0 | 49 | // This is a little evil. We set __proto__ to an object to try to make it look |
michael@0 | 50 | // up the prototype chain. |
michael@0 | 51 | dict.set("__proto__", {prototest: "prototest"}); |
michael@0 | 52 | |
michael@0 | 53 | // Now check that the entries exist. |
michael@0 | 54 | do_check_true(dict.has("toString")); |
michael@0 | 55 | do_check_true(dict.has("watch")); |
michael@0 | 56 | do_check_true(dict.has("__proto__")); |
michael@0 | 57 | // ...and that we aren't looking up the prototype chain. |
michael@0 | 58 | do_check_false(dict.has("prototest")); |
michael@0 | 59 | } |
michael@0 | 60 | |
michael@0 | 61 | /** |
michael@0 | 62 | * Test that the "count" property works as expected. |
michael@0 | 63 | */ |
michael@0 | 64 | function test_count() { |
michael@0 | 65 | let dict = new Dict({foo: "bar"}); |
michael@0 | 66 | do_check_eq(dict.count, 1); |
michael@0 | 67 | dict.set("baz", "quux"); |
michael@0 | 68 | do_check_eq(dict.count, 2); |
michael@0 | 69 | // This shouldn't change the count |
michael@0 | 70 | dict.set("baz", "quux2"); |
michael@0 | 71 | do_check_eq(dict.count, 2); |
michael@0 | 72 | |
michael@0 | 73 | do_check_true(dict.del("baz")); |
michael@0 | 74 | do_check_eq(dict.count, 1); |
michael@0 | 75 | // This shouldn't change the count either |
michael@0 | 76 | do_check_false(dict.del("not")); |
michael@0 | 77 | do_check_eq(dict.count, 1); |
michael@0 | 78 | do_check_true(dict.del("foo")); |
michael@0 | 79 | do_check_eq(dict.count, 0); |
michael@0 | 80 | } |
michael@0 | 81 | |
michael@0 | 82 | /** |
michael@0 | 83 | * Test that the copy function works as expected. |
michael@0 | 84 | */ |
michael@0 | 85 | function test_copy() { |
michael@0 | 86 | let obj = {}; |
michael@0 | 87 | let dict1 = new Dict({foo: "bar", baz: obj}); |
michael@0 | 88 | let dict2 = dict1.copy(); |
michael@0 | 89 | do_check_eq(dict2.get("foo"), "bar"); |
michael@0 | 90 | do_check_eq(dict2.get("baz"), obj); |
michael@0 | 91 | // Make sure the two update independent of each other. |
michael@0 | 92 | dict1.del("foo"); |
michael@0 | 93 | do_check_false(dict1.has("foo")); |
michael@0 | 94 | do_check_true(dict2.has("foo")); |
michael@0 | 95 | dict2.set("test", 400); |
michael@0 | 96 | do_check_true(dict2.has("test")); |
michael@0 | 97 | do_check_false(dict1.has("test")); |
michael@0 | 98 | |
michael@0 | 99 | // Check that the copy is shallow and not deep. |
michael@0 | 100 | dict1.get("baz").prop = "proptest"; |
michael@0 | 101 | do_check_eq(dict2.get("baz").prop, "proptest"); |
michael@0 | 102 | } |
michael@0 | 103 | |
michael@0 | 104 | // This is used by both test_listers and test_iterators. |
michael@0 | 105 | function _check_lists(keys, values, items) { |
michael@0 | 106 | do_check_eq(keys.length, 2); |
michael@0 | 107 | do_check_true(keys.indexOf("x") != -1); |
michael@0 | 108 | do_check_true(keys.indexOf("y") != -1); |
michael@0 | 109 | |
michael@0 | 110 | do_check_eq(values.length, 2); |
michael@0 | 111 | do_check_true(values.indexOf("a") != -1); |
michael@0 | 112 | do_check_true(values.indexOf("b") != -1); |
michael@0 | 113 | |
michael@0 | 114 | // This is a little more tricky -- we need to check that one of the two |
michael@0 | 115 | // entries is ["x", "a"] and the other is ["y", "b"]. |
michael@0 | 116 | do_check_eq(items.length, 2); |
michael@0 | 117 | do_check_eq(items[0].length, 2); |
michael@0 | 118 | do_check_eq(items[1].length, 2); |
michael@0 | 119 | let ix = (items[0][0] == "x") ? 0 : 1; |
michael@0 | 120 | let iy = (ix == 0) ? 1 : 0; |
michael@0 | 121 | do_check_eq(items[ix][0], "x"); |
michael@0 | 122 | do_check_eq(items[ix][1], "a"); |
michael@0 | 123 | do_check_eq(items[iy][0], "y"); |
michael@0 | 124 | do_check_eq(items[iy][1], "b"); |
michael@0 | 125 | } |
michael@0 | 126 | |
michael@0 | 127 | /** |
michael@0 | 128 | * Test the list functions. |
michael@0 | 129 | */ |
michael@0 | 130 | function test_listers() { |
michael@0 | 131 | let dict = new Dict({"x": "a", "y": "b"}); |
michael@0 | 132 | let keys = dict.listkeys(); |
michael@0 | 133 | let values = dict.listvalues(); |
michael@0 | 134 | let items = dict.listitems(); |
michael@0 | 135 | _check_lists(keys, values, items); |
michael@0 | 136 | } |
michael@0 | 137 | |
michael@0 | 138 | /** |
michael@0 | 139 | * Test the iterator functions. |
michael@0 | 140 | */ |
michael@0 | 141 | function test_iterators() { |
michael@0 | 142 | let dict = new Dict({"x": "a", "y": "b"}); |
michael@0 | 143 | // Convert the generators to lists |
michael@0 | 144 | let keys = [x for (x in dict.keys)]; |
michael@0 | 145 | let values = [x for (x in dict.values)]; |
michael@0 | 146 | let items = [x for (x in dict.items)]; |
michael@0 | 147 | _check_lists(keys, values, items); |
michael@0 | 148 | } |
michael@0 | 149 | |
michael@0 | 150 | /** |
michael@0 | 151 | * Test that setting a property throws an exception in strict mode. |
michael@0 | 152 | */ |
michael@0 | 153 | function test_set_property_strict() { |
michael@0 | 154 | "use strict"; |
michael@0 | 155 | var dict = new Dict(); |
michael@0 | 156 | var thrown = false; |
michael@0 | 157 | try { |
michael@0 | 158 | dict.foo = "bar"; |
michael@0 | 159 | } |
michael@0 | 160 | catch (ex) { |
michael@0 | 161 | thrown = true; |
michael@0 | 162 | } |
michael@0 | 163 | do_check_true(thrown); |
michael@0 | 164 | } |
michael@0 | 165 | |
michael@0 | 166 | /** |
michael@0 | 167 | * Test that setting a property has no effect in non-strict mode. |
michael@0 | 168 | */ |
michael@0 | 169 | function test_set_property_non_strict() { |
michael@0 | 170 | let dict = new Dict(); |
michael@0 | 171 | dict.foo = "bar"; |
michael@0 | 172 | do_check_false("foo" in dict); |
michael@0 | 173 | let realget = dict.get; |
michael@0 | 174 | dict.get = "baz"; |
michael@0 | 175 | do_check_eq(dict.get, realget); |
michael@0 | 176 | } |
michael@0 | 177 | |
michael@0 | 178 | /** |
michael@0 | 179 | * Tests setting a property by a lazy getter. |
michael@0 | 180 | */ |
michael@0 | 181 | function test_set_property_lazy_getter() { |
michael@0 | 182 | let thunkCalled = false; |
michael@0 | 183 | |
michael@0 | 184 | let setThunk = function(dict) { |
michael@0 | 185 | thunkCalled = false; |
michael@0 | 186 | dict.setAsLazyGetter("foo", function() { |
michael@0 | 187 | thunkCalled = true; |
michael@0 | 188 | return "bar"; |
michael@0 | 189 | }); |
michael@0 | 190 | }; |
michael@0 | 191 | |
michael@0 | 192 | let (dict = new Dict()) { |
michael@0 | 193 | setThunk(dict); |
michael@0 | 194 | |
michael@0 | 195 | // Test that checking for the key existence does not invoke |
michael@0 | 196 | // the getter function. |
michael@0 | 197 | do_check_true(dict.has("foo")); |
michael@0 | 198 | do_check_false(thunkCalled); |
michael@0 | 199 | do_check_true(dict.isLazyGetter("foo")); |
michael@0 | 200 | |
michael@0 | 201 | // Calling get the first time should invoke the getter function |
michael@0 | 202 | // and unmark the key as a lazy getter. |
michael@0 | 203 | do_check_eq(dict.get("foo"), "bar"); |
michael@0 | 204 | do_check_true(thunkCalled); |
michael@0 | 205 | do_check_false(dict.isLazyGetter("foo")); |
michael@0 | 206 | |
michael@0 | 207 | // Calling get again should not invoke the getter function |
michael@0 | 208 | thunkCalled = false; |
michael@0 | 209 | do_check_eq(dict.get("foo"), "bar"); |
michael@0 | 210 | do_check_false(thunkCalled); |
michael@0 | 211 | do_check_false(dict.isLazyGetter("foo")); |
michael@0 | 212 | } |
michael@0 | 213 | |
michael@0 | 214 | // Test that listvalues works for lazy keys. |
michael@0 | 215 | let (dict = new Dict()) { |
michael@0 | 216 | setThunk(dict); |
michael@0 | 217 | do_check_true(dict.isLazyGetter("foo")); |
michael@0 | 218 | |
michael@0 | 219 | let (listvalues = dict.listvalues()) { |
michael@0 | 220 | do_check_false(dict.isLazyGetter("foo")); |
michael@0 | 221 | do_check_true(thunkCalled); |
michael@0 | 222 | do_check_true(listvalues.length, 1); |
michael@0 | 223 | do_check_eq(listvalues[0], "bar"); |
michael@0 | 224 | } |
michael@0 | 225 | |
michael@0 | 226 | thunkCalled = false; |
michael@0 | 227 | |
michael@0 | 228 | // Retrieving the list again shouldn't invoke our getter. |
michael@0 | 229 | let (listvalues = dict.listvalues()) { |
michael@0 | 230 | do_check_false(dict.isLazyGetter("foo")); |
michael@0 | 231 | do_check_false(thunkCalled); |
michael@0 | 232 | do_check_true(listvalues.length, 1); |
michael@0 | 233 | do_check_eq(listvalues[0], "bar"); |
michael@0 | 234 | } |
michael@0 | 235 | } |
michael@0 | 236 | |
michael@0 | 237 | // Test that the values iterator also works as expected. |
michael@0 | 238 | let (dict = new Dict()) { |
michael@0 | 239 | setThunk(dict); |
michael@0 | 240 | let values = dict.values; |
michael@0 | 241 | |
michael@0 | 242 | // Our getter shouldn't be called before the iterator reaches it. |
michael@0 | 243 | do_check_true(dict.isLazyGetter("foo")); |
michael@0 | 244 | do_check_false(thunkCalled); |
michael@0 | 245 | do_check_eq(values.next(), "bar"); |
michael@0 | 246 | do_check_true(thunkCalled); |
michael@0 | 247 | |
michael@0 | 248 | thunkCalled = false; |
michael@0 | 249 | do_check_false(dict.isLazyGetter("foo")); |
michael@0 | 250 | do_check_eq(dict.get("foo"), "bar"); |
michael@0 | 251 | do_check_false(thunkCalled); |
michael@0 | 252 | } |
michael@0 | 253 | } |
michael@0 | 254 | |
michael@0 | 255 | // This is used by both test_construct_dict_from_json_string and test_serialize_dict_to_json_string |
michael@0 | 256 | function _sort_comp_arr(arr1,arr2){ |
michael@0 | 257 | arr1.sort(); |
michael@0 | 258 | arr2.sort(); |
michael@0 | 259 | do_check_eq(arr1.toString(),arr2.toString()); |
michael@0 | 260 | } |
michael@0 | 261 | |
michael@0 | 262 | /** |
michael@0 | 263 | * Tests constructing a dictionary from a JSON string. |
michael@0 | 264 | */ |
michael@0 | 265 | function test_construct_dict_from_json_string() { |
michael@0 | 266 | let d1 = new Dict({a:1, b:2, c:"foobar"}); |
michael@0 | 267 | let d2 = new Dict(JSON.stringify(({a:1, b:2, c:"foobar"}))); |
michael@0 | 268 | _sort_comp_arr(d1.listkeys(),d2.listkeys()); |
michael@0 | 269 | do_check_eq(d1.get("a"), d2.get("a")); |
michael@0 | 270 | do_check_eq(d1.get("b"), d2.get("b")); |
michael@0 | 271 | do_check_eq(d1.get("c"), d2.get("c")); |
michael@0 | 272 | } |
michael@0 | 273 | |
michael@0 | 274 | /** |
michael@0 | 275 | * Tests serializing a dictionary to a JSON string. |
michael@0 | 276 | */ |
michael@0 | 277 | function test_serialize_dict_to_json_string() { |
michael@0 | 278 | let d1 = new Dict({a:1, b:2, c:"foobar"}); |
michael@0 | 279 | let d2 = new Dict(d1.toJSON()); |
michael@0 | 280 | _sort_comp_arr(d1.listkeys(),d2.listkeys()); |
michael@0 | 281 | do_check_eq(d1.get("a"), d2.get("a")); |
michael@0 | 282 | do_check_eq(d1.get("b"), d2.get("b")); |
michael@0 | 283 | do_check_eq(d1.get("c"), d2.get("c")); |
michael@0 | 284 | } |
michael@0 | 285 | |
michael@0 | 286 | var tests = [ |
michael@0 | 287 | test_get_set_has_del, |
michael@0 | 288 | test_get_default, |
michael@0 | 289 | test_collisions_with_builtins, |
michael@0 | 290 | test_count, |
michael@0 | 291 | test_copy, |
michael@0 | 292 | test_listers, |
michael@0 | 293 | test_iterators, |
michael@0 | 294 | test_set_property_strict, |
michael@0 | 295 | test_set_property_non_strict, |
michael@0 | 296 | test_set_property_lazy_getter, |
michael@0 | 297 | test_construct_dict_from_json_string, |
michael@0 | 298 | test_serialize_dict_to_json_string |
michael@0 | 299 | ]; |
michael@0 | 300 | |
michael@0 | 301 | function run_test() { |
michael@0 | 302 | for (let [, test] in Iterator(tests)) |
michael@0 | 303 | test(); |
michael@0 | 304 | } |