Merge remote-tracking branch 'upstream/master' into merge

This commit is contained in:
Jesse Boyd
2019-11-19 21:23:47 +00:00
272 changed files with 16041 additions and 6107 deletions

View File

@ -25,6 +25,8 @@ import com.sk89q.worldedit.world.block.BlockType;
import java.util.HashSet;
import java.util.Set;
import org.junit.jupiter.api.BeforeEach;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;

View File

@ -0,0 +1,100 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.internal.expression;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.extension.platform.Platform;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
* Common setup code for expression tests.
*/
class BaseExpressionTest {
static double readSlot(Expression expr, String name) {
return expr.getSlots().getSlotValue(name).orElseThrow(IllegalStateException::new);
}
private Platform mockPlat = mock(Platform.class);
@BeforeEach
void setup() {
when(mockPlat.getConfiguration()).thenReturn(new LocalConfiguration() {
@Override
public void load() {
}
});
WorldEdit.getInstance().getPlatformManager().register(mockPlat);
}
double simpleEval(String expressionString) throws ExpressionException {
final Expression expression = compile(expressionString);
expression.setEnvironment(new ExpressionEnvironment() {
@Override
public int getBlockType(double x, double y, double z) {
return (int) x;
}
@Override
public int getBlockData(double x, double y, double z) {
return (int) y;
}
@Override
public int getBlockTypeAbs(double x, double y, double z) {
return (int) x*10;
}
@Override
public int getBlockDataAbs(double x, double y, double z) {
return (int) y*10;
}
@Override
public int getBlockTypeRel(double x, double y, double z) {
return (int) x*100;
}
@Override
public int getBlockDataRel(double x, double y, double z) {
return (int) y*100;
}
});
return expression.evaluate();
}
@AfterEach
void tearDown() {
WorldEdit.getInstance().getPlatformManager().unregister(mockPlat);
}
Expression compile(String expressionString, String... variableNames) throws ExpressionException {
final Expression expression = Expression.compile(expressionString, variableNames);
expression.optimize();
return expression;
}
}

View File

@ -19,17 +19,13 @@
package com.sk89q.worldedit.internal.expression;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.extension.platform.Platform;
import com.sk89q.worldedit.internal.expression.lexer.LexerException;
import com.sk89q.worldedit.internal.expression.parser.ParserException;
import com.sk89q.worldedit.internal.expression.runtime.EvaluationException;
import com.sk89q.worldedit.internal.expression.runtime.ExpressionEnvironment;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively;
import java.time.Duration;
import com.sk89q.worldedit.internal.expression.runtime.ExpressionTimeoutException;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static java.lang.Math.atan2;
import static java.lang.Math.sin;
@ -40,20 +36,10 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class ExpressionTest {
class ExpressionTest extends BaseExpressionTest {
private Platform mockPlat = mock(Platform.class);
@BeforeEach
public void setup() {
when(mockPlat.getConfiguration()).thenReturn(new LocalConfiguration() {
@Override
public void load() {
}
});
WorldEdit.getInstance().getPlatformManager().register(mockPlat);
}
@AfterEach
public void tearDown() {
WorldEdit.getInstance().getPlatformManager().unregister(mockPlat);
@ -77,73 +63,78 @@ public class ExpressionTest {
assertEquals(8, compile("foo+bar", "foo", "bar").evaluate(5D, 3D), 0);
}
@Test
void testTightTokenization() {
assertEquals(4, simpleEval("3+1"), 0);
}
@Test
public void testErrors() {
assertAll(
// test lexer errors
() -> {
LexerException e = assertThrows(LexerException.class,
() -> compile("#"));
assertEquals(0, e.getPosition(), "Error position");
},
// test parser errors
() -> {
ParserException e = assertThrows(ParserException.class,
() -> compile("x"));
assertEquals(0, e.getPosition(), "Error position");
},
() -> {
ParserException e = assertThrows(ParserException.class,
() -> compile("x()"));
assertEquals(0, e.getPosition(), "Error position");
},
() -> assertThrows(ParserException.class,
() -> compile("(")),
() -> assertThrows(ParserException.class,
() -> compile("x(")),
// test overloader errors
() -> {
ParserException e = assertThrows(ParserException.class,
() -> compile("atan2(1)"));
assertEquals(0, e.getPosition(), "Error position");
},
() -> {
ParserException e = assertThrows(ParserException.class,
() -> compile("atan2(1, 2, 3)"));
assertEquals(0, e.getPosition(), "Error position");
},
() -> {
ParserException e = assertThrows(ParserException.class,
() -> compile("rotate(1, 2, 3)"));
assertEquals(0, e.getPosition(), "Error position");
}
);
// test lexer errors
{
ExpressionException e = assertThrows(ExpressionException.class,
() -> compile("#"));
assertEquals(0, e.getPosition(), "Error position");
}
// test parser errors
{
ExpressionException e = assertThrows(ExpressionException.class,
() -> compile("x"));
assertEquals(0, e.getPosition(), "Error position");
}
{
ExpressionException e = assertThrows(ExpressionException.class,
() -> compile("x()"));
assertEquals(0, e.getPosition(), "Error position");
}
assertThrows(ExpressionException.class,
() -> compile("("));
assertThrows(ExpressionException.class,
() -> compile("x("));
// test overloader errors
{
ExpressionException e = assertThrows(ExpressionException.class,
() -> compile("atan2(1)"));
assertEquals(0, e.getPosition(), "Error position");
}
{
ExpressionException e = assertThrows(ExpressionException.class,
() -> compile("atan2(1, 2, 3)"));
assertEquals(0, e.getPosition(), "Error position");
}
{
ExpressionException e = assertThrows(ExpressionException.class,
() -> compile("rotate(1, 2, 3)"));
e.printStackTrace();
assertEquals(7, e.getPosition(), "Error position");
}
}
@Test
public void testAssign() throws ExpressionException {
Expression foo = compile("{a=x} b=y; c=z", "x", "y", "z", "a", "b", "c");
foo.evaluate(2D, 3D, 5D);
assertEquals(2, foo.getVariable("a", false).getValue(), 0);
assertEquals(3, foo.getVariable("b", false).getValue(), 0);
assertEquals(5, foo.getVariable("c", false).getValue(), 0);
assertEquals(2, foo.getSlots().getSlotValue("a").orElse(-1), 0);
assertEquals(3, foo.getSlots().getSlotValue("b").orElse(-1), 0);
assertEquals(5, foo.getSlots().getSlotValue("c").orElse(-1), 0);
}
@Test
public void testIf() throws ExpressionException {
assertEquals(40, simpleEval("if (1) x=4; else y=5; x*10+y;"), 0);
assertEquals(5, simpleEval("if (0) x=4; else y=5; x*10+y;"), 0);
assertEquals(40, simpleEval("y=0; if (1) x=4; else y=5; x*10+y;"), 0);
assertEquals(5, simpleEval("x=0; if (0) x=4; else y=5; x*10+y;"), 0);
// test 'dangling else'
final Expression expression1 = compile("if (1) if (0) x=4; else y=5;", "x", "y");
expression1.evaluate(1D, 2D);
assertEquals(1, expression1.getVariable("x", false).getValue(), 0);
assertEquals(5, expression1.getVariable("y", false).getValue(), 0);
assertEquals(1, expression1.getSlots().getSlotValue("x").orElse(-1), 0);
assertEquals(5, expression1.getSlots().getSlotValue("y").orElse(-1), 0);
// test if the if construct is correctly recognized as a statement
final Expression expression2 = compile("if (0) if (1) x=5; y=4;", "x", "y");
expression2.evaluate(1D, 2D);
assertEquals(4, expression2.getVariable("y", false).getValue(), 0);
assertEquals(4, expression2.getSlots().getSlotValue("y").orElse(-1), 0);
}
@Test
@ -182,53 +173,12 @@ public class ExpressionTest {
@Test
public void testTimeout() {
ExpressionTimeoutException e = assertThrows(ExpressionTimeoutException.class,
() -> simpleEval("for(i=0;i<256;i++){for(j=0;j<256;j++){for(k=0;k<256;k++){for(l=0;l<256;l++){ln(pi)}}}}"),
"Loop was not stopped.");
ExpressionTimeoutException e = assertTimeoutPreemptively(Duration.ofSeconds(10), () ->
assertThrows(ExpressionTimeoutException.class,
() -> simpleEval("for(i=0;i<256;i++){for(j=0;j<256;j++){for(k=0;k<256;k++){for(l=0;l<256;l++){ln(pi)}}}}"),
"Loop was not stopped.")
);
assertTrue(e.getMessage().contains("Calculations exceeded time limit"));
}
private double simpleEval(String expressionString) throws ExpressionException {
final Expression expression = compile(expressionString);
expression.setEnvironment(new ExpressionEnvironment() {
@Override
public int getBlockType(double x, double y, double z) {
return (int) x;
}
@Override
public int getBlockData(double x, double y, double z) {
return (int) y;
}
@Override
public int getBlockTypeAbs(double x, double y, double z) {
return (int) x*10;
}
@Override
public int getBlockDataAbs(double x, double y, double z) {
return (int) y*10;
}
@Override
public int getBlockTypeRel(double x, double y, double z) {
return (int) x*100;
}
@Override
public int getBlockDataRel(double x, double y, double z) {
return (int) y*100;
}
});
return expression.evaluate();
}
private Expression compile(String expressionString, String... variableNames) throws ExpressionException, EvaluationException {
final Expression expression = Expression.compile(expressionString, variableNames);
expression.optimize();
return expression;
}
}

View File

@ -0,0 +1,171 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.internal.expression;
import com.sk89q.worldedit.math.Vector3;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.function.Consumer;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* Test class for various real-world expressions.
*/
class RealExpressionTest extends BaseExpressionTest {
private static final class TestCase {
final Vector3 loc;
final double result;
final Consumer<Expression> postChecks;
private TestCase(Vector3 loc, double result, Consumer<Expression> postChecks) {
this.loc = loc;
this.result = result;
this.postChecks = postChecks;
}
TestCase withData(int expectedData) {
return new TestCase(loc, result, expr -> {
postChecks.accept(expr);
double data = readSlot(expr, "data");
assertEquals(expectedData, (int) data,
"Test case " + this + " failed (data)");
});
}
@Override
public String toString() {
return loc + " -> " + result;
}
}
private static TestCase testCase(Vector3 loc, double result) {
return testCase(loc, result, e -> {
});
}
private static TestCase testCase(Vector3 loc, double result, Consumer<Expression> postChecks) {
return new TestCase(loc, result, postChecks);
}
private void checkExpression(String expr, TestCase... cases) {
Expression compiled = compile(expr, "x", "y", "z");
for (TestCase aCase : cases) {
Vector3 loc = aCase.loc;
assertEquals(aCase.result, compiled.evaluate(loc.getX(), loc.getY(), loc.getZ()), 0,
"Test case " + aCase + " failed (result)");
aCase.postChecks.accept(compiled);
}
}
@Test
void torus() {
checkExpression("(0.75-sqrt(x^2+y^2))^2+z^2 < 0.25^2",
testCase(Vector3.at(0, 0, 0), 0),
testCase(Vector3.at(0.5, 0.5, 0.5), 0),
testCase(Vector3.at(1, 0, 0), 0),
testCase(Vector3.at(0.5, 0.5, 0), 1),
testCase(Vector3.at(0.75, 0.5, 0), 1),
testCase(Vector3.at(0.75, 0, 0), 1));
}
@Test
void gnarledOakTree() {
checkExpression("(0.5+sin(atan2(x,z)*8)*0.2)*(sqrt(x*x+z*z)/0.5)^(-2)-1.2 < y",
testCase(Vector3.at(-1, -1, -1), 1),
testCase(Vector3.at(-1, 0, 1), 1),
testCase(Vector3.at(1, 1, 1), 1),
testCase(Vector3.at(0, 0, -1), 1),
testCase(Vector3.at(0, 0, 0), 0),
testCase(Vector3.at(0, 1, 0), 0),
testCase(Vector3.at(0, 0, 0.32274), 0),
testCase(Vector3.at(0, 0, 0.32275), 1));
}
@Test
void rainbowTorus() {
checkExpression("data=(32+15/2/pi*atan2(x,y))%16; (0.75-sqrt(x^2+y^2))^2+z^2 < 0.25^2",
testCase(Vector3.at(0, 0, 0), 0),
testCase(Vector3.at(0.5, 0.5, 0.5), 0),
testCase(Vector3.at(1, 0, 0), 0),
testCase(Vector3.at(0.5, 0.5, 0), 1).withData(1),
testCase(Vector3.at(0.75, 0.5, 0), 1).withData(2),
testCase(Vector3.at(0.75, 0, 0), 1).withData(3));
}
@Test
void rainbowEgg() {
TestCase[] testCases = new TestCase[15];
for (int i = 0; i < testCases.length; i++) {
testCases[i] = testCase(Vector3.at(0, i / 16.0 - 0.5, 0), 1)
.withData((i + 9) % 16);
}
testCases = Stream.concat(Stream.of(testCases), Stream.of(
testCase(Vector3.at(0, 1, 0), 0)
)).toArray(TestCase[]::new);
checkExpression("data=(32+y*16+1)%16; y^2/9+x^2/6*(1/(1-0.4*y))+z^2/6*(1/(1-0.4*y))<0.08",
testCases);
}
@Test
void heart() {
checkExpression("(z/2)^2+x^2+(5*y/4-sqrt(abs(x)))^2<0.6",
testCase(Vector3.at(0, 0, -1), 1),
testCase(Vector3.at(0, 1, -1), 0),
testCase(Vector3.at(-0.5, 1, 0), 1));
}
@Test
void sineWave() {
checkExpression("sin(x*5)/2<y",
testCase(Vector3.at(1, -0.47947, 0), 0),
testCase(Vector3.at(1, -0.47946, 0), 1),
testCase(Vector3.at(2, -0.27202, 0), 0),
testCase(Vector3.at(2, -0.27201, 0), 1),
testCase(Vector3.at(3, 0.32513, 0), 0),
testCase(Vector3.at(3, 0.32515, 0), 1));
}
@Test
void radialCosine() {
checkExpression("cos(sqrt(x^2+z^2)*5)/2<y",
testCase(Vector3.at(0, 0.5, 0), 0),
testCase(Vector3.at(0, 0.51, 0), 1),
testCase(Vector3.at(Math.PI / 5, -0.5, 0), 0),
testCase(Vector3.at(Math.PI / 5, -0.49, 0), 1),
testCase(Vector3.at(Math.PI / 10, 0, 0), 0),
testCase(Vector3.at(Math.PI / 10, 0.1, 0), 1));
}
@Test
void circularHyperboloid() {
checkExpression("-(z^2/12)+(y^2/4)-(x^2/12)>-0.03",
testCase(Vector3.at(0, 0, 0), 1),
testCase(Vector3.at(0, 1, 0), 1),
testCase(Vector3.at(0, 1, 1), 1),
testCase(Vector3.at(1, 1, 1), 1),
testCase(Vector3.at(0, 0, 1), 0),
testCase(Vector3.at(1, 0, 1), 0));
}
}

View File

@ -20,11 +20,11 @@
package com.sk89q.worldedit.util;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mock;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.world.World;
import org.junit.jupiter.api.Test;
import static org.mockito.Mockito.mock;
/**
* Tests {@link Location}.

View File

@ -0,0 +1,588 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.util.collection;
import com.google.common.collect.ImmutableMap;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.extension.platform.Platform;
import com.sk89q.worldedit.extension.platform.PlatformManager;
import com.sk89q.worldedit.extension.platform.Preference;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.registry.Registry;
import com.sk89q.worldedit.util.VariedVectorsProvider;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.block.BlockTypes;
import com.sk89q.worldedit.world.registry.BundledRegistries;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledIfSystemProperty;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.lang.reflect.Field;
import java.util.AbstractMap;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assumptions.assumeFalse;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
@DisplayName("An ordered block map")
class BlockMapTest {
private static Platform mockedPlatform = mock(Platform.class);
@BeforeAll
static void setupFakePlatform() {
when(mockedPlatform.getRegistries()).thenReturn(new BundledRegistries() {
});
when(mockedPlatform.getCapabilities()).thenReturn(ImmutableMap.of(
Capability.WORLD_EDITING, Preference.PREFERRED,
Capability.GAME_HOOKS, Preference.PREFERRED
));
PlatformManager platformManager = WorldEdit.getInstance().getPlatformManager();
platformManager.register(mockedPlatform);
registerBlock("minecraft:air");
registerBlock("minecraft:oak_wood");
}
@AfterAll
static void tearDownFakePlatform() throws Exception {
WorldEdit.getInstance().getPlatformManager().unregister(mockedPlatform);
Field map = Registry.class.getDeclaredField("map");
map.setAccessible(true);
((Map<?, ?>) map.get(BlockType.REGISTRY)).clear();
}
private static void registerBlock(String id) {
BlockType.REGISTRY.register(id, new BlockType(id));
}
@Mock
private Function<? super BlockVector3, ? extends BaseBlock> function;
@Mock
private BiFunction<? super BlockVector3, ? super BaseBlock, ? extends BaseBlock> biFunction;
@Mock
private BiFunction<? super BaseBlock, ? super BaseBlock, ? extends BaseBlock> mergeFunction;
@Mock
private BiConsumer<? super BlockVector3, ? super BaseBlock> biConsumer;
private final BaseBlock air = checkNotNull(BlockTypes.AIR).getDefaultState().toBaseBlock();
private final BaseBlock oakWood = checkNotNull(BlockTypes.OAK_WOOD).getDefaultState().toBaseBlock();
private BlockMap map = BlockMap.create();
@BeforeEach
void setUp() {
MockitoAnnotations.initMocks(this);
}
@AfterEach
void tearDown() {
map.clear();
}
@Test
@DisplayName("throws ClassCastException if invalid argument to get")
void throwsFromGetOnInvalidArgument() {
assertThrows(ClassCastException.class, () -> map.get(""));
}
@Nested
@DisplayName("when created")
class WhenCreated {
@Test
@DisplayName("is empty")
void isEmpty() {
assertEquals(0, map.size());
}
@Test
@DisplayName("is equal to another empty map")
void isEqualToEmptyMap() {
assertEquals(ImmutableMap.of(), map);
}
@Test
@DisplayName("has the same hashCode as another empty map")
void isHashCodeEqualToEmptyMap() {
assertEquals(ImmutableMap.of().hashCode(), map.hashCode());
}
@Test
@DisplayName("returns `null` from get")
void returnsNullFromGet() {
assertNull(map.get(BlockVector3.ZERO));
}
@Test
@DisplayName("contains no keys")
void containsNoKeys() {
assertEquals(0, map.keySet().size());
assertFalse(map.containsKey(BlockVector3.ZERO));
}
@Test
@DisplayName("contains no values")
void containsNoValues() {
assertEquals(0, map.values().size());
assertFalse(map.containsValue(air));
}
@Test
@DisplayName("contains no entries")
void containsNoEntries() {
assertEquals(0, map.entrySet().size());
}
@Test
@DisplayName("returns the default value from getOrDefault")
void returnsDefaultFromGetOrDefault() {
assertEquals(air, map.getOrDefault(BlockVector3.ZERO, air));
}
@Test
@DisplayName("never calls the forEach action")
void neverCallsForEachAction() {
map.forEach(biConsumer);
verifyZeroInteractions(biConsumer);
}
@Test
@DisplayName("never calls the replaceAll function")
void neverCallsReplaceAllFunction() {
map.replaceAll(biFunction);
verifyZeroInteractions(biFunction);
}
@Test
@DisplayName("inserts on putIfAbsent")
void insertOnPutIfAbsent() {
assertNull(map.putIfAbsent(BlockVector3.ZERO, air));
assertEquals(1, map.size());
assertEquals(air, map.get(BlockVector3.ZERO));
}
@Test
@DisplayName("remove(key) returns null")
void removeKeyReturnsNull() {
assertNull(map.remove(BlockVector3.ZERO));
}
@Test
@DisplayName("remove(key, value) returns false")
void removeKeyValueReturnsFalse() {
assertFalse(map.remove(BlockVector3.ZERO, air));
}
@Test
@DisplayName("does nothing on replace")
void doesNothingOnReplace() {
assertNull(map.replace(BlockVector3.ZERO, air));
assertEquals(0, map.size());
assertFalse(map.replace(BlockVector3.ZERO, null, air));
assertEquals(0, map.size());
}
@Test
@DisplayName("inserts on computeIfAbsent")
void insertOnComputeIfAbsent() {
assertEquals(air, map.computeIfAbsent(BlockVector3.ZERO, k -> air));
assertEquals(1, map.size());
assertEquals(air, map.get(BlockVector3.ZERO));
}
@Test
@DisplayName("inserts on compute")
void insertOnCompute() {
assertEquals(air, map.compute(BlockVector3.ZERO, (k, v) -> air));
assertEquals(1, map.size());
assertEquals(air, map.get(BlockVector3.ZERO));
}
@Test
@DisplayName("does nothing on computeIfPresent")
void doesNothingOnComputeIfPresent() {
assertNull(map.computeIfPresent(BlockVector3.ZERO, (k, v) -> air));
assertEquals(0, map.size());
}
@Test
@DisplayName("inserts on merge, without calling merge function")
void insertsOnMerge() {
assertEquals(air, map.merge(BlockVector3.ZERO, air, mergeFunction));
assertEquals(1, map.size());
assertEquals(air, map.get(BlockVector3.ZERO));
verifyZeroInteractions(mergeFunction);
}
}
@Nested
@DisplayName("after having an entry added")
@EnabledIfSystemProperty(named = "blockmap.fulltesting", matches = "true")
class AfterEntryAdded {
// Note: This section of tests would really benefit from
// being able to parameterize classes. It's not part of JUnit
// yet though: https://github.com/junit-team/junit5/issues/878
@VariedVectorsProvider.Test
@DisplayName("has a size of one")
void hasSizeOne(BlockVector3 vec) {
map.put(vec, air);
assertEquals(1, map.size());
}
@VariedVectorsProvider.Test
@DisplayName("is equal to another map with the same entry")
void isEqualToSimilarMap(BlockVector3 vec) {
map.put(vec, air);
assertEquals(ImmutableMap.of(vec, air), map);
}
@VariedVectorsProvider.Test(provideNonMatching = true)
@DisplayName("is not equal to another map with a different key")
void isNotEqualToDifferentKeyMap(BlockVector3 vec, BlockVector3 nonMatch) {
map.put(vec, air);
assertNotEquals(ImmutableMap.of(nonMatch, air), map);
}
@VariedVectorsProvider.Test
@DisplayName("is not equal to another map with a different value")
void isNotEqualToDifferentValueMap(BlockVector3 vec) {
map.put(vec, air);
assertNotEquals(ImmutableMap.of(vec, oakWood), map);
}
@VariedVectorsProvider.Test
@DisplayName("is not equal to an empty map")
void isNotEqualToEmptyMap(BlockVector3 vec) {
map.put(vec, air);
assertNotEquals(ImmutableMap.of(), map);
}
@VariedVectorsProvider.Test
@DisplayName("has the same hashCode as another map with the same entry")
void isHashCodeEqualToSimilarMap(BlockVector3 vec) {
map.put(vec, air);
assertEquals(ImmutableMap.of(vec, air).hashCode(), map.hashCode());
}
@VariedVectorsProvider.Test(provideNonMatching = true)
@DisplayName("has a different hashCode from another map with a different key")
void isHashCodeNotEqualToDifferentKeyMap(BlockVector3 vec, BlockVector3 nonMatch) {
assumeFalse(vec.hashCode() == nonMatch.hashCode(),
"Vectors have equivalent hashCodes, maps will too.");
map.put(vec, air);
assertNotEquals(ImmutableMap.of(nonMatch, air).hashCode(), map.hashCode());
}
@VariedVectorsProvider.Test
@DisplayName("has a different hashCode from another map with a different value")
void isHashCodeNotEqualToDifferentValueMap(BlockVector3 vec) {
map.put(vec, air);
assertNotEquals(ImmutableMap.of(vec, oakWood).hashCode(), map.hashCode());
}
@VariedVectorsProvider.Test
@DisplayName("has a different hashCode from an empty map")
void isHashCodeNotEqualToEmptyMap(BlockVector3 vec) {
map.put(vec, air);
assertNotEquals(ImmutableMap.of().hashCode(), map.hashCode());
}
@VariedVectorsProvider.Test
@DisplayName("returns value from get")
void returnsValueFromGet(BlockVector3 vec) {
map.put(vec, air);
assertEquals(air, map.get(vec));
}
@VariedVectorsProvider.Test(provideNonMatching = true)
@DisplayName("returns `null` from get with different key")
void returnsValueFromGet(BlockVector3 vec, BlockVector3 nonMatch) {
map.put(vec, air);
assertNotEquals(air, map.get(nonMatch));
}
@VariedVectorsProvider.Test
@DisplayName("contains the key")
void containsTheKey(BlockVector3 vec) {
map.put(vec, air);
assertEquals(1, map.keySet().size());
assertTrue(map.keySet().contains(vec));
assertTrue(map.containsKey(vec));
}
@VariedVectorsProvider.Test
@DisplayName("contains the value")
void containsTheValue(BlockVector3 vec) {
map.put(vec, air);
assertEquals(1, map.values().size());
assertTrue(map.values().contains(air));
assertTrue(map.containsValue(air));
}
@VariedVectorsProvider.Test
@DisplayName("contains the entry")
void containsTheEntry(BlockVector3 vec) {
map.put(vec, air);
assertEquals(1, map.entrySet().size());
assertEquals(new AbstractMap.SimpleImmutableEntry<>(vec, air), map.entrySet().iterator().next());
}
@VariedVectorsProvider.Test
@DisplayName("returns the provided value from getOrDefault")
void returnsProvidedFromGetOrDefault(BlockVector3 vec) {
map.put(vec, air);
assertEquals(air, map.getOrDefault(vec, oakWood));
}
@VariedVectorsProvider.Test(provideNonMatching = true)
@DisplayName("returns the default value from getOrDefault with a different key")
void returnsDefaultFromGetOrDefaultWrongKey(BlockVector3 vec, BlockVector3 nonMatch) {
map.put(vec, air);
assertEquals(oakWood, map.getOrDefault(nonMatch, oakWood));
}
@VariedVectorsProvider.Test
@DisplayName("calls the forEach action once")
void neverCallsForEachAction(BlockVector3 vec) {
map.put(vec, air);
map.forEach(biConsumer);
verify(biConsumer).accept(vec, air);
verifyNoMoreInteractions(biConsumer);
}
@VariedVectorsProvider.Test
@DisplayName("replaces value using replaceAll")
void neverCallsReplaceAllFunction(BlockVector3 vec) {
map.put(vec, air);
map.replaceAll((v, b) -> oakWood);
assertEquals(oakWood, map.get(vec));
}
@VariedVectorsProvider.Test
@DisplayName("does not insert on `putIfAbsent`")
void noInsertOnPutIfAbsent(BlockVector3 vec) {
map.put(vec, air);
assertEquals(air, map.putIfAbsent(vec, oakWood));
assertEquals(1, map.size());
assertEquals(air, map.get(vec));
}
@VariedVectorsProvider.Test(provideNonMatching = true)
@DisplayName("inserts on `putIfAbsent` to a different key")
void insertOnPutIfAbsentDifferentKey(BlockVector3 vec, BlockVector3 nonMatch) {
map.put(vec, air);
assertNull(map.putIfAbsent(nonMatch, oakWood));
assertEquals(2, map.size());
assertEquals(air, map.get(vec));
assertEquals(oakWood, map.get(nonMatch));
}
@VariedVectorsProvider.Test
@DisplayName("remove(key) returns the old value")
void removeKeyReturnsOldValue(BlockVector3 vec) {
map.put(vec, air);
assertEquals(air, map.remove(vec));
assertEquals(0, map.size());
}
@VariedVectorsProvider.Test(provideNonMatching = true)
@DisplayName("remove(nonMatch) returns null")
void removeNonMatchingKeyReturnsNull(BlockVector3 vec, BlockVector3 nonMatch) {
map.put(vec, air);
assertNull(map.remove(nonMatch));
assertEquals(1, map.size());
}
@VariedVectorsProvider.Test
@DisplayName("remove(key, value) returns true")
void removeKeyValueReturnsTrue(BlockVector3 vec) {
map.put(vec, air);
assertTrue(map.remove(vec, air));
assertEquals(0, map.size());
}
@VariedVectorsProvider.Test
@DisplayName("remove(key, value) returns false for wrong value")
void removeKeyValueReturnsFalseWrongValue(BlockVector3 vec) {
map.put(vec, air);
assertFalse(map.remove(vec, oakWood));
assertEquals(1, map.size());
}
@VariedVectorsProvider.Test
@DisplayName("replaces value at key")
void replacesValueAtKey(BlockVector3 vec) {
map.put(vec, air);
assertEquals(air, map.replace(vec, oakWood));
assertEquals(1, map.size());
assertEquals(oakWood, map.get(vec));
assertTrue(map.replace(vec, oakWood, air));
assertEquals(1, map.size());
assertEquals(air, map.get(vec));
}
@VariedVectorsProvider.Test(provideNonMatching = true)
@DisplayName("does not replace value at different key")
void doesNotReplaceAtDifferentKey(BlockVector3 vec, BlockVector3 nonMatch) {
map.put(vec, air);
assertNull(map.replace(nonMatch, oakWood));
assertEquals(1, map.size());
assertEquals(air, map.get(vec));
assertFalse(map.replace(nonMatch, air, oakWood));
assertEquals(1, map.size());
assertEquals(air, map.get(vec));
}
@VariedVectorsProvider.Test
@DisplayName("does not insert on computeIfAbsent")
void doesNotInsertComputeIfAbsent(BlockVector3 vec) {
map.put(vec, air);
assertEquals(air, map.computeIfAbsent(vec, k -> {
assertEquals(vec, k);
return oakWood;
}));
assertEquals(1, map.size());
assertEquals(air, map.get(vec));
}
@VariedVectorsProvider.Test(provideNonMatching = true)
@DisplayName("inserts on computeIfAbsent with different key")
void insertsOnComputeIfAbsentDifferentKey(BlockVector3 vec, BlockVector3 nonMatch) {
map.put(vec, air);
assertEquals(oakWood, map.computeIfAbsent(nonMatch, k -> {
assertEquals(nonMatch, k);
return oakWood;
}));
assertEquals(2, map.size());
assertEquals(air, map.get(vec));
assertEquals(oakWood, map.get(nonMatch));
}
@VariedVectorsProvider.Test
@DisplayName("replaces on compute")
void replaceOnCompute(BlockVector3 vec) {
map.put(vec, air);
assertEquals(oakWood, map.compute(vec, (k, v) -> {
assertEquals(vec, k);
assertEquals(air, v);
return oakWood;
}));
assertEquals(1, map.size());
assertEquals(oakWood, map.get(vec));
assertNull(map.compute(vec, (k, v) -> null));
assertEquals(0, map.size());
}
@VariedVectorsProvider.Test(provideNonMatching = true)
@DisplayName("inserts on compute with different key")
void insertOnComputeDifferentKey(BlockVector3 vec, BlockVector3 nonMatch) {
map.put(vec, air);
assertEquals(oakWood, map.compute(nonMatch, (k, v) -> {
assertEquals(nonMatch, k);
assertNull(v);
return oakWood;
}));
assertEquals(2, map.size());
assertEquals(air, map.get(vec));
assertEquals(oakWood, map.get(nonMatch));
assertNull(map.compute(nonMatch, (k, v) -> null));
assertEquals(1, map.size());
assertEquals(air, map.get(vec));
}
@VariedVectorsProvider.Test
@DisplayName("replaces on computeIfPresent")
void replacesOnComputeIfPresent(BlockVector3 vec) {
map.put(vec, air);
assertEquals(oakWood, map.computeIfPresent(vec, (k, v) -> {
assertEquals(vec, k);
assertEquals(air, v);
return oakWood;
}));
assertEquals(1, map.size());
assertEquals(oakWood, map.get(vec));
assertNull(map.computeIfPresent(vec, (k, v) -> null));
assertEquals(0, map.size());
}
@VariedVectorsProvider.Test
@DisplayName("inserts on merge, with call to merge function")
void insertsOnMerge(BlockVector3 vec) {
map.put(vec, air);
assertEquals(oakWood, map.merge(vec, oakWood, (o, n) -> {
assertEquals(air, o);
assertEquals(oakWood, n);
return n;
}));
assertEquals(1, map.size());
assertEquals(oakWood, map.get(vec));
}
}
@Test
@DisplayName("contains all inserted vectors")
void containsAllInsertedVectors() {
Set<BlockVector3> allVectors = VariedVectorsProvider.makeVectorsStream().collect(Collectors.toSet());
for (BlockVector3 vec : allVectors) {
map.put(vec, air);
}
assertEquals(allVectors.size(), map.size());
assertEquals(allVectors, map.keySet());
for (Map.Entry<BlockVector3, BaseBlock> entry : map.entrySet()) {
assertTrue(allVectors.contains(entry.getKey()));
assertEquals(air, entry.getValue());
}
}
}

View File

@ -19,13 +19,14 @@
package com.sk89q.worldedit.util.eventbus;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.List;
import org.junit.jupiter.api.Test;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class EventBusTest {

View File

@ -2,4 +2,4 @@ junit.jupiter.execution.parallel.enabled=true
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
junit.jupiter.execution.parallel.config.dynamic.factor=1