diff --git a/Mage.Common/pom.xml b/Mage.Common/pom.xml index f6b346f88c..a84170a4a9 100644 --- a/Mage.Common/pom.xml +++ b/Mage.Common/pom.xml @@ -56,6 +56,21 @@ gson 2.8.6 + + org.junit.jupiter + junit-jupiter + test + + + org.assertj + assertj-core + test + + + org.apache.commons + commons-lang3 + test + @@ -82,7 +97,10 @@ UTF-8 - + + org.apache.maven.plugins + maven-surefire-plugin + mage-common diff --git a/Mage.Common/src/main/java/mage/utils/FluentBuilder.java b/Mage.Common/src/main/java/mage/utils/FluentBuilder.java new file mode 100644 index 0000000000..3e4ab75b91 --- /dev/null +++ b/Mage.Common/src/main/java/mage/utils/FluentBuilder.java @@ -0,0 +1,36 @@ +package mage.utils; + +import java.util.ArrayList; +import java.util.function.Consumer; +import java.util.function.Supplier; + +public abstract class FluentBuilder> { + + final ArrayList> buildSequence; + private final Supplier newReference; + + protected FluentBuilder(Supplier newReference) { + this.buildSequence = new ArrayList<>(); + this.newReference = newReference; + } + + private RealBuilder copy() { + final RealBuilder realBuilder = newReference.get(); + realBuilder.buildSequence.addAll(buildSequence); + return realBuilder; + } + + protected abstract ToBuild makeValue(); + + public RealBuilder with(Consumer consumer) { + final RealBuilder nextBuilder = this.copy(); + nextBuilder.buildSequence.add(consumer); + return nextBuilder; + } + + public ToBuild build() { + final RealBuilder instance = this.copy(); + instance.buildSequence.forEach(c -> c.accept(instance)); + return instance.makeValue(); + } +} \ No newline at end of file diff --git a/Mage.Common/src/test/java/mage/remote/ConnectionTest.java b/Mage.Common/src/test/java/mage/remote/ConnectionTest.java new file mode 100644 index 0000000000..1e49ed9c37 --- /dev/null +++ b/Mage.Common/src/test/java/mage/remote/ConnectionTest.java @@ -0,0 +1,123 @@ +package mage.remote; + +import mage.utils.FluentBuilder; +import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.RandomUtils; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import java.net.URI; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ConnectionTest { + + static class ConnectionBuilder extends FluentBuilder { + + public int port; + public String host; + public String parameter; + + private ConnectionBuilder() { + super(ConnectionBuilder::new); + } + + @Override + protected Connection makeValue() { + final Connection result = new Connection(parameter); + result.setHost(host); + result.setPort(port); + return result; + } + } + + private ConnectionBuilder baseBuilder() { + return new ConnectionBuilder(); + } + + class TestsTemplate { + final ConnectionBuilder testeeBuilder; + + TestsTemplate(ConnectionBuilder testeeBuilder) { + this.testeeBuilder = testeeBuilder; + } + + @Test + @DisplayName("produce the expected scheme") + void scheme() throws Exception { + final URI testee = make(testeeBuilder); + assertThat(testee.getScheme()).isEqualTo("bisocket"); + } + + URI make(ConnectionBuilder builder) { + try { + return new URI(builder.build().getURI()); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Test + @DisplayName("generate the expected port") + void port() { + final int expected = RandomUtils.nextInt(1000, 65000); + final int port = make(testeeBuilder.with(c -> c.port = expected)).getPort(); + + assertThat(port).isEqualTo(expected); + } + + @Test + @DisplayName("generate the expected serialisation parameter") + void serialisation() { + final String query = make(testeeBuilder).getQuery(); + + assertThat(query).contains("serializationtype=jboss"); + } + + @Test + @DisplayName("generate the expected threadpool parameter") + void threadpool() { + final String parameter = RandomStringUtils.randomAlphanumeric(12); + final String query = make(testeeBuilder.with(c -> c.parameter = parameter)).getQuery(); + + assertThat(query).contains("onewayThreadPool=mage.remote.CustomThreadPool" + parameter); + } + + } + + @Nested + @DisplayName("getUri when host is localhost should") + class LocalhostTest extends TestsTemplate { + + LocalhostTest() { + super(baseBuilder().with(c -> c.host = "localhost")); + } + + @Test + @DisplayName("generate an ipv4 as host") + void ipv4Gen() { + final String host = make(testeeBuilder).getHost(); + + assertThat(host).matches("[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+"); + } + } + + private final String randomHost = RandomStringUtils.randomAlphabetic(15); + + @Nested + @DisplayName("getUri when host is not localhost should") + class StandardHostTest extends TestsTemplate { + StandardHostTest() { + super(baseBuilder().with(c -> c.host = randomHost)); + } + + @Test + @DisplayName("generate the selected host as host") + void hostGen() { + final String host = make(testeeBuilder).getHost(); + + assertThat(host).isEqualTo(randomHost); + } + } +} diff --git a/Mage.Common/src/test/java/mage/utils/FluentBuilderTest.java b/Mage.Common/src/test/java/mage/utils/FluentBuilderTest.java new file mode 100644 index 0000000000..180f82ef20 --- /dev/null +++ b/Mage.Common/src/test/java/mage/utils/FluentBuilderTest.java @@ -0,0 +1,116 @@ +package mage.utils; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; + +public class FluentBuilderTest { + + + private ABuilder baseBuilder() { + return new ABuilder(); + } + + @Test + @DisplayName("build with default parameters") + void testDefault() { + final A actual = baseBuilder().build(); + + verifyAB(actual, null, 0); + } + + private void verifyAB(A actual, String a, int b) { + assertThat(actual.getA()).isEqualTo(a); + assertThat(actual.getB()).isEqualTo(b); + } + + @Test + @DisplayName("chain with clause and add new parameters") + void testBaseChain() { + final A actual = baseBuilder().with(a -> a.a = "hello").build(); + + verifyAB(actual, "hello", 0); + } + + @Test + @DisplayName("chain multiple with clauses and add new parameters") + void testMultiChain() { + final A actual = baseBuilder().with(a -> a.a = "world").with(a -> a.b = 6).build(); + + verifyAB(actual, "world", 6); + } + + @Test + @DisplayName("chain multiple with clauses and override latest writes") + void testMultiChainOverride() { + final A actual = baseBuilder().with(a -> a.a = "world").with(a -> a.b = 4).with(a -> a.a = "foobar").build(); + + verifyAB(actual, "foobar", 4); + } + + @Test + @DisplayName("not mutate the state of previous builder in the chain") + void testImmutability() { + final ABuilder builder1 = baseBuilder().with(a -> a.a = "world"); + final ABuilder builder2 = builder1.with(a -> { + a.a = "hello"; + a.b = 42; + }); + + verifyAB(builder1.build(), "world", 0); + verifyAB(builder2.build(), "hello", 42); + } + + @Test + @DisplayName("produce different objects") + void differentObjects() { + final ABuilder builder = baseBuilder().with(a -> { + a.a = "hello"; + a.b = 42; + }); + final A a1 = builder.build(); + final A a2 = builder.build(); + + assertThat(a1).isNotSameAs(a2); + verifyAB(a1, "hello", 42); + verifyAB(a2, "hello", 42); + } + + static class A { + public final String a; + private int b; + + public A(String a) { + this.a = a; + } + + public String getA() { + return a; + } + + public int getB() { + return b; + } + + public void setB(int b) { + this.b = b; + } + } + + static class ABuilder extends FluentBuilder { + public String a; + public int b; + + private ABuilder() { + super(ABuilder::new); + } + + @Override + protected A makeValue() { + final A result = new A(a); + result.setB(b); + return result; + } + } +} diff --git a/Mage.Server/config/config_error.xml b/Mage.Server/config/config_error.xml new file mode 100644 index 0000000000..cf0b854367 --- /dev/null +++ b/Mage.Server/config/config_error.xml @@ -0,0 +1,173 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Mage.Server/pom.xml b/Mage.Server/pom.xml index 826e3c5533..2136236c01 100644 --- a/Mage.Server/pom.xml +++ b/Mage.Server/pom.xml @@ -285,6 +285,18 @@ sqlite-jdbc 3.32.3.2 + + + + org.junit.jupiter + junit-jupiter + test + + + org.assertj + assertj-core + test + @@ -358,6 +370,10 @@ + + org.apache.maven.plugins + maven-surefire-plugin + mage-server diff --git a/Mage.Server/src/main/java/mage/server/util/ConfigFactory.java b/Mage.Server/src/main/java/mage/server/util/ConfigFactory.java new file mode 100644 index 0000000000..793419d06e --- /dev/null +++ b/Mage.Server/src/main/java/mage/server/util/ConfigFactory.java @@ -0,0 +1,20 @@ +package mage.server.util; + +import mage.server.util.config.Config; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.Unmarshaller; +import java.io.File; + +public class ConfigFactory { + + public static Config loadFromFile(final String filePath) { + try { + final JAXBContext jaxbContext = JAXBContext.newInstance("mage.server.util.config"); + final Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); + return (Config) unmarshaller.unmarshal(new File(filePath)); + } catch (Exception e) { + throw new ConfigurationException(e); + } + } +} diff --git a/Mage.Server/src/main/java/mage/server/util/ConfigSettings.java b/Mage.Server/src/main/java/mage/server/util/ConfigSettings.java index ac65aae03b..e66e8f9276 100644 --- a/Mage.Server/src/main/java/mage/server/util/ConfigSettings.java +++ b/Mage.Server/src/main/java/mage/server/util/ConfigSettings.java @@ -14,7 +14,7 @@ import org.apache.log4j.Logger; /** * @author BetaSteward_at_googlemail.com */ -public enum ConfigSettings { +public enum ConfigSettings implements ConfigSettingsContract { instance; private final Logger logger = Logger.getLogger(ConfigSettings.class); diff --git a/Mage.Server/src/main/java/mage/server/util/ConfigSettingsContract.java b/Mage.Server/src/main/java/mage/server/util/ConfigSettingsContract.java new file mode 100644 index 0000000000..a8ded69912 --- /dev/null +++ b/Mage.Server/src/main/java/mage/server/util/ConfigSettingsContract.java @@ -0,0 +1,72 @@ +package mage.server.util; + +import mage.server.util.config.GamePlugin; +import mage.server.util.config.Plugin; + +import java.util.List; + +public interface ConfigSettingsContract { + String getServerAddress(); + + String getServerName(); + + int getPort(); + + int getSecondaryBindPort(); + + int getLeasePeriod(); + + int getSocketWriteTimeout(); + + int getMaxPoolSize(); + + int getNumAcceptThreads(); + + int getBacklogSize(); + + int getMaxGameThreads(); + + int getMaxSecondsIdle(); + + int getMinUserNameLength(); + + int getMaxUserNameLength(); + + String getInvalidUserNamePattern(); + + int getMinPasswordLength(); + + int getMaxPasswordLength(); + + String getMaxAiOpponents(); + + Boolean isSaveGameActivated(); + + Boolean isAuthenticationActivated(); + + String getGoogleAccount(); + + String getMailgunApiKey(); + + String getMailgunDomain(); + + String getMailSmtpHost(); + + String getMailSmtpPort(); + + String getMailUser(); + + String getMailPassword(); + + String getMailFromAddress(); + + List getPlayerTypes(); + + List getGameTypes(); + + List getTournamentTypes(); + + List getDraftCubes(); + + List getDeckTypes(); +} diff --git a/Mage.Server/src/main/java/mage/server/util/ConfigWrapper.java b/Mage.Server/src/main/java/mage/server/util/ConfigWrapper.java new file mode 100644 index 0000000000..1a461a73aa --- /dev/null +++ b/Mage.Server/src/main/java/mage/server/util/ConfigWrapper.java @@ -0,0 +1,145 @@ +package mage.server.util; + +import mage.server.util.config.Config; +import mage.server.util.config.GamePlugin; +import mage.server.util.config.Plugin; + +import java.util.List; + +public class ConfigWrapper implements ConfigSettingsContract { + + private final Config config; + + public ConfigWrapper(final Config config) { + this.config = config; + } + + public String getServerAddress() { + return config.getServer().getServerAddress(); + } + + public String getServerName() { + return config.getServer().getServerName(); + } + + public int getPort() { + return config.getServer().getPort().intValue(); + } + + public int getSecondaryBindPort() { + return config.getServer().getSecondaryBindPort().intValue(); + } + + public int getLeasePeriod() { + return config.getServer().getLeasePeriod().intValue(); + } + + public int getSocketWriteTimeout() { + return config.getServer().getSocketWriteTimeout().intValue(); + } + + public int getMaxPoolSize() { + return config.getServer().getMaxPoolSize().intValue(); + } + + public int getNumAcceptThreads() { + return config.getServer().getNumAcceptThreads().intValue(); + } + + public int getBacklogSize() { + return config.getServer().getBacklogSize().intValue(); + } + + public int getMaxGameThreads() { + return config.getServer().getMaxGameThreads().intValue(); + } + + public int getMaxSecondsIdle() { + return config.getServer().getMaxSecondsIdle().intValue(); + } + + public int getMinUserNameLength() { + return config.getServer().getMinUserNameLength().intValue(); + } + + public int getMaxUserNameLength() { + return config.getServer().getMaxUserNameLength().intValue(); + } + + public String getInvalidUserNamePattern() { + return config.getServer().getInvalidUserNamePattern(); + } + + public int getMinPasswordLength() { + return config.getServer().getMinPasswordLength().intValue(); + } + + public int getMaxPasswordLength() { + return config.getServer().getMaxPasswordLength().intValue(); + } + + public String getMaxAiOpponents() { + return config.getServer().getMaxAiOpponents(); + } + + public Boolean isSaveGameActivated() { + return config.getServer().isSaveGameActivated(); + } + + public Boolean isAuthenticationActivated() { + return config.getServer().isAuthenticationActivated(); + } + + public String getGoogleAccount() { + return config.getServer().getGoogleAccount(); + } + + public String getMailgunApiKey() { + return config.getServer().getMailgunApiKey(); + } + + public String getMailgunDomain() { + return config.getServer().getMailgunDomain(); + } + + public String getMailSmtpHost() { + return config.getServer().getMailSmtpHost(); + } + + public String getMailSmtpPort() { + return config.getServer().getMailSmtpPort(); + } + + public String getMailUser() { + return config.getServer().getMailUser(); + } + + public String getMailPassword() { + return config.getServer().getMailPassword(); + } + + public String getMailFromAddress() { + return config.getServer().getMailFromAddress(); + } + + public List getPlayerTypes() { + return config.getPlayerTypes().getPlayerType(); + } + + public List getGameTypes() { + return config.getGameTypes().getGameType(); + } + + public List getTournamentTypes() { + return config.getTournamentTypes().getTournamentType(); + } + + public List getDraftCubes() { + return config.getDraftCubes().getDraftCube(); + } + + public List getDeckTypes() { + return config.getDeckTypes().getDeckType(); + } + +} diff --git a/Mage.Server/src/main/java/mage/server/util/ConfigurationException.java b/Mage.Server/src/main/java/mage/server/util/ConfigurationException.java new file mode 100644 index 0000000000..e1c1e5d0f0 --- /dev/null +++ b/Mage.Server/src/main/java/mage/server/util/ConfigurationException.java @@ -0,0 +1,7 @@ +package mage.server.util; + +public class ConfigurationException extends RuntimeException { + public ConfigurationException(Throwable cause) { + super(cause); + } +} diff --git a/Mage.Server/src/test/java/mage/server/util/ConfigFactoryTest.java b/Mage.Server/src/test/java/mage/server/util/ConfigFactoryTest.java new file mode 100644 index 0000000000..aab38e713a --- /dev/null +++ b/Mage.Server/src/test/java/mage/server/util/ConfigFactoryTest.java @@ -0,0 +1,34 @@ +package mage.server.util; + +import mage.server.util.config.Config; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; + +public class ConfigFactoryTest { + + @Test + @DisplayName("should unmarshal configuration from file") + void loadConfig() { + final Config config = ConfigFactory.loadFromFile("config/config.xml"); + + assertThat(config.getServer().getServerName()).isEqualTo("mage-server"); + assertThat(config.getServer().getPort()).isEqualTo(17171); + } + + @Test + @DisplayName("should fail if config is malformed") + void failOnMalformed() { + assertThatExceptionOfType(ConfigurationException.class) + .isThrownBy(() -> ConfigFactory.loadFromFile("config/config_error.xml")); + } + + @Test + @DisplayName("should fail if file does not exist") + void failOnNotFound() { + assertThatExceptionOfType(ConfigurationException.class) + .isThrownBy(() -> ConfigFactory.loadFromFile("does not exist")); + } +} diff --git a/Mage.Server/src/test/java/mage/server/util/ConfigWrapperTest.java b/Mage.Server/src/test/java/mage/server/util/ConfigWrapperTest.java new file mode 100644 index 0000000000..c8a80c34c4 --- /dev/null +++ b/Mage.Server/src/test/java/mage/server/util/ConfigWrapperTest.java @@ -0,0 +1,294 @@ +package mage.server.util; + +import mage.server.util.config.*; +import mage.utils.FluentBuilder; +import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.RandomUtils; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.DynamicTest; +import org.junit.jupiter.api.TestFactory; + +import java.math.BigInteger; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Objects; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ConfigWrapperTest { + + static class ConfigBuilder extends FluentBuilder { + + public String serverAddress; + public String serverName; + public int port; + public int secondaryBindPort; + public int leasePeriod; + public int socketWriteTimeout; + public int maxPoolSize; + public int numAcceptThreads; + public int backlogSize; + public int maxGameThreads; + public int maxSecondsIdle; + public int minUsernameLength; + public int maxUsernameLength; + public String invalidUsernamePattern; + public int minPasswordLength; + public int maxPasswordLength; + public String maxAiOpponents; + public boolean saveGameActivated; + public boolean authenticationActivated; + public String googleAccount; + public String mailgunApiKey; + public String mailgunDomain; + public String mailSmtpHost; + public String mailSmtpPort; + public String mailUser; + public String mailPassword; + public String mailFromAddress; + public List playerTypes = Collections.emptyList(); + public List gameTypes = Collections.emptyList(); + public List tournamentTypes = Collections.emptyList(); + public List draftCubes = Collections.emptyList(); + public List deckTypes = Collections.emptyList(); + + private ConfigBuilder() { + super(ConfigBuilder::new); + } + + @Override + protected Config makeValue() { + final Config result = new Config(); + result.setServer(makeServer()); + result.setPlayerTypes(makePlayerTypes()); + result.setGameTypes(makeGameTypes()); + result.setTournamentTypes(makeTournamentTypes()); + result.setDraftCubes(makeDraftCubes()); + result.setDeckTypes(makeDeckTypes()); + return result; + } + + private Server makeServer() { + final Server server = new Server(); + server.setServerAddress(serverAddress); + server.setServerName(serverName); + server.setPort(BigInteger.valueOf(port)); + server.setSecondaryBindPort(bi(secondaryBindPort)); + server.setLeasePeriod(bi(leasePeriod)); + server.setSocketWriteTimeout(bi(socketWriteTimeout)); + server.setMaxPoolSize(bi(maxPoolSize)); + server.setNumAcceptThreads(bi(numAcceptThreads)); + server.setBacklogSize(bi(backlogSize)); + server.setMaxGameThreads(bi(maxGameThreads)); + server.setMaxSecondsIdle(bi(maxSecondsIdle)); + server.setMinUserNameLength(bi(minUsernameLength)); + server.setMaxUserNameLength(bi(maxUsernameLength)); + server.setInvalidUserNamePattern(invalidUsernamePattern); + server.setMinPasswordLength(bi(minPasswordLength)); + server.setMaxPasswordLength(bi(maxPasswordLength)); + server.setMaxAiOpponents(maxAiOpponents); + server.setSaveGameActivated(saveGameActivated); + server.setAuthenticationActivated(authenticationActivated); + server.setGoogleAccount(googleAccount); + server.setMailgunApiKey(mailgunApiKey); + server.setMailgunDomain(mailgunDomain); + server.setMailSmtpHost(mailSmtpHost); + server.setMailSmtpPort(mailSmtpPort); + server.setMailUser(mailUser); + server.setMailPassword(mailPassword); + server.setMailFromAddress(mailFromAddress); + return server; + } + + private PlayerTypes makePlayerTypes() { + final PlayerTypes playerTypes = new PlayerTypes(); + this.playerTypes.forEach(p -> playerTypes.getPlayerType().add(p)); + return playerTypes; + } + + private GameTypes makeGameTypes() { + final GameTypes gameTypes = new GameTypes(); + this.gameTypes.forEach(g -> gameTypes.getGameType().add(g)); + return gameTypes; + } + + private TournamentTypes makeTournamentTypes() { + final TournamentTypes tournamentTypes = new TournamentTypes(); + this.tournamentTypes.forEach(t -> tournamentTypes.getTournamentType().add(t)); + return tournamentTypes; + } + + private DraftCubes makeDraftCubes() { + final DraftCubes draftCubes = new DraftCubes(); + this.draftCubes.forEach(d -> draftCubes.getDraftCube().add(d)); + return draftCubes; + } + + private DeckTypes makeDeckTypes() { + final DeckTypes deckTypes = new DeckTypes(); + this.deckTypes.forEach(d -> deckTypes.getDeckType().add(d)); + return deckTypes; + } + + private BigInteger bi(int value) { + return BigInteger.valueOf(value); + } + } + + private ConfigBuilder baseConfigBuilder() { + return new ConfigBuilder(); + } + + private final String expectedString = RandomStringUtils.randomAlphanumeric(15); + private final int expectedPositiveInt = RandomUtils.nextInt(0, Integer.MAX_VALUE); + + + @TestFactory + @DisplayName("should return from server") + Stream assignmentFromServer() { + return Stream.of( + testString("server address", c -> c.serverAddress = expectedString, ConfigWrapper::getServerAddress), + testString("server name", c -> c.serverName = expectedString, ConfigWrapper::getServerName), + testInt("port", c -> c.port = expectedPositiveInt, ConfigWrapper::getPort), + testInt("secondary bind port", c -> c.secondaryBindPort = expectedPositiveInt, ConfigWrapper::getSecondaryBindPort), + testInt("lease period", c -> c.leasePeriod = expectedPositiveInt, ConfigWrapper::getLeasePeriod), + testInt("socket write timeout", c -> c.socketWriteTimeout = expectedPositiveInt, ConfigWrapper::getSocketWriteTimeout), + testInt("max pool size", c -> c.maxPoolSize = expectedPositiveInt, ConfigWrapper::getMaxPoolSize), + testInt("number of accept threads", c -> c.numAcceptThreads = expectedPositiveInt, ConfigWrapper::getNumAcceptThreads), + testInt("backlog size", c -> c.backlogSize = expectedPositiveInt, ConfigWrapper::getBacklogSize), + testInt("max game threads", c -> c.maxGameThreads = expectedPositiveInt, ConfigWrapper::getMaxGameThreads), + testInt("max seconds idle", c -> c.maxSecondsIdle = expectedPositiveInt, ConfigWrapper::getMaxSecondsIdle), + testInt("min username length", c -> c.minUsernameLength = expectedPositiveInt, ConfigWrapper::getMinUserNameLength), + testInt("max username length", c -> c.maxUsernameLength = expectedPositiveInt, ConfigWrapper::getMaxUserNameLength), + testString("invalid username pattern", c -> c.invalidUsernamePattern = expectedString, ConfigWrapper::getInvalidUserNamePattern), + testInt("min password length", c -> c.minPasswordLength = expectedPositiveInt, ConfigWrapper::getMinPasswordLength), + testInt("max password length", c -> c.maxPasswordLength = expectedPositiveInt, ConfigWrapper::getMaxPasswordLength), + testString("max AI opponents", c -> c.maxAiOpponents = expectedString, ConfigWrapper::getMaxAiOpponents), + testTrue("save game activated", c -> c.saveGameActivated = true, ConfigWrapper::isSaveGameActivated), + testTrue("authentication activated", c -> c.authenticationActivated = true, ConfigWrapper::isAuthenticationActivated), + testString("google account", c -> c.googleAccount = expectedString, ConfigWrapper::getGoogleAccount), + testString("mailgun api key", c -> c.mailgunApiKey = expectedString, ConfigWrapper::getMailgunApiKey), + testString("mailgun domain", c -> c.mailgunDomain = expectedString, ConfigWrapper::getMailgunDomain), + testString("mail smtp host", c -> c.mailSmtpHost = expectedString, ConfigWrapper::getMailSmtpHost), + testString("mail smtp port", c -> c.mailSmtpPort = expectedString, ConfigWrapper::getMailSmtpPort), + testString("mail from address", c -> c.mailFromAddress = expectedString, ConfigWrapper::getMailFromAddress), + testString("mail user", c -> c.mailUser = expectedString, ConfigWrapper::getMailUser), + testString("mail password", c -> c.mailPassword = expectedString, ConfigWrapper::getMailPassword) + ); + } + + private DynamicTest testString(String description, Consumer builderSetter, Function valueExtractor) { + return testTemplate(description, builderSetter, valueExtractor, expectedString); + } + + private DynamicTest testTemplate(String description, Consumer builderSetter, Function valueExtractor, Object expectedValue) { + return DynamicTest.dynamicTest(description, () -> assertThat(valueExtractor.apply(makeTestee(baseConfigBuilder().with(builderSetter)))).isEqualTo(expectedValue)); + } + + private ConfigWrapper makeTestee(ConfigBuilder builder) { + return new ConfigWrapper(builder.build()); + } + + private DynamicTest testInt(String description, Consumer builderSetter, Function valueExtractor) { + return testTemplate(description, builderSetter, valueExtractor, expectedPositiveInt); + } + + private DynamicTest testTrue(String description, Consumer builderSetter, Function valueExtractor) { + return testTemplate(description, builderSetter, valueExtractor, true); + } + + + private final Comparator pluginComparator = (p1, p2) -> { + if (Objects.equals(p1.getName(), p2.getName()) && + Objects.equals(p1.getJar(), p2.getJar()) && + Objects.equals(p1.getClassName(), p2.getClassName())) { + return 0; + } else { + return -1; + } + }; + + private final Comparator gamePluginComparator = (p1, p2) -> { + if (Objects.equals(p1.getName(), p2.getName()) && + Objects.equals(p1.getJar(), p2.getJar()) && + Objects.equals(p1.getClassName(), p2.getClassName()) && + Objects.equals(p1.getTypeName(), p2.getTypeName())) { + return 0; + } else { + return -1; + } + }; + + private final List randomPlugins = IntStream.range(0, RandomUtils.nextInt(1, 10)) + .mapToObj(i -> makePlugin( + RandomStringUtils.randomAlphanumeric(15), + RandomStringUtils.randomAlphanumeric(16), + RandomStringUtils.randomAlphanumeric(17)) + ).collect(Collectors.toList()); + private final List randomGamePlugins = IntStream.range(0, RandomUtils.nextInt(1, 10)) + .mapToObj(i -> makeGamePlugin( + RandomStringUtils.randomAlphanumeric(15), + RandomStringUtils.randomAlphanumeric(16), + RandomStringUtils.randomAlphanumeric(17), + RandomStringUtils.randomAlphanumeric(18)) + ).collect(Collectors.toList()); + + private Plugin makePlugin(String name, String jar, String className) { + final Plugin plugin = new Plugin(); + plugin.setName(name); + plugin.setJar(jar); + plugin.setClassName(className); + return plugin; + } + + private GamePlugin makeGamePlugin(String name, String jar, String className, String typeName) { + final GamePlugin plugin = new GamePlugin(); + plugin.setName(name); + plugin.setJar(jar); + plugin.setClassName(className); + plugin.setTypeName(typeName); + return plugin; + } + + @TestFactory + @DisplayName("should extract") + Stream pluginsExtraction() { + return Stream.of( + pluginTest("playerTypes from playerTypes", c -> c.playerTypes = randomPlugins, ConfigWrapper::getPlayerTypes), + gamePluginTest("gameTypes from gameTypes", c -> c.gameTypes = randomGamePlugins, ConfigWrapper::getGameTypes), + gamePluginTest("tournamentTypes from tournamentTypes", c -> c.tournamentTypes = randomGamePlugins, ConfigWrapper::getTournamentTypes), + pluginTest("draftCubes from draftCubes", c -> c.draftCubes = randomPlugins, ConfigWrapper::getDraftCubes), + pluginTest("deckTypes from deckTypes", c -> c.deckTypes = randomPlugins, ConfigWrapper::getDeckTypes) + ); + } + + private DynamicTest pluginTest(String description, + Consumer builderSetter, + Function> listExtractor) { + return testTemplateForLists(description, builderSetter, listExtractor, randomPlugins, pluginComparator); + } + + private DynamicTest gamePluginTest(String description, + Consumer builderSetter, + Function> listExtractor) { + return testTemplateForLists(description, builderSetter, listExtractor, randomGamePlugins, gamePluginComparator); + } + + private DynamicTest testTemplateForLists(String description, + Consumer builderSetter, + Function> listExtractor, + List expectedValue, + Comparator comparator) { + return DynamicTest.dynamicTest(description, () -> + assertThat(listExtractor.apply(makeTestee(baseConfigBuilder().with(builderSetter)))) + .usingElementComparator(comparator) + .containsExactlyElementsOf(expectedValue) + ); + } +} diff --git a/pom.xml b/pom.xml index 61c118cd57..1032f1a955 100644 --- a/pom.xml +++ b/pom.xml @@ -52,6 +52,18 @@ + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.22.2 + + -Dfile.encoding=UTF-8 + + + + Mage @@ -113,6 +125,21 @@ guava 29.0-jre + + org.junit.jupiter + junit-jupiter + 5.7.0 + + + org.assertj + assertj-core + 3.18.0 + + + org.apache.commons + commons-lang3 + 3.11 +