-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adds unit tests for a variety of classes in the streamline framework. These unit tests were added as-needed to debug problems, and aren't meant to give comprehensive or systematic coverage.
- Loading branch information
David Legg
committed
Dec 19, 2023
1 parent
2963c74
commit 12e0ed6
Showing
10 changed files
with
1,743 additions
and
0 deletions.
There are no files selected for viewing
157 changes: 157 additions & 0 deletions
157
contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/core/CellRefV2Test.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
package gov.nasa.jpl.aerie.contrib.streamline.core; | ||
|
||
import gov.nasa.jpl.aerie.contrib.streamline.modeling.discrete.Discrete; | ||
import gov.nasa.jpl.aerie.merlin.framework.Registrar; | ||
import gov.nasa.jpl.aerie.merlin.framework.junit.MerlinExtension; | ||
import org.junit.jupiter.api.Nested; | ||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.api.TestInstance; | ||
import org.junit.jupiter.api.TestInstance.Lifecycle; | ||
import org.junit.jupiter.api.extension.ExtendWith; | ||
|
||
import static gov.nasa.jpl.aerie.contrib.streamline.core.CellRefV2.autoEffects; | ||
import static gov.nasa.jpl.aerie.contrib.streamline.core.CellRefV2.commutingEffects; | ||
import static gov.nasa.jpl.aerie.contrib.streamline.core.CellRefV2.noncommutingEffects; | ||
import static gov.nasa.jpl.aerie.contrib.streamline.core.MutableResource.resource; | ||
import static gov.nasa.jpl.aerie.contrib.streamline.core.Resources.currentValue; | ||
import static gov.nasa.jpl.aerie.contrib.streamline.modeling.discrete.Discrete.discrete; | ||
import static gov.nasa.jpl.aerie.contrib.streamline.modeling.discrete.monads.DiscreteDynamicsMonad.effect; | ||
import static gov.nasa.jpl.aerie.merlin.framework.ModelActions.delay; | ||
import static gov.nasa.jpl.aerie.merlin.framework.ModelActions.spawn; | ||
import static gov.nasa.jpl.aerie.merlin.protocol.types.Duration.ZERO; | ||
import static org.junit.jupiter.api.Assertions.*; | ||
|
||
class MutableResourceTest { | ||
@Nested | ||
@ExtendWith(MerlinExtension.class) | ||
@TestInstance(Lifecycle.PER_CLASS) | ||
class NonCommutingEffects { | ||
public NonCommutingEffects(final Registrar registrar) { | ||
Resources.init(); | ||
} | ||
|
||
private final MutableResource<Discrete<Integer>> cell = MutableResource.resource(discrete(42), noncommutingEffects()); | ||
|
||
@Test | ||
void gets_initial_value_if_no_effects_are_emitted() { | ||
assertEquals(42, currentValue(cell)); | ||
} | ||
|
||
@Test | ||
void applies_singleton_effect() { | ||
int initialValue = currentValue(cell); | ||
cell.emit(effect(n -> 3 * n)); | ||
assertEquals(3 * initialValue, currentValue(cell)); | ||
} | ||
|
||
@Test | ||
void applies_sequential_effects_in_order() { | ||
int initialValue = currentValue(cell); | ||
cell.emit(effect(n -> 3 * n)); | ||
cell.emit(effect(n -> n + 1)); | ||
assertEquals(3 * initialValue + 1, currentValue(cell)); | ||
} | ||
|
||
@Test | ||
void throws_exception_when_concurrent_effects_are_applied() { | ||
spawn(() -> cell.emit(effect(n -> 3 * n))); | ||
spawn(() -> cell.emit(effect(n -> 3 * n))); | ||
delay(ZERO); | ||
assertInstanceOf(ErrorCatching.Failure.class, cell.getDynamics()); | ||
} | ||
} | ||
|
||
@Nested | ||
@ExtendWith(MerlinExtension.class) | ||
@TestInstance(Lifecycle.PER_CLASS) | ||
class CommutingEffects { | ||
public CommutingEffects(final Registrar registrar) { | ||
Resources.init(); | ||
} | ||
|
||
private final MutableResource<Discrete<Integer>> cell = MutableResource.resource(discrete(42), commutingEffects()); | ||
|
||
@Test | ||
void gets_initial_value_if_no_effects_are_emitted() { | ||
assertEquals(42, currentValue(cell)); | ||
} | ||
|
||
@Test | ||
void applies_singleton_effect() { | ||
int initialValue = currentValue(cell); | ||
cell.emit(effect(n -> 3 * n)); | ||
assertEquals(3 * initialValue, currentValue(cell)); | ||
} | ||
|
||
@Test | ||
void applies_sequential_effects_in_order() { | ||
int initialValue = currentValue(cell); | ||
cell.emit(effect(n -> 3 * n)); | ||
cell.emit(effect(n -> n + 1)); | ||
assertEquals(3 * initialValue + 1, currentValue(cell)); | ||
} | ||
|
||
@Test | ||
void applies_concurrent_effects_in_any_order() { | ||
int initialValue = currentValue(cell); | ||
// These effects do not in fact commute, | ||
// but the point of the commutingEffects is that it *doesn't* check. | ||
spawn(() -> cell.emit(effect(n -> 3 * n))); | ||
spawn(() -> cell.emit(effect(n -> n + 1))); | ||
delay(ZERO); | ||
int result = currentValue(cell); | ||
assertTrue(result == 3*initialValue + 1 || result == 3 * (initialValue + 1)); | ||
} | ||
} | ||
|
||
@Nested | ||
@ExtendWith(MerlinExtension.class) | ||
@TestInstance(Lifecycle.PER_CLASS) | ||
class AutoEffects { | ||
public AutoEffects(final Registrar registrar) { | ||
Resources.init(); | ||
} | ||
|
||
private final MutableResource<Discrete<Integer>> cell = MutableResource.resource(discrete(42), autoEffects()); | ||
|
||
@Test | ||
void gets_initial_value_if_no_effects_are_emitted() { | ||
assertEquals(42, currentValue(cell)); | ||
} | ||
|
||
@Test | ||
void applies_singleton_effect() { | ||
int initialValue = currentValue(cell); | ||
cell.emit(effect(n -> 3 * n)); | ||
assertEquals(3 * initialValue, currentValue(cell)); | ||
} | ||
|
||
@Test | ||
void applies_sequential_effects_in_order() { | ||
int initialValue = currentValue(cell); | ||
cell.emit(effect(n -> 3 * n)); | ||
cell.emit(effect(n -> n + 1)); | ||
assertEquals(3 * initialValue + 1, currentValue(cell)); | ||
} | ||
|
||
@Test | ||
void applies_commuting_concurrent_effects() { | ||
int initialValue = currentValue(cell); | ||
// These effects do not in fact commute, | ||
// but the point of the commutingEffects is that it *doesn't* check. | ||
spawn(() -> cell.emit(effect(n -> 3 * n))); | ||
spawn(() -> cell.emit(effect(n -> 4 * n))); | ||
delay(ZERO); | ||
int result = currentValue(cell); | ||
assertEquals(12 * initialValue, result); | ||
} | ||
|
||
@Test | ||
void throws_exception_when_non_commuting_concurrent_effects_are_applied() { | ||
spawn(() -> cell.emit(effect(n -> 3 * n))); | ||
spawn(() -> cell.emit(effect(n -> n + 1))); | ||
delay(ZERO); | ||
assertInstanceOf(ErrorCatching.Failure.class, cell.getDynamics()); | ||
} | ||
} | ||
} |
153 changes: 153 additions & 0 deletions
153
contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/core/ExpiryTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
package gov.nasa.jpl.aerie.contrib.streamline.core; | ||
|
||
import org.junit.jupiter.api.Nested; | ||
import org.junit.jupiter.api.Test; | ||
|
||
import java.util.Optional; | ||
|
||
import static gov.nasa.jpl.aerie.contrib.streamline.core.Expiry.NEVER; | ||
import static gov.nasa.jpl.aerie.contrib.streamline.core.Expiry.at; | ||
import static gov.nasa.jpl.aerie.contrib.streamline.core.Expiry.expiry; | ||
import static gov.nasa.jpl.aerie.merlin.protocol.types.Duration.HOUR; | ||
import static gov.nasa.jpl.aerie.merlin.protocol.types.Duration.MINUTE; | ||
import static org.junit.jupiter.api.Assertions.*; | ||
|
||
class ExpiryTest { | ||
@Nested | ||
class Value { | ||
@Test | ||
void never_expiring_has_empty_value() { | ||
assertEquals(Optional.empty(), NEVER.value()); | ||
} | ||
|
||
@Test | ||
void expiring_at_t_has_value_of_t() { | ||
assertEquals(Optional.of(MINUTE), Expiry.at(MINUTE).value()); | ||
} | ||
} | ||
|
||
@Nested | ||
class Equals { | ||
@Test | ||
void never_equals_never() { | ||
assertEquals(NEVER, NEVER); | ||
assertEquals(NEVER, expiry(Optional.empty())); | ||
assertEquals(expiry(Optional.empty()), NEVER); | ||
assertEquals(expiry(Optional.empty()), expiry(Optional.empty())); | ||
} | ||
|
||
@Test | ||
void at_t_equals_at_t() { | ||
assertEquals(at(MINUTE), at(MINUTE)); | ||
} | ||
|
||
@Test | ||
void at_t_does_not_equal_never() { | ||
assertNotEquals(at(MINUTE), NEVER); | ||
assertNotEquals(NEVER, at(MINUTE)); | ||
} | ||
|
||
@Test | ||
void at_t_does_not_equal_at_s() { | ||
assertNotEquals(at(MINUTE), at(HOUR)); | ||
assertNotEquals(at(HOUR), at(MINUTE)); | ||
} | ||
} | ||
|
||
@Nested | ||
class IsNever { | ||
@Test | ||
void never_is_never() { | ||
assertTrue(NEVER.isNever()); | ||
} | ||
|
||
@Test | ||
void at_t_is_not_never() { | ||
assertFalse(at(MINUTE).isNever()); | ||
} | ||
} | ||
|
||
@Nested | ||
class Or { | ||
@Test | ||
void never_or_never_returns_never() { | ||
assertEquals(NEVER, NEVER.or(NEVER)); | ||
} | ||
|
||
@Test | ||
void never_or_at_t_returns_at_t() { | ||
assertEquals(at(MINUTE), NEVER.or(at(MINUTE))); | ||
} | ||
|
||
@Test | ||
void at_t_or_never_returns_at_t() { | ||
assertEquals(at(MINUTE), at(MINUTE).or(NEVER)); | ||
} | ||
|
||
@Test | ||
void at_t_or_at_greater_than_t_returns_at_t() { | ||
assertEquals(at(MINUTE), at(MINUTE).or(at(HOUR))); | ||
} | ||
|
||
@Test | ||
void at_greater_than_t_or_at_t_returns_at_t() { | ||
assertEquals(at(MINUTE), at(HOUR).or(at(MINUTE))); | ||
} | ||
} | ||
|
||
@Nested | ||
class Minus { | ||
@Test | ||
void never_minus_t_returns_never() { | ||
assertEquals(NEVER, NEVER.minus(MINUTE)); | ||
} | ||
|
||
@Test | ||
void at_t_minus_s_returns_at_difference() { | ||
assertEquals(at(HOUR.minus(MINUTE)), at(HOUR).minus(MINUTE)); | ||
} | ||
} | ||
|
||
@Nested | ||
class Comparisons { | ||
@Test | ||
void never_equals_never() { | ||
assertFalse(NEVER.shorterThan(NEVER)); | ||
assertTrue(NEVER.noShorterThan(NEVER)); | ||
assertFalse(NEVER.longerThan(NEVER)); | ||
assertTrue(NEVER.noLongerThan(NEVER)); | ||
} | ||
|
||
@Test | ||
void at_t_equals_at_t() { | ||
assertFalse(at(MINUTE).shorterThan(at(MINUTE))); | ||
assertTrue(at(MINUTE).noShorterThan(at(MINUTE))); | ||
assertFalse(at(MINUTE).longerThan(at(MINUTE))); | ||
assertTrue(at(MINUTE).noLongerThan(at(MINUTE))); | ||
} | ||
|
||
@Test | ||
void at_t_shorter_than_never() { | ||
assertTrue(at(MINUTE).shorterThan(NEVER)); | ||
assertFalse(at(MINUTE).noShorterThan(NEVER)); | ||
assertFalse(at(MINUTE).longerThan(NEVER)); | ||
assertTrue(at(MINUTE).noLongerThan(NEVER)); | ||
} | ||
|
||
@Test | ||
void never_longer_than_at_t() { | ||
assertFalse(NEVER.shorterThan(at(MINUTE))); | ||
assertTrue(NEVER.noShorterThan(at(MINUTE))); | ||
assertTrue(NEVER.longerThan(at(MINUTE))); | ||
assertFalse(NEVER.noLongerThan(at(MINUTE))); | ||
} | ||
|
||
@Test | ||
void at_t_shorter_than_at_greater_than_t() { | ||
assertTrue(at(MINUTE).shorterThan(at(HOUR))); | ||
assertFalse(at(MINUTE).noShorterThan(at(HOUR))); | ||
assertFalse(at(MINUTE).longerThan(at(HOUR))); | ||
assertTrue(at(MINUTE).noLongerThan(at(HOUR))); | ||
} | ||
} | ||
} |
67 changes: 67 additions & 0 deletions
67
contrib/src/test/java/gov/nasa/jpl/aerie/contrib/streamline/debugging/DependenciesTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
package gov.nasa.jpl.aerie.contrib.streamline.debugging; | ||
|
||
import gov.nasa.jpl.aerie.contrib.streamline.core.MutableResource; | ||
import gov.nasa.jpl.aerie.contrib.streamline.core.Resource; | ||
import gov.nasa.jpl.aerie.contrib.streamline.modeling.discrete.Discrete; | ||
import gov.nasa.jpl.aerie.contrib.streamline.modeling.discrete.DiscreteResources; | ||
import gov.nasa.jpl.aerie.contrib.streamline.modeling.polynomial.Polynomial; | ||
import gov.nasa.jpl.aerie.merlin.framework.junit.MerlinExtension; | ||
import org.junit.jupiter.api.Nested; | ||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.api.TestInstance; | ||
import org.junit.jupiter.api.extension.ExtendWith; | ||
|
||
import static gov.nasa.jpl.aerie.contrib.streamline.core.MutableResource.resource; | ||
import static gov.nasa.jpl.aerie.contrib.streamline.core.monads.ResourceMonad.*; | ||
import static gov.nasa.jpl.aerie.contrib.streamline.modeling.polynomial.Polynomial.polynomial; | ||
import static gov.nasa.jpl.aerie.contrib.streamline.modeling.polynomial.PolynomialResources.constant; | ||
import static org.junit.jupiter.api.Assertions.*; | ||
|
||
@Nested | ||
@ExtendWith(MerlinExtension.class) | ||
@TestInstance(TestInstance.Lifecycle.PER_CLASS) | ||
class DependenciesTest { | ||
Resource<Discrete<Boolean>> constantTrue = DiscreteResources.constant(true); | ||
Resource<Polynomial> constant1234 = constant(1234); | ||
Resource<Polynomial> constant5678 = constant(5678); | ||
Resource<Polynomial> polynomialCell = resource(polynomial(1)); | ||
Resource<Polynomial> derived = map(constantTrue, constant1234, constant5678, | ||
(b, x, y) -> b.extract() ? x : y); | ||
|
||
@Test | ||
void constants_are_named_by_their_value() { | ||
assertTrue(Naming.getName(constantTrue).get().contains("true")); | ||
assertTrue(Naming.getName(constant1234).get().contains("1234")); | ||
assertTrue(Naming.getName(constant5678).get().contains("5678")); | ||
} | ||
|
||
@Test | ||
void cell_resources_are_not_inherently_named() { | ||
assertTrue(Naming.getName(polynomialCell).isEmpty()); | ||
} | ||
|
||
@Test | ||
void derived_resources_are_not_inherently_named() { | ||
assertTrue(Naming.getName(derived).isEmpty()); | ||
} | ||
|
||
@Test | ||
void constants_have_no_dependencies() { | ||
assertTrue(Dependencies.getDependencies(constantTrue).isEmpty()); | ||
assertTrue(Dependencies.getDependencies(constant1234).isEmpty()); | ||
assertTrue(Dependencies.getDependencies(constant5678).isEmpty()); | ||
} | ||
|
||
@Test | ||
void cell_resources_have_no_dependencies() { | ||
assertTrue(Dependencies.getDependencies(polynomialCell).isEmpty()); | ||
} | ||
|
||
@Test | ||
void derived_resources_have_their_sources_as_dependencies() { | ||
var graphDescription = Dependencies.describeDependencyGraph(derived, true); | ||
assertTrue(graphDescription.contains("true")); | ||
assertTrue(graphDescription.contains("1234")); | ||
assertTrue(graphDescription.contains("5678")); | ||
} | ||
} |
Oops, something went wrong.