1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/modules/tests/xpcshell/test_dict.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,304 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +Components.utils.import("resource://gre/modules/Dict.jsm"); 1.9 + 1.10 +/** 1.11 + * Test that a few basic get, set, has and del operations work. 1.12 + */ 1.13 +function test_get_set_has_del() { 1.14 + let dict = new Dict({foo: "bar"}); 1.15 + dict.set("baz", 200); 1.16 + do_check_eq(dict.get("foo"), "bar"); 1.17 + do_check_eq(dict.get("baz"), 200); 1.18 + do_check_true(dict.has("foo")); 1.19 + do_check_true(dict.has("baz")); 1.20 + // Now delete the entries 1.21 + do_check_true(dict.del("foo")); 1.22 + do_check_true(dict.del("baz")); 1.23 + do_check_false(dict.has("foo")); 1.24 + do_check_false(dict.has("baz")); 1.25 + // and make sure del returns false 1.26 + do_check_false(dict.del("foo")); 1.27 + do_check_false(dict.del("baz")); 1.28 +} 1.29 + 1.30 +/** 1.31 + * Test that the second parameter of get (default value) works. 1.32 + */ 1.33 +function test_get_default() { 1.34 + let dict = new Dict(); 1.35 + do_check_true(dict.get("foo") === undefined); 1.36 + do_check_eq(dict.get("foo", "bar"), "bar"); 1.37 +} 1.38 + 1.39 +/** 1.40 + * Test that there are no collisions with builtins. 1.41 + */ 1.42 +function test_collisions_with_builtins() { 1.43 + let dict = new Dict(); 1.44 + // First check that a new dictionary doesn't already have builtins. 1.45 + do_check_false(dict.has("toString")); 1.46 + do_check_false(dict.has("watch")); 1.47 + do_check_false(dict.has("__proto__")); 1.48 + 1.49 + // Add elements in an attempt to collide with builtins. 1.50 + dict.set("toString", "toString"); 1.51 + dict.set("watch", "watch"); 1.52 + // This is a little evil. We set __proto__ to an object to try to make it look 1.53 + // up the prototype chain. 1.54 + dict.set("__proto__", {prototest: "prototest"}); 1.55 + 1.56 + // Now check that the entries exist. 1.57 + do_check_true(dict.has("toString")); 1.58 + do_check_true(dict.has("watch")); 1.59 + do_check_true(dict.has("__proto__")); 1.60 + // ...and that we aren't looking up the prototype chain. 1.61 + do_check_false(dict.has("prototest")); 1.62 +} 1.63 + 1.64 +/** 1.65 + * Test that the "count" property works as expected. 1.66 + */ 1.67 +function test_count() { 1.68 + let dict = new Dict({foo: "bar"}); 1.69 + do_check_eq(dict.count, 1); 1.70 + dict.set("baz", "quux"); 1.71 + do_check_eq(dict.count, 2); 1.72 + // This shouldn't change the count 1.73 + dict.set("baz", "quux2"); 1.74 + do_check_eq(dict.count, 2); 1.75 + 1.76 + do_check_true(dict.del("baz")); 1.77 + do_check_eq(dict.count, 1); 1.78 + // This shouldn't change the count either 1.79 + do_check_false(dict.del("not")); 1.80 + do_check_eq(dict.count, 1); 1.81 + do_check_true(dict.del("foo")); 1.82 + do_check_eq(dict.count, 0); 1.83 +} 1.84 + 1.85 +/** 1.86 + * Test that the copy function works as expected. 1.87 + */ 1.88 +function test_copy() { 1.89 + let obj = {}; 1.90 + let dict1 = new Dict({foo: "bar", baz: obj}); 1.91 + let dict2 = dict1.copy(); 1.92 + do_check_eq(dict2.get("foo"), "bar"); 1.93 + do_check_eq(dict2.get("baz"), obj); 1.94 + // Make sure the two update independent of each other. 1.95 + dict1.del("foo"); 1.96 + do_check_false(dict1.has("foo")); 1.97 + do_check_true(dict2.has("foo")); 1.98 + dict2.set("test", 400); 1.99 + do_check_true(dict2.has("test")); 1.100 + do_check_false(dict1.has("test")); 1.101 + 1.102 + // Check that the copy is shallow and not deep. 1.103 + dict1.get("baz").prop = "proptest"; 1.104 + do_check_eq(dict2.get("baz").prop, "proptest"); 1.105 +} 1.106 + 1.107 +// This is used by both test_listers and test_iterators. 1.108 +function _check_lists(keys, values, items) { 1.109 + do_check_eq(keys.length, 2); 1.110 + do_check_true(keys.indexOf("x") != -1); 1.111 + do_check_true(keys.indexOf("y") != -1); 1.112 + 1.113 + do_check_eq(values.length, 2); 1.114 + do_check_true(values.indexOf("a") != -1); 1.115 + do_check_true(values.indexOf("b") != -1); 1.116 + 1.117 + // This is a little more tricky -- we need to check that one of the two 1.118 + // entries is ["x", "a"] and the other is ["y", "b"]. 1.119 + do_check_eq(items.length, 2); 1.120 + do_check_eq(items[0].length, 2); 1.121 + do_check_eq(items[1].length, 2); 1.122 + let ix = (items[0][0] == "x") ? 0 : 1; 1.123 + let iy = (ix == 0) ? 1 : 0; 1.124 + do_check_eq(items[ix][0], "x"); 1.125 + do_check_eq(items[ix][1], "a"); 1.126 + do_check_eq(items[iy][0], "y"); 1.127 + do_check_eq(items[iy][1], "b"); 1.128 +} 1.129 + 1.130 +/** 1.131 + * Test the list functions. 1.132 + */ 1.133 +function test_listers() { 1.134 + let dict = new Dict({"x": "a", "y": "b"}); 1.135 + let keys = dict.listkeys(); 1.136 + let values = dict.listvalues(); 1.137 + let items = dict.listitems(); 1.138 + _check_lists(keys, values, items); 1.139 +} 1.140 + 1.141 +/** 1.142 + * Test the iterator functions. 1.143 + */ 1.144 +function test_iterators() { 1.145 + let dict = new Dict({"x": "a", "y": "b"}); 1.146 + // Convert the generators to lists 1.147 + let keys = [x for (x in dict.keys)]; 1.148 + let values = [x for (x in dict.values)]; 1.149 + let items = [x for (x in dict.items)]; 1.150 + _check_lists(keys, values, items); 1.151 +} 1.152 + 1.153 +/** 1.154 + * Test that setting a property throws an exception in strict mode. 1.155 + */ 1.156 +function test_set_property_strict() { 1.157 + "use strict"; 1.158 + var dict = new Dict(); 1.159 + var thrown = false; 1.160 + try { 1.161 + dict.foo = "bar"; 1.162 + } 1.163 + catch (ex) { 1.164 + thrown = true; 1.165 + } 1.166 + do_check_true(thrown); 1.167 +} 1.168 + 1.169 +/** 1.170 + * Test that setting a property has no effect in non-strict mode. 1.171 + */ 1.172 +function test_set_property_non_strict() { 1.173 + let dict = new Dict(); 1.174 + dict.foo = "bar"; 1.175 + do_check_false("foo" in dict); 1.176 + let realget = dict.get; 1.177 + dict.get = "baz"; 1.178 + do_check_eq(dict.get, realget); 1.179 +} 1.180 + 1.181 +/** 1.182 + * Tests setting a property by a lazy getter. 1.183 + */ 1.184 +function test_set_property_lazy_getter() { 1.185 + let thunkCalled = false; 1.186 + 1.187 + let setThunk = function(dict) { 1.188 + thunkCalled = false; 1.189 + dict.setAsLazyGetter("foo", function() { 1.190 + thunkCalled = true; 1.191 + return "bar"; 1.192 + }); 1.193 + }; 1.194 + 1.195 + let (dict = new Dict()) { 1.196 + setThunk(dict); 1.197 + 1.198 + // Test that checking for the key existence does not invoke 1.199 + // the getter function. 1.200 + do_check_true(dict.has("foo")); 1.201 + do_check_false(thunkCalled); 1.202 + do_check_true(dict.isLazyGetter("foo")); 1.203 + 1.204 + // Calling get the first time should invoke the getter function 1.205 + // and unmark the key as a lazy getter. 1.206 + do_check_eq(dict.get("foo"), "bar"); 1.207 + do_check_true(thunkCalled); 1.208 + do_check_false(dict.isLazyGetter("foo")); 1.209 + 1.210 + // Calling get again should not invoke the getter function 1.211 + thunkCalled = false; 1.212 + do_check_eq(dict.get("foo"), "bar"); 1.213 + do_check_false(thunkCalled); 1.214 + do_check_false(dict.isLazyGetter("foo")); 1.215 + } 1.216 + 1.217 + // Test that listvalues works for lazy keys. 1.218 + let (dict = new Dict()) { 1.219 + setThunk(dict); 1.220 + do_check_true(dict.isLazyGetter("foo")); 1.221 + 1.222 + let (listvalues = dict.listvalues()) { 1.223 + do_check_false(dict.isLazyGetter("foo")); 1.224 + do_check_true(thunkCalled); 1.225 + do_check_true(listvalues.length, 1); 1.226 + do_check_eq(listvalues[0], "bar"); 1.227 + } 1.228 + 1.229 + thunkCalled = false; 1.230 + 1.231 + // Retrieving the list again shouldn't invoke our getter. 1.232 + let (listvalues = dict.listvalues()) { 1.233 + do_check_false(dict.isLazyGetter("foo")); 1.234 + do_check_false(thunkCalled); 1.235 + do_check_true(listvalues.length, 1); 1.236 + do_check_eq(listvalues[0], "bar"); 1.237 + } 1.238 + } 1.239 + 1.240 + // Test that the values iterator also works as expected. 1.241 + let (dict = new Dict()) { 1.242 + setThunk(dict); 1.243 + let values = dict.values; 1.244 + 1.245 + // Our getter shouldn't be called before the iterator reaches it. 1.246 + do_check_true(dict.isLazyGetter("foo")); 1.247 + do_check_false(thunkCalled); 1.248 + do_check_eq(values.next(), "bar"); 1.249 + do_check_true(thunkCalled); 1.250 + 1.251 + thunkCalled = false; 1.252 + do_check_false(dict.isLazyGetter("foo")); 1.253 + do_check_eq(dict.get("foo"), "bar"); 1.254 + do_check_false(thunkCalled); 1.255 + } 1.256 +} 1.257 + 1.258 +// This is used by both test_construct_dict_from_json_string and test_serialize_dict_to_json_string 1.259 +function _sort_comp_arr(arr1,arr2){ 1.260 + arr1.sort(); 1.261 + arr2.sort(); 1.262 + do_check_eq(arr1.toString(),arr2.toString()); 1.263 +} 1.264 + 1.265 +/** 1.266 + * Tests constructing a dictionary from a JSON string. 1.267 + */ 1.268 +function test_construct_dict_from_json_string() { 1.269 + let d1 = new Dict({a:1, b:2, c:"foobar"}); 1.270 + let d2 = new Dict(JSON.stringify(({a:1, b:2, c:"foobar"}))); 1.271 + _sort_comp_arr(d1.listkeys(),d2.listkeys()); 1.272 + do_check_eq(d1.get("a"), d2.get("a")); 1.273 + do_check_eq(d1.get("b"), d2.get("b")); 1.274 + do_check_eq(d1.get("c"), d2.get("c")); 1.275 +} 1.276 + 1.277 +/** 1.278 + * Tests serializing a dictionary to a JSON string. 1.279 + */ 1.280 +function test_serialize_dict_to_json_string() { 1.281 + let d1 = new Dict({a:1, b:2, c:"foobar"}); 1.282 + let d2 = new Dict(d1.toJSON()); 1.283 + _sort_comp_arr(d1.listkeys(),d2.listkeys()); 1.284 + do_check_eq(d1.get("a"), d2.get("a")); 1.285 + do_check_eq(d1.get("b"), d2.get("b")); 1.286 + do_check_eq(d1.get("c"), d2.get("c")); 1.287 +} 1.288 + 1.289 +var tests = [ 1.290 + test_get_set_has_del, 1.291 + test_get_default, 1.292 + test_collisions_with_builtins, 1.293 + test_count, 1.294 + test_copy, 1.295 + test_listers, 1.296 + test_iterators, 1.297 + test_set_property_strict, 1.298 + test_set_property_non_strict, 1.299 + test_set_property_lazy_getter, 1.300 + test_construct_dict_from_json_string, 1.301 + test_serialize_dict_to_json_string 1.302 +]; 1.303 + 1.304 +function run_test() { 1.305 + for (let [, test] in Iterator(tests)) 1.306 + test(); 1.307 +}