Skip to content

Commit f93cf81

Browse files

File tree

2 files changed

+143
-0
lines changed

2 files changed

+143
-0
lines changed

vavr/src/main/java/io/vavr/control/Validation.java

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,50 @@ static <E, T> Validation<E, T> narrow(Validation<? extends E, ? extends T> valid
189189
return (Validation<E, T>) validation;
190190
}
191191

192+
/**
193+
* Decides which {@code Validation<E, T>} to return, depending on the test value -
194+
* if it's true, the result will be a {@link Validation.Valid},
195+
* if it's false - the result will be a {@link Validation.Invalid}
196+
*
197+
* @param test A {@code boolean} value to evaluate
198+
* @param valid A {@code Supplier<? extends T>} supplier of valid value, called if test is true
199+
* @param error A {@code Supplier<? extends E>} supplier of error, called if test is false
200+
* @param <E> Type of error
201+
* @param <T> Type of valid value
202+
*
203+
* @return {@code Validation<E, T>} with valid value or error, depending on the test condition evaluation
204+
*
205+
* @throws NullPointerException if any of the arguments is null
206+
*/
207+
static <E, T> Validation<E, T> cond(boolean test, Supplier<? extends T> valid, Supplier<? extends E> error) {
208+
Objects.requireNonNull(valid, "valid is null");
209+
Objects.requireNonNull(error, "error is null");
210+
211+
return test ? valid(valid.get()) : invalid(error.get());
212+
}
213+
214+
/**
215+
* Decides which {@code Validation<E, T>} to return, depending on the test value -
216+
* if it's true, the result will be a {@link Validation.Valid},
217+
* if it's false - the result will be a {@link Validation.Invalid}
218+
*
219+
* @param test A {@code boolean} value to evaluate
220+
* @param valid A {@code T} valid value, called if test is true
221+
* @param error An {@code E} error value, called if test is false
222+
* @param <E> Type of error
223+
* @param <T> Type of valid value
224+
*
225+
* @return {@code Validation<E, T>} with valid value or error, depending on the test condition evaluation
226+
*
227+
* @throws NullPointerException if any of the arguments is null
228+
*/
229+
static <E, T> Validation<E, T> cond(boolean test, T valid, E error) {
230+
Objects.requireNonNull(valid, "valid is null");
231+
Objects.requireNonNull(error, "error is null");
232+
233+
return test ? valid(valid) : invalid(error);
234+
}
235+
192236
/**
193237
* Combines two {@code Validation}s into a {@link Builder}.
194238
*

vavr/src/test/java/io/vavr/control/ValidationTest.java

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,11 @@
2626
import java.util.ArrayList;
2727
import java.util.Objects;
2828
import java.util.Spliterator;
29+
import org.junit.jupiter.api.Nested;
2930
import org.junit.jupiter.api.Test;
3031

3132
import static org.junit.jupiter.api.Assertions.assertThrows;
33+
import static org.junit.jupiter.api.Assertions.fail;
3234

3335
public class ValidationTest extends AbstractValueTest {
3436

@@ -127,6 +129,103 @@ public void shouldNarrowInvalid() {
127129
assertThat(narrow.getError()).isEqualTo("vavr");
128130
}
129131

132+
@Nested
133+
public class CondTests {
134+
135+
@Test
136+
public void shouldReturnValidIfTestTrue() {
137+
Validation<String, Integer> validation = Validation.cond(true, () -> 21, () -> "vavr");
138+
assertThat(validation).isEqualTo(Validation.valid(21));
139+
}
140+
141+
@Test
142+
public void shouldReturnInvalidIfTestFalse() {
143+
Validation<String, Integer> validation = Validation.cond(false, () -> 21, () -> "vavr");
144+
assertThat(validation).isEqualTo(Validation.invalid("vavr"));
145+
}
146+
147+
@Test
148+
public void shouldNotEvaluateValidSupplierOnFalse() {
149+
Validation<String, Integer> validation = Validation.cond(false, () -> {
150+
fail("Should not be called");
151+
return 21;
152+
}, () -> "vavr");
153+
assertThat(validation).isEqualTo(Validation.invalid("vavr"));
154+
}
155+
156+
@Test
157+
public void shouldNotEvaluateErrorSupplierOnTrue() {
158+
Validation<String, Integer> validation = Validation.cond(true, () -> 21, () -> {
159+
fail("Should not be called");
160+
return "vavr";
161+
});
162+
assertThat(validation).isEqualTo(Validation.valid(21));
163+
}
164+
165+
private class Car {
166+
String name;
167+
168+
Car(String name) {
169+
this.name = name;
170+
}
171+
172+
@Override
173+
public boolean equals(Object o) {
174+
if (this == o) return true;
175+
if (!(o instanceof Car)) return false;
176+
Car other = (Car) o;
177+
return name.equals(other.name);
178+
}
179+
180+
@Override
181+
public int hashCode() {
182+
return name.hashCode();
183+
}
184+
}
185+
186+
private class Hatchback extends Car {
187+
Hatchback(String name) {
188+
super(name);
189+
}
190+
}
191+
192+
private class Sedan extends Car {
193+
Sedan(String name) {
194+
super(name);
195+
}
196+
}
197+
198+
@Test
199+
public void shouldBeFineWithCovariantError() {
200+
Validation<Car, Integer> validation = Validation.cond(false, () -> 21, () -> new Hatchback("vavr"));
201+
assertThat(validation).isEqualTo(Validation.invalid(new Hatchback("vavr")));
202+
}
203+
204+
@Test
205+
public void shouldBeFineWithCovariantValid() {
206+
Validation<String, Car> validation = Validation.cond(true, () -> new Sedan("vavr"), () -> "vavr");
207+
assertThat(validation).isEqualTo(Validation.valid(new Sedan("vavr")));
208+
}
209+
210+
@Test
211+
public void shouldMakeTheSameDecisionNoMatterHowItsCalled() {
212+
Validation<String, Integer> v1 = Validation.cond(true, () -> 21, () -> "vavr");
213+
Validation<String, Integer> v2 = Validation.cond(true, 21, "vavr");
214+
215+
Validation<String, Integer> v3 = Validation.cond(false, () -> 21, () -> "vavr");
216+
Validation<String, Integer> v4 = Validation.cond(false, 21, "vavr");
217+
218+
assertThat(List.of(v1, v2)).allMatch(e -> e.equals(Validation.valid(21)));
219+
assertThat(List.of(v3, v4)).allMatch(e -> e.equals(Validation.invalid("vavr")));
220+
}
221+
222+
@Test
223+
public void shouldThrowWhenProvidedWithNull() {
224+
assertThrows(NullPointerException.class, () -> Validation.cond(false, 1, null));
225+
assertThrows(NullPointerException.class, () -> Validation.cond(false, null, 2));
226+
}
227+
}
228+
130229
// -- Validation.sequence
131230

132231
@Test

0 commit comments

Comments
 (0)