Skip to content

Commit

Permalink
Clean up documentation of implicit new/const insertions tests.
Browse files Browse the repository at this point in the history
Add Expect.allIdentical to complement Expect.allDistinct.

Change-Id: I65e4e0005f141434bd8fb47d9c60153f32b293aa
Reviewed-on: https://dart-review.googlesource.com/50421
Reviewed-by: Dmitry Stefantsov <[email protected]>
Commit-Queue: Lasse R.H. Nielsen <[email protected]>
  • Loading branch information
lrhn authored and [email protected] committed Apr 10, 2018
1 parent cf93009 commit 5ea271b
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 111 deletions.
71 changes: 54 additions & 17 deletions pkg/expect/lib/expect.dart
Original file line number Diff line number Diff line change
Expand Up @@ -179,35 +179,31 @@ class Expect {
}

/**
* Checks whether the expected and actual values are *not* identical
* (using `identical`).
*/
static void notIdentical(var unexpected, var actual, [String reason = null]) {
if (!_identical(unexpected, actual)) return;
String msg = _getMessage(reason);
_fail("Expect.notIdentical(expected and actual: <$actual>$msg) fails.");
}

/**
* Checks that no two [objects] are `identical`.
* Finds equivalence classes of objects (by index) wrt. identity.
*
* Returns a list of lists of identical object indices per object.
* That is, `objects[i]` is identical to objects with indices in
* `_findEquivalences(objects)[i]`.
*
* Uses `null` for objects that are only identical to themselves.
*/
static void allDistinct(List<Object> objects, [String reason = null]) {
String msg = _getMessage(reason);
static List<List<int>> _findEquivalences(List<Object> objects) {
var equivalences = new List<List<int>>(objects.length);
bool hasEquivalence = false;
for (int i = 0; i < objects.length; i++) {
if (equivalences[i] != null) continue;
var o = objects[i];
for (int j = i + 1; j < objects.length; j++) {
if (equivalences[j] != null) continue;
if (_identical(o, objects[j])) {
equivalences[j] = (equivalences[i] ??= <int>[i])..add(j);
hasEquivalence = true;
}
}
}
if (!hasEquivalence) return;
var buffer = new StringBuffer("Expect.allDistinct([");
return equivalences;
}

static void _writeEquivalences(
List<Object> objects, List<List<int>> equivalences, StringBuffer buffer) {
var separator = "";
for (int i = 0; i < objects.length; i++) {
buffer.write(separator);
Expand All @@ -223,6 +219,47 @@ class Expect {
}
}
}
}

static void allIdentical(Iterable<Object> objects, [String reason]) {
if (objects.length <= 1) return;
String msg = _getMessage(reason);
var equivalences = _findEquivalences(objects);
var first = equivalences[0];
if (first != null && first.length == objects.length) return;
var buffer = new StringBuffer("Expect.allIdentical([");
_writeEquivalences(objects, equivalences, buffer);
buffer..write("]")..write(msg)..write(")");
_fail(buffer.toString());
}

/**
* Checks whether the expected and actual values are *not* identical
* (using `identical`).
*/
static void notIdentical(var unexpected, var actual, [String reason = null]) {
if (!_identical(unexpected, actual)) return;
String msg = _getMessage(reason);
_fail("Expect.notIdentical(expected and actual: <$actual>$msg) fails.");
}

/**
* Checks that no two [objects] are `identical`.
*/
static void allDistinct(List<Object> objects, [String reason = null]) {
String msg = _getMessage(reason);
var equivalences = _findEquivalences(objects);

bool hasEquivalence = false;
for (int i = 0; i < equivalences.length; i++) {
if (equivalences[i] != null) {
hasEquivalence = true;
break;
}
}
if (!hasEquivalence) return;
var buffer = new StringBuffer("Expect.allDistinct([");
_writeEquivalences(objects, equivalences, buffer);
buffer..write("]")..write(msg)..write(")");
_fail(buffer.toString());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,9 @@

import "package:expect/expect.dart";

// Tests that const/new-insertion does the right thing for
// composite object creations.
//
// The right thing is that map and list literals are only constant
// if in a constant context.
// Object creation is const if constructor is const and all arguments are const.
// Tests that new-insertion always inserts `new` when not in const context,
// no matter what the arguments are.
// There is (currently) no automatic const insertion in non-const context.
//
// Not testing inference, so all type arguments are explicit.

Expand All @@ -34,27 +31,22 @@ main() {
var cd5 = C(d42); // Non-constant context, so `new`.

Expect.identical(cd1, cd2);
Expect.allDistinct([cd1, cd3]);
Expect.allDistinct([cd1, cd4, cd5]);
Expect.allDistinct([cd1, cd3, cd4, cd5]);
}

{
// List inside other constructor
const cl1 = const C(const <int>[37]);
const cl2 = C(clist); // Constant context.
const cl3 = C(const <int>[37]); // Constant context.
const cl4 = C(<int>[37]);
const cl4 = C(<int>[37]); // Constant context.
var cl5 = C(clist); // Non-constant context, so `new`.
var cl6 = C(const <int>[37]); // Non-constant context, so `new`.
var cl7 = C(list); // Non-constant context, so `new`.
var cl8 = C(<int>[37]); // Non-constant context, so `new`.

Expect.identical(cl1, cl2);
Expect.identical(cl1, cl3);
Expect.identical(cl1, cl4);
Expect.allDistinct([cl1, cl5]);
Expect.allDistinct([cl1, cl6]);
Expect.allDistinct([cl1, cl7, cl8]);
Expect.allIdentical([cl1, cl2, cl3, cl4]);
Expect.allDistinct([cl1, cl5, cl6, cl7, cl8]);
}

{
Expand All @@ -69,9 +61,7 @@ main() {

Expect.identical(cm1, cm2);
Expect.identical(cm1, cm3);
Expect.allDistinct([cm1, cm4]);
Expect.allDistinct([cm1, cm5]);
Expect.allDistinct([cm1, cm6, cm7]);
Expect.allDistinct([cm1, cm4, cm5, cm6, cm7]);
}

{
Expand All @@ -93,22 +83,14 @@ main() {

Expect.identical(n1, n2);
Expect.identical(n1, n3);
Expect.allDistinct([n1, n4]);
Expect.allDistinct([n1, n8]);
Expect.allDistinct([n1, n5, n6, n7, n9, n10, n11, n12, n13, n14]);
Expect.allDistinct([n1, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14]);

Expect.identical(clist, n6.left);
Expect.identical(clist, n10.left);
Expect.identical(clist, n12.left);
Expect.identical(clist, n13.left);
Expect.identical(clist, n14.left);
Expect
.allIdentical([clist, n6.left, n10.left, n12.left, n13.left, n14.left]);
Expect.allDistinct([n5.left, n7.left, n9.left, n11.left]);

Expect.identical(cmap, n5.right);
Expect.identical(cmap, n9.right);
Expect.identical(cmap, n12.right);
Expect.identical(cmap, n13.right);
Expect.identical(cmap, n14.right);
Expect.allIdentical(
[cmap, n5.right, n9.right, n12.right, n13.right, n14.right]);
Expect.allDistinct([n6.right, n7.right, n10.right, n11.right]);

const n20 = const N(const C(42), const <int>[37]);
Expand All @@ -124,21 +106,13 @@ main() {
var n30 = N(c42, clist);
var n31 = N(cc42, list);

Expect.identical(n20, n21);
Expect.identical(n20, n22);
Expect.identical(n20, n23);
Expect.identical(n20, n24);
Expect.allDistinct([n20, n25]);
Expect.allDistinct([n20, n26]);
Expect.allDistinct([n20, n27]);
Expect.allDistinct([n28, n29, n30, n31]);
Expect.allDistinct([cc42, n28.left]);
Expect.allDistinct([cc42, n29.left]);
Expect.allIdentical([n20, n21, n22, n23, n24]);
Expect.allDistinct([n20, n25, n26, n27, n28, n29, n30, n31]);

Expect.allDistinct([cc42, n28.left, n29.left]);
Expect.identical(cc42, n30.left);
Expect.identical(cc42, n31.left);
Expect.identical(clist, n29.right);
Expect.identical(clist, n30.right);
Expect.identical(clist, n31.right);
Expect.allIdentical([clist, n29.right, n30.right, n31.right]);
Expect.notIdentical(clist, n28.right);
}

Expand Down Expand Up @@ -178,25 +152,13 @@ main() {
var l30 = [c42, clist];
var l31 = [cc42, list];

Expect.identical(l20, l21);
Expect.identical(l20, l22);
Expect.identical(l20, l23);
Expect.identical(l20, l24);
Expect.allIdentical([l20, l21, l22, l23, l24]);
// List literals are never const unless in const context.
Expect.allDistinct([l20, l25, l26, l27, l28, l29, l30, l31]);
Expect.identical(cc42, l25[0]);
Expect.allDistinct([cc42, l26[0]]);
Expect.allDistinct([cc42, l27[0]]);
Expect.allDistinct([cc42, l28[0]]);
Expect.allDistinct([cc42, l29[0]]);
Expect.identical(cc42, l30[0]);
Expect.identical(cc42, l31[0]);
Expect.identical(clist, l25[1]);
Expect.identical(clist, l26[1]);
Expect.identical(clist, l27[1]);
Expect.identical(clist, l29[1]);
Expect.identical(clist, l30[1]);
Expect.identical(clist, l31[1]);
Expect.allIdentical([cc42, l25[0], l30[0], l31[0]]);
Expect.allDistinct([cc42, l26[0], l27[0], l28[0], l29[0]]);
Expect
.allIdentical([clist, l25[1], l26[1], l27[1], l29[1], l30[1], l31[1]]);
Expect.notIdentical(clist, l28[1]);
}

Expand Down Expand Up @@ -229,25 +191,23 @@ main() {
var m30 = {c42: clist};
var m31 = {cc42: list};

Expect.identical(m20, m21);
Expect.identical(m20, m22);
Expect.identical(m20, m23);
Expect.identical(m20, m24);
Expect.allIdentical([m20, m21, m22, m23, m24]);
// Map literals are never const unless in const context.
Expect.allDistinct([m20, m25, m26, m27, m28, m29, m30, m31]);
Expect.identical(cc42, m25.keys.first);
Expect.allDistinct([cc42, m26.keys.first]);
Expect.allDistinct([cc42, m27.keys.first]);
Expect.allDistinct([cc42, m28.keys.first]);
Expect.allDistinct([cc42, m29.keys.first]);
Expect.allDistinct(
[cc42, m26.keys.first, m27.keys.first, m28.keys.first, m29.keys.first]);
Expect.identical(cc42, m30.keys.first);
Expect.identical(cc42, m31.keys.first);
Expect.identical(clist, m25.values.first);
Expect.identical(clist, m26.values.first);
Expect.identical(clist, m27.values.first);
Expect.identical(clist, m29.values.first);
Expect.identical(clist, m30.values.first);
Expect.identical(clist, m31.values.first);
Expect.allIdentical([
clist,
m25.values.first,
m26.values.first,
m27.values.first,
m29.values.first,
m30.values.first,
m31.values.first
]);
Expect.notIdentical(clist, m28.values.first);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ import "package:expect/expect.dart";

import "implicit_new_or_const_generic_test.dart" as prefix;

// Test that const constructors with const arguments become const,
// and non-const constructors or const-constructors with non-const arguments
// do not (except in a const context, which is tested elsewhere).
// Test that const constructors with const arguments do not become const
// if not in a const context.

// This test uses a generic class, which requires new syntax.
// This test uses a generic class cosntructor with no prefix,
// which requires new Dart 2 syntax.

main() {
// Various valid object creation expressions.
var x = 42; // non constant variable.
var x = 42; // non constant variable.

// Various valid object creation expressions of a generic constructor.
// (Requires inference to infer `<int>` for the invocations of `D`.)
Expand All @@ -24,43 +24,36 @@ main() {
const D(42),
D(x),
D(42),

new D.named(x),
new D.named(42),
const D.named(42),
D.named(x),
D.named(42),

new prefix.D(x),
new prefix.D(42),
const prefix.D(42),
prefix.D(x),
prefix.D(42),

new prefix.D.named(x),
new prefix.D.named(42),
const prefix.D.named(42),
prefix.D.named(x),
prefix.D.named(42),

new D<int>(x),
new D<int>(42),
const D<int>(42),
D<int>(x),
D<int>(42),

new D<int>.named(x),
new D<int>.named(42),
const D<int>.named(42),
D<int>.named(x),
D<int>.named(42),

new prefix.D<int>(x),
new prefix.D<int>(42),
const prefix.D<int>(42),
prefix.D<int>(x),
prefix.D<int>(42),

new prefix.D<int>.named(x),
new prefix.D<int>.named(42),
const prefix.D<int>.named(42),
Expand Down Expand Up @@ -92,7 +85,7 @@ class D<T> {
const D.named(this.x);

int get hashCode => x.hashCode;
bool operator==(Object other) => other is D<Object> && x == other.x;
bool operator ==(Object other) => other is D<Object> && x == other.x;
}

class G<T> {
Expand All @@ -102,13 +95,10 @@ class G<T> {
var instances = [
new D<T>(null),
D<T>(null),

new D<T>.named(null),
D<T>.named(null),

new prefix.D<T>(null),
prefix.D<T>(null),

new prefix.D<T>.named(null),
prefix.D<T>.named(null),
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@ import "package:expect/expect.dart";

import "implicit_new_or_const_test.dart" as prefix;

// Test that const constructors with const arguments become const,
// and non-const constructors or const-constructors with non-const arguments
// do not (except in a const context, which is tested elsewhere).
// Test that const constructors with const arguments do not become const
// if not in a const context.

main() {
// Various valid object creation expressions.
Expand Down

0 comments on commit 5ea271b

Please sign in to comment.