Skip to content

Commit

Permalink
Merge pull request #57 from ba-st/equality_checker
Browse files Browse the repository at this point in the history
Equality checker
  • Loading branch information
gcotelli authored Jun 19, 2020
2 parents 02693d9 + d8b0b7c commit ea7ccfa
Show file tree
Hide file tree
Showing 15 changed files with 376 additions and 185 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
smalltalk: [ Pharo64-8.0, Pharo64-7.0, Pharo32-7.0, Pharo32-6.1 ]
smalltalk: [ Pharo64-8.0, Pharo64-7.0, Pharo32-7.0 ]
name: ${{ matrix.smalltalk }}
steps:
- uses: actions/checkout@v2
Expand Down
7 changes: 0 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
[![GitHub release](https://img.shields.io/github/release/ba-st/Buoy.svg)](https://github.com/ba-st/Buoy/releases/latest)
[![Build Status](https://github.com/ba-st/Buoy/workflows/Build/badge.svg?branch=release-candidate)](https://github.com/ba-st/Buoy/actions?query=workflow%3ABuild)
[![Coverage Status](https://codecov.io/github/ba-st/Buoy/coverage.svg?branch=release-candidate)](https://codecov.io/gh/ba-st/Buoy/branch/release-candidate)
[![Pharo 6.1](https://img.shields.io/badge/Pharo-6.1-informational)](https://pharo.org)
[![Pharo 7.0](https://img.shields.io/badge/Pharo-7.0-informational)](https://pharo.org)
[![Pharo 8.0](https://img.shields.io/badge/Pharo-8.0-informational)](https://pharo.org)

Expand Down Expand Up @@ -57,12 +56,6 @@ Provides [extensions to the SUnit framework](docs/SUnit.md).
- The code is licensed under [MIT](LICENSE).
- The documentation is licensed under [CC BY-SA 4.0](http://creativecommons.org/licenses/by-sa/4.0/).

## Quick Start

- Download the latest [Pharo 32](https://get.pharo.org/) or [64 bits VM](https://get.pharo.org/64/).
- Download a ready to use image from the [release page](https://github.com/ba-st/Buoy/releases/latest)
- Explore the [documentation](docs/)

## Installation

To load the project in a Pharo image, or declare it as a dependency of your own project follow this [instructions](docs/Installation.md).
Expand Down
53 changes: 31 additions & 22 deletions docs/Comparison.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,36 +23,45 @@ hash
^ self equalityHashCombinator combineHashesOfAll: { alpha. beta. gamma }
```

## `StandardComparator`
It eases the implementation of comparison for equality of objects. Instances can be built in different ways:
## Equality Checkers
Equality checkers help to implement the equality method for objects. Any object can send to itself the message `equalityChecker`, configure it and then use it to check against the target object of the comparison.

- `StandardComparator differentiatingType`: compares for identity (`==`) or if an object `isKindOf` anotherObject.
- `StandardComparator differentiatingSending: aSelectorsCollection`: compares for identity (`==`), or if an object `isKindOf` anotherObject and all selectors are equal for both objects.
- `StandardComparator differentiatingThrough: aBlock`: compares for identity (`==`), or if an object `isKindOf` anotherObject and the block returns true when applied to both objects.
Equality checkers always performs a `==` comparison first and proceeds with the rest of the rules only if the objects are not identical.

Some examples
By default `equalityChecker` is an instance of `PropertyBasedEqualityChecker` and it alredy knowns the receiving instance. It can be configured with:
- `compare: selector` will add a rule to the checker that sends the provided message on the receiver and target object and compare the results by `=`
- `compare: block` will add a rule to the checker that evaluates the provided block on the receiver and target object and compare the results by `=`
- `compareAll:` it's like `compare:` but receives a collection of selectors or blocks.
- `compareWith: block` receives a two argument block and will add a rule to the checker that evaluates that block with the receiver and target objects. It expects that `block` evaluates to a `Boolean`.

The property based equality checker has always an implicit rule checking first if the target object is of the same type of the receiver. You check all the configured rules by sending `checkAgainst:` to the checker with the target object.

Buoy also offers a `SequenceableCollectionEqualityChecker` that can be used to compare two sequenceable collections by sending to it the message `check:against:` with both collections. It will check that both collections are sequenceable and contains the same elements in the same order.

### Examples

This examples assumes that equalityChecker is not reimplemented.

```smalltalk
|comparator|
comparator := StandardComparator differentiatingType.
comparator check: (Set with: 11) against: (Set with: 22) >>> true.
comparator check: (Set with: 11) against: (OrderedCollection with: 11) >>> false.
"Just type checking"
|checker|
checker := (Set with: 11) equalityChecker.
(checker checkAgainst: (Set with: 22)) >>> true.
(checker checkAgainst: #(11)) >>> false.
```

```smalltalk
| comparator |
comparator := StandardComparator differentiatingSending: #(abs).
comparator check: 1 against: -1 >>> true.
comparator check: 1 against: 2 >>> false.
| checker |
checker := 1 equalityChecker.
checker compare: #abs.
(checker checkAgainst: -1) >>> true.
(checker checkAgainst: 2) >>> false
```

```smalltalk
| comparator |
comparator :=
StandardComparator differentiatingThrough: [:oneObject :anotherObject |
oneObject asArray = anotherObject asArray].
comparator check: (Set with: 34) against: (Set with: 34) >>> true.
comparator check: (Set with: 34) against: (Set with: 33) >>> false.
| checker |
checker := (Set with: 34) equalityChecker.
checker compareWith: [:a :b | a asArray = b asArray].
(checker checkAgainst: (Set with: 34)) >>> true.
(checker checkAgainst: (Set with: 33)) >>> false.
```
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,19 @@ Class {
#category : #'Buoy-Comparison-Tests'
}

{ #category : #tests }
BuoyComparisonObjectExtensionsTest >> testEqual [

self
assert: ( ObjectUsingComparisonAffordances with: 1 and: 2 )
equals: ( ObjectUsingComparisonAffordances with: 1 and: 2 );
deny: ( ObjectUsingComparisonAffordances with: 1 and: 2 )
equals: ( ObjectUsingComparisonAffordances with: 2 and: 1 );
deny: ( ObjectUsingComparisonAffordances with: 1 and: 2 ) equals: self
]

{ #category : #tests }
BuoyComparisonObjectExtensionsTest >> testHash [

self assert: ( ObjectUsingEqualityHashCombinator with: 1 and: 2 ) hash equals: ( 1 bitXor: 2 )
self assert: ( ObjectUsingComparisonAffordances with: 1 and: 2 ) hash equals: ( 1 bitXor: 2 )
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
"
I'm an example used for testing purposes
"
Class {
#name : #ObjectUsingComparisonAffordances,
#superclass : #Object,
#instVars : [
'first',
'second'
],
#category : #'Buoy-Comparison-Tests'
}

{ #category : #'instance creation' }
ObjectUsingComparisonAffordances class >> with: anInteger and: anInteger2 [

^ self new initializeWith: anInteger and: anInteger2
]

{ #category : #comparing }
ObjectUsingComparisonAffordances >> = anObject [

^ self equalityChecker
compareAll: #(#first #second);
checkAgainst: anObject
]

{ #category : #accessing }
ObjectUsingComparisonAffordances >> first [
^ first
]

{ #category : #comparing }
ObjectUsingComparisonAffordances >> hash [

^ self equalityHashCombinator combineHashOf: first with: second
]

{ #category : #initialization }
ObjectUsingComparisonAffordances >> initializeWith: anInteger and: anInteger2 [

first := anInteger.
second := anInteger2
]

{ #category : #accessing }
ObjectUsingComparisonAffordances >> second [
^ second
]

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
"
An #PropertyBasedEqualityCheckerTest is a test class for testing the behavior of #PropertyBasedEqualityChecker
"
Class {
#name : #PropertyBasedEqualityCheckerTest,
#superclass : #TestCase,
#category : #'Buoy-Comparison-Tests'
}

{ #category : #tests }
PropertyBasedEqualityCheckerTest >> testCheckingIdenticalObjects [

| checker |

checker := self equalityChecker.
checker compareWith: [ :a :b | self fail ].

self assert: ( checker checkAgainst: self )
]

{ #category : #tests }
PropertyBasedEqualityCheckerTest >> testPropertyBlockComparison [

| checker |

checker := #(1 2 3 4) equalityChecker.
checker compare: [ :collection | collection last even ].

self
assert: ( checker checkAgainst: #(2) );
assert: ( checker checkAgainst: #(1 2 3 4) );
deny: ( checker checkAgainst: #(3) );
deny: ( checker checkAgainst: #(1 2 3 3) ).

checker := #(1 2 3 3) equalityChecker.
checker compare: [ :collection | collection last even ].

self
assert: ( checker checkAgainst: #(1) );
assert: ( checker checkAgainst: #(1 2 3 3) );
deny: ( checker checkAgainst: #(2) );
deny: ( checker checkAgainst: #(1 2 3 4) )
]

{ #category : #tests }
PropertyBasedEqualityCheckerTest >> testPropertyComparison [

| checker |

checker := #(1 2 3 4) equalityChecker.
checker compare: #first.

self
assert: ( checker checkAgainst: #(1 1 1 1) );
deny: ( checker checkAgainst: #(2 2 3 4) )
]

{ #category : #tests }
PropertyBasedEqualityCheckerTest >> testSeveralPropertiesComparison [

| checker |

checker := #(1 2 3 4) equalityChecker.
checker compareAll: #(#first #second).

self
assert: ( checker checkAgainst: #(1 2 1 2) );
deny: ( checker checkAgainst: #(1 1 3 4) );
deny: ( checker checkAgainst: #(2 2 3 4) )
]

{ #category : #tests }
PropertyBasedEqualityCheckerTest >> testTypeComparison [

| checker |

checker := self equalityChecker.

self
assert: ( checker checkAgainst: self class new );
deny: ( checker checkAgainst: self class superclass new )
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
"
A SequenceableCollectionEqualityCheckerTest is a test class for testing the behavior of SequenceableCollectionEqualityChecker
"
Class {
#name : #SequenceableCollectionEqualityCheckerTest,
#superclass : #TestCase,
#category : #'Buoy-Comparison-Tests'
}

{ #category : #tests }
SequenceableCollectionEqualityCheckerTest >> testCheckAgainst [

| checker base |

base := #(1 2 3 4).
checker := SequenceableCollectionEqualityChecker new.

self
assert: ( checker check: base against: #(1 2 3 4) );
assert: ( checker check: base against: #(1 2 3 4) asOrderedCollection );
deny: ( checker check: base against: #(1 2 3) );
deny: ( checker check: base against: #(0 2 3 4) );
deny: ( checker check: base against: #(1 0 3 4) );
deny: ( checker check: base against: #(1 2 0 4) );
deny: ( checker check: base against: #(1 2 3 0) )
]
79 changes: 0 additions & 79 deletions source/Buoy-Comparison-Tests/StandardComparatorTest.class.st

This file was deleted.

Loading

0 comments on commit ea7ccfa

Please sign in to comment.