blob: 4b2bc7fbc6859f9531e88435c1b64dcadf9992d8 [file] [log] [blame] [edit]
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:collection';
import 'package:expect/expect.dart';
/// Bug in dev-compiler's [putIfAbsent](https://dartbug.com/47852).
void originalError() {
final map = {};
final key = DateTime.now(); // Overrides Object.==/hashCode
bool wasAbsent = false;
map.putIfAbsent(key, () {
wasAbsent = true;
Expect.isFalse(
map.containsKey(key),
'containsKey should be false in putIfAbsent',
);
return key;
});
Expect.isTrue(wasAbsent);
}
enum AnEnum { element1, element2 }
class Dumb {
final Object field;
Dumb(this.field);
// Dumb hashCode to stress same-bucket paths.
int get hashCode => 0;
bool operator ==(Object other) => other is Dumb && this.field == other.field;
String toString() => 'Dumb($field)';
}
// Test keys. These instances of classes that do and don't override `==` and
// `hashCode`, and a variety of primitive values since we generally don't know
// whether they have overrides.
final keys = [
123,
3.14,
10.0, // int or double depending on platform.
'aString',
#someSymbol,
true,
false,
null,
AnEnum.element1,
AnEnum.element2,
DateTime.now(),
Dumb(1),
Dumb(2),
Dumb(3),
Object(),
const [1],
const {1},
const {'x'},
// const maps have different implementation types depending on keys.
const {'x': 1},
const {123: 1},
const {AnEnum.element1: 1, #foo: 2},
];
void testMap(Map<Object?, Object?> map) {
for (final key in keys) {
bool wasAbsent = false;
map.putIfAbsent(key, () {
wasAbsent = true;
Expect.isFalse(
map.containsKey(key),
'containsKey should be false in putIfAbsent. key = $key',
);
return key;
});
Expect.isTrue(wasAbsent);
Expect.isTrue(map.containsKey(key), 'Key was not added. key = $key');
}
}
void main() {
originalError();
testMap({});
testMap(Map()); // Should be same as `{}`.
testMap(HashMap());
testMap(LinkedHashMap()); // Should be same as `{}`.
testMap(Map.identity());
testMap(HashMap.identity());
testMap(LinkedHashMap.identity()); // Should be same as `Map.identity()`.
// Custom maps:
testMap(
HashMap(
equals: (k1, k2) => k2 == k1,
hashCode: (key) => key.hashCode + 1,
isValidKey: (_) => true,
),
);
testMap(
LinkedHashMap(
equals: (k1, k2) => k2 == k1,
hashCode: (key) => key.hashCode + 1,
isValidKey: (_) => true,
),
);
}