Skip to content

Commit 0571d81

Browse files
authored
Add requireIfPresent validator (#60)
Fix #57.
1 parent 05e7ae7 commit 0571d81

File tree

7 files changed

+127
-0
lines changed

7 files changed

+127
-0
lines changed

belgif-rest-problem-validator/src/main/java/io/github/belgif/rest/problem/validation/RequestValidator.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,18 @@ public <T> RequestValidator require(Input<T> input) {
357357
return this;
358358
}
359359

360+
/**
361+
* Validate that all the given inputs are present when the given target input is present.
362+
*
363+
* @param target the target input
364+
* @param inputs the inputs that are required when the target input is present
365+
* @return this RequestValidator
366+
*/
367+
public RequestValidator requireIfPresent(Input<?> target, Input<?>... inputs) {
368+
validators.add(new RequiredIfPresentValidator(target, Arrays.asList(inputs)));
369+
return this;
370+
}
371+
360372
/**
361373
* Conditionally register input validators.
362374
*
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package io.github.belgif.rest.problem.validation;
2+
3+
import java.util.List;
4+
import java.util.Objects;
5+
import java.util.Optional;
6+
7+
import io.github.belgif.rest.problem.api.Input;
8+
import io.github.belgif.rest.problem.api.InputValidationIssue;
9+
import io.github.belgif.rest.problem.api.InputValidationIssues;
10+
11+
/**
12+
* Validate that all the given inputs are present when the given target input is present.
13+
*/
14+
class RequiredIfPresentValidator extends AbstractMultiInputValidator<Object> {
15+
16+
private final Input<?> target;
17+
18+
RequiredIfPresentValidator(Input<?> target, List<Input<?>> inputs) {
19+
super(inputs);
20+
this.target = target;
21+
}
22+
23+
@Override
24+
public Optional<InputValidationIssue> validate() {
25+
if (target.getValue() != null && getInputValueStream().anyMatch(Objects::isNull)) {
26+
return Optional.of(InputValidationIssues.requiredInputsIfPresent(target, getInputs()));
27+
}
28+
return Optional.empty();
29+
}
30+
31+
}

belgif-rest-problem-validator/src/test/java/io/github/belgif/rest/problem/validation/RequestValidatorTest.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,24 @@ void requireInvalid() {
380380
InputValidationIssues.requiredInput(QUERY, "require"));
381381
}
382382

383+
@Test
384+
void requireIfPresentValid() {
385+
assertValid(new RequestValidator().requireIfPresent(Input.query("target", "ok"),
386+
Input.query("a", "ok"), Input.query("b", "ok")));
387+
assertValid(new RequestValidator().requireIfPresent(Input.query("target", null),
388+
Input.query("a", "ok"), Input.query("b", "ok")));
389+
assertValid(new RequestValidator().requireIfPresent(Input.query("target", null),
390+
Input.query("a", null), Input.query("b", "ok")));
391+
}
392+
393+
@Test
394+
void requireIfPresentInvalid() {
395+
assertInvalid(new RequestValidator().requireIfPresent(Input.query("target", "ok"),
396+
Input.query("a", null), Input.query("b", "ok")),
397+
InputValidationIssues.requiredInputsIfPresent(Input.query("target", "ok"),
398+
Arrays.asList(Input.query("a", null), Input.query("b", "ok"))));
399+
}
400+
383401
@Test
384402
void whenValid() {
385403
assertValid(new RequestValidator().when(false, validator -> validator.reject(Input.query("reject", "nok"))));
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package io.github.belgif.rest.problem.validation;
2+
3+
import static org.assertj.core.api.Assertions.*;
4+
5+
import java.util.Arrays;
6+
import java.util.List;
7+
8+
import org.junit.jupiter.api.Test;
9+
10+
import io.github.belgif.rest.problem.api.Input;
11+
import io.github.belgif.rest.problem.api.InputValidationIssues;
12+
13+
class RequiredIfPresentValidatorTest {
14+
15+
@Test
16+
void okTargetNotPresent() {
17+
assertThat(new RequiredIfPresentValidator(Input.query("x", null),
18+
Arrays.asList(Input.query("a", "value"), Input.query("b", null)))
19+
.validate()).isEmpty();
20+
}
21+
22+
@Test
23+
void okTargetPresent() {
24+
assertThat(new RequiredIfPresentValidator(Input.query("x", "value"),
25+
Arrays.asList(Input.query("a", "value"), Input.query("b", "ok")))
26+
.validate()).isEmpty();
27+
}
28+
29+
@Test
30+
void nok() {
31+
Input<?> target = Input.query("x", "value");
32+
List<Input<?>> inputs = Arrays.asList(Input.query("a", "value"), Input.query("b", null));
33+
assertThat(new RequiredIfPresentValidator(target, inputs).validate()).contains(
34+
InputValidationIssues.requiredInputsIfPresent(target, inputs));
35+
}
36+
37+
}

belgif-rest-problem/src/main/java/io/github/belgif/rest/problem/api/InputValidationIssues.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,18 @@ public static InputValidationIssue requiredInput(InEnum in, String name) {
120120
.in(in, name, null);
121121
}
122122

123+
public static InputValidationIssue requiredInputsIfPresent(Input<?> target, List<Input<?>> inputs) {
124+
InputValidationIssue issue =
125+
new InputValidationIssue(ISSUE_TYPE_REQUIRED_INPUT, "Input is required in this context")
126+
.detail(String.format("All of these inputs must be present if %s is present: %s",
127+
target.getName(), getJoinedNames(inputs)));
128+
issue.addInput(target);
129+
for (Input<?> input : inputs) {
130+
issue.addInput(input);
131+
}
132+
return issue;
133+
}
134+
123135
public static InputValidationIssue replacedSsin(InEnum in, String name, String ssin, String newSsin) {
124136
return new InputValidationIssue(ISSUE_TYPE_REPLACED_SSIN, "SSIN has been replaced, use new SSIN")
125137
.detail(String.format("SSIN %s has been replaced by %s", ssin, newSsin))

belgif-rest-problem/src/test/java/io/github/belgif/rest/problem/api/InputValidationIssuesTest.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,19 @@ void requiredInput() {
141141
assertThat(issue).extracting("href", "inputs", "additionalProperties").allMatch(this::isEmpty);
142142
}
143143

144+
@Test
145+
void requiredInputsIfPresent() {
146+
Input<?> target = Input.query("x", "value");
147+
List<Input<?>> inputs = Arrays.asList(Input.query("a", null), Input.query("b", "value"));
148+
InputValidationIssue issue = InputValidationIssues.requiredInputsIfPresent(target, inputs);
149+
assertThat(issue.getType()).hasToString("urn:problem-type:cbss:input-validation:requiredInput");
150+
assertThat(issue.getTitle()).isEqualTo("Input is required in this context");
151+
assertThat(issue.getDetail()).isEqualTo("All of these inputs must be present if x is present: a, b");
152+
assertThat(issue.getInputs()).contains(target).containsAll(inputs);
153+
assertThat(issue).extracting("href", "in", "name", "value", "additionalProperties")
154+
.allMatch(this::isEmpty);
155+
}
156+
144157
@Test
145158
void replacedSsin() {
146159
InputValidationIssue issue =

src/main/asciidoc/index.adoc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ The library consists of these modules:
3434

3535
* Removed deprecated InvalidParamProblem: use InputValidationProblem, which supports both the legacy invalidParams[] and the new issues[] structure
3636

37+
*belgif-rest-problem-validator:*
38+
39+
* Added requireIfPresent check for validating input(s) that must be present when a given target input is present
40+
3741
=== Version 0.3
3842

3943
*belgif-rest-problem:*

0 commit comments

Comments
 (0)