Skip to content

Commit

Permalink
Merge pull request #3 from emlagowski/feature/integer_validations
Browse files Browse the repository at this point in the history
Added integer validations.
  • Loading branch information
emlagowski authored Apr 4, 2020
2 parents 98f0f86 + 35ce5ee commit ddd42a1
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 5 deletions.
75 changes: 71 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,73 @@
<!-- ![Sonar Test Count](https://img.shields.io/sonar/total_tests/io.github.emlagowski:validify?server=https%3A%2F%2Fsonarcloud.io&sonarVersion=8.2&style=for-the-badge) -->
<!-- ![Sonar Tests](https://img.shields.io/sonar/tests/io.github.emlagowski:validify?compact_message&server=https%3A%2F%2Fsonarcloud.io&style=for-the-badge) -->

This library purpose is to make validation process more straightforward.
It helps to validate objects and keep information about errors occurred during validation.
The main purpose of this library is to provide a simple way to create more complicated validations and to accurately return information about errors that occurred during the validation.
The secondary goal is to not use any external dependencies.

## Usage example
## Available validations

You can combine multiple validators with logical operators like 'AND' and 'OR'.
At this moment some factory classes provides few out-of-the box self-explanatory (I hope so) validations.

```shell script
CoreValidations
- lengthIsEqual
- lengthInRange
- matches
- allCharactersAreDigits
- isEmpty
- isNotEmpty
- is
- isIn
- startsWith
- endsWith
IntegerValidations
- valueInRange
```

### Custom validation

Creating custom validations is as simple as implementing `io.github.emlagowski.validify.Validation` functional interface.
It have to return `ValidationResult` and to do that methods `ValidationsResult.valid()` and `ValidationResult invalid(String message, Object... args)` can be used.

Example of providing custom validation with implementing Validation interface.

```java
public class IntegerValueInRangeValidation implements Validation<Integer> {

private final Integer min;
private final Integer max;

public IntegerValueInRangeValidation(Integer min, Integer max) {
this.min = min;
this.max = max;
}

@Override
public ValidationResult apply(Integer value) {
return Optional.ofNullable(value)
.filter(v -> min <= v && v <= max)
.map(v -> ValidationResult.valid())
.orElseGet(() -> ValidationResult.invalid("Value '%s' should be in the range [%d, %d]", value, min, max));
}
}
```

Or it can be even shorter if you would use lambda expression like

```java
public static Validation<Integer> valueInRange(int min, int max) {
return value -> Optional.ofNullable(value)
.filter(v -> min <= v && v <= max)
.map(v -> ValidationResult.valid())
.orElseGet(() -> ValidationResult.invalid("Value '%s' should be in the range [%d, %d]", value, min, max));
}
```

## Validation API

On all Validations you can use `and` and `or` methods to combine them into one Validation.

### Usage example

Example below shows how to achieve validation that checks if
(value is 1-2 length string with only digits characters)
Expand Down Expand Up @@ -46,3 +107,9 @@ Length of 'value that not apply' not in range [1, 2]
'value that not apply' is not 'N/A'
'value that not apply' is not in [A, B, C]
```

### More examples

For more examples please see `examples` module or tests inside the `validify-core` module.


Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package io.github.emlagowski.validify;

import java.util.Optional;

public class IntegerValueInRangeValidation implements Validation<Integer> {

private final Integer min;
private final Integer max;

public IntegerValueInRangeValidation(Integer min, Integer max) {
this.min = min;
this.max = max;
}

@Override
public ValidationResult apply(Integer value) {
return Optional.ofNullable(value)
.filter(v -> min <= v && v <= max)
.map(v -> ValidationResult.valid())
.orElseGet(() -> ValidationResult.invalid("Value '%s' should be in the range [%d, %d]", value, min, max));
}
}
1 change: 0 additions & 1 deletion validify-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
<artifactId>validify-core</artifactId>

<properties>
<sonar.projectKey>emlagowski_validify</sonar.projectKey>
<sonar.tests>src/test/groovy</sonar.tests>
</properties>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package io.github.emlagowski.validify;

import java.util.Optional;

public class IntegerValidations {

private IntegerValidations() {
// utility class
}

public static Validation<Integer> valueInRange(int min, int max) {
return value -> Optional.ofNullable(value)
.filter(v -> min <= v && v <= max)
.map(v -> ValidationResult.valid())
.orElseGet(() -> ValidationResult.invalid("Value '%s' should be in the range [%d, %d]", value, min, max));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.function.Function;

@FunctionalInterface
public interface Validation<T> extends Function<T, ValidationResult> {

default Validation<T> and(Validation<T> other) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package io.github.emlagowski.validify

import spock.lang.Specification
import spock.lang.Unroll

class ValueInRangeTest extends Specification {

@Unroll
def 'validation should check if value #value is between #min and #max and result with success=#expectedSuccess'() {
when:
def result = IntegerValidations.valueInRange(min, max).apply(value)

then:
expectedSuccess == result.success
messages == result.messages.size()

where:
value | min | max || expectedSuccess | messages
0 | 0 | 1 || true | 0
1 | 0 | 1 || true | 0
2 | 0 | 1 || false | 1
2 | 100 | 200 || false | 1
-3 | -5 | 5 || true | 0
null | -5 | 5 || false | 1
}

def 'return message has all important information'() {
when:
def result = IntegerValidations.valueInRange(1, 2).apply(15)

then:
result.messages.size() == 1
result.messages.first().message.contains("1")
result.messages.first().message.contains("2")
result.messages.first().message.contains("15")
}

}

0 comments on commit ddd42a1

Please sign in to comment.