| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | |
| 2 // for details. All rights reserved. Use of this source code is governed by a | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 library map_test; | |
| 6 | |
| 7 import "package:expect/expect.dart"; | |
| 8 import 'dart:collection'; | |
| 9 import 'dart:convert' show JSON; | |
| 10 | |
| 11 Map newJsonMap() => JSON.decode('{}'); | |
| 12 Map newJsonMapCustomReviver() => | |
| 13 JSON.decode('{}', reviver: (key, value) => value); | |
| 14 | |
| 15 void main() { | |
| 16 test(new HashMap()); | |
| 17 test(new LinkedHashMap()); | |
| 18 test(new SplayTreeMap()); | |
| 19 test(new SplayTreeMap(Comparable.compare)); | |
| 20 test(new MapView(new HashMap())); | |
| 21 test(new MapView(new SplayTreeMap())); | |
| 22 test(new MapBaseMap()); | |
| 23 test(new MapMixinMap()); | |
| 24 test(newJsonMap()); | |
| 25 test(newJsonMapCustomReviver()); | |
| 26 testLinkedHashMap(); | |
| 27 testMapLiteral(); | |
| 28 testNullValue(); | |
| 29 testTypes(); | |
| 30 | |
| 31 testWeirdStringKeys(new Map()); | |
| 32 testWeirdStringKeys(new Map<String, String>()); | |
| 33 testWeirdStringKeys(new HashMap()); | |
| 34 testWeirdStringKeys(new HashMap<String, String>()); | |
| 35 testWeirdStringKeys(new LinkedHashMap()); | |
| 36 testWeirdStringKeys(new LinkedHashMap<String, String>()); | |
| 37 testWeirdStringKeys(new SplayTreeMap()); | |
| 38 testWeirdStringKeys(new SplayTreeMap<String, String>()); | |
| 39 testWeirdStringKeys(new MapBaseMap<String, String>()); | |
| 40 testWeirdStringKeys(new MapMixinMap<String, String>()); | |
| 41 testWeirdStringKeys(newJsonMap()); | |
| 42 testWeirdStringKeys(newJsonMapCustomReviver()); | |
| 43 | |
| 44 testNumericKeys(new Map()); | |
| 45 testNumericKeys(new Map<num, String>()); | |
| 46 testNumericKeys(new HashMap()); | |
| 47 testNumericKeys(new HashMap<num, String>()); | |
| 48 testNumericKeys(new HashMap.identity()); | |
| 49 testNumericKeys(new HashMap<num, String>.identity()); | |
| 50 testNumericKeys(new LinkedHashMap()); | |
| 51 testNumericKeys(new LinkedHashMap<num, String>()); | |
| 52 testNumericKeys(new LinkedHashMap.identity()); | |
| 53 testNumericKeys(new LinkedHashMap<num, String>.identity()); | |
| 54 testNumericKeys(new MapBaseMap<num, String>()); | |
| 55 testNumericKeys(new MapMixinMap<num, String>()); | |
| 56 testNumericKeys(newJsonMap()); | |
| 57 testNumericKeys(newJsonMapCustomReviver()); | |
| 58 | |
| 59 testNaNKeys(new Map()); | |
| 60 testNaNKeys(new Map<num, String>()); | |
| 61 testNaNKeys(new HashMap()); | |
| 62 testNaNKeys(new HashMap<num, String>()); | |
| 63 testNaNKeys(new LinkedHashMap()); | |
| 64 testNaNKeys(new LinkedHashMap<num, String>()); | |
| 65 testNaNKeys(new MapBaseMap<num, String>()); | |
| 66 testNaNKeys(new MapMixinMap<num, String>()); | |
| 67 testNaNKeys(newJsonMap()); | |
| 68 testNaNKeys(newJsonMapCustomReviver()); | |
| 69 // Identity maps fail the NaN-keys tests because the test assumes that | |
| 70 // NaN is not equal to NaN. | |
| 71 | |
| 72 testIdentityMap(new Map.identity()); | |
| 73 testIdentityMap(new HashMap.identity()); | |
| 74 testIdentityMap(new LinkedHashMap.identity()); | |
| 75 testIdentityMap(new HashMap(equals: identical, hashCode: identityHashCode)); | |
| 76 testIdentityMap( | |
| 77 new LinkedHashMap(equals: identical, hashCode: identityHashCode)); | |
| 78 testIdentityMap(new HashMap( | |
| 79 equals: (x, y) => identical(x, y), hashCode: (x) => identityHashCode(x))); | |
| 80 testIdentityMap(new LinkedHashMap( | |
| 81 equals: (x, y) => identical(x, y), hashCode: (x) => identityHashCode(x))); | |
| 82 | |
| 83 testCustomMap(new HashMap( | |
| 84 equals: myEquals, | |
| 85 hashCode: myHashCode, | |
| 86 isValidKey: (v) => v is Customer)); | |
| 87 testCustomMap(new LinkedHashMap( | |
| 88 equals: myEquals, | |
| 89 hashCode: myHashCode, | |
| 90 isValidKey: (v) => v is Customer)); | |
| 91 testCustomMap( | |
| 92 new HashMap<Customer, dynamic>(equals: myEquals, hashCode: myHashCode)); | |
| 93 | |
| 94 testCustomMap(new LinkedHashMap<Customer, dynamic>( | |
| 95 equals: myEquals, hashCode: myHashCode)); | |
| 96 | |
| 97 testIterationOrder(new LinkedHashMap()); | |
| 98 testIterationOrder(new LinkedHashMap.identity()); | |
| 99 testIterationOrder(newJsonMap()); | |
| 100 testIterationOrder(newJsonMapCustomReviver()); | |
| 101 | |
| 102 testOtherKeys(new SplayTreeMap<int, int>()); | |
| 103 testOtherKeys( | |
| 104 new SplayTreeMap<int, int>((int a, int b) => a - b, (v) => v is int)); | |
| 105 testOtherKeys(new SplayTreeMap((int a, int b) => a - b, (v) => v is int)); | |
| 106 testOtherKeys(new HashMap<int, int>()); | |
| 107 testOtherKeys(new HashMap<int, int>.identity()); | |
| 108 testOtherKeys(new HashMap<int, int>( | |
| 109 hashCode: (v) => v.hashCode, isValidKey: (v) => v is int)); | |
| 110 testOtherKeys(new HashMap( | |
| 111 equals: (int x, int y) => x == y, | |
| 112 hashCode: (int v) => v.hashCode, | |
| 113 isValidKey: (v) => v is int)); | |
| 114 testOtherKeys(new LinkedHashMap<int, int>()); | |
| 115 testOtherKeys(new LinkedHashMap<int, int>.identity()); | |
| 116 testOtherKeys(new LinkedHashMap<int, int>( | |
| 117 hashCode: (v) => v.hashCode, isValidKey: (v) => v is int)); | |
| 118 testOtherKeys(new LinkedHashMap( | |
| 119 equals: (int x, int y) => x == y, | |
| 120 hashCode: (int v) => v.hashCode, | |
| 121 isValidKey: (v) => v is int)); | |
| 122 testOtherKeys(new MapBaseMap<int, int>()); | |
| 123 testOtherKeys(new MapMixinMap<int, int>()); | |
| 124 testOtherKeys(newJsonMap()); | |
| 125 testOtherKeys(newJsonMapCustomReviver()); | |
| 126 | |
| 127 testUnmodifiableMap(const {1: 37}); | |
| 128 testUnmodifiableMap(new UnmodifiableMapView({1: 37})); | |
| 129 testUnmodifiableMap(new UnmodifiableMapBaseMap([1, 37])); | |
| 130 | |
| 131 testFrom(); | |
| 132 } | |
| 133 | |
| 134 void test(Map map) { | |
| 135 testDeletedElement(map); | |
| 136 testMap(map, 1, 2, 3, 4, 5, 6, 7, 8); | |
| 137 map.clear(); | |
| 138 testMap(map, "value1", "value2", "value3", "value4", "value5", "value6", | |
| 139 "value7", "value8"); | |
| 140 } | |
| 141 | |
| 142 void testLinkedHashMap() { | |
| 143 LinkedHashMap map = new LinkedHashMap(); | |
| 144 Expect.equals(false, map.containsKey(1)); | |
| 145 map[1] = 1; | |
| 146 map[1] = 2; | |
| 147 testLength(1, map); | |
| 148 } | |
| 149 | |
| 150 void testMap(Map map, key1, key2, key3, key4, key5, key6, key7, key8) { | |
| 151 int value1 = 10; | |
| 152 int value2 = 20; | |
| 153 int value3 = 30; | |
| 154 int value4 = 40; | |
| 155 int value5 = 50; | |
| 156 int value6 = 60; | |
| 157 int value7 = 70; | |
| 158 int value8 = 80; | |
| 159 | |
| 160 testLength(0, map); | |
| 161 | |
| 162 map[key1] = value1; | |
| 163 Expect.equals(value1, map[key1]); | |
| 164 map[key1] = value2; | |
| 165 Expect.equals(false, map.containsKey(key2)); | |
| 166 testLength(1, map); | |
| 167 | |
| 168 map[key1] = value1; | |
| 169 Expect.equals(value1, map[key1]); | |
| 170 // Add enough entries to make sure the table grows. | |
| 171 map[key2] = value2; | |
| 172 Expect.equals(value2, map[key2]); | |
| 173 testLength(2, map); | |
| 174 map[key3] = value3; | |
| 175 Expect.equals(value2, map[key2]); | |
| 176 Expect.equals(value3, map[key3]); | |
| 177 map[key4] = value4; | |
| 178 Expect.equals(value3, map[key3]); | |
| 179 Expect.equals(value4, map[key4]); | |
| 180 map[key5] = value5; | |
| 181 Expect.equals(value4, map[key4]); | |
| 182 Expect.equals(value5, map[key5]); | |
| 183 map[key6] = value6; | |
| 184 Expect.equals(value5, map[key5]); | |
| 185 Expect.equals(value6, map[key6]); | |
| 186 map[key7] = value7; | |
| 187 Expect.equals(value6, map[key6]); | |
| 188 Expect.equals(value7, map[key7]); | |
| 189 map[key8] = value8; | |
| 190 Expect.equals(value1, map[key1]); | |
| 191 Expect.equals(value2, map[key2]); | |
| 192 Expect.equals(value3, map[key3]); | |
| 193 Expect.equals(value4, map[key4]); | |
| 194 Expect.equals(value5, map[key5]); | |
| 195 Expect.equals(value6, map[key6]); | |
| 196 Expect.equals(value7, map[key7]); | |
| 197 Expect.equals(value8, map[key8]); | |
| 198 testLength(8, map); | |
| 199 | |
| 200 map.remove(key4); | |
| 201 Expect.equals(false, map.containsKey(key4)); | |
| 202 testLength(7, map); | |
| 203 | |
| 204 // Test clearing the table. | |
| 205 map.clear(); | |
| 206 testLength(0, map); | |
| 207 Expect.equals(false, map.containsKey(key1)); | |
| 208 Expect.equals(false, map.containsKey(key2)); | |
| 209 Expect.equals(false, map.containsKey(key3)); | |
| 210 Expect.equals(false, map.containsKey(key4)); | |
| 211 Expect.equals(false, map.containsKey(key5)); | |
| 212 Expect.equals(false, map.containsKey(key6)); | |
| 213 Expect.equals(false, map.containsKey(key7)); | |
| 214 Expect.equals(false, map.containsKey(key8)); | |
| 215 | |
| 216 // Test adding and removing again. | |
| 217 map[key1] = value1; | |
| 218 Expect.equals(value1, map[key1]); | |
| 219 testLength(1, map); | |
| 220 map[key2] = value2; | |
| 221 Expect.equals(value2, map[key2]); | |
| 222 testLength(2, map); | |
| 223 map[key3] = value3; | |
| 224 Expect.equals(value3, map[key3]); | |
| 225 map.remove(key3); | |
| 226 testLength(2, map); | |
| 227 map[key4] = value4; | |
| 228 Expect.equals(value4, map[key4]); | |
| 229 map.remove(key4); | |
| 230 testLength(2, map); | |
| 231 map[key5] = value5; | |
| 232 Expect.equals(value5, map[key5]); | |
| 233 map.remove(key5); | |
| 234 testLength(2, map); | |
| 235 map[key6] = value6; | |
| 236 Expect.equals(value6, map[key6]); | |
| 237 map.remove(key6); | |
| 238 testLength(2, map); | |
| 239 map[key7] = value7; | |
| 240 Expect.equals(value7, map[key7]); | |
| 241 map.remove(key7); | |
| 242 testLength(2, map); | |
| 243 map[key8] = value8; | |
| 244 Expect.equals(value8, map[key8]); | |
| 245 map.remove(key8); | |
| 246 testLength(2, map); | |
| 247 | |
| 248 Expect.equals(true, map.containsKey(key1)); | |
| 249 Expect.equals(true, map.containsValue(value1)); | |
| 250 | |
| 251 // Test Map.forEach. | |
| 252 Map otherMap = new Map(); | |
| 253 void testForEachMap(key, value) { | |
| 254 otherMap[key] = value; | |
| 255 } | |
| 256 | |
| 257 map.forEach(testForEachMap); | |
| 258 Expect.equals(true, otherMap.containsKey(key1)); | |
| 259 Expect.equals(true, otherMap.containsKey(key2)); | |
| 260 Expect.equals(true, otherMap.containsValue(value1)); | |
| 261 Expect.equals(true, otherMap.containsValue(value2)); | |
| 262 Expect.equals(2, otherMap.length); | |
| 263 | |
| 264 otherMap.clear(); | |
| 265 Expect.equals(0, otherMap.length); | |
| 266 | |
| 267 // Test Collection.keys. | |
| 268 void testForEachCollection(value) { | |
| 269 otherMap[value] = value; | |
| 270 } | |
| 271 | |
| 272 Iterable keys = map.keys; | |
| 273 keys.forEach(testForEachCollection); | |
| 274 Expect.equals(true, otherMap.containsKey(key1)); | |
| 275 Expect.equals(true, otherMap.containsKey(key2)); | |
| 276 Expect.equals(true, otherMap.containsValue(key1)); | |
| 277 Expect.equals(true, otherMap.containsValue(key2)); | |
| 278 Expect.equals(true, !otherMap.containsKey(value1)); | |
| 279 Expect.equals(true, !otherMap.containsKey(value2)); | |
| 280 Expect.equals(true, !otherMap.containsValue(value1)); | |
| 281 Expect.equals(true, !otherMap.containsValue(value2)); | |
| 282 Expect.equals(2, otherMap.length); | |
| 283 otherMap.clear(); | |
| 284 Expect.equals(0, otherMap.length); | |
| 285 | |
| 286 // Test Collection.values. | |
| 287 Iterable values = map.values; | |
| 288 values.forEach(testForEachCollection); | |
| 289 Expect.equals(true, !otherMap.containsKey(key1)); | |
| 290 Expect.equals(true, !otherMap.containsKey(key2)); | |
| 291 Expect.equals(true, !otherMap.containsValue(key1)); | |
| 292 Expect.equals(true, !otherMap.containsValue(key2)); | |
| 293 Expect.equals(true, otherMap.containsKey(value1)); | |
| 294 Expect.equals(true, otherMap.containsKey(value2)); | |
| 295 Expect.equals(true, otherMap.containsValue(value1)); | |
| 296 Expect.equals(true, otherMap.containsValue(value2)); | |
| 297 Expect.equals(2, otherMap.length); | |
| 298 otherMap.clear(); | |
| 299 Expect.equals(0, otherMap.length); | |
| 300 | |
| 301 // Test Map.putIfAbsent. | |
| 302 map.clear(); | |
| 303 Expect.equals(false, map.containsKey(key1)); | |
| 304 map.putIfAbsent(key1, () => 10); | |
| 305 Expect.equals(true, map.containsKey(key1)); | |
| 306 Expect.equals(10, map[key1]); | |
| 307 Expect.equals(10, map.putIfAbsent(key1, () => 11)); | |
| 308 | |
| 309 // Test Map.addAll. | |
| 310 map.clear(); | |
| 311 otherMap.clear(); | |
| 312 otherMap[99] = 1; | |
| 313 otherMap[50] = 50; | |
| 314 otherMap[1] = 99; | |
| 315 map.addAll(otherMap); | |
| 316 Expect.equals(3, map.length); | |
| 317 Expect.equals(1, map[99]); | |
| 318 Expect.equals(50, map[50]); | |
| 319 Expect.equals(99, map[1]); | |
| 320 otherMap[50] = 42; | |
| 321 map.addAll(new HashMap.from(otherMap)); | |
| 322 Expect.equals(3, map.length); | |
| 323 Expect.equals(1, map[99]); | |
| 324 Expect.equals(42, map[50]); | |
| 325 Expect.equals(99, map[1]); | |
| 326 otherMap[99] = 7; | |
| 327 map.addAll(new SplayTreeMap.from(otherMap)); | |
| 328 Expect.equals(3, map.length); | |
| 329 Expect.equals(7, map[99]); | |
| 330 Expect.equals(42, map[50]); | |
| 331 Expect.equals(99, map[1]); | |
| 332 otherMap.remove(99); | |
| 333 map[99] = 0; | |
| 334 map.addAll(otherMap); | |
| 335 Expect.equals(3, map.length); | |
| 336 Expect.equals(0, map[99]); | |
| 337 Expect.equals(42, map[50]); | |
| 338 Expect.equals(99, map[1]); | |
| 339 map.clear(); | |
| 340 otherMap.clear(); | |
| 341 map.addAll(otherMap); | |
| 342 Expect.equals(0, map.length); | |
| 343 } | |
| 344 | |
| 345 void testDeletedElement(Map map) { | |
| 346 map.clear(); | |
| 347 for (int i = 0; i < 100; i++) { | |
| 348 map[1] = 2; | |
| 349 testLength(1, map); | |
| 350 map.remove(1); | |
| 351 testLength(0, map); | |
| 352 } | |
| 353 testLength(0, map); | |
| 354 } | |
| 355 | |
| 356 void testMapLiteral() { | |
| 357 Map m = {"a": 1, "b": 2, "c": 3}; | |
| 358 Expect.equals(3, m.length); | |
| 359 int sum = 0; | |
| 360 m.forEach((a, b) { | |
| 361 sum += b; | |
| 362 }); | |
| 363 Expect.equals(6, sum); | |
| 364 | |
| 365 List values = m.keys.toList(); | |
| 366 Expect.equals(3, values.length); | |
| 367 String first = values[0]; | |
| 368 String second = values[1]; | |
| 369 String third = values[2]; | |
| 370 String all = "${first}${second}${third}"; | |
| 371 Expect.equals(3, all.length); | |
| 372 Expect.equals(true, all.contains("a", 0)); | |
| 373 Expect.equals(true, all.contains("b", 0)); | |
| 374 Expect.equals(true, all.contains("c", 0)); | |
| 375 } | |
| 376 | |
| 377 void testNullValue() { | |
| 378 Map m = {"a": 1, "b": null, "c": 3}; | |
| 379 | |
| 380 Expect.equals(null, m["b"]); | |
| 381 Expect.equals(true, m.containsKey("b")); | |
| 382 Expect.equals(3, m.length); | |
| 383 | |
| 384 m["a"] = null; | |
| 385 m["c"] = null; | |
| 386 Expect.equals(null, m["a"]); | |
| 387 Expect.equals(true, m.containsKey("a")); | |
| 388 Expect.equals(null, m["c"]); | |
| 389 Expect.equals(true, m.containsKey("c")); | |
| 390 Expect.equals(3, m.length); | |
| 391 | |
| 392 m.remove("a"); | |
| 393 Expect.equals(2, m.length); | |
| 394 Expect.equals(null, m["a"]); | |
| 395 Expect.equals(false, m.containsKey("a")); | |
| 396 } | |
| 397 | |
| 398 void testTypes() { | |
| 399 testMap(Map<num, String> map) { | |
| 400 Expect.isTrue(map is Map<num, String>); | |
| 401 Expect.isTrue(map is! Map<String, dynamic>); | |
| 402 Expect.isTrue(map is! Map<dynamic, int>); | |
| 403 | |
| 404 // Use with properly typed keys and values. | |
| 405 map[42] = "text1"; | |
| 406 map[43] = "text2"; | |
| 407 map[42] = "text3"; | |
| 408 Expect.equals("text3", map.remove(42)); | |
| 409 Expect.equals(null, map[42]); | |
| 410 map[42] = "text4"; | |
| 411 | |
| 412 // Ensure that "containsKey", "containsValue" and "remove" | |
| 413 // accepts any object. | |
| 414 for (var object in [true, null, new Object()]) { | |
| 415 Expect.isFalse(map.containsKey(object)); | |
| 416 Expect.isFalse(map.containsValue(object)); | |
| 417 Expect.isNull(map.remove(object)); | |
| 418 Expect.isNull(map[object]); | |
| 419 } | |
| 420 } | |
| 421 | |
| 422 testMap(new HashMap<int, String>()); | |
| 423 testMap(new LinkedHashMap<int, String>()); | |
| 424 testMap(new SplayTreeMap<int, String>()); | |
| 425 testMap(new SplayTreeMap<int, String>(Comparable.compare)); | |
| 426 testMap(new SplayTreeMap<int, String>((int a, int b) => a.compareTo(b))); | |
| 427 testMap(new HashMap<num, String>()); | |
| 428 testMap(new LinkedHashMap<num, String>()); | |
| 429 testMap(new SplayTreeMap<num, String>()); | |
| 430 testMap(new SplayTreeMap<num, String>(Comparable.compare)); | |
| 431 testMap(new SplayTreeMap<num, String>((num a, num b) => a.compareTo(b))); | |
| 432 } | |
| 433 | |
| 434 void testWeirdStringKeys(Map map) { | |
| 435 // Test weird keys. | |
| 436 var weirdKeys = const [ | |
| 437 'hasOwnProperty', | |
| 438 'constructor', | |
| 439 'toLocaleString', | |
| 440 'propertyIsEnumerable', | |
| 441 '__defineGetter__', | |
| 442 '__defineSetter__', | |
| 443 '__lookupGetter__', | |
| 444 '__lookupSetter__', | |
| 445 'isPrototypeOf', | |
| 446 'toString', | |
| 447 'valueOf', | |
| 448 '__proto__', | |
| 449 '__count__', | |
| 450 '__parent__', | |
| 451 '' | |
| 452 ]; | |
| 453 Expect.isTrue(map.isEmpty); | |
| 454 for (var key in weirdKeys) { | |
| 455 Expect.isFalse(map.containsKey(key)); | |
| 456 Expect.equals(null, map[key]); | |
| 457 var value = 'value:$key'; | |
| 458 map[key] = value; | |
| 459 Expect.isTrue(map.containsKey(key)); | |
| 460 Expect.equals(value, map[key]); | |
| 461 Expect.equals(value, map.remove(key)); | |
| 462 Expect.isFalse(map.containsKey(key)); | |
| 463 Expect.equals(null, map[key]); | |
| 464 } | |
| 465 Expect.isTrue(map.isEmpty); | |
| 466 } | |
| 467 | |
| 468 void testNumericKeys(Map map) { | |
| 469 var numericKeys = const [ | |
| 470 double.INFINITY, | |
| 471 double.NEGATIVE_INFINITY, | |
| 472 0, | |
| 473 0.0, | |
| 474 -0.0 | |
| 475 ]; | |
| 476 | |
| 477 Expect.isTrue(map.isEmpty); | |
| 478 for (var key in numericKeys) { | |
| 479 Expect.isFalse(map.containsKey(key)); | |
| 480 Expect.equals(null, map[key]); | |
| 481 var value = 'value:$key'; | |
| 482 map[key] = value; | |
| 483 Expect.isTrue(map.containsKey(key)); | |
| 484 Expect.equals(value, map[key]); | |
| 485 Expect.equals(value, map.remove(key)); | |
| 486 Expect.isFalse(map.containsKey(key)); | |
| 487 Expect.equals(null, map[key]); | |
| 488 } | |
| 489 Expect.isTrue(map.isEmpty); | |
| 490 } | |
| 491 | |
| 492 void testNaNKeys(Map map) { | |
| 493 Expect.isTrue(map.isEmpty); | |
| 494 // Test NaN. | |
| 495 var nan = double.NAN; | |
| 496 Expect.isFalse(map.containsKey(nan)); | |
| 497 Expect.equals(null, map[nan]); | |
| 498 | |
| 499 map[nan] = 'value:0'; | |
| 500 Expect.isFalse(map.containsKey(nan)); | |
| 501 Expect.equals(null, map[nan]); | |
| 502 testLength(1, map); | |
| 503 | |
| 504 map[nan] = 'value:1'; | |
| 505 Expect.isFalse(map.containsKey(nan)); | |
| 506 Expect.equals(null, map[nan]); | |
| 507 testLength(2, map); | |
| 508 | |
| 509 Expect.equals(null, map.remove(nan)); | |
| 510 testLength(2, map); | |
| 511 | |
| 512 var count = 0; | |
| 513 map.forEach((key, value) { | |
| 514 if (key.isNaN) count++; | |
| 515 }); | |
| 516 Expect.equals(2, count); | |
| 517 | |
| 518 map.clear(); | |
| 519 Expect.isTrue(map.isEmpty); | |
| 520 } | |
| 521 | |
| 522 void testLength(int length, Map map) { | |
| 523 Expect.equals(length, map.length); | |
| 524 Expect.equals(length, map.keys.length); | |
| 525 Expect.equals(length, map.values.length); | |
| 526 // Check being-empty. | |
| 527 var ifEmpty = (length == 0) ? Expect.isTrue : Expect.isFalse; | |
| 528 var ifNotEmpty = (length != 0) ? Expect.isTrue : Expect.isFalse; | |
| 529 ifEmpty(map.isEmpty); | |
| 530 ifNotEmpty(map.isNotEmpty); | |
| 531 ifEmpty(map.keys.isEmpty); | |
| 532 ifNotEmpty(map.keys.isNotEmpty); | |
| 533 ifEmpty(map.values.isEmpty); | |
| 534 ifNotEmpty(map.values.isNotEmpty); | |
| 535 // Test key/value iterators match their isEmpty/isNotEmpty. | |
| 536 ifNotEmpty(map.keys.iterator.moveNext()); | |
| 537 ifNotEmpty(map.values.iterator.moveNext()); | |
| 538 if (length == 0) { | |
| 539 for (var k in map.keys) Expect.fail("contains key when iterating: $k"); | |
| 540 for (var v in map.values) Expect.fail("contains values when iterating: $v"); | |
| 541 } | |
| 542 } | |
| 543 | |
| 544 testIdentityMap(Map map) { | |
| 545 Expect.isTrue(map.isEmpty); | |
| 546 | |
| 547 var nan = double.NAN; | |
| 548 // TODO(11551): Remove guard when dart2js makes identical(NaN, NaN) true. | |
| 549 if (identical(nan, nan)) { | |
| 550 map[nan] = 42; | |
| 551 testLength(1, map); | |
| 552 Expect.isTrue(map.containsKey(nan)); | |
| 553 Expect.equals(42, map[nan]); | |
| 554 map[nan] = 37; | |
| 555 testLength(1, map); | |
| 556 Expect.equals(37, map[nan]); | |
| 557 Expect.equals(37, map.remove(nan)); | |
| 558 testLength(0, map); | |
| 559 } | |
| 560 | |
| 561 Vampire v1 = const Vampire(1); | |
| 562 Vampire v2 = const Vampire(2); | |
| 563 Expect.isFalse(v1 == v1); | |
| 564 Expect.isFalse(v2 == v2); | |
| 565 Expect.isTrue(v2 == v1); // Snob! | |
| 566 | |
| 567 map[v1] = 1; | |
| 568 map[v2] = 2; | |
| 569 testLength(2, map); | |
| 570 | |
| 571 Expect.isTrue(map.containsKey(v1)); | |
| 572 Expect.isTrue(map.containsKey(v2)); | |
| 573 | |
| 574 Expect.equals(1, map[v1]); | |
| 575 Expect.equals(2, map[v2]); | |
| 576 | |
| 577 Expect.equals(1, map.remove(v1)); | |
| 578 testLength(1, map); | |
| 579 Expect.isFalse(map.containsKey(v1)); | |
| 580 Expect.isTrue(map.containsKey(v2)); | |
| 581 | |
| 582 Expect.isNull(map.remove(v1)); | |
| 583 Expect.equals(2, map.remove(v2)); | |
| 584 testLength(0, map); | |
| 585 | |
| 586 var eq01 = new Equalizer(0); | |
| 587 var eq02 = new Equalizer(0); | |
| 588 var eq11 = new Equalizer(1); | |
| 589 var eq12 = new Equalizer(1); | |
| 590 // Sanity. | |
| 591 Expect.equals(eq01, eq02); | |
| 592 Expect.equals(eq02, eq01); | |
| 593 Expect.equals(eq11, eq12); | |
| 594 Expect.equals(eq12, eq11); | |
| 595 Expect.notEquals(eq01, eq11); | |
| 596 Expect.notEquals(eq01, eq12); | |
| 597 Expect.notEquals(eq02, eq11); | |
| 598 Expect.notEquals(eq02, eq12); | |
| 599 Expect.notEquals(eq11, eq01); | |
| 600 Expect.notEquals(eq11, eq02); | |
| 601 Expect.notEquals(eq12, eq01); | |
| 602 Expect.notEquals(eq12, eq02); | |
| 603 | |
| 604 map[eq01] = 0; | |
| 605 map[eq02] = 1; | |
| 606 map[eq11] = 2; | |
| 607 map[eq12] = 3; | |
| 608 testLength(4, map); | |
| 609 | |
| 610 Expect.equals(0, map[eq01]); | |
| 611 Expect.equals(1, map[eq02]); | |
| 612 Expect.equals(2, map[eq11]); | |
| 613 Expect.equals(3, map[eq12]); | |
| 614 | |
| 615 Expect.isTrue(map.containsKey(eq01)); | |
| 616 Expect.isTrue(map.containsKey(eq02)); | |
| 617 Expect.isTrue(map.containsKey(eq11)); | |
| 618 Expect.isTrue(map.containsKey(eq12)); | |
| 619 | |
| 620 Expect.equals(1, map.remove(eq02)); | |
| 621 Expect.equals(3, map.remove(eq12)); | |
| 622 testLength(2, map); | |
| 623 Expect.isTrue(map.containsKey(eq01)); | |
| 624 Expect.isFalse(map.containsKey(eq02)); | |
| 625 Expect.isTrue(map.containsKey(eq11)); | |
| 626 Expect.isFalse(map.containsKey(eq12)); | |
| 627 | |
| 628 Expect.equals(0, map[eq01]); | |
| 629 Expect.equals(null, map[eq02]); | |
| 630 Expect.equals(2, map[eq11]); | |
| 631 Expect.equals(null, map[eq12]); | |
| 632 | |
| 633 Expect.equals(0, map.remove(eq01)); | |
| 634 Expect.equals(2, map.remove(eq11)); | |
| 635 testLength(0, map); | |
| 636 | |
| 637 map[eq01] = 0; | |
| 638 map[eq02] = 1; | |
| 639 map[eq11] = 2; | |
| 640 map[eq12] = 3; | |
| 641 testLength(4, map); | |
| 642 | |
| 643 // Transfer to equality-based map will collapse elements. | |
| 644 Map eqMap = new HashMap(); | |
| 645 eqMap.addAll(map); | |
| 646 testLength(2, eqMap); | |
| 647 Expect.isTrue(eqMap.containsKey(eq01)); | |
| 648 Expect.isTrue(eqMap.containsKey(eq02)); | |
| 649 Expect.isTrue(eqMap.containsKey(eq11)); | |
| 650 Expect.isTrue(eqMap.containsKey(eq12)); | |
| 651 | |
| 652 // Changing objects will not affect identity map. | |
| 653 map.clear(); | |
| 654 var m1 = new Mutable(1); | |
| 655 var m2 = new Mutable(2); | |
| 656 var m3 = new Mutable(3); | |
| 657 map[m1] = 1; | |
| 658 map[m2] = 2; | |
| 659 map[m3] = 3; | |
| 660 Expect.equals(3, map.length); | |
| 661 Expect.isTrue(map.containsKey(m1)); | |
| 662 Expect.isTrue(map.containsKey(m2)); | |
| 663 Expect.isTrue(map.containsKey(m3)); | |
| 664 Expect.notEquals(m1, m3); | |
| 665 m3.id = 1; | |
| 666 Expect.equals(m1, m3); | |
| 667 // Even if keys are equal, they are still not identical. | |
| 668 // Even if hashcode of m3 changed, it can still be found. | |
| 669 Expect.equals(1, map[m1]); | |
| 670 Expect.equals(3, map[m3]); | |
| 671 } | |
| 672 | |
| 673 /** Class of objects that are equal if they hold the same id. */ | |
| 674 class Equalizer { | |
| 675 int id; | |
| 676 Equalizer(this.id); | |
| 677 int get hashCode => id; | |
| 678 bool operator ==(Object other) => | |
| 679 other is Equalizer && id == (other as Equalizer).id; | |
| 680 } | |
| 681 | |
| 682 /** | |
| 683 * Objects that are not reflexive. | |
| 684 * | |
| 685 * They think they are better than their equals. | |
| 686 */ | |
| 687 class Vampire { | |
| 688 final int generation; | |
| 689 const Vampire(this.generation); | |
| 690 | |
| 691 int get hashCode => generation; | |
| 692 | |
| 693 // The double-fang operator falsely claims that a vampire is equal to | |
| 694 // any of its sire's generation. | |
| 695 bool operator ==(Object other) => | |
| 696 other is Vampire && generation - 1 == (other as Vampire).generation; | |
| 697 } | |
| 698 | |
| 699 void testCustomMap(Map map) { | |
| 700 testLength(0, map); | |
| 701 var c11 = const Customer(1, 1); | |
| 702 var c12 = const Customer(1, 2); | |
| 703 var c21 = const Customer(2, 1); | |
| 704 var c22 = const Customer(2, 2); | |
| 705 // Sanity. | |
| 706 Expect.equals(c11, c12); | |
| 707 Expect.notEquals(c11, c21); | |
| 708 Expect.notEquals(c11, c22); | |
| 709 Expect.equals(c21, c22); | |
| 710 Expect.notEquals(c21, c11); | |
| 711 Expect.notEquals(c21, c12); | |
| 712 | |
| 713 Expect.isTrue(myEquals(c11, c21)); | |
| 714 Expect.isFalse(myEquals(c11, c12)); | |
| 715 Expect.isFalse(myEquals(c11, c22)); | |
| 716 Expect.isTrue(myEquals(c12, c22)); | |
| 717 Expect.isFalse(myEquals(c12, c11)); | |
| 718 Expect.isFalse(myEquals(c12, c21)); | |
| 719 | |
| 720 map[c11] = 42; | |
| 721 testLength(1, map); | |
| 722 Expect.isTrue(map.containsKey(c11)); | |
| 723 Expect.isTrue(map.containsKey(c21)); | |
| 724 Expect.isFalse(map.containsKey(c12)); | |
| 725 Expect.isFalse(map.containsKey(c22)); | |
| 726 Expect.equals(42, map[c11]); | |
| 727 Expect.equals(42, map[c21]); | |
| 728 | |
| 729 map[c21] = 37; | |
| 730 testLength(1, map); | |
| 731 Expect.isTrue(map.containsKey(c11)); | |
| 732 Expect.isTrue(map.containsKey(c21)); | |
| 733 Expect.isFalse(map.containsKey(c12)); | |
| 734 Expect.isFalse(map.containsKey(c22)); | |
| 735 Expect.equals(37, map[c11]); | |
| 736 Expect.equals(37, map[c21]); | |
| 737 | |
| 738 map[c22] = 42; | |
| 739 testLength(2, map); | |
| 740 Expect.isTrue(map.containsKey(c11)); | |
| 741 Expect.isTrue(map.containsKey(c21)); | |
| 742 Expect.isTrue(map.containsKey(c12)); | |
| 743 Expect.isTrue(map.containsKey(c22)); | |
| 744 Expect.equals(37, map[c11]); | |
| 745 Expect.equals(37, map[c21]); | |
| 746 Expect.equals(42, map[c12]); | |
| 747 Expect.equals(42, map[c22]); | |
| 748 | |
| 749 Expect.equals(42, map.remove(c12)); | |
| 750 testLength(1, map); | |
| 751 Expect.isTrue(map.containsKey(c11)); | |
| 752 Expect.isTrue(map.containsKey(c21)); | |
| 753 Expect.isFalse(map.containsKey(c12)); | |
| 754 Expect.isFalse(map.containsKey(c22)); | |
| 755 Expect.equals(37, map[c11]); | |
| 756 Expect.equals(37, map[c21]); | |
| 757 | |
| 758 Expect.equals(37, map.remove(c11)); | |
| 759 testLength(0, map); | |
| 760 } | |
| 761 | |
| 762 void testUnmodifiableMap(Map map) { | |
| 763 Expect.isTrue(map.containsKey(1)); | |
| 764 testLength(1, map); | |
| 765 Expect.equals(1, map.keys.first); | |
| 766 Expect.equals(37, map.values.first); | |
| 767 | |
| 768 Expect.throws(map.clear); | |
| 769 Expect.throws(() { | |
| 770 map.remove(1); | |
| 771 }); | |
| 772 Expect.throws(() { | |
| 773 map[2] = 42; | |
| 774 }); | |
| 775 Expect.throws(() { | |
| 776 map.addAll({2: 42}); | |
| 777 }); | |
| 778 } | |
| 779 | |
| 780 class Customer { | |
| 781 final int id; | |
| 782 final int secondId; | |
| 783 const Customer(this.id, this.secondId); | |
| 784 int get hashCode => id; | |
| 785 bool operator ==(Object other) { | |
| 786 if (other is! Customer) return false; | |
| 787 Customer otherCustomer = other; | |
| 788 return id == otherCustomer.id; | |
| 789 } | |
| 790 } | |
| 791 | |
| 792 int myHashCode(Customer c) => c.secondId; | |
| 793 bool myEquals(Customer a, Customer b) => a.secondId == b.secondId; | |
| 794 | |
| 795 void testIterationOrder(Map map) { | |
| 796 var order = [0, 6, 4, 2, 7, 9, 7, 1, 2, 5, 3]; | |
| 797 for (int i = 0; i < order.length; i++) map[order[i]] = i; | |
| 798 Expect.listEquals(map.keys.toList(), [0, 6, 4, 2, 7, 9, 1, 5, 3]); | |
| 799 Expect.listEquals(map.values.toList(), [0, 1, 2, 8, 6, 5, 7, 9, 10]); | |
| 800 } | |
| 801 | |
| 802 void testOtherKeys(Map<int, int> map) { | |
| 803 // Test that non-int keys are allowed in containsKey/remove/lookup. | |
| 804 // Custom hash sets and tree sets must be constructed so they don't | |
| 805 // use the equality/comparator on incompatible objects. | |
| 806 | |
| 807 // This should not throw in either checked or unchecked mode. | |
| 808 map[0] = 0; | |
| 809 map[1] = 1; | |
| 810 map[2] = 2; | |
| 811 Expect.isFalse(map.containsKey("not an int")); | |
| 812 Expect.isFalse(map.containsKey(1.5)); | |
| 813 Expect.isNull(map.remove("not an int")); | |
| 814 Expect.isNull(map.remove(1.5)); | |
| 815 Expect.isNull(map["not an int"]); | |
| 816 Expect.isNull(map[1.5]); | |
| 817 } | |
| 818 | |
| 819 class Mutable { | |
| 820 int id; | |
| 821 Mutable(this.id); | |
| 822 int get hashCode => id; | |
| 823 bool operator ==(other) => other is Mutable && other.id == id; | |
| 824 } | |
| 825 | |
| 826 // Slow implementation of Map based on MapBase. | |
| 827 abstract class MapBaseOperations<K, V> { | |
| 828 final List _keys = <K>[]; | |
| 829 final List _values = <V>[]; | |
| 830 int _modCount = 0; | |
| 831 | |
| 832 V operator [](Object key) { | |
| 833 int index = _keys.indexOf(key); | |
| 834 if (index < 0) return null; | |
| 835 return _values[index]; | |
| 836 } | |
| 837 | |
| 838 Iterable<K> get keys => new TestKeyIterable<K>(this); | |
| 839 | |
| 840 void operator []=(K key, V value) { | |
| 841 int index = _keys.indexOf(key); | |
| 842 if (index >= 0) { | |
| 843 _values[index] = value; | |
| 844 } else { | |
| 845 _modCount++; | |
| 846 _keys.add(key); | |
| 847 _values.add(value); | |
| 848 } | |
| 849 } | |
| 850 | |
| 851 V remove(Object key) { | |
| 852 int index = _keys.indexOf(key); | |
| 853 if (index >= 0) { | |
| 854 var result = _values[index]; | |
| 855 key = _keys.removeLast(); | |
| 856 var value = _values.removeLast(); | |
| 857 if (index != _keys.length) { | |
| 858 _keys[index] = key; | |
| 859 _values[index] = value; | |
| 860 } | |
| 861 _modCount++; | |
| 862 return result; | |
| 863 } | |
| 864 return null; | |
| 865 } | |
| 866 | |
| 867 void clear() { | |
| 868 // Clear cannot be based on remove, since remove won't remove keys that | |
| 869 // are not equal to themselves. It will fail the testNaNKeys test. | |
| 870 _keys.clear(); | |
| 871 _values.clear(); | |
| 872 _modCount++; | |
| 873 } | |
| 874 } | |
| 875 | |
| 876 class MapBaseMap<K, V> = MapBase<K, V> with MapBaseOperations<K, V>; | |
| 877 class MapMixinMap<K, V> = MapBaseOperations<K, V> with MapMixin<K, V>; | |
| 878 | |
| 879 class TestKeyIterable<K> extends IterableBase<K> { | |
| 880 final _map; | |
| 881 TestKeyIterable(this._map); | |
| 882 int get length => _map._keys.length; | |
| 883 Iterator<K> get iterator => new TestKeyIterator<K>(_map); | |
| 884 } | |
| 885 | |
| 886 class TestKeyIterator<K> implements Iterator<K> { | |
| 887 final _map; | |
| 888 final int _modCount; | |
| 889 int _index = 0; | |
| 890 var _current; | |
| 891 TestKeyIterator(map) | |
| 892 : _map = map, | |
| 893 _modCount = map._modCount; | |
| 894 bool moveNext() { | |
| 895 if (_modCount != _map._modCount) { | |
| 896 throw new ConcurrentModificationError(_map); | |
| 897 } | |
| 898 if (_index == _map._keys.length) { | |
| 899 _current = null; | |
| 900 return false; | |
| 901 } | |
| 902 _current = _map._keys[_index++]; | |
| 903 return true; | |
| 904 } | |
| 905 | |
| 906 K get current => _current; | |
| 907 } | |
| 908 | |
| 909 // Slow implementation of Map based on MapBase. | |
| 910 class UnmodifiableMapBaseMap<K, V> extends UnmodifiableMapBase<K, V> { | |
| 911 final List _keys = <K>[]; | |
| 912 final List _values = <V>[]; | |
| 913 UnmodifiableMapBaseMap(List pairs) { | |
| 914 for (int i = 0; i < pairs.length; i += 2) { | |
| 915 _keys.add(pairs[i]); | |
| 916 _values.add(pairs[i + 1]); | |
| 917 } | |
| 918 } | |
| 919 | |
| 920 int get _modCount => 0; | |
| 921 | |
| 922 V operator [](K key) { | |
| 923 int index = _keys.indexOf(key); | |
| 924 if (index < 0) return null; | |
| 925 return _values[index]; | |
| 926 } | |
| 927 | |
| 928 Iterable<K> get keys => _keys.skip(0); | |
| 929 } | |
| 930 | |
| 931 abstract class Super implements Comparable {} | |
| 932 | |
| 933 abstract class Interface implements Comparable {} | |
| 934 | |
| 935 class Sub extends Super implements Interface, Comparable { | |
| 936 int compareTo(Sub other) => 0; | |
| 937 int get hashCode => 0; | |
| 938 bool operator ==(other) => other is Sub; | |
| 939 } | |
| 940 | |
| 941 expectMap(Map expect, Map actual) { | |
| 942 Expect.equals(expect.length, actual.length, "length"); | |
| 943 for (var key in expect.keys) { | |
| 944 Expect.isTrue(actual.containsKey(key), "containsKey $key"); | |
| 945 Expect.equals(expect[key], actual[key]); | |
| 946 } | |
| 947 } | |
| 948 | |
| 949 void testFrom() { | |
| 950 // Check contents. | |
| 951 for (var map in [ | |
| 952 {}, | |
| 953 {1: 1}, | |
| 954 {1: 2, 3: 4, 5: 6, 7: 8} | |
| 955 ]) { | |
| 956 expectMap(map, new Map.from(map)); | |
| 957 expectMap(map, new HashMap.from(map)); | |
| 958 expectMap(map, new LinkedHashMap.from(map)); | |
| 959 expectMap(map, new SplayTreeMap.from(map)); | |
| 960 } | |
| 961 // Test type combinations allowed. | |
| 962 Map<int, int> intMap = <int, int>{1: 2, 3: 4}; | |
| 963 Map<num, num> numMap = <num, num>{1: 2, 3: 4}; | |
| 964 expectMap(intMap, new Map<int, int>.from(numMap)); | |
| 965 expectMap(intMap, new Map<num, num>.from(intMap)); | |
| 966 expectMap(intMap, new HashMap<int, int>.from(numMap)); | |
| 967 expectMap(intMap, new HashMap<num, num>.from(intMap)); | |
| 968 expectMap(intMap, new LinkedHashMap<int, int>.from(numMap)); | |
| 969 expectMap(intMap, new LinkedHashMap<num, num>.from(intMap)); | |
| 970 expectMap(intMap, new SplayTreeMap<int, int>.from(numMap)); | |
| 971 expectMap(intMap, new SplayTreeMap<num, num>.from(intMap)); | |
| 972 | |
| 973 var sub = new Sub(); | |
| 974 Map<Super, Super> superMap = <Super, Super>{sub: sub}; | |
| 975 Map<Interface, Interface> interfaceMap = <Interface, Interface>{sub: sub}; | |
| 976 expectMap(superMap, new Map<Super, Super>.from(interfaceMap)); | |
| 977 expectMap(superMap, new Map<Interface, Interface>.from(superMap)); | |
| 978 expectMap(superMap, new HashMap<Super, Super>.from(interfaceMap)); | |
| 979 expectMap(superMap, new HashMap<Interface, Interface>.from(superMap)); | |
| 980 expectMap(superMap, new LinkedHashMap<Super, Super>.from(interfaceMap)); | |
| 981 expectMap(superMap, new LinkedHashMap<Interface, Interface>.from(superMap)); | |
| 982 expectMap(superMap, new SplayTreeMap<Super, Super>.from(interfaceMap)); | |
| 983 expectMap(superMap, new SplayTreeMap<Interface, Interface>.from(superMap)); | |
| 984 } | |
| OLD | NEW |