From 5943e1681204250f33a833eb5550f270357ad6c8 Mon Sep 17 00:00:00 2001 From: Sam Rawlins Date: Thu, 22 Feb 2018 23:08:24 -0800 Subject: [PATCH] Remove usage of Maps.mapToString() (#71) --- lib/src/canonicalized_map.dart | 33 +++++++++++++++++++++++++++++++- test/canonicalized_map_test.dart | 29 ++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/lib/src/canonicalized_map.dart b/lib/src/canonicalized_map.dart index 122bb35f74487..117cd63a63e7b 100644 --- a/lib/src/canonicalized_map.dart +++ b/lib/src/canonicalized_map.dart @@ -153,9 +153,40 @@ class CanonicalizedMap implements Map { Iterable get values => _base.values.map((pair) => pair.last); - String toString() => Maps.mapToString(this); + String toString() { + // Detect toString() cycles. + if (_isToStringVisiting(this)) { + return '{...}'; + } + + var result = new StringBuffer(); + try { + _toStringVisiting.add(this); + result.write('{'); + bool first = true; + forEach((k, v) { + if (!first) { + result.write(', '); + } + first = false; + result.write('$k: $v'); + }); + result.write('}'); + } finally { + assert(identical(_toStringVisiting.last, this)); + _toStringVisiting.removeLast(); + } + + return result.toString(); + } bool _isValidKey(Object key) => (key == null || key is K) && (_isValidKeyFn == null || _isValidKeyFn(key)); } + +/// A collection used to identify cyclic maps during toString() calls. +final List _toStringVisiting = []; + +/// Check if we are currently visiting `o` in a toString() call. +bool _isToStringVisiting(o) => _toStringVisiting.any((e) => identical(o, e)); diff --git a/test/canonicalized_map_test.dart b/test/canonicalized_map_test.dart index 716e738d6bfed..f48778da4b59d 100644 --- a/test/canonicalized_map_test.dart +++ b/test/canonicalized_map_test.dart @@ -132,6 +132,35 @@ void main() { }); }); + group("CanonicalizedMap builds an informative string representation", () { + var map; + setUp(() { + map = new CanonicalizedMap(int.parse, + isValidKey: (s) => new RegExp(r"^\d+$").hasMatch(s as String)); + }); + + test("for an empty map", () { + expect(map.toString(), equals('{}')); + }); + + test("for a map with one value", () { + map.addAll({"1": "value 1"}); + expect(map.toString(), equals('{1: value 1}')); + }); + + test("for a map with multiple values", () { + map.addAll( + {"1": "value 1", "01": "value 01", "2": "value 2", "03": "value 03"}); + expect( + map.toString(), equals('{01: value 01, 2: value 2, 03: value 03}')); + }); + + test("for a map with a loop", () { + map.addAll({"1": "value 1", "2": map}); + expect(map.toString(), equals('{1: value 1, 2: {...}}')); + }); + }); + group("CanonicalizedMap.from", () { test("canonicalizes its keys", () { var map = new CanonicalizedMap.from(