Skip to content

Commit

Permalink
Refactor error message and add behavior to chain queries
Browse files Browse the repository at this point in the history
  • Loading branch information
Patouche committed Feb 13, 2021
1 parent 60b49a8 commit a9dc913
Show file tree
Hide file tree
Showing 121 changed files with 4,802 additions and 2,395 deletions.
84 changes: 53 additions & 31 deletions TODOS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# TODOS


## Features

### Nodes
Expand All @@ -24,37 +23,60 @@ class SampleTests {

```

* Provider assertions on the main "raw" Java Bold driver types (Records...)
* Provider assertions on query results
* Should support both String and Cypher-DSL constructs
* Provider higher level experience à la AssertJ-DB
* Entities (commons nodes & relationships) :
* [X] `ignoringIds`: Remove id to entities and create a new assertions
* [X] `havePropertyKeys`: Verify if property's entities have the expected keys
* [ ] `havePropertyType` : Verify if all property's entities have the expected type
* [ ] `havePropertyCount`: Verify if entities have the number of properties
* [ ] `haveProperty` :
* [ ] `haveProperty` :
* [ ] `haveProperty` :
* [ ] `haveProperties` :
* [X] `contains` :
* [ ] `filteredOn`
* [ ] `filteredOnPropertyExists`
* [ ] `filteredOnProperty`
* [ ]
* [ ]
* [ ]
* [ ]
* [ ]
* [ ]
* Nodes :
* [X] `haveLabels`
## Tasks

### Goals

* [ ] Provider assertions on the main "raw" Java Bold driver types (Records...)
* [ ] `haveColumnSize`
* [ ] `isNode`
* [ ] `isRelationships`
* [ ] ``
* [ ] Provider assertions on query results
* [ ] Should support both String
* [ ] Cypher-DSL constructs
* [ ] Provider higher level experience à la AssertJ-DB
* [ ] Entities (commons nodes & relationships) :
* [X] `toParentAssert` : Go to the parent assertion
* [X] `ignoringIds`: Create a new assertion that will not compare the entity with theirs ids
* [X] `havePropertyKeys`: Verify that all entities have the expected keys
* [X] `havePropertyOfType` : Verify that all entities have a property with a value matching the provided type
* [X] `havePropertySize`: Verify that all entities have the expected number of properties
* [X] `havePropertyValue` : Verify that all entities have the property value
* [X] `havePropertyValueMatching` : Verify that all entities have the property matching the provided predicate
* [X] `haveListPropertyOfType` : Verify that all entities have a list property with elements of the provided type
* [X] `contains` : Verify that there is an entity that is equal to the one provided
* [X] `filteredOn` : Filter entities on a predicate. Create a new assertion
* [X] `filteredOnPropertyExists` : Filter entities that have the provided property key
* [X] `filteredOnPropertyValue` : Filter entities that have the provided property key
* [ ] Add negative assertions
* [ ] Nodes :
* [ ] `toRootAssert` : Retrieve the root assertion
* [X] `haveLabels` : Verify that the nodes have the expected labels
* [X] `filteredOnLabels` : Filter on nodes having the labels
* [X] `Drivers.node()....`
* [ ] `toParent`
* Relationships :
* [X] `incomingRelationships`
* [X] `outgoindRelationships`
* [X] `haveNoIncomingRelationships`
* [X] `haveNoOutgoingRelationships`
* [ ] Add negative assertions
* [ ] Relationships :
* [ ] `toRootAssert` : Retrieve the root assertion
* [X] `haveType` : Verify that a relationships if of the expected type
* [X] `Drivers.relationship()....`
* [X] `haveType`: Really useful ?
* [ ] `toParent`
* Request
* [ ]
* [ ] `startingNodes`
* [ ] `endingNodes`
* [ ] `haveNoStartingNodes`
* [ ] `haveNoEndingNodes`
* [ ] ``
* [ ] Add negative assertions
* [ ] Request : See bellow
* [ ] Changes :
* [ ] ``

### Others

* [ ] Simplify error message factory
* [ ]
* [ ] Simplify assertions
8 changes: 8 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
<testcontainers.version>1.15.1</testcontainers.version>
<logback.version>1.2.3</logback.version>
<slf4j.version>1.7.30</slf4j.version>
<neo4j-cypher-dsl.version>2020.1.6</neo4j-cypher-dsl.version>
</properties>

<dependencyManagement>
Expand All @@ -61,6 +62,13 @@
<version>${neo4j-driver.version}</version>
<scope>provided</scope>
</dependency>
<!-- Optional -->
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-cypher-dsl</artifactId>
<version>${neo4j-cypher-dsl.version}</version>
<optional>true</optional>
</dependency>
<!-- Test dependencies -->
<dependency>
<groupId>org.junit.jupiter</groupId>
Expand Down
131 changes: 95 additions & 36 deletions src/main/java/org/assertj/neo4j/api/beta/AbstractEntitiesAssert.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,33 @@

import org.assertj.core.api.AbstractAssert;
import org.assertj.core.error.ErrorMessageFactory;
import org.assertj.core.error.ShouldBeEmpty;
import org.assertj.core.internal.ComparisonStrategy;
import org.assertj.core.internal.Iterables;
import org.assertj.core.util.VisibleForTesting;
import org.assertj.neo4j.api.beta.error.ElementsShouldHavePropertyInstanceOf;
import org.assertj.neo4j.api.beta.error.ElementsShouldHavePropertyKeys;
import org.assertj.neo4j.api.beta.error.ElementsShouldHavePropertySize;
import org.assertj.neo4j.api.beta.error.ElementsShouldHavePropertyValue;
import org.assertj.neo4j.api.beta.error.ElementsShouldHavePropertyValueType;
import org.assertj.neo4j.api.beta.error.ShouldBeEmptyQueryResult;
import org.assertj.neo4j.api.beta.error.ShouldHavePropertyInstanceOf;
import org.assertj.neo4j.api.beta.error.ShouldHavePropertyListOfType;
import org.assertj.neo4j.api.beta.error.ShouldHavePropertySize;
import org.assertj.neo4j.api.beta.error.ShouldHavePropertyValue;
import org.assertj.neo4j.api.beta.error.ShouldHavePropertyValueType;
import org.assertj.neo4j.api.beta.error.ShouldHavePropertyKeys;
import org.assertj.neo4j.api.beta.error.ShouldPropertyMatch;
import org.assertj.neo4j.api.beta.type.DataLoader;
import org.assertj.neo4j.api.beta.type.DbEntity;
import org.assertj.neo4j.api.beta.type.RecordType;
import org.assertj.neo4j.api.beta.type.ValueType;
import org.assertj.neo4j.api.beta.util.Checks;
import org.assertj.neo4j.api.beta.util.Predicates;
import org.assertj.neo4j.api.beta.util.Presentations;
import org.assertj.neo4j.api.beta.util.Utils;
import org.assertj.neo4j.api.beta.util.Wip;

import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
Expand All @@ -42,7 +50,7 @@
* @param <ENTITY> the entity type
* @param <PARENT_ASSERT> the parent assertions type
* @param <ROOT_ASSERT> the root assertions type
* @author patouche - 24/11/2020
* @author Patrick Allain - 24/11/2020
*/
//@formatter:off
public abstract class AbstractEntitiesAssert<SELF extends AbstractEntitiesAssert<SELF, ENTITY, PARENT_ASSERT, ROOT_ASSERT>,
Expand All @@ -62,7 +70,11 @@ public abstract class AbstractEntitiesAssert<SELF extends AbstractEntitiesAssert
/** The data loader. */
protected final DataLoader<ENTITY> dataLoader;

/** True if comparison should be made ignoring ids */
// /** Comparison strategy. */
// protected final ComparisonStrategy comparisonStrategy;

/** True if comparison should be made ignoring ids. */
/** TODO: Check if it's possible to use a ComparisonStrategy instead. */
protected final boolean ignoreIds;

/** Factory for creating new assertions on restricted list of entities. */
Expand Down Expand Up @@ -140,14 +152,26 @@ protected List<Long> entityIds() {
*/
protected SELF shouldAllVerify(final Predicate<ENTITY> predicate,
final ErrorMessageCallback<ENTITY> callback) {
final List<ENTITY> notSatisfies = actual.stream()
.filter(predicate.negate()).collect(Collectors.toList());
final List<ENTITY> notSatisfies = actual.stream().filter(predicate.negate()).collect(Collectors.toList());
if (!notSatisfies.isEmpty()) {
throwAssertionError(callback.create(notSatisfies));
}
return myself;
}

public SELF isEmpty() {
return isEmpty(
(entities) -> ShouldBeEmptyQueryResult.elements(entities, dataLoader.query()).notSatisfies(entities)
);
}

protected SELF isEmpty(final ErrorMessageCallback<ENTITY> callback) {
if (!actual.isEmpty()) {
throwAssertionError(callback.create(actual));
}
return myself;
}

/**
* Verifies that actual entities (nodes or relationships) retrieve have the expected size.
* <p/>
Expand Down Expand Up @@ -216,7 +240,7 @@ public SELF filteredOn(final Predicate<ENTITY> predicate) {
}

/**
* Filtered entities to create a new {@link SELF} assertions.
* Filtered entities having existing properties to create a new {@link SELF} assertions.
* <p/>
* Example:
* <pre><code class='java'> Nodes nodes = new Nodes(driver, "Person");
Expand All @@ -234,7 +258,7 @@ public SELF filteredOnPropertyExists(final String... keys) {
}

/**
* Filtered entities to create a new {@link SELF} assertions.
* Filtered entities having existing properties to create a new {@link SELF} assertions.
* <p/>
* Example:
* <pre><code class='java'> Nodes nodes = new Nodes(driver, "Person");
Expand All @@ -248,10 +272,32 @@ public SELF filteredOnPropertyExists(final String... keys) {
* @return a new assertion object
*/
public SELF filteredOnPropertyExists(final Iterable<String> keys) {
Checks.notNullOrEmpty(keys, "The iterable of property keys should not be empty");
Checks.nonNullElementsIn(keys, "The iterable of property keys should not be empty");
return filteredOn(Predicates.propertyKeysExists(keys));
}

/**
* Filtered entities on a property value to create a new {@link SELF} assertions.
* <p/>
* Example:
* <pre><code class='java'> Nodes nodes = new Nodes(driver, "Person");
* assertThat(nodes)
* .hasSize(10)
* .filteredOnPropertyValue("name", "civility")
* .hasSize(5)
* </code></pre>
*
* @param key the property key that the filtered entities will have
* @param value the property value that the filtered entities will have
* @return a new assertion object
*/
public SELF filteredOnPropertyValue(final String key, final Object value) {
return filteredOn(Predicates.propertyValue(
Objects.requireNonNull(key, "The property key cannot be null"),
value
));
}

/**
* Provide a easy way to create new assertions on the current list of {@link ENTITY} without specifying the {@link
* ENTITY#getId()}
Expand Down Expand Up @@ -293,7 +339,7 @@ public SELF ignoringIds() {
* @throws AssertionError if the actual value is not equal to the given one.
*/
public SELF havePropertyKeys(final String... expectedKeys) {
return havePropertyKeys(Checks.notNullOrEmpty(expectedKeys, "The property keys should not be null or empty"));
return havePropertyKeys(Utils.listOf(expectedKeys));
}

/**
Expand All @@ -313,10 +359,11 @@ public SELF havePropertyKeys(final String... expectedKeys) {
* @throws AssertionError if the actual value is not equal to the given one.
*/
public SELF havePropertyKeys(final Iterable<String> expectedKeys) {
final List<String> keys = Checks.notNullOrEmpty(expectedKeys, "The property keys should not be null or empty");
final List<String> keys = Checks.nonNullElementsIn(expectedKeys, "The property keys should not be null or "
+ "empty");
return shouldAllVerify(
Predicates.propertyKeysExists(keys),
(notSatisfying) -> ElementsShouldHavePropertyKeys.create(recordType, actual, keys)
(notSatisfies) -> ShouldHavePropertyKeys.elements(actual, keys).notSatisfies(notSatisfies)
);
}

Expand All @@ -330,15 +377,15 @@ public SELF havePropertyKeys(final Iterable<String> expectedKeys) {
* .havePropertySize(8);
* </code></pre>
*
* @param expectedSizeOfProperties the expected size of properties
* @param expectedSize the expected size of properties
* @return {@code this} assertion object.
* @throws AssertionError if one entities don't have the expected size of properties
*/
public SELF havePropertySize(final int expectedSizeOfProperties) {
return shouldAllVerify(Predicates.propertySize(expectedSizeOfProperties),
(notSatifies) -> ElementsShouldHavePropertySize
.create(recordType, actual, notSatifies, expectedSizeOfProperties)
);
public SELF havePropertySize(final int expectedSize) {
return shouldAllVerify(
Predicates.propertySize(expectedSize),
(notSatisfies) -> ShouldHavePropertySize.elements(actual, expectedSize).notSatisfies(notSatisfies)
);
}

/**
Expand All @@ -364,12 +411,11 @@ public SELF havePropertySize(final int expectedSizeOfProperties) {
*/
public SELF havePropertyOfType(final String key, final ValueType expectedType) {
Objects.requireNonNull(key, "The property key shouldn't be null");
Objects.requireNonNull(expectedType, "The expected value type shouldn't be null");
final ValueType type = Objects.requireNonNull(expectedType, "The expected value type shouldn't be null");
havePropertyKeys(key);
return shouldAllVerify(
Predicates.propertyValueType(key, expectedType),
(notSatisfies) -> ElementsShouldHavePropertyValueType
.create(recordType, actual, key, expectedType)
Predicates.propertyValueType(key, type),
(notSatisfies) -> ShouldHavePropertyValueType.elements(actual, key, type).notSatisfies(notSatisfies)
);
}

Expand All @@ -396,12 +442,11 @@ public SELF havePropertyOfType(final String key, final ValueType expectedType) {
*/
public SELF havePropertyInstanceOf(final String key, final Class<?> expectedClass) {
Objects.requireNonNull(key, "The property key shouldn't be null");
Objects.requireNonNull(expectedClass, "The expected class shouldn't be null");
final Class<?> clazz = Objects.requireNonNull(expectedClass, "The expected class shouldn't be null");
havePropertyKeys(key);
return shouldAllVerify(
Predicates.propertyValueInstanceOf(key, expectedClass),
(notSatisfies) -> ElementsShouldHavePropertyInstanceOf
.create(recordType, actual, key, expectedClass)
Predicates.propertyValueInstanceOf(key, clazz),
(notSatisfies) -> ShouldHavePropertyInstanceOf.elements(actual, key, clazz).notSatisfies(notSatisfies)
);
}

Expand All @@ -424,16 +469,29 @@ public SELF havePropertyInstanceOf(final String key, final Class<?> expectedClas
public SELF haveListPropertyOfType(final String key, final ValueType expectedType) {
havePropertyKeys(key);
havePropertyOfType(key, ValueType.LIST);
final ValueType type = Objects.requireNonNull(expectedType, "The expected value type shouldn't be null");
return shouldAllVerify(
Predicates.propertyListContainsValueType(key, expectedType),
(notSatisfies) -> ElementsShouldHavePropertyValueType
.create(recordType, actual, key, expectedType)
Predicates.propertyListContainsValueType(key, type),
(notSatisfies) -> ShouldHavePropertyListOfType.elements(actual, key, type).notSatisfies(notSatisfies)
);
}

public SELF havePropertyValueMatching(final String key, final Predicate<Object> predicate) {
Wip.TODO(this, "havePropertyMatching");
return myself;
havePropertyKeys(key);
return shouldAllVerify(
Predicates.propertyValueMatch(key, predicate),
(notSatisfies) -> ShouldPropertyMatch.elements(actual, key).notSatisfies(notSatisfies)
);
}

public <T> SELF havePropertyValueMatching(final String key, final Class<T> expectedClass,
final Predicate<T> predicate) {
havePropertyKeys(key);
havePropertyInstanceOf(key, expectedClass);
return shouldAllVerify(
Predicates.propertyValueMatch(key, predicate),
(notSatisfies) -> ShouldPropertyMatch.elements(actual, key).notSatisfies(notSatisfies)
);
}

/**
Expand All @@ -455,8 +513,9 @@ public SELF haveProperty(final String key, final Object expectedValue) {
havePropertyKeys(key);
return shouldAllVerify(
Predicates.propertyValue(key, expectedValue),
(notSatisfies) -> ElementsShouldHavePropertyValue
.create(recordType, actual, notSatisfies, key, expectedValue)
(notSatisfies) -> ShouldHavePropertyValue
.elements(actual, key, expectedValue)
.notSatisfies(notSatisfies)
);
}

Expand Down
Loading

0 comments on commit a9dc913

Please sign in to comment.