Skip to content

Commit

Permalink
Add property-based testing for SideEffectSet
Browse files Browse the repository at this point in the history
  • Loading branch information
octylFractal committed Sep 7, 2024
1 parent e54a683 commit c61b273
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 90 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ target
forge-download
out
run
.jqwik-database

/dependency-reduced-pom.xml
*-private.sh
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,17 @@ configure<CheckstyleExtension> {
}

tasks.withType<Test>().configureEach {
useJUnitPlatform()
useJUnitPlatform {
includeEngines("junit-jupiter", "jqwik")
}
}

dependencies {
"compileOnly"(stringyLibs.getLibrary("jsr305"))
"testImplementation"(platform(stringyLibs.getLibrary("junit-bom")))
"testImplementation"(stringyLibs.getLibrary("junit-jupiter-api"))
"testImplementation"(stringyLibs.getLibrary("junit-jupiter-params"))
"testImplementation"(stringyLibs.getLibrary("jqwik"))
"testImplementation"(platform(stringyLibs.getLibrary("mockito-bom")))
"testImplementation"(stringyLibs.getLibrary("mockito-core"))
"testImplementation"(stringyLibs.getLibrary("mockito-junit-jupiter"))
Expand Down
2 changes: 2 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ junit-jupiter-api.module = "org.junit.jupiter:junit-jupiter-api"
junit-jupiter-params.module = "org.junit.jupiter:junit-jupiter-params"
junit-jupiter-engine.module = "org.junit.jupiter:junit-jupiter-engine"

jqwik = "net.jqwik:jqwik:1.9.0"

mockito-bom = "org.mockito:mockito-bom:5.11.0"
mockito-core.module = "org.mockito:mockito-core"
mockito-junit-jupiter.module = "org.mockito:mockito-junit-jupiter"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,107 +19,60 @@

package com.sk89q.worldedit.util;

import com.google.common.base.Preconditions;
import com.google.common.collect.Maps;
import org.junit.jupiter.api.Test;
import net.jqwik.api.ForAll;
import net.jqwik.api.Property;

import java.util.Arrays;
import java.util.EnumSet;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class SideEffectSetTest {
private static void assertAppliesWithState(Map<SideEffect, SideEffect.State> expected, SideEffectSet set) {
Preconditions.checkArgument(
expected.keySet().containsAll(EnumSet.allOf(SideEffect.class)),
"Expected map must contain all side effects"
);

Set<SideEffect> appliedSet = expected.entrySet().stream()
.filter(e -> e.getValue() != SideEffect.State.OFF)
.map(Map.Entry::getKey)
.collect(Collectors.toSet());
assertEquals(appliedSet, set.getSideEffectsToApply());
assertEquals(!appliedSet.isEmpty(), set.doesApplyAny());
for (SideEffect effect : SideEffect.values()) {
assertEquals(
appliedSet.contains(effect), set.shouldApply(effect), "Does not apply expected effect: " + effect
);
assertEquals(
expected.get(effect), set.getState(effect),
"Does not have expected state for effect: " + effect
);
}
}

private static Map<SideEffect, SideEffect.State> initStateMap(Function<SideEffect, SideEffect.State> stateFunction) {
return Arrays.stream(SideEffect.values()).collect(Collectors.toMap(Function.identity(), stateFunction));
}

@Test
public void defaults() {
assertAppliesWithState(
initStateMap(SideEffect::getDefaultValue),
SideEffectSet.defaults()
);
@Property
public boolean stateOrDefaultIsCorrect(
@ForAll Map<SideEffect, SideEffect.State> stateMap,
@ForAll SideEffect effectToTest
) {
SideEffectSet set = new SideEffectSet(stateMap);
return set.getState(effectToTest) == stateMap.getOrDefault(effectToTest, effectToTest.getDefaultValue());
}

@Test
public void noneExposed() {
assertAppliesWithState(
initStateMap(effect -> {
if (effect.isExposed()) {
return SideEffect.State.OFF;
} else {
return effect.getDefaultValue();
}
}),
SideEffectSet.none()
);
@Property
public boolean shouldApplyUnlessOff(
@ForAll Map<SideEffect, SideEffect.State> stateMap,
@ForAll SideEffect effectToTest
) {
SideEffectSet set = new SideEffectSet(stateMap);
return set.shouldApply(effectToTest)
== (stateMap.getOrDefault(effectToTest, effectToTest.getDefaultValue()) != SideEffect.State.OFF);
}

@Test
public void allOn() {
Map<SideEffect, SideEffect.State> expected = initStateMap(effect -> SideEffect.State.ON);
assertAppliesWithState(
expected,
new SideEffectSet(expected)
);
@Property
public boolean withChangesState(
@ForAll Map<SideEffect, SideEffect.State> stateMap,
@ForAll SideEffect effectToTest,
@ForAll SideEffect.State stateToSet
) {
SideEffectSet set = new SideEffectSet(stateMap).with(effectToTest, stateToSet);
return set.getState(effectToTest) == stateToSet;
}

@Test
public void allDelayed() {
Map<SideEffect, SideEffect.State> expected = initStateMap(effect -> SideEffect.State.DELAYED);
assertAppliesWithState(
expected,
new SideEffectSet(expected)
);
}

@Test
public void allOff() {
Map<SideEffect, SideEffect.State> expected = initStateMap(effect -> SideEffect.State.OFF);
assertAppliesWithState(
expected,
new SideEffectSet(expected)
);
}

@Test
public void with() {
Map<SideEffect, SideEffect.State> expected = initStateMap(SideEffect::getDefaultValue);
SideEffectSet set = SideEffectSet.defaults();

@Property
public boolean anyShouldApplyEqualsDoesApplyAny(@ForAll Map<SideEffect, SideEffect.State> stateMap) {
SideEffectSet set = new SideEffectSet(stateMap);
boolean anyShouldApply = false;
for (SideEffect effect : SideEffect.values()) {
for (SideEffect.State state : SideEffect.State.values()) {
expected = Maps.transformEntries(expected, (e, s) -> e == effect ? state : s);
set = set.with(effect, state);
assertAppliesWithState(expected, set);
if (set.shouldApply(effect)) {
anyShouldApply = true;
break;
}
}
return anyShouldApply == set.doesApplyAny();
}

@Property
public boolean shouldApplyEqualsApplySetContains(
@ForAll Map<SideEffect, SideEffect.State> stateMap,
@ForAll SideEffect effectToTest
) {
SideEffectSet set = new SideEffectSet(stateMap);
return set.shouldApply(effectToTest) == set.getSideEffectsToApply().contains(effectToTest);
}
}
2 changes: 2 additions & 0 deletions worldedit-core/src/test/resources/junit-platform.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ junit.jupiter.execution.parallel.mode.default=concurrent
junit.jupiter.execution.parallel.mode.classes.default=same_thread
junit.jupiter.execution.parallel.config.strategy=dynamic
junit.jupiter.execution.parallel.config.dynamic.factor=4

jqwik.tries.default = 10000

0 comments on commit c61b273

Please sign in to comment.