From f370037289811e8cd78474cc8bb334eb5b03fdd3 Mon Sep 17 00:00:00 2001 From: Manuel Friedli Date: Fri, 13 Dec 2024 21:11:18 +0100 Subject: [PATCH 1/3] Use record for ServerConfig. --- .../ch/fritteli/maze/server/MazeServer.java | 4 +-- .../ch/fritteli/maze/server/ServerConfig.java | 27 ++++++++----------- .../maze/server/ServerConfigTest.java | 14 +++++----- 3 files changed, 19 insertions(+), 26 deletions(-) diff --git a/src/main/java/ch/fritteli/maze/server/MazeServer.java b/src/main/java/ch/fritteli/maze/server/MazeServer.java index b41da69..f1639cb 100644 --- a/src/main/java/ch/fritteli/maze/server/MazeServer.java +++ b/src/main/java/ch/fritteli/maze/server/MazeServer.java @@ -18,8 +18,8 @@ public class MazeServer { private final Undertow undertow; private MazeServer(@NotNull final ServerConfig config) { - final String hostAddress = config.getAddress().getHostAddress(); - final int port = config.getPort(); + final String hostAddress = config.address().getHostAddress(); + final int port = config.port(); log.info("Starting Server at http://{}:{}/", hostAddress, port); final RoutingHandler routingHandler = new RoutingHandler() .get(CreateHandler.PATH_TEMPLATE, new CreateHandler()) diff --git a/src/main/java/ch/fritteli/maze/server/ServerConfig.java b/src/main/java/ch/fritteli/maze/server/ServerConfig.java index ce25a6b..374606f 100644 --- a/src/main/java/ch/fritteli/maze/server/ServerConfig.java +++ b/src/main/java/ch/fritteli/maze/server/ServerConfig.java @@ -1,32 +1,27 @@ package ch.fritteli.maze.server; import io.vavr.control.Try; -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.Value; import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.wildfly.common.annotation.NotNull; import java.net.InetAddress; -@AllArgsConstructor(access = AccessLevel.PRIVATE) @Slf4j -@Value -public class ServerConfig { +public record ServerConfig(@NotNull InetAddress address, int port) { public static final String SYSPROP_HOST = "fritteli.maze.server.host"; public static final String SYSPROP_PORT = "fritteli.maze.server.port"; - @NotNull - InetAddress address; - int port; - - public ServerConfig(@Nullable final String address, final int port) throws ConfigurationException { - this.address = validateAddress(address); + public ServerConfig(@NotNull final InetAddress address, int port) { + this.address = address; this.port = validatePort(port); log.debug("host={}, port={}", this.address, this.port); } + public ServerConfig(@Nullable final String address, final int port) throws ConfigurationException { + this(validateAddress(address), port); + } + @NotNull public static ServerConfig init() throws ConfigurationException { final String host = System.getProperty(SYSPROP_HOST); @@ -36,7 +31,7 @@ public class ServerConfig { } @NotNull - private static InetAddress validateAddress(@Nullable final String address) { + private static InetAddress validateAddress(@Nullable final String address) throws ConfigurationException { return Try.of(() -> InetAddress.getByName(address)) .getOrElseThrow(cause -> new ConfigurationException( "Invalid hostname/address: %s".formatted(address), @@ -44,14 +39,14 @@ public class ServerConfig { )); } - private static int validatePort(final int port) { + private static int validatePort(final int port) throws ConfigurationException { if (port < 0 || port > 0xFFFF) { throw new ConfigurationException("Port out of range (0..65535): %s".formatted(port)); } return port; } - private static int validatePort(@Nullable final String portString) { + private static int validatePort(@Nullable final String portString) throws ConfigurationException { if (portString == null) { log.info("No port configured; using default."); return 0; diff --git a/src/test/java/ch/fritteli/maze/server/ServerConfigTest.java b/src/test/java/ch/fritteli/maze/server/ServerConfigTest.java index 7760147..999bb0f 100644 --- a/src/test/java/ch/fritteli/maze/server/ServerConfigTest.java +++ b/src/test/java/ch/fritteli/maze/server/ServerConfigTest.java @@ -3,8 +3,6 @@ package ch.fritteli.maze.server; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import java.net.UnknownHostException; - import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -22,9 +20,9 @@ class ServerConfigTest { final ServerConfig sut = ServerConfig.init(); // assert - assertEquals("127.0.0.1", sut.getAddress().getHostAddress()); - assertEquals("localhost", sut.getAddress().getHostName()); - assertEquals(0, sut.getPort()); + assertEquals("127.0.0.1", sut.address().getHostAddress()); + assertEquals("localhost", sut.address().getHostName()); + assertEquals(0, sut.port()); } @Test @@ -46,7 +44,7 @@ class ServerConfigTest { } @Test - void testInit() throws ConfigurationException, UnknownHostException { + void testInit() throws ConfigurationException { // arrange System.setProperty(ServerConfig.SYSPROP_HOST, "127.0.0.1"); System.setProperty(ServerConfig.SYSPROP_PORT, "12345"); @@ -55,7 +53,7 @@ class ServerConfigTest { final ServerConfig sut = ServerConfig.init(); // assert - assertEquals("127.0.0.1", sut.getAddress().getHostAddress()); - assertEquals(12345, sut.getPort()); + assertEquals("127.0.0.1", sut.address().getHostAddress()); + assertEquals(12345, sut.port()); } } From 87b16cb24a1b49fb27b2e3b2445aec9dc0cac4ff Mon Sep 17 00:00:00 2001 From: Manuel Friedli Date: Fri, 13 Dec 2024 22:01:53 +0100 Subject: [PATCH 2/3] Allow limiting max height and/or width when creating a maze. --- .../ch/fritteli/maze/server/MazeServer.java | 4 +- .../ch/fritteli/maze/server/ServerConfig.java | 47 +++++++++++++++++-- .../maze/server/handler/CreateHandler.java | 12 ++++- .../handler/ParametersToMazeExtractor.java | 17 ++++++- 4 files changed, 69 insertions(+), 11 deletions(-) diff --git a/src/main/java/ch/fritteli/maze/server/MazeServer.java b/src/main/java/ch/fritteli/maze/server/MazeServer.java index f1639cb..84a1fcb 100644 --- a/src/main/java/ch/fritteli/maze/server/MazeServer.java +++ b/src/main/java/ch/fritteli/maze/server/MazeServer.java @@ -22,7 +22,7 @@ public class MazeServer { final int port = config.port(); log.info("Starting Server at http://{}:{}/", hostAddress, port); final RoutingHandler routingHandler = new RoutingHandler() - .get(CreateHandler.PATH_TEMPLATE, new CreateHandler()) + .get(CreateHandler.PATH_TEMPLATE, new CreateHandler(config.maxMazeHeight(), config.maxMazeWidth())) .post(RenderV1Handler.PATH_TEMPLATE, new RenderV1Handler()) .post(RenderV2Handler.PATH_TEMPLATE, new RenderV2Handler()); @@ -47,7 +47,7 @@ public class MazeServer { private void start() { Runtime.getRuntime().addShutdownHook(new Thread(this::stop, "listener-stopper")); this.undertow.start(); - final InetSocketAddress address = (InetSocketAddress) this.undertow.getListenerInfo().get(0).getAddress(); + final InetSocketAddress address = (InetSocketAddress) this.undertow.getListenerInfo().getFirst().getAddress(); final String hostAddress = address.getAddress().getHostAddress(); final int port = address.getPort(); diff --git a/src/main/java/ch/fritteli/maze/server/ServerConfig.java b/src/main/java/ch/fritteli/maze/server/ServerConfig.java index 374606f..cd85ab9 100644 --- a/src/main/java/ch/fritteli/maze/server/ServerConfig.java +++ b/src/main/java/ch/fritteli/maze/server/ServerConfig.java @@ -8,26 +8,41 @@ import org.jetbrains.annotations.Nullable; import java.net.InetAddress; @Slf4j -public record ServerConfig(@NotNull InetAddress address, int port) { +public record ServerConfig(@NotNull InetAddress address, + int port, + int maxMazeHeight, + int maxMazeWidth) { public static final String SYSPROP_HOST = "fritteli.maze.server.host"; public static final String SYSPROP_PORT = "fritteli.maze.server.port"; + public static final String SYSPROP_MAX_MAZE_HEIGHT = "fritteli.maze.maxheight"; + public static final String SYSPROP_MAX_MAZE_WIDTH = "fritteli.maze.maxwidth"; - public ServerConfig(@NotNull final InetAddress address, int port) { + public ServerConfig(@NotNull final InetAddress address, + final int port, + final int maxMazeHeight, + final int maxMazeWidth) { this.address = address; this.port = validatePort(port); + this.maxMazeHeight = validateDimension(maxMazeHeight, "height"); + this.maxMazeWidth = validateDimension(maxMazeWidth, "width"); log.debug("host={}, port={}", this.address, this.port); } - public ServerConfig(@Nullable final String address, final int port) throws ConfigurationException { - this(validateAddress(address), port); + public ServerConfig(@Nullable final String address, final int port, final int maxMazeHeight, final int maxMazeWidth) + throws ConfigurationException { + this(validateAddress(address), port, maxMazeHeight, maxMazeWidth); } @NotNull public static ServerConfig init() throws ConfigurationException { final String host = System.getProperty(SYSPROP_HOST); final String portString = System.getProperty(SYSPROP_PORT); + final String maxMazeHeightString = System.getProperty(SYSPROP_MAX_MAZE_HEIGHT); + final String maxMazeWidthString = System.getProperty(SYSPROP_MAX_MAZE_WIDTH); final int port = validatePort(portString); - return new ServerConfig(host, port); + final int maxMazeHeight = validateDimension(maxMazeHeightString, "height", SYSPROP_MAX_MAZE_HEIGHT); + final int maxMazeWidth = validateDimension(maxMazeWidthString, "width", SYSPROP_MAX_MAZE_WIDTH); + return new ServerConfig(host, port, maxMazeHeight, maxMazeWidth); } @NotNull @@ -57,4 +72,26 @@ public record ServerConfig(@NotNull InetAddress address, int port) { cause )); } + + private static int validateDimension(final int dimension, @NotNull final String identifier) { + if (dimension < 0) { + throw new ConfigurationException("Maximum %s is negative : %s".formatted(dimension, identifier)); + } + return dimension; + } + + private static int validateDimension(@Nullable final String dimensionString, + @NotNull final String identifier, + @NotNull final String syspropName) { + if (dimensionString == null) { + log.info("No maximum {} configured; using default (unlimited).", identifier); + return 0; + } + return Try.of(() -> Integer.valueOf(dimensionString)) + .getOrElseThrow(cause -> new ConfigurationException( + "Failed to parse maximum %s specified in system property '%s': %s" + .formatted(identifier, syspropName, dimensionString), + cause + )); + } } diff --git a/src/main/java/ch/fritteli/maze/server/handler/CreateHandler.java b/src/main/java/ch/fritteli/maze/server/handler/CreateHandler.java index a14954b..7ad7892 100644 --- a/src/main/java/ch/fritteli/maze/server/handler/CreateHandler.java +++ b/src/main/java/ch/fritteli/maze/server/handler/CreateHandler.java @@ -22,6 +22,13 @@ import java.util.Map; public class CreateHandler extends AbstractHttpHandler { public static final String PATH_TEMPLATE = "/create/{output}"; + private final int maxHeight; + private final int maxWidth; + + public CreateHandler(final int maxHeight, final int maxWidth) { + this.maxHeight = maxHeight; + this.maxWidth = maxWidth; + } @Override protected void handle(@NotNull final HttpServerExchange exchange) { @@ -29,10 +36,11 @@ public class CreateHandler extends AbstractHttpHandler { log.debug("Handling create request"); this.createMazeFromRequestParameters(exchange.getQueryParameters()) .onFailure(e -> { - log.error("Error creating maze from request", e); if (e instanceof InvalidRequestParameterException) { + log.debug("Error creating maze from request", e); exchange.setStatusCode(StatusCodes.BAD_REQUEST); } else { + log.error("Error creating maze from request", e); exchange.setStatusCode(StatusCodes.INTERNAL_SERVER_ERROR); } exchange.getResponseSender() @@ -75,6 +83,6 @@ public class CreateHandler extends AbstractHttpHandler { @NotNull private Try createMazeFromRequestParameters(final Map> queryParameters) { - return new ParametersToMazeExtractor(queryParameters).createMaze(); + return new ParametersToMazeExtractor(queryParameters, this.maxHeight, this.maxWidth).createMaze(); } } diff --git a/src/main/java/ch/fritteli/maze/server/handler/ParametersToMazeExtractor.java b/src/main/java/ch/fritteli/maze/server/handler/ParametersToMazeExtractor.java index bca9efa..1b93e38 100644 --- a/src/main/java/ch/fritteli/maze/server/handler/ParametersToMazeExtractor.java +++ b/src/main/java/ch/fritteli/maze/server/handler/ParametersToMazeExtractor.java @@ -20,6 +20,8 @@ class ParametersToMazeExtractor { @NotNull private final Map> queryParameters; + private final int maxHeight; + private final int maxWidth; @NotNull Try createMaze() { @@ -49,12 +51,23 @@ class ParametersToMazeExtractor { ))); } + final int desiredHeight = height.get(); + final int desiredWidth = width.get(); + + if (this.maxHeight != 0 && desiredHeight > this.maxHeight) { + return Try.failure(new InvalidRequestParameterException("Specified height (%s) is greater than allowed maximum of %s".formatted(desiredHeight, this.maxHeight))); + } + + if (this.maxWidth != 0 && desiredWidth > this.maxWidth) { + return Try.failure(new InvalidRequestParameterException("Specified width (%s) is greater than allowed maximum of %s".formatted(desiredWidth, this.maxWidth))); + } + return Try.of(() -> { final Maze maze; if (start.isDefined() && end.isDefined()) { - maze = new Maze(width.get(), height.get(), id.getOrElse(() -> new Random().nextLong()), start.get(), end.get()); + maze = new Maze(desiredWidth, desiredHeight, id.getOrElse(() -> new Random().nextLong()), start.get(), end.get()); } else { - maze = new Maze(width.get(), height.get(), id.getOrElse(() -> new Random().nextLong())); + maze = new Maze(desiredWidth, desiredHeight, id.getOrElse(() -> new Random().nextLong())); } new RandomDepthFirst(maze).run(); return new GeneratedMaze(maze, output.get(), RandomDepthFirst.class.getSimpleName()); From a613a92adb71edbf24cc0d99a79c3344929c669e Mon Sep 17 00:00:00 2001 From: Manuel Friedli Date: Fri, 13 Dec 2024 22:35:10 +0100 Subject: [PATCH 3/3] Make dimension limits Option instead of using the magic value of 0 for "no limit", and add more tests for the ServerConfig. --- pom.xml | 13 +- .../ch/fritteli/maze/server/ServerConfig.java | 42 ++++--- .../maze/server/handler/CreateHandler.java | 9 +- .../handler/ParametersToMazeExtractor.java | 20 ++- .../maze/server/ServerConfigTest.java | 114 ++++++++++++++++-- 5 files changed, 158 insertions(+), 40 deletions(-) diff --git a/pom.xml b/pom.xml index 3ec91a4..aed0ac3 100644 --- a/pom.xml +++ b/pom.xml @@ -1,5 +1,6 @@ - + 4.0.0 @@ -57,7 +58,7 @@ 0.2.1 4.0.0-M8 - 2.3.13.Final + 2.3.18.Final @@ -95,6 +96,11 @@ org.junit.jupiter junit-jupiter-api + + org.assertj + assertj-core + test + @@ -104,7 +110,8 @@ maven-shade-plugin - + ch.fritteli.maze.server.Main diff --git a/src/main/java/ch/fritteli/maze/server/ServerConfig.java b/src/main/java/ch/fritteli/maze/server/ServerConfig.java index cd85ab9..401fd6d 100644 --- a/src/main/java/ch/fritteli/maze/server/ServerConfig.java +++ b/src/main/java/ch/fritteli/maze/server/ServerConfig.java @@ -1,5 +1,6 @@ package ch.fritteli.maze.server; +import io.vavr.control.Option; import io.vavr.control.Try; import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; @@ -10,8 +11,8 @@ import java.net.InetAddress; @Slf4j public record ServerConfig(@NotNull InetAddress address, int port, - int maxMazeHeight, - int maxMazeWidth) { + @NotNull Option maxMazeHeight, + @NotNull Option maxMazeWidth) { public static final String SYSPROP_HOST = "fritteli.maze.server.host"; public static final String SYSPROP_PORT = "fritteli.maze.server.port"; public static final String SYSPROP_MAX_MAZE_HEIGHT = "fritteli.maze.maxheight"; @@ -19,16 +20,19 @@ public record ServerConfig(@NotNull InetAddress address, public ServerConfig(@NotNull final InetAddress address, final int port, - final int maxMazeHeight, - final int maxMazeWidth) { + @NotNull final Option maxMazeHeight, + @NotNull final Option maxMazeWidth) { this.address = address; this.port = validatePort(port); this.maxMazeHeight = validateDimension(maxMazeHeight, "height"); this.maxMazeWidth = validateDimension(maxMazeWidth, "width"); - log.debug("host={}, port={}", this.address, this.port); + log.debug("host={}, port={}, maxHeight={}, maxWidth={}", this.address, this.port, this.maxMazeHeight, this.maxMazeWidth); } - public ServerConfig(@Nullable final String address, final int port, final int maxMazeHeight, final int maxMazeWidth) + public ServerConfig(@Nullable final String address, + final int port, + @NotNull final Option maxMazeHeight, + @NotNull final Option maxMazeWidth) throws ConfigurationException { this(validateAddress(address), port, maxMazeHeight, maxMazeWidth); } @@ -40,8 +44,8 @@ public record ServerConfig(@NotNull InetAddress address, final String maxMazeHeightString = System.getProperty(SYSPROP_MAX_MAZE_HEIGHT); final String maxMazeWidthString = System.getProperty(SYSPROP_MAX_MAZE_WIDTH); final int port = validatePort(portString); - final int maxMazeHeight = validateDimension(maxMazeHeightString, "height", SYSPROP_MAX_MAZE_HEIGHT); - final int maxMazeWidth = validateDimension(maxMazeWidthString, "width", SYSPROP_MAX_MAZE_WIDTH); + final Option maxMazeHeight = validateDimension(maxMazeHeightString, "height", SYSPROP_MAX_MAZE_HEIGHT); + final Option maxMazeWidth = validateDimension(maxMazeWidthString, "width", SYSPROP_MAX_MAZE_WIDTH); return new ServerConfig(host, port, maxMazeHeight, maxMazeWidth); } @@ -66,32 +70,36 @@ public record ServerConfig(@NotNull InetAddress address, log.info("No port configured; using default."); return 0; } - return Try.of(() -> Integer.valueOf(portString)) + return Try.of(() -> Integer.parseInt(portString)) .getOrElseThrow(cause -> new ConfigurationException( "Failed to parse port specified in system property '%s': %s".formatted(SYSPROP_PORT, portString), cause )); } - private static int validateDimension(final int dimension, @NotNull final String identifier) { - if (dimension < 0) { - throw new ConfigurationException("Maximum %s is negative : %s".formatted(dimension, identifier)); + @NotNull + private static Option validateDimension(@NotNull final Option dimension, + @NotNull final String identifier) { + if (dimension.exists(d -> d <= 1)) { + throw new ConfigurationException("Maximum %s must be greater than 1: %s" + .formatted(identifier, dimension.get())); } return dimension; } - private static int validateDimension(@Nullable final String dimensionString, - @NotNull final String identifier, - @NotNull final String syspropName) { + private static Option validateDimension(@Nullable final String dimensionString, + @NotNull final String identifier, + @NotNull final String syspropName) { if (dimensionString == null) { log.info("No maximum {} configured; using default (unlimited).", identifier); - return 0; + return Option.none(); } - return Try.of(() -> Integer.valueOf(dimensionString)) + final int desiredDimension = Try.of(() -> Integer.parseInt(dimensionString)) .getOrElseThrow(cause -> new ConfigurationException( "Failed to parse maximum %s specified in system property '%s': %s" .formatted(identifier, syspropName, dimensionString), cause )); + return Option.some(desiredDimension); } } diff --git a/src/main/java/ch/fritteli/maze/server/handler/CreateHandler.java b/src/main/java/ch/fritteli/maze/server/handler/CreateHandler.java index 7ad7892..4d44ab2 100644 --- a/src/main/java/ch/fritteli/maze/server/handler/CreateHandler.java +++ b/src/main/java/ch/fritteli/maze/server/handler/CreateHandler.java @@ -7,6 +7,7 @@ import io.undertow.server.HttpServerExchange; import io.undertow.util.Headers; import io.undertow.util.HttpString; import io.undertow.util.StatusCodes; +import io.vavr.control.Option; import io.vavr.control.Try; import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; @@ -22,10 +23,12 @@ import java.util.Map; public class CreateHandler extends AbstractHttpHandler { public static final String PATH_TEMPLATE = "/create/{output}"; - private final int maxHeight; - private final int maxWidth; + @NotNull + private final Option maxHeight; + @NotNull + private final Option maxWidth; - public CreateHandler(final int maxHeight, final int maxWidth) { + public CreateHandler(@NotNull final Option maxHeight, @NotNull final Option maxWidth) { this.maxHeight = maxHeight; this.maxWidth = maxWidth; } diff --git a/src/main/java/ch/fritteli/maze/server/handler/ParametersToMazeExtractor.java b/src/main/java/ch/fritteli/maze/server/handler/ParametersToMazeExtractor.java index 1b93e38..6c747e5 100644 --- a/src/main/java/ch/fritteli/maze/server/handler/ParametersToMazeExtractor.java +++ b/src/main/java/ch/fritteli/maze/server/handler/ParametersToMazeExtractor.java @@ -20,8 +20,10 @@ class ParametersToMazeExtractor { @NotNull private final Map> queryParameters; - private final int maxHeight; - private final int maxWidth; + @NotNull + private final Option maxHeight; + @NotNull + private final Option maxWidth; @NotNull Try createMaze() { @@ -54,12 +56,18 @@ class ParametersToMazeExtractor { final int desiredHeight = height.get(); final int desiredWidth = width.get(); - if (this.maxHeight != 0 && desiredHeight > this.maxHeight) { - return Try.failure(new InvalidRequestParameterException("Specified height (%s) is greater than allowed maximum of %s".formatted(desiredHeight, this.maxHeight))); + if (desiredHeight <= 1) { + return Try.failure(new InvalidRequestParameterException("Specified height (%s) must be > 1".formatted(desiredHeight))); + } + if (desiredWidth <= 1) { + return Try.failure(new InvalidRequestParameterException("Specified width (%s) must be > 1".formatted(desiredHeight))); + } + if (this.maxHeight.exists(max -> desiredHeight > max)) { + return Try.failure(new InvalidRequestParameterException("Specified height (%s) is greater than allowed maximum of %s".formatted(desiredHeight, this.maxHeight.get()))); } - if (this.maxWidth != 0 && desiredWidth > this.maxWidth) { - return Try.failure(new InvalidRequestParameterException("Specified width (%s) is greater than allowed maximum of %s".formatted(desiredWidth, this.maxWidth))); + if (this.maxWidth.exists(max -> desiredWidth > max)) { + return Try.failure(new InvalidRequestParameterException("Specified width (%s) is greater than allowed maximum of %s".formatted(desiredWidth, this.maxWidth.get()))); } return Try.of(() -> { diff --git a/src/test/java/ch/fritteli/maze/server/ServerConfigTest.java b/src/test/java/ch/fritteli/maze/server/ServerConfigTest.java index 999bb0f..68aae74 100644 --- a/src/test/java/ch/fritteli/maze/server/ServerConfigTest.java +++ b/src/test/java/ch/fritteli/maze/server/ServerConfigTest.java @@ -3,14 +3,16 @@ package ch.fritteli.maze.server; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; class ServerConfigTest { @BeforeEach void clearSysProperties() { System.clearProperty(ServerConfig.SYSPROP_HOST); System.clearProperty(ServerConfig.SYSPROP_PORT); + System.clearProperty(ServerConfig.SYSPROP_MAX_MAZE_HEIGHT); + System.clearProperty(ServerConfig.SYSPROP_MAX_MAZE_WIDTH); } @Test @@ -20,9 +22,27 @@ class ServerConfigTest { final ServerConfig sut = ServerConfig.init(); // assert - assertEquals("127.0.0.1", sut.address().getHostAddress()); - assertEquals("localhost", sut.address().getHostName()); - assertEquals(0, sut.port()); + assertThat(sut.address()) + .satisfies( + address -> assertThat(address.getHostAddress()).isEqualTo("127.0.0.1"), + address -> assertThat(address.getHostName()).isEqualTo("localhost") + ); + assertThat(sut.port()).isZero(); + assertThat(sut.maxMazeHeight()).isEmpty(); + assertThat(sut.maxMazeWidth()).isEmpty(); + } + + + @Test + void testInit_invalidAddress() { + // arrange + System.setProperty(ServerConfig.SYSPROP_HOST, "256.2515.19.0"); + + // act / assert + assertThatExceptionOfType(ConfigurationException.class) + .isThrownBy(ServerConfig::init) + .withMessageContaining("Invalid hostname/address") + .withMessageContaining("256.2515.19.0"); } @Test @@ -31,29 +51,101 @@ class ServerConfigTest { System.setProperty(ServerConfig.SYSPROP_PORT, "Hello World!"); // act / assert - assertThrows(ConfigurationException.class, ServerConfig::init); + assertThatExceptionOfType(ConfigurationException.class) + .isThrownBy(ServerConfig::init) + .withMessageContaining("Failed to parse port") + .withMessageContaining("Hello World!"); } @Test - void testInit_invalidPort() { + void testInit_invalidPortTooSmall() { + // arrange + System.setProperty(ServerConfig.SYSPROP_PORT, "-5"); + + // act / assert + assertThatExceptionOfType(ConfigurationException.class) + .isThrownBy(ServerConfig::init) + .withMessageContaining("Port out of range") + .withMessageContaining("-5"); + } + + @Test + void testInit_invalidPortTooLarge() { // arrange System.setProperty(ServerConfig.SYSPROP_PORT, "99999"); // act / assert - assertThrows(ConfigurationException.class, ServerConfig::init); + assertThatExceptionOfType(ConfigurationException.class) + .isThrownBy(ServerConfig::init) + .withMessageContaining("Port out of range") + .withMessageContaining("99999"); + } + + @Test + void testInit_unparseableMaxMazeHeight() { + // arrange + System.setProperty(ServerConfig.SYSPROP_MAX_MAZE_HEIGHT, "Hello World!"); + + // act / assert + assertThatExceptionOfType(ConfigurationException.class) + .isThrownBy(ServerConfig::init) + .withMessageContaining("Failed to parse maximum height") + .withMessageContaining("Hello World!"); + + } + + @Test + void testInit_invalidMaxMazeHeight() { + // arrange + System.setProperty(ServerConfig.SYSPROP_MAX_MAZE_HEIGHT, "1"); + + // act / assert + assertThatExceptionOfType(ConfigurationException.class) + .isThrownBy(ServerConfig::init) + .withMessageContaining("Maximum height must be greater than 1:") + .withMessageEndingWith("1"); + } + + @Test + void testInit_unparseableMaxMazeWidth() { + // arrange + System.setProperty(ServerConfig.SYSPROP_MAX_MAZE_WIDTH, "Hello World!"); + + // act / assert + assertThatExceptionOfType(ConfigurationException.class) + .isThrownBy(ServerConfig::init) + .withMessageContaining("Failed to parse maximum width") + .withMessageContaining("Hello World!"); + + } + + @Test + void testInit_invalidMaxMazeWidth() { + // arrange + System.setProperty(ServerConfig.SYSPROP_MAX_MAZE_WIDTH, "-24"); + + // act / assert + assertThatExceptionOfType(ConfigurationException.class) + .isThrownBy(ServerConfig::init) + .withMessageContaining("Maximum width must be greater than 1:") + .withMessageContaining("-24"); } @Test void testInit() throws ConfigurationException { // arrange - System.setProperty(ServerConfig.SYSPROP_HOST, "127.0.0.1"); + System.setProperty(ServerConfig.SYSPROP_HOST, "10.0.9.12"); System.setProperty(ServerConfig.SYSPROP_PORT, "12345"); + System.setProperty(ServerConfig.SYSPROP_MAX_MAZE_HEIGHT, "100"); + System.setProperty(ServerConfig.SYSPROP_MAX_MAZE_WIDTH, "42"); // act final ServerConfig sut = ServerConfig.init(); // assert - assertEquals("127.0.0.1", sut.address().getHostAddress()); - assertEquals(12345, sut.port()); + assertThat(sut.address().getHostAddress()).isEqualTo("10.0.9.12"); + assertThat(sut.port()).isEqualTo(12345); + assertThat(sut.maxMazeHeight()).singleElement().isEqualTo(100); + assertThat(sut.maxMazeWidth()).singleElement().isEqualTo(42); } }