- Add VariableSpec class with magnitude field validation - Add Formula class supporting multiple input/output variables - Support d4rt_code as string or object with code field - Add comprehensive tests for parsing and serialization - Fix broken test import in pruebas_d4rt_test.dart Follows README.md format requirements exactly
363 lines
10 KiB
Dart
363 lines
10 KiB
Dart
// Copyright (c) 2016, 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.
|
|
|
|
// ignore_for_file: deprecated_member_use_from_same_package
|
|
|
|
import 'package:collection/collection.dart';
|
|
import 'package:test/test.dart';
|
|
|
|
void main() {
|
|
group('mapMap()', () {
|
|
test('with an empty map returns an empty map', () {
|
|
expect(
|
|
mapMap({},
|
|
key: expectAsync2((_, __) {}, count: 0),
|
|
value: expectAsync2((_, __) {}, count: 0)),
|
|
isEmpty);
|
|
});
|
|
|
|
test('with no callbacks, returns a copy of the map', () {
|
|
var map = {'foo': 1, 'bar': 2};
|
|
var result = mapMap<String, int, String, int>(map);
|
|
expect(result, equals({'foo': 1, 'bar': 2}));
|
|
|
|
// The resulting map should be a copy.
|
|
result['foo'] = 3;
|
|
expect(map, equals({'foo': 1, 'bar': 2}));
|
|
});
|
|
|
|
test("maps the map's keys", () {
|
|
expect(
|
|
mapMap<String, int, dynamic, int>({'foo': 1, 'bar': 2},
|
|
key: (dynamic key, dynamic value) => key[value]),
|
|
equals({'o': 1, 'r': 2}));
|
|
});
|
|
|
|
test("maps the map's values", () {
|
|
expect(
|
|
mapMap<String, int, String, dynamic>({'foo': 1, 'bar': 2},
|
|
value: (dynamic key, dynamic value) => key[value]),
|
|
equals({'foo': 'o', 'bar': 'r'}));
|
|
});
|
|
|
|
test("maps both the map's keys and values", () {
|
|
expect(
|
|
mapMap({'foo': 1, 'bar': 2},
|
|
key: (dynamic key, dynamic value) => '$key$value',
|
|
value: (dynamic key, dynamic value) => key[value]),
|
|
equals({'foo1': 'o', 'bar2': 'r'}));
|
|
});
|
|
});
|
|
|
|
group('mergeMaps()', () {
|
|
test('with empty maps returns an empty map', () {
|
|
expect(
|
|
mergeMaps({}, {},
|
|
value: expectAsync2((dynamic _, dynamic __) {}, count: 0)),
|
|
isEmpty);
|
|
});
|
|
|
|
test('returns a map with all values in both input maps', () {
|
|
expect(mergeMaps({'foo': 1, 'bar': 2}, {'baz': 3, 'qux': 4}),
|
|
equals({'foo': 1, 'bar': 2, 'baz': 3, 'qux': 4}));
|
|
});
|
|
|
|
test("the second map's values win by default", () {
|
|
expect(mergeMaps({'foo': 1, 'bar': 2}, {'bar': 3, 'baz': 4}),
|
|
equals({'foo': 1, 'bar': 3, 'baz': 4}));
|
|
});
|
|
|
|
test('uses the callback to merge values', () {
|
|
expect(
|
|
mergeMaps({'foo': 1, 'bar': 2}, {'bar': 3, 'baz': 4},
|
|
value: (dynamic value1, dynamic value2) => value1 + value2),
|
|
equals({'foo': 1, 'bar': 5, 'baz': 4}));
|
|
});
|
|
});
|
|
|
|
group('lastBy()', () {
|
|
test('returns an empty map for an empty iterable', () {
|
|
expect(
|
|
lastBy([], (_) => fail('Must not be called for empty input')),
|
|
isEmpty,
|
|
);
|
|
});
|
|
|
|
test("keeps the latest element for the function's return value", () {
|
|
expect(
|
|
lastBy(['foo', 'bar', 'baz', 'bop', 'qux'],
|
|
(String string) => string[1]),
|
|
equals({
|
|
'o': 'bop',
|
|
'a': 'baz',
|
|
'u': 'qux',
|
|
}));
|
|
});
|
|
});
|
|
|
|
group('groupBy()', () {
|
|
test('returns an empty map for an empty iterable', () {
|
|
expect(groupBy([], expectAsync1((dynamic _) {}, count: 0)), isEmpty);
|
|
});
|
|
|
|
test("groups elements by the function's return value", () {
|
|
expect(
|
|
groupBy(['foo', 'bar', 'baz', 'bop', 'qux'],
|
|
(dynamic string) => string[1]),
|
|
equals({
|
|
'o': ['foo', 'bop'],
|
|
'a': ['bar', 'baz'],
|
|
'u': ['qux']
|
|
}));
|
|
});
|
|
});
|
|
|
|
group('minBy()', () {
|
|
test('returns null for an empty iterable', () {
|
|
expect(
|
|
minBy([], expectAsync1((dynamic _) {}, count: 0),
|
|
compare: expectAsync2((dynamic _, dynamic __) => -1, count: 0)),
|
|
isNull);
|
|
});
|
|
|
|
test(
|
|
'returns the element for which the ordering function returns the '
|
|
'smallest value', () {
|
|
expect(
|
|
minBy([
|
|
{'foo': 3},
|
|
{'foo': 5},
|
|
{'foo': 4},
|
|
{'foo': 1},
|
|
{'foo': 2}
|
|
], (dynamic map) => map['foo']),
|
|
equals({'foo': 1}));
|
|
});
|
|
|
|
test('uses a custom comparator if provided', () {
|
|
expect(
|
|
minBy<Map<String, int>, Map<String, int>>([
|
|
{'foo': 3},
|
|
{'foo': 5},
|
|
{'foo': 4},
|
|
{'foo': 1},
|
|
{'foo': 2}
|
|
], (map) => map,
|
|
compare: (map1, map2) => map1['foo']!.compareTo(map2['foo']!)),
|
|
equals({'foo': 1}));
|
|
});
|
|
});
|
|
|
|
group('maxBy()', () {
|
|
test('returns null for an empty iterable', () {
|
|
expect(
|
|
maxBy([], expectAsync1((dynamic _) {}, count: 0),
|
|
compare: expectAsync2((dynamic _, dynamic __) => 0, count: 0)),
|
|
isNull);
|
|
});
|
|
|
|
test(
|
|
'returns the element for which the ordering function returns the '
|
|
'largest value', () {
|
|
expect(
|
|
maxBy([
|
|
{'foo': 3},
|
|
{'foo': 5},
|
|
{'foo': 4},
|
|
{'foo': 1},
|
|
{'foo': 2}
|
|
], (dynamic map) => map['foo']),
|
|
equals({'foo': 5}));
|
|
});
|
|
|
|
test('uses a custom comparator if provided', () {
|
|
expect(
|
|
maxBy<Map<String, int>, Map<String, int>>([
|
|
{'foo': 3},
|
|
{'foo': 5},
|
|
{'foo': 4},
|
|
{'foo': 1},
|
|
{'foo': 2}
|
|
], (map) => map,
|
|
compare: (map1, map2) => map1['foo']!.compareTo(map2['foo']!)),
|
|
equals({'foo': 5}));
|
|
});
|
|
});
|
|
|
|
group('transitiveClosure()', () {
|
|
test('returns an empty map for an empty graph', () {
|
|
expect(transitiveClosure({}), isEmpty);
|
|
});
|
|
|
|
test('returns the input when there are no transitive connections', () {
|
|
expect(
|
|
transitiveClosure({
|
|
'foo': ['bar'],
|
|
'bar': [],
|
|
'bang': ['qux', 'zap'],
|
|
'qux': [],
|
|
'zap': []
|
|
}),
|
|
equals({
|
|
'foo': ['bar'],
|
|
'bar': [],
|
|
'bang': ['qux', 'zap'],
|
|
'qux': [],
|
|
'zap': []
|
|
}));
|
|
});
|
|
|
|
test('flattens transitive connections', () {
|
|
expect(
|
|
transitiveClosure({
|
|
'qux': [],
|
|
'bar': ['baz'],
|
|
'baz': ['qux'],
|
|
'foo': ['bar']
|
|
}),
|
|
equals({
|
|
'foo': ['bar', 'baz', 'qux'],
|
|
'bar': ['baz', 'qux'],
|
|
'baz': ['qux'],
|
|
'qux': []
|
|
}));
|
|
});
|
|
|
|
test('handles loops', () {
|
|
expect(
|
|
transitiveClosure({
|
|
'foo': ['bar'],
|
|
'bar': ['baz'],
|
|
'baz': ['foo']
|
|
}),
|
|
equals({
|
|
'foo': ['bar', 'baz', 'foo'],
|
|
'bar': ['baz', 'foo', 'bar'],
|
|
'baz': ['foo', 'bar', 'baz']
|
|
}));
|
|
});
|
|
});
|
|
|
|
group('stronglyConnectedComponents()', () {
|
|
test('returns an empty list for an empty graph', () {
|
|
expect(stronglyConnectedComponents({}), isEmpty);
|
|
});
|
|
|
|
test('returns one set for a singleton graph', () {
|
|
expect(
|
|
stronglyConnectedComponents({'a': []}),
|
|
equals([
|
|
{'a'}
|
|
]));
|
|
});
|
|
|
|
test('returns two sets for a two-element tree', () {
|
|
expect(
|
|
stronglyConnectedComponents({
|
|
'a': ['b'],
|
|
'b': []
|
|
}),
|
|
equals([
|
|
{'a'},
|
|
{'b'}
|
|
]));
|
|
});
|
|
|
|
test('returns one set for a two-element loop', () {
|
|
expect(
|
|
stronglyConnectedComponents({
|
|
'a': ['b'],
|
|
'b': ['a']
|
|
}),
|
|
equals([
|
|
{'a', 'b'}
|
|
]));
|
|
});
|
|
|
|
test('returns individual vertices for a tree', () {
|
|
expect(
|
|
stronglyConnectedComponents({
|
|
'foo': ['bar'],
|
|
'bar': ['baz', 'bang'],
|
|
'baz': ['qux'],
|
|
'bang': ['zap'],
|
|
'qux': [],
|
|
'zap': []
|
|
}),
|
|
equals([
|
|
// This is expected to return *a* topological ordering, but this isn't
|
|
// the only valid one. If the function implementation changes in the
|
|
// future, this test may need to be updated.
|
|
{'foo'},
|
|
{'bar'},
|
|
{'bang'},
|
|
{'zap'},
|
|
{'baz'},
|
|
{'qux'}
|
|
]),
|
|
);
|
|
});
|
|
|
|
test('returns a single set for a fully cyclic graph', () {
|
|
expect(
|
|
stronglyConnectedComponents({
|
|
'foo': ['bar'],
|
|
'bar': ['baz'],
|
|
'baz': ['bang'],
|
|
'bang': ['foo']
|
|
}),
|
|
equals([
|
|
{'foo', 'bar', 'baz', 'bang'}
|
|
]));
|
|
});
|
|
|
|
test('returns separate sets for each strongly connected component', () {
|
|
// https://en.wikipedia.org/wiki/Strongly_connected_component#/media/File:Scc.png
|
|
expect(
|
|
stronglyConnectedComponents({
|
|
'a': ['b'],
|
|
'b': ['c', 'e', 'f'],
|
|
'c': ['d', 'g'],
|
|
'd': ['c', 'h'],
|
|
'e': ['a', 'f'],
|
|
'f': ['g'],
|
|
'g': ['f'],
|
|
'h': ['g', 'd']
|
|
}),
|
|
equals([
|
|
// This is expected to return *a* topological ordering, but this isn't
|
|
// the only valid one. If the function implementation changes in the
|
|
// future, this test may need to be updated.
|
|
{'a', 'b', 'e'},
|
|
{'c', 'd', 'h'},
|
|
{'f', 'g'},
|
|
]),
|
|
);
|
|
});
|
|
|
|
test('always returns components in topological order', () {
|
|
expect(
|
|
stronglyConnectedComponents({
|
|
'bar': ['baz', 'bang'],
|
|
'zap': [],
|
|
'baz': ['qux'],
|
|
'qux': [],
|
|
'foo': ['bar'],
|
|
'bang': ['zap']
|
|
}),
|
|
equals([
|
|
// This is expected to return *a* topological ordering, but this isn't
|
|
// the only valid one. If the function implementation changes in the
|
|
// future, this test may need to be updated.
|
|
{'foo'},
|
|
{'bar'},
|
|
{'bang'},
|
|
{'zap'},
|
|
{'baz'},
|
|
{'qux'}
|
|
]),
|
|
);
|
|
});
|
|
});
|
|
}
|