Skip to content

Commit

Permalink
Merge pull request #60 from jecisc/20-assert-x-isEmpty--assertEmpty--co
Browse files Browse the repository at this point in the history
20-assert-x-isEmpty--assertEmpty--co
  • Loading branch information
jecisc authored Apr 28, 2020
2 parents 8b16997 + 675aaa1 commit a4443f2
Show file tree
Hide file tree
Showing 3 changed files with 217 additions and 1 deletion.
27 changes: 26 additions & 1 deletion resources/doc/documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -313,4 +313,29 @@ Chanel try to use the system method categorizer to classify unclassified methods
- The protocol of the method needs to by `as yet unclassified`.

*Warnings:*
This cleaning should not have any counter indication.
This cleaning should not have any counter indication.


### Empty assertions

Chanel iterates on all the tests of the packages and clean empty assertions.
Here is the list of rewrites it will apply:

| Original | Transformation |
| ------------- | ------------- |
| `x assert: y isEmpty` | `x assertEmpty: y` |
| `x deny: y isEmpty` | `x denyEmpty: y` |
| `x assert: y isNotEmpty` | `x denyEmpty: y` |
| `x deny: y isNotEmpty` | `x assertEmpty: y` |

`#assertEmpty:` and `denyEmpty:` were added in Pharo 8 and gives better descriptions in case of failure than simple asserts.

*Conditions for the cleanings to by applied:*
- Only subclasses of TestCase are cleaned.
- Does not clean the traits in the packages.
- A pattern from the list above match.
- The minimal pharo version provided is supperior to 8.

*Warnings:*
The danger of this cleaning happens on projects working in Pharo < 8. Some of this new assertions were introduced in Pharo 8.
You can precise the minimal Pharo version on which the project should run to avoid the application of those rules.
153 changes: 153 additions & 0 deletions src/Chanel-Tests/ChanelTestEmptyAssertionsCleanerTest.class.st
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
"
A ChanelTestEmptyAssertionsCleanerTest is a test class for testing the behavior of ChanelTestEmptyAssertionsCleaner
"
Class {
#name : #ChanelTestEmptyAssertionsCleanerTest,
#superclass : #ChanelAbstractCleanerTest,
#category : #'Chanel-Tests'
}

{ #category : #running }
ChanelTestEmptyAssertionsCleanerTest >> setUp [
super setUp.
class := self createDefaultTestClass
]

{ #category : #tests }
ChanelTestEmptyAssertionsCleanerTest >> testAssertEmpty [
self assert: 'self assert: #() isEmpty' isRewrittenAs: 'self assertEmpty: #()'
]

{ #category : #tests }
ChanelTestEmptyAssertionsCleanerTest >> testAssertEmpty2 [
self assert: 'self deny: #() isNotEmpty' isRewrittenAs: 'self assertEmpty: #()'
]

{ #category : #tests }
ChanelTestEmptyAssertionsCleanerTest >> testAssertEmpty2NotReplacedForPharo7 [
self deny: 'self deny: #() isNotEmpty' isRewrittenForPharo: 7
]

{ #category : #tests }
ChanelTestEmptyAssertionsCleanerTest >> testAssertEmptyNotReplacedForPharo7 [
self deny: 'self assert: #() isEmpty' isRewrittenForPharo: 7
]

{ #category : #tests }
ChanelTestEmptyAssertionsCleanerTest >> testDenyEmpty [
self assert: 'self deny: #() isEmpty' isRewrittenAs: 'self denyEmpty: #()'
]

{ #category : #tests }
ChanelTestEmptyAssertionsCleanerTest >> testDenyEmpty2 [
self assert: 'self assert: #() isNotEmpty' isRewrittenAs: 'self denyEmpty: #()'
]

{ #category : #tests }
ChanelTestEmptyAssertionsCleanerTest >> testDenyEmpty2NotReplacedForPharo7 [
self deny: 'self assert: #() isNotEmpty' isRewrittenForPharo: 7
]

{ #category : #tests }
ChanelTestEmptyAssertionsCleanerTest >> testDenyEmptyNotReplacedForPharo7 [
self deny: 'self deny: #() isEmpty' isRewrittenForPharo: 7
]

{ #category : #tests }
ChanelTestEmptyAssertionsCleanerTest >> testDoesNotRemoveExtensions [
class
compile:
('{1}
{2}' format: {self selector . 'self assert: #() isEmpty'})
classified: self extensionProtocol.

self runCleaner.

self
assert: (class >> self selector) sourceCode
equals:
('{1}
{2}' format: {self selector . 'self assertEmpty: #()'}).

self assert: (class >> self selector) protocol equals: self extensionProtocol
]

{ #category : #tests }
ChanelTestEmptyAssertionsCleanerTest >> testDoesNotReplaceInTraits [
| trait |
trait := self createDefaultTrait.

class setTraitComposition: trait.

trait
compile:
('{1}
{2}' format: {self selector . 'self assert: #() isEmpty'}).

self runCleaner.

self
assert: (trait >> self selector) sourceCode
equals:
('{1}
{2}' format: {self selector . 'self assert: #() isEmpty'}).

self assert: (trait localSelectors includes: self selector).
self deny: (class localSelectors includes: self selector)
]

{ #category : #tests }
ChanelTestEmptyAssertionsCleanerTest >> testReplacementOnClassSide [
class class
compile:
('{1}
{2}' format: {self selector . 'self assert: #() isEmpty'}).

self runCleaner.

self
assert: (class class >> self selector) sourceCode
equals:
('{1}
{2}' format: {self selector . 'self assertEmpty: #()'})
]

{ #category : #tests }
ChanelTestEmptyAssertionsCleanerTest >> testShouldNotReplaceIfNotATestCase [
"We only replace the assertion of TestCase because other objects are much poorer in term of assertions."

class := self createDefaultClass.

class
compile:
('{1}
{2}' format: {self selector . 'self assert: #() isEmpty'}).

self runCleaner.

self
assert: (class >> self selector) sourceCode
equals:
('{1}
{2}' format: {self selector . 'self assert: #() isEmpty'})
]

{ #category : #tests }
ChanelTestEmptyAssertionsCleanerTest >> testWithNothingToReplace [
| oldMethod |
class
compile:
('{1}
{2}' format: {self selector . 'self assert: 3 equals: 2'}).

oldMethod := class >> self selector.
self runCleaner.

self
assert: (class >> self selector) sourceCode
equals:
('{1}
{2}' format: {self selector . 'self assert: 3 equals: 2'}).

self assert: class >> self selector identicalTo: oldMethod
]
38 changes: 38 additions & 0 deletions src/Chanel/ChanelTestEmptyAssertionsCleaner.class.st
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"
Description
--------------------
I am a cleaner replacing the invocation of #assert: with #isEmpty or #isNotEmpty by #assertEmpty: or #denyEmpty: in Pharo >= 8.
The reason is that it gives better logs in case of failure.
"
Class {
#name : #ChanelTestEmptyAssertionsCleaner,
#superclass : #ChanelMethodRewriterCleaner,
#category : #Chanel
}

{ #category : #testing }
ChanelTestEmptyAssertionsCleaner class >> isAvailableForPharo: anInteger [
^ anInteger >= 8
]

{ #category : #accessing }
ChanelTestEmptyAssertionsCleaner class >> priority [
^ 1100
]

{ #category : #cleaning }
ChanelTestEmptyAssertionsCleaner >> rewriter [
^ RBParseTreeRewriter new
replace: '`@receiver assert: `@arg isEmpty' with: '`@receiver assertEmpty: `@arg';
replace: '`@receiver deny: `@arg isEmpty' with: '`@receiver denyEmpty: `@arg';
replace: '`@receiver assert: `@arg isNotEmpty' with: '`@receiver denyEmpty: `@arg';
replace: '`@receiver deny: `@arg isNotEmpty' with: '`@receiver assertEmpty: `@arg';
yourself
]

{ #category : #cleaning }
ChanelTestEmptyAssertionsCleaner >> scope [
^ self configuration definedTestCases
]

0 comments on commit a4443f2

Please sign in to comment.