OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 Google Inc. All Rights Reserved. |
| 2 // |
| 3 // Licensed under the Apache License, Version 2.0 (the 'License'); |
| 4 // you may not use this file except in compliance with the License. |
| 5 // You may obtain a copy of the License at |
| 6 // |
| 7 // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 // |
| 9 // Unless required by applicable law or agreed to in writing, software |
| 10 // distributed under the License is distributed on an 'AS IS' BASIS, |
| 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 // See the License for the specific language governing permissions and |
| 13 // limitations under the License. |
| 14 |
| 15 library quiver.testing.util.equalstester; |
| 16 |
| 17 import 'package:quiver/testing/equality.dart'; |
| 18 import 'package:test/test.dart'; |
| 19 |
| 20 main() { |
| 21 group('expectEquals', () { |
| 22 _ValidTestObject reference; |
| 23 _ValidTestObject equalObject1; |
| 24 _ValidTestObject equalObject2; |
| 25 _ValidTestObject notEqualObject1; |
| 26 |
| 27 setUp(() { |
| 28 reference = new _ValidTestObject(1, 2); |
| 29 equalObject1 = new _ValidTestObject(1, 2); |
| 30 equalObject2 = new _ValidTestObject(1, 2); |
| 31 notEqualObject1 = new _ValidTestObject(0, 2); |
| 32 }); |
| 33 |
| 34 test('Test null reference yields error', () { |
| 35 try { |
| 36 expect(null, areEqualityGroups); |
| 37 fail('Should fail with null reference'); |
| 38 } catch (e) { |
| 39 expect(e.toString(), contains('Equality Group must not be null')); |
| 40 } |
| 41 }); |
| 42 |
| 43 test('Test null group name yields error', () { |
| 44 try { |
| 45 expect({'null': [reference], null: [reference]}, areEqualityGroups); |
| 46 fail('Should fail with null group name'); |
| 47 } catch (e) { |
| 48 expect(e.toString(), contains('Group name must not be null')); |
| 49 } |
| 50 }); |
| 51 |
| 52 test('Test null group yields error', () { |
| 53 try { |
| 54 expect({'bad group': null}, areEqualityGroups); |
| 55 fail('Should fail with null group'); |
| 56 } catch (e) { |
| 57 expect(e.toString(), contains('Group must not be null')); |
| 58 } |
| 59 }); |
| 60 |
| 61 test('Test after adding multiple instances at once with a null', () { |
| 62 try { |
| 63 expect( |
| 64 {'bad group': [reference, equalObject1, null]}, areEqualityGroups); |
| 65 fail('Should fail with null group'); |
| 66 } catch (e) { |
| 67 expect(e.toString(), contains("$reference [group 'bad group', item 1]" |
| 68 " must be equal to null [group 'bad group', item 3]")); |
| 69 } |
| 70 }); |
| 71 |
| 72 test('Test adding non-equal objects only in single group.', () { |
| 73 try { |
| 74 expect( |
| 75 {'not equal': [equalObject1, notEqualObject1]}, areEqualityGroups); |
| 76 fail("Should get not equal to equal object error"); |
| 77 } catch (e) { |
| 78 expect(e.toString(), contains("$equalObject1 [group 'not equal', item" |
| 79 " 1] must be equal to $notEqualObject1 [group 'not equal'" |
| 80 ", item 2]")); |
| 81 } |
| 82 }); |
| 83 |
| 84 test('Test with no equals or not equals objects. This checks' |
| 85 ' proper handling of null, incompatible class and reflexive tests', () { |
| 86 expect({'single object': [reference]}, areEqualityGroups); |
| 87 }); |
| 88 |
| 89 test('Test after populating equal objects. This checks proper' |
| 90 ' handling of equality and verifies hashCode for valid objects', () { |
| 91 expect({ |
| 92 'all equal': [reference, equalObject1, equalObject2] |
| 93 }, areEqualityGroups); |
| 94 }); |
| 95 |
| 96 test('Test proper handling of case where an object is not equal to itself', |
| 97 () { |
| 98 Object obj = new _NonReflexiveObject(); |
| 99 try { |
| 100 expect({'non-reflexive': [obj]}, areEqualityGroups); |
| 101 fail("Should get non-reflexive error"); |
| 102 } catch (e) { |
| 103 expect(e.toString(), contains("$obj must be equal to itself")); |
| 104 } |
| 105 }); |
| 106 |
| 107 test('Test proper handling of case where hashcode is not idempotent', () { |
| 108 Object obj = new _InconsistentHashCodeObject(1, 2); |
| 109 try { |
| 110 expect({'non-reflexive': [obj]}, areEqualityGroups); |
| 111 fail("Should get non-reflexive error"); |
| 112 } catch (e) { |
| 113 expect(e.toString(), contains( |
| 114 "the implementation of hashCode of $obj must be idempotent")); |
| 115 } |
| 116 }); |
| 117 |
| 118 test('Test proper handling where an object incorrectly tests for an ' |
| 119 'incompatible class', () { |
| 120 Object obj = new _InvalidEqualsIncompatibleClassObject(); |
| 121 try { |
| 122 expect({'equals method broken': [obj]}, areEqualityGroups); |
| 123 fail("Should get equal to incompatible class error"); |
| 124 } catch (e) { |
| 125 expect(e.toString(), contains("$obj must not be equal to an " |
| 126 "arbitrary object of another class")); |
| 127 } |
| 128 }); |
| 129 |
| 130 test('Test proper handling where an object is not equal to one the user ' |
| 131 'has said should be equal', () { |
| 132 try { |
| 133 expect({'non-equal': [reference, notEqualObject1]}, areEqualityGroups); |
| 134 fail("Should get not equal to equal object error"); |
| 135 } catch (e) { |
| 136 expect( |
| 137 e.toString(), contains("$reference [group 'non-equal', item 1]")); |
| 138 expect(e.toString(), |
| 139 contains("$notEqualObject1 [group 'non-equal', item 2]")); |
| 140 } |
| 141 }); |
| 142 |
| 143 test('Test for an invalid hashCode method, i.e., one that returns ' |
| 144 'different value for objects that are equal according to the equals ' |
| 145 'method', () { |
| 146 Object a = new _InvalidHashCodeObject(1, 2); |
| 147 Object b = new _InvalidHashCodeObject(1, 2); |
| 148 try { |
| 149 expect({'invalid hashcode': [a, b]}, areEqualityGroups); |
| 150 fail("Should get invalid hashCode error"); |
| 151 } catch (e) { |
| 152 expect(e.toString(), contains("the hashCode (${a.hashCode}) of $a" |
| 153 " [group 'invalid hashcode', item 1] must be equal to the" |
| 154 " hashCode (${b.hashCode}) of $b")); |
| 155 } |
| 156 }); |
| 157 |
| 158 test('Symmetry Broken', () { |
| 159 try { |
| 160 expect({ |
| 161 'broken symmetry': [named('foo')..addPeers(['bar']), named('bar')] |
| 162 }, areEqualityGroups); |
| 163 fail("should fail because symmetry is broken"); |
| 164 } catch (e) { |
| 165 expect(e.toString(), contains("bar [group 'broken symmetry', item 2] " |
| 166 "must be equal to foo [group 'broken symmetry', item 1]")); |
| 167 } |
| 168 }); |
| 169 |
| 170 test('Transitivity Broken In EqualityGroup', () { |
| 171 try { |
| 172 expect({ |
| 173 'transitivity broken': [ |
| 174 named('foo')..addPeers(['bar', 'baz']), |
| 175 named('bar')..addPeers(['foo']), |
| 176 named('baz')..addPeers(['foo']) |
| 177 ] |
| 178 }, areEqualityGroups); |
| 179 fail("should fail because transitivity is broken"); |
| 180 } catch (e) { |
| 181 expect(e.toString(), contains("bar [group 'transitivity broken', " |
| 182 "item 2] must be equal to baz [group 'transitivity " |
| 183 "broken', item 3]")); |
| 184 } |
| 185 }); |
| 186 |
| 187 test('Unequal Objects In EqualityGroup', () { |
| 188 try { |
| 189 expect({ |
| 190 'unequal objects': [named('foo'), named('bar')] |
| 191 }, areEqualityGroups); |
| 192 fail('should fail because of unequal objects in the same equality ' |
| 193 'group'); |
| 194 } catch (e) { |
| 195 expect(e.toString(), contains("foo [group 'unequal objects', item 1] " |
| 196 "must be equal to bar [group 'unequal objects', item 2]")); |
| 197 } |
| 198 }); |
| 199 |
| 200 test('Transitivity Broken Across EqualityGroups', () { |
| 201 try { |
| 202 expect({ |
| 203 'transitivity one': [ |
| 204 named('foo')..addPeers(['bar']), |
| 205 named('bar')..addPeers(['foo', 'x']) |
| 206 ], |
| 207 'transitivity two': [ |
| 208 named('baz')..addPeers(['x']), |
| 209 named('x')..addPeers(['baz', 'bar']) |
| 210 ] |
| 211 }, areEqualityGroups); |
| 212 fail('should fail because transitivity is broken'); |
| 213 } catch (e) { |
| 214 expect(e.toString(), contains("bar [group 'transitivity one', item 2]" |
| 215 " must not be equal to x [group 'transitivity two'," |
| 216 " item 2]")); |
| 217 } |
| 218 }); |
| 219 |
| 220 test('EqualityGroups', () { |
| 221 expect({ |
| 222 'valid groups one': [ |
| 223 named('foo').addPeers(['bar']), |
| 224 named('bar').addPeers(['foo']) |
| 225 ], |
| 226 'valid groups two': [named('baz'), named('baz')] |
| 227 }, areEqualityGroups); |
| 228 }); |
| 229 }); |
| 230 } |
| 231 |
| 232 /// Test class that violates reflexitivity. It is not equal to itself. |
| 233 class _NonReflexiveObject { |
| 234 @override |
| 235 bool operator ==(Object o) => false; |
| 236 |
| 237 @override |
| 238 int get hashCode => super.hashCode; |
| 239 } |
| 240 |
| 241 /** |
| 242 * Test class with valid equals and hashCode methods. Testers created |
| 243 * with instances of this class should always pass. |
| 244 */ |
| 245 class _ValidTestObject { |
| 246 int aspect1; |
| 247 int aspect2; |
| 248 |
| 249 _ValidTestObject(this.aspect1, this.aspect2); |
| 250 |
| 251 @override |
| 252 bool operator ==(Object o) { |
| 253 if (!(o is _ValidTestObject)) { |
| 254 return false; |
| 255 } |
| 256 _ValidTestObject other = o as _ValidTestObject; |
| 257 if (aspect1 != other.aspect1) { |
| 258 return false; |
| 259 } |
| 260 if (aspect2 != other.aspect2) { |
| 261 return false; |
| 262 } |
| 263 return true; |
| 264 } |
| 265 |
| 266 @override |
| 267 int get hashCode { |
| 268 int result = 17; |
| 269 result = 37 * result + aspect1; |
| 270 result = 37 * result + aspect2; |
| 271 return result; |
| 272 } |
| 273 } |
| 274 |
| 275 ///Test class that returns true even if the test object is of the wrong class. |
| 276 class _InvalidEqualsIncompatibleClassObject { |
| 277 @override |
| 278 bool operator ==(Object o) { |
| 279 return true; |
| 280 } |
| 281 |
| 282 @override |
| 283 int get hashCode => 0; |
| 284 } |
| 285 |
| 286 /// Test class with inconsistent hashCode method. |
| 287 class _InconsistentHashCodeObject { |
| 288 int _aspect1; |
| 289 int _aspect2; |
| 290 int _hashCode = 0; |
| 291 |
| 292 _InconsistentHashCodeObject(this._aspect1, this._aspect2); |
| 293 |
| 294 @override |
| 295 int get hashCode => _hashCode++; |
| 296 |
| 297 @override |
| 298 bool operator ==(Object o) { |
| 299 if (!(o is _InconsistentHashCodeObject)) { |
| 300 return false; |
| 301 } |
| 302 _InconsistentHashCodeObject other = o as _InconsistentHashCodeObject; |
| 303 if (_aspect1 != other._aspect1) return false; |
| 304 if (_aspect2 != other._aspect2) return false; |
| 305 return true; |
| 306 } |
| 307 } |
| 308 |
| 309 /// Test class with invalid hashCode method. |
| 310 class _InvalidHashCodeObject { |
| 311 static int hashCodeSource = 0; |
| 312 int _aspect1; |
| 313 int _aspect2; |
| 314 int _hashCode = hashCodeSource++; |
| 315 |
| 316 _InvalidHashCodeObject(this._aspect1, this._aspect2); |
| 317 |
| 318 @override |
| 319 int get hashCode => _hashCode; |
| 320 |
| 321 @override |
| 322 bool operator ==(Object o) { |
| 323 if (!(o is _InvalidHashCodeObject)) { |
| 324 return false; |
| 325 } |
| 326 _InvalidHashCodeObject other = o as _InvalidHashCodeObject; |
| 327 if (_aspect1 != other._aspect1) return false; |
| 328 if (_aspect2 != other._aspect2) return false; |
| 329 return true; |
| 330 } |
| 331 } |
| 332 |
| 333 _NamedObject named(String name) => new _NamedObject(name); |
| 334 |
| 335 class _NamedObject { |
| 336 final Set<String> peerNames = new Set(); |
| 337 final String name; |
| 338 |
| 339 _NamedObject(this.name); |
| 340 |
| 341 void addPeers(List<String> names) { |
| 342 peerNames.addAll(names); |
| 343 } |
| 344 |
| 345 @override |
| 346 bool operator ==(Object obj) { |
| 347 if (obj is _NamedObject) { |
| 348 _NamedObject that = obj; |
| 349 return name == that.name || peerNames.contains(that.name); |
| 350 } |
| 351 return false; |
| 352 } |
| 353 |
| 354 @override |
| 355 int get hashCode => 0; |
| 356 |
| 357 @override String toString() => name; |
| 358 } |
OLD | NEW |