2019-05-04 16:40:05 +02:00
# Cajon - Concise AssertJ Optimizing Nitpicker [![Build Status](https://travis-ci.org/chrisly42/cajon-plugin.svg?branch=master)](https://travis-ci.org/chrisly42/cajon-plugin) [![Coverage Status](https://coveralls.io/repos/github/chrisly42/cajon-plugin/badge.svg?branch=master)](https://coveralls.io/github/chrisly42/cajon-plugin?branch=master)
2019-03-10 18:19:46 +01:00
2019-04-22 18:52:09 +02:00
Cajon is an IntelliJ IDEA Plugin for shortening and optimizing [AssertJ ](https://assertj.github.io/doc/ ) assertions.
2019-03-10 18:19:46 +01:00
2019-04-22 18:52:09 +02:00
## Purpose
2019-03-10 18:19:46 +01:00
2019-03-24 09:15:07 +01:00
First, code is easier to read, when it is concise and reflects the intention clearly.
AssertJ has plenty of different convenience methods that describing various intentions precisely.
2019-03-10 18:19:46 +01:00
Why write longer, more complex code that can be expressed in brevity?
2019-04-22 18:52:09 +02:00
Second, when using the available special assertion methods of AssertJ, a failure of a condition
can be expressed in better detail and with more meaningful descriptions.
2019-03-24 09:15:07 +01:00
This makes finding bugs and fixing failed tests more efficient.
2019-04-22 18:52:09 +02:00
Nobody likes to read failures of the kind "failed because true is not false".
2019-03-24 09:15:07 +01:00
For example:
2019-03-31 15:15:06 +02:00
```
assertThat(collection.size()).isEqualTo(5);
```
2019-03-24 09:15:07 +01:00
2019-04-18 22:12:48 +02:00
If the collection has more or less than five elements, the assertion will fail, but will not
2019-03-24 09:15:07 +01:00
tell you about the contents, making it hard to guess what went wrong.
Instead, if you wrote the same assertion the following way:
2019-03-31 15:15:06 +02:00
```
assertThat(collection).hasSize(5);
```
2019-03-24 09:15:07 +01:00
2019-04-18 22:12:48 +02:00
Then AssertJ would tell you the _actual contents_ of the collection on failure.
2019-03-10 18:19:46 +01:00
2019-03-31 15:15:06 +02:00
## Conversion of JUnit assertions to AssertJ
The plugin also supports the conversion of the most common JUnit 4 assertions to AssertJ.
2019-04-18 22:12:48 +02:00
## Lookup and refactoring of string-based extracting()
AssertJ allows [extracting POJO fields/properties on iterables/arrays ](http://joel-costigliola.github.io/assertj/assertj-core-features-highlight.html#extracted-properties-assertion ).
Using strings is not safe for refactoring (and before Java 8 Lambdas were available,
creating extractor functions just for testing purpose was a bit too tedious).
This plugin adds support for referencing these fields (so you can ctrl(/cmd)-click on the
string to go to the definition) and also allows safe refactoring on the
fields (refactoring a getter method without a corresponding field will not work
correctly right now).
2019-04-11 16:26:11 +02:00
## Usage
The plugin will report inspections in your opened editor file as warnings.
You can then quick-fix these with your quick-fix hotkey (usually Alt-Return or Opt-Return).
Or, you can use the "Run Inspection by Name..." action to run one inspection on a bigger scope (e.g. the whole project).
2019-04-22 18:52:09 +02:00
Applying a quick fix might result in further optimization possibilities, so
you might need to perform a couple of fixes before you get to the final result.
2019-04-20 09:04:38 +02:00
2019-04-22 18:52:09 +02:00
Check out this example where every line represents the result after a Cajon quickfix:
2019-04-20 09:04:38 +02:00
```
2019-04-20 18:40:38 +02:00
assertFalse(!(array.length == collection.size()));
2019-04-20 09:04:38 +02:00
2019-04-20 18:40:38 +02:00
assertThat(!(array.length == collection.size())).isFalse();
2019-04-20 09:04:38 +02:00
2019-04-20 18:40:38 +02:00
assertThat(array.length == collection.size()).isTrue();
assertThat(array.length).isEqualTo(collection.size());
2019-04-20 09:04:38 +02:00
assertThat(array).hasSameSizeAs(collection);
```
2019-04-11 16:26:11 +02:00
You can toggle the various inspections in the Settings/Editor/Inspections in the AssertJ group.
2019-04-28 20:43:42 +02:00
## Implemented inspections and quickfixes
2019-03-10 18:19:46 +01:00
2019-04-28 20:43:42 +02:00
- JoinAssertThatStatements
```
from: assertThat(expected).someCondition();
assertThat(expected).anotherCondition();
to: assertThat(expected).someCondition().anotherCondition();
```
2019-04-29 19:42:46 +02:00
Joining will work on actual expressions inside assertThat() that are equivalent expressions,
except for method calls with known side-effect methods such as ```Iterator.next()``` -- please notify me about others.
2019-04-28 20:43:42 +02:00
The comments of the statements will be preserved. When using ```.extracting()``` or similar, the statements will not be merged.
2019-04-06 17:41:32 +02:00
- AssertThatObjectIsNullOrNotNull
2019-03-31 15:15:06 +02:00
```
from: assertThat(object).isEqualTo(null);
to: assertThat(object).isNull();
2019-04-06 17:41:32 +02:00
2019-03-31 15:15:06 +02:00
from: assertThat(object).isNotEqualTo(null);
to: assertThat(object).isNotNull();
```
2019-04-19 19:43:20 +02:00
2019-04-20 18:40:38 +02:00
- AssertThatBooleanCondition
2019-03-31 15:15:06 +02:00
```
from: assertThat(booleanValue).isEqualTo(true/false/Boolean.TRUE/Boolean.FALSE);
to: assertThat(booleanValue).isTrue()/isFalse();
```
2019-04-19 19:43:20 +02:00
2019-04-20 18:40:38 +02:00
- AssertThatInvertedBooleanCondition
```
from: assertThat(!booleanValue).isEqualTo(true/false/Boolean.TRUE/Boolean.FALSE);
from: assertThat(!booleanValue).isTrue()/isFalse();
2019-04-22 18:52:09 +02:00
to: assertThat(booleanValue).isFalse()/isTrue();
```
- AssertThatInstanceOf
```
from: assertThat(object instanceof classname).isEqualTo(true);
from: assertThat(object instanceof classname).isTrue();
to: assertThat(object).isInstanceOf(classname.class);
from: assertThat(object instanceof classname).isEqualTo(false);
from: assertThat(object instanceof classname).isFalse();
to: assertThat(object).isNotInstanceOf(classname.class);
2019-04-20 18:40:38 +02:00
```
2019-03-23 22:44:22 +01:00
- AssertThatStringIsEmpty
2019-03-31 15:15:06 +02:00
```
from: assertThat(charSequence/string).isEqualTo("");
from: assertThat(charSequence/string).hasSize(0);
to: assertThat(charSequence/string).isEmpty();
```
2019-04-19 19:43:20 +02:00
- AssertThatStringExpression
```
from: assertThat(stringActual.isEmpty()).isTrue();
to: assertThat(stringActual).isEmpty();
from: assertThat(stringActual.equals(stringExpected)).isTrue();
from: assertThat(stringActual.contentEquals(charSeqExpected)).isTrue();
to: assertThat(stringActual).isEqualTo(stringExpected);
from: assertThat(stringActual.equalsIgnoreCase(stringExpected)).isTrue();
to: assertThat(stringActual).isEqualToIgnoringCase(stringExpected);
from: assertThat(stringActual.contains(stringExpected)).isTrue();
to: assertThat(stringActual).contains(stringExpected);
from: assertThat(stringActual.startsWith(stringExpected)).isTrue();
to: assertThat(stringActual).startsWith(stringExpected);
from: assertThat(stringActual.endsWith(stringExpected)).isTrue();
to: assertThat(stringActual).endsWith(stringExpected);
```
Analogously with ```isFalse()```.
2019-03-24 14:42:02 +01:00
- AssertThatEnumerableIsEmpty
2019-03-31 15:15:06 +02:00
```
from: assertThat(enumerable).hasSize(0);
to: assertThat(enumerable).isEmpty();
2019-03-31 20:44:52 +02:00
```
2019-04-19 19:43:20 +02:00
2019-03-31 20:44:52 +02:00
- AssertThatSize
```
from: assertThat(array.length).isEqualTo(0);
from: assertThat(array.length).isLessThanOrEqualTo(0);
from: assertThat(array.length).isLessThan(1);
from: assertThat(array.length).isZero();
to: assertThat(array).isEmpty();
from: assertThat(array.length).isGreaterThan(0);
from: assertThat(array.length).isGreaterThanOrEqualTo(1);
from: assertThat(array.length).isNotZero();
to: assertThat(array).isNotEmpty();
from: assertThat(array.length).isEqualTo(anotherArray.length);
to: assertThat(array).hasSameSizeAs(anotherArray);
2019-04-23 20:16:43 +02:00
from: assertThat(array).hasSize(anotherArray.length);
to: assertThat(array).hasSameSizeAs(anotherArray);
2019-03-31 20:44:52 +02:00
```
2019-04-20 09:04:38 +02:00
and additionally with AssertJ 13.2.0 or later
2019-04-06 16:53:20 +02:00
```
from: assertThat(array.length).isLessThanOrEqualTo(expression);
to: assertThat(array).hasSizeLessThanOrEqualTo(expression);
from: assertThat(array.length).isLessThan(expression);
to: assertThat(array).hasSizeLessThan(expression);
from: assertThat(array.length).isGreaterThan(expression);
to: assertThat(array).hasSizeGreaterThan(expression);
from: assertThat(array.length).isGreaterThanOrEqualTo(expression);
to: assertThat(array).hasSizeGreaterThanOrEqualTo(expression);
```
2019-04-20 09:04:38 +02:00
and analogously for collections, strings and CharSequences, e.g:
```
from: assertThat("string".length()).isLessThan(1);
to: assertThat("string").isEmpty();
from: assertThat("string".length()).isEqualTo(collection.size())
to: assertThat("string").hasSameSizeAs(collection);
2019-04-23 20:16:43 +02:00
from: assertThat("string".length()).hasSize("strong".length())
to: assertThat("string").hasSameSizeAs("strong");
2019-04-20 09:04:38 +02:00
```
2019-03-31 20:44:52 +02:00
2019-04-20 18:40:38 +02:00
- AssertThatBinaryExpression
2019-04-07 11:29:07 +02:00
```
from: assertThat(primActual == primExpected).isTrue();
to: assertThat(primActual).isEqualTo(primExpected);
from: assertThat(10 < primActual ) . isNotEqualTo ( false ) ;
to: assertThat(primActual).isGreaterThan(primExpected);
from: assertThat(objActual != objExpected).isEqualTo(true);
to: assertThat(objActual).isNotSameAs(objExpected);
from: assertThat(null == objActual).isFalse();
to: assertThat(objActual).isNotNull();
2019-04-19 19:33:14 +02:00
from: assertThat(objActual.equals(objExpected).isTrue();
to: assertThat(objActual).isEqualTo(objExpected);
2019-04-07 11:29:07 +02:00
```
2019-04-18 22:12:48 +02:00
...and many, many more combinations (more than 150).
2019-04-19 19:33:14 +02:00
2019-04-11 16:26:11 +02:00
- AssertThatJava8Optional
```
from: assertThat(opt.isPresent()).isEqualTo(true);
from: assertThat(opt.isPresent()).isNotEqualTo(false);
from: assertThat(opt.isPresent()).isTrue();
to: assertThat(opt).isPresent();
from: assertThat(opt.isPresent()).isEqualTo(false);
from: assertThat(opt.isPresent()).isNotEqualTo(true);
from: assertThat(opt.isPresent()).isFalse();
to: assertThat(opt).isNotPresent();
from: assertThat(opt.get()).isEqualTo("foo");
to: assertThat(opt).contains("foo");
from: assertThat(opt.get()).isSameAs("foo");
to: assertThat(opt).containsSame("foo");
from: assertThat(opt).isEqualTo(Optional.of("foo"));
from: assertThat(opt).isEqualTo(Optional.ofNullable("foo"));
to: assertThat(opt).contains("foo");
from: assertThat(opt).isEqualTo(Optional.empty());
to: assertThat(opt).isNotPresent();
from: assertThat(opt).isNotEqualTo(Optional.empty());
to: assertThat(opt).isPresent();
```
- AssertThatGuavaOptional
```
from: assertThat(opt.isPresent()).isEqualTo(true);
from: assertThat(opt.isPresent()).isNotEqualTo(false);
from: assertThat(opt.isPresent()).isTrue();
to: assertThat(opt).isPresent();
from: assertThat(opt.isPresent()).isEqualTo(false);
from: assertThat(opt.isPresent()).isNotEqualTo(true);
from: assertThat(opt.isPresent()).isFalse();
to: assertThat(opt).isAbsent();
from: assertThat(opt.get()).isEqualTo("foo");
to: assertThat(opt).contains("foo");
from: assertThat(opt).isEqualTo(Optional.of("foo"));
from: assertThat(opt).isEqualTo(Optional.fromNullable("foo"));
to: assertThat(opt).contains("foo");
from: assertThat(opt).isEqualTo(Optional.absent());
to: assertThat(opt).isAbsent();
2019-04-06 16:53:20 +02:00
2019-04-11 16:26:11 +02:00
from: assertThat(opt).isNotEqualTo(Optional.absent());
to: assertThat(opt).isPresent();
2019-04-06 16:53:20 +02:00
```
2019-04-11 16:26:11 +02:00
2019-04-11 23:55:35 +02:00
AssertJ for Guava needs to be available in the classpath.
2019-04-19 19:33:14 +02:00
- JUnitAssertToAssertJ
```
assertTrue(condition);
assertTrue(message, condition);
assertFalse(condition);
assertFalse(message, condition);
assertNull(object);
assertNull(message, object);
assertNonNull(object);
assertNonNull(message, object);
assertEquals(expected, actual);
assertEquals(message, expected, actual);
assertEquals(expectedDoubleOrFloat, actualDoubleOrFloat, delta);
assertEquals(message, expectedDoubleOrFloat, actualDoubleOrFloat, delta);
assertNotEquals(unexpected, actual);
assertNotEquals(message, unexpected, actual);
assertNotEquals(unexpectedDoubleOrFloat, actualDoubleOrFloat, delta);
assertNotEquals(message, unexpectedDoubleOrFloat, actualDoubleOrFloat, delta);
assertSame(expected, actual);
assertSame(message, expected, actual);
assertNotSame(unexpected, actual);
assertNotSame(message, unexpected, actual);
assertArrayEquals(expected, actual);
assertArrayEquals(message, expectedArray, actualArray);
assertArrayEquals(expectedDoubleOrFloatArray, actualDoubleOrFloatArray, delta);
assertArrayEquals(message, expectedDoubleOrFloatArray, actualDoubleOrFloatArray, delta);
```
2019-04-18 22:12:48 +02:00
### Implemented referencing
```
.extracting("field")
2019-04-19 19:43:20 +02:00
.extracting("outerField.fieldInsideObjectTypeOfOuterField.andSoOn")
2019-04-18 22:12:48 +02:00
.extracting("property") // where the class has a getProperty() (or isProperty() for boolean) method
.extracting("bareMethod") // supported with AssertJ 13.12.0
.extracting(Extractors.byName("fieldOrPropertyOrBareMethod")
.extracting(Extractors.byName("fieldOrPropertyOrBareMethod.orAPathLikeAbove")
.extracting(Extractors.resultOf("bareMethod")
.extractingResultOf("bareMethod")
.flatExtracting("fieldOrPropertyOrBareMethod.orAPathLikeAbove")
.flatExtracting(Extractors.byName("fieldOrPropertyOrBareMethod.orAPathLikeAbove")
.flatExtracting(Extractors.resultOf("bareMethod")
```
2019-04-19 19:43:20 +02:00
Works on both POJOs and ```Iterable```s/```Array```s.
Implementation is very basic though and does not work with fancy cascaded .extracting() sequences.
If there's demand, I will add it.
2019-04-18 22:12:48 +02:00
2019-04-11 23:55:35 +02:00
## Development notice
Cajon is written in Kotlin 1.3.
Cajon is probably the only plugin that uses JUnit 5 Jupiter for unit testing so far (or at least the only one that I'm aware of ;) ).
2019-04-22 18:52:09 +02:00
The IntelliJ framework actually uses the JUnit 3 TestCase for plugin testing and it took me quite a while to make it work with JUnit 5.
2019-04-11 23:55:35 +02:00
Feel free to use the code (in package de.platon42.intellij.jupiter) for your projects (with attribution).
2019-04-28 20:43:42 +02:00
## Planned features
2019-04-19 19:33:14 +02:00
- AssumeThatInsteadOfReturn
2019-04-06 16:53:20 +02:00
- Extraction with property names to lambda with Java 8
```
from: assertThat(object).extracting("propOne", "propNoGetter", "propTwo.innerProp")...
to: assertThat(object).extracting(type::getPropOne, it -> it.propNoGetter, it -> it.getPropTwo().getInnerProp())...
```
2019-04-19 19:33:14 +02:00
- Kotlin support (right now, however, with less than 100 downloads after a month, this is unlikely to happen)
2019-04-11 16:26:11 +02:00
## Changelog
2019-04-29 19:42:46 +02:00
#### V0.8 (unreleased)
- Fixed missing description for JoinAssertThatStatements and detection of equivalent expressions (sorry, released it too hastily).
2019-05-01 13:07:05 +02:00
- Fixed ```isEmpty()``` for enumerables and strings and ```isNull()``` for object conversions to be applied only if it is the terminal method call as ```isEmpty()``` and ```isNull()``` return void.
2019-05-04 15:36:04 +02:00
- Heavily reworked inspections for edge cases, such as multiple ```isEqualTo()``` calls inside a single statement.
- Some inspections could generate bogus code for weird situations, this has been made more fool-proof.
- Corrected highlighting for many inspections.
- Fixed family names for inspections in batch mode.
- Reworded many inspection messages for better understanding.
2019-04-29 19:42:46 +02:00
2019-04-28 20:43:42 +02:00
#### V0.7 (28-Apr-19)
2019-04-23 18:19:47 +02:00
- Another fix for AssertThatGuavaOptional inspection regarding using the same family name for slightly different quick fix executions
(really, Jetbrains, this sucks for no reason).
2019-04-23 20:16:43 +02:00
- Extended AssertThatSize inspection to transform ```hasSize()``` into ```hasSameSizeAs()```, if possible.
2019-04-28 20:43:42 +02:00
- Implemented first version of JoinAssertThatStatements inspection that will try to merge ```assertThat()``` statements with the same
actual object together, preserving comments.
2019-04-23 18:19:47 +02:00
2019-04-22 18:52:09 +02:00
#### V0.6 (22-Apr-19)
2019-04-20 18:40:38 +02:00
- New AssertThatStringExpression inspection that will move ```isEmpty()```, ```equals()```, ```equalsIgnoreCase()```, ```contains()```,
2019-04-19 19:33:14 +02:00
```startsWith()```, and ```endsWith()``` out of actual expression.
2019-04-20 18:40:38 +02:00
- Extended AssertThatSize inspection to take ```String```s and ```CharSequences``` into account, too.
- New AssertThatInvertedBooleanCondition inspection that will remove inverted boolean expressions inside ```assertThat()```.
- Renamed a few inspections to better/shorter names.
2019-04-22 18:52:09 +02:00
- New AssertThatInstanceOf inspection that moves instanceof expressions out of ```assertThat()```.
2019-04-20 09:04:38 +02:00
2019-04-22 18:52:09 +02:00
#### V0.5 (18-Apr-19)
2019-04-18 22:12:48 +02:00
- Fixed incompatibility with IDEA versions < 2018.2 ( affected AssertThatSizeInspection ). Minimal version is now 2017 . 3 .
2019-04-13 18:35:49 +02:00
- Fixed missing Guava imports (if not already present) for AssertThatGuavaInspection. This was a major PITA to get right.
2019-04-18 22:12:48 +02:00
- Added support for referencing and refactoring inside ```.extracting()``` methods with fields, properties and methods (though
getter renaming does not work that perfect, but I'm giving up for now as the IntelliJ SDK docs are seriously lacking).
- Fixed an exception in batch mode if the description string was the same but for different fixes.
Now descriptions are different for quick fixes triggered by AssertThatJava8OptionalInspection and AssertThatGuavaOptionalInspection.
2019-04-13 18:35:49 +02:00
2019-04-11 23:55:35 +02:00
#### V0.4 (11-Apr-19)
- Reduced minimal supported IDEA version from 2018.2 to 2017.2.
2019-04-18 22:12:48 +02:00
- New inspection AssertThatJava8Optional that operates on Java 8 ```Optional``` objects and tries to use ```contains()```, ```containsSame()```, ```isPresent()```, and ```isNotPresent()``` instead.
- New inspection AssertThatGuavaOptional that operates on Guava ```Optional``` objects and tries to use ```contains()```, ```isPresent()```, and ```isAbsent()``` instead.
- Added support in AssertThatBinaryExpressionIsTrueOrFalse for ```is(Not)EqualTo(Boolean.TRUE/FALSE)```.
2019-04-11 23:55:35 +02:00
2019-04-11 16:26:11 +02:00
#### V0.3 (07-Apr-19)
2019-04-18 22:12:48 +02:00
- New inspection AssertThatBinaryExpressionIsTrueOrFalse that will find and fix common binary expressions and ```equals()``` statements (more than 150 combinations) inside ```assertThat()```.
2019-04-11 16:26:11 +02:00
- Merged AssertThatObjectIsNull and AssertThatObjectIsNotNull to AssertThatObjectIsNullOrNotNull.
2019-04-18 22:12:48 +02:00
- Support for ```hasSizeLessThan()```, ```hasSizeLessThanOrEqualTo()```, ```hasSizeGreaterThanOrEqualTo()```, and ```hasSizeGreaterThan()``` for AssertThatSizeInspection (with AssertJ >=13.2.0).
2019-04-11 16:26:11 +02:00
- Really fixed highlighting for JUnit conversion. Sorry.
#### V0.2 (01-Apr-19)
- Fixed descriptions and quick fix texts.
- Fixed highlighting of found problems and also 'Run inspection by Name' returning nothing.
#### V0.1 (31-Mar-19)
- Initial release.