From b13a7db67b48568fa4614a1aa1182a52fdb93e71 Mon Sep 17 00:00:00 2001 From: Yannik Bretschneider Date: Wed, 2 Jun 2021 16:10:35 +0200 Subject: [PATCH] feat: implemented proper CharacterConfig json stuff --- .../json/config/CharacterConfig.java | 20 +- .../json/config/CharacterProperties.java | 18 + .../json/config/CharacterConfigJSONTest.java | 390 ++++++++++++++++++ .../config/CharacterPropertiesJSONTest.java | 124 ++++++ 4 files changed, 549 insertions(+), 3 deletions(-) create mode 100644 src/test/java/uulm/teamname/marvelous/gamelibrary/json/config/CharacterConfigJSONTest.java create mode 100644 src/test/java/uulm/teamname/marvelous/gamelibrary/json/config/CharacterPropertiesJSONTest.java diff --git a/src/main/java/uulm/teamname/marvelous/gamelibrary/json/config/CharacterConfig.java b/src/main/java/uulm/teamname/marvelous/gamelibrary/json/config/CharacterConfig.java index 38f875f..cc41170 100644 --- a/src/main/java/uulm/teamname/marvelous/gamelibrary/json/config/CharacterConfig.java +++ b/src/main/java/uulm/teamname/marvelous/gamelibrary/json/config/CharacterConfig.java @@ -2,9 +2,7 @@ package uulm.teamname.marvelous.gamelibrary.json.config; import com.fasterxml.jackson.annotation.JsonIgnore; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; +import java.util.*; /** * POJO describing the CharacterConfig as defined by the standard document. @@ -19,6 +17,7 @@ public class CharacterConfig { * @return a unmodifiable {@link Map}<{@link String}, {@link CharacterProperties}> containing all properties. * If not yet existent, initialize the Map */ + @JsonIgnore public Map getMap() { // lazy initialization if (propertyMap == null) { @@ -31,4 +30,19 @@ public class CharacterConfig { return unmodifiablePropertyMap; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + CharacterConfig that = (CharacterConfig) o; + return Arrays.equals(characters, that.characters) && Objects.equals(propertyMap, that.propertyMap) && Objects.equals(unmodifiablePropertyMap, that.unmodifiablePropertyMap); + } + + @Override + public int hashCode() { + int result = Objects.hash(propertyMap, unmodifiablePropertyMap); + result = 31 * result + Arrays.hashCode(characters); + return result; + } } diff --git a/src/main/java/uulm/teamname/marvelous/gamelibrary/json/config/CharacterProperties.java b/src/main/java/uulm/teamname/marvelous/gamelibrary/json/config/CharacterProperties.java index 130ff68..fd1c3d3 100644 --- a/src/main/java/uulm/teamname/marvelous/gamelibrary/json/config/CharacterProperties.java +++ b/src/main/java/uulm/teamname/marvelous/gamelibrary/json/config/CharacterProperties.java @@ -1,11 +1,16 @@ package uulm.teamname.marvelous.gamelibrary.json.config; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import java.util.Objects; + +@JsonPropertyOrder({"characterID", "name", "HP", "MP", "AP", "meleeDamage", "rangeCombatDamage", "rangeCombatReach"}) /** * Represents properties of a character in the {@link CharacterConfig}. */ public class CharacterProperties { + public int characterID; public String name; public int HP; public int MP; @@ -15,4 +20,17 @@ public class CharacterProperties { public int rangedDamage; @JsonProperty("rangeCombatReach") public int attackRange; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + CharacterProperties that = (CharacterProperties) o; + return characterID == that.characterID && HP == that.HP && MP == that.MP && AP == that.AP && meleeDamage == that.meleeDamage && rangedDamage == that.rangedDamage && attackRange == that.attackRange && Objects.equals(name, that.name); + } + + @Override + public int hashCode() { + return Objects.hash(characterID, name, HP, MP, AP, meleeDamage, rangedDamage, attackRange); + } } diff --git a/src/test/java/uulm/teamname/marvelous/gamelibrary/json/config/CharacterConfigJSONTest.java b/src/test/java/uulm/teamname/marvelous/gamelibrary/json/config/CharacterConfigJSONTest.java new file mode 100644 index 0000000..00ced57 --- /dev/null +++ b/src/test/java/uulm/teamname/marvelous/gamelibrary/json/config/CharacterConfigJSONTest.java @@ -0,0 +1,390 @@ +package uulm.teamname.marvelous.gamelibrary.json.config; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import net.jqwik.api.*; +import net.jqwik.api.lifecycle.BeforeProperty; +import org.junit.jupiter.api.Test; + +import java.util.HashSet; +import java.util.concurrent.ThreadLocalRandom; + +import static org.mockito.Mockito.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.assertj.core.api.Assertions.*; + +class CharacterConfigJSONTest { + private static final String json = """ + { + "characters": [ + { + "characterID": 1, + "name": "Rocket Raccoon", + "HP": 100, + "MP": 2, + "AP": 2, + "meleeDamage": 10, + "rangeCombatDamage": 30, + "rangeCombatReach": 5 + }, + { + "characterID": 2, + "name": "Quicksilver", + "HP": 100, + "MP": 6, + "AP": 1, + "meleeDamage": 10, + "rangeCombatDamage": 10, + "rangeCombatReach": 3 + }, + { + "characterID": 3, + "name": "Hulk", + "HP": 100, + "MP": 2, + "AP": 2, + "meleeDamage": 10, + "rangeCombatDamage": 30, + "rangeCombatReach": 5 + }, + { + "characterID": 4, + "name": "Black Widow", + "HP": 100, + "MP": 6, + "AP": 1, + "meleeDamage": 10, + "rangeCombatDamage": 10, + "rangeCombatReach": 3 + }, + { + "characterID": 5, + "name": "Hawkeye", + "HP": 100, + "MP": 6, + "AP": 1, + "meleeDamage": 10, + "rangeCombatDamage": 10, + "rangeCombatReach": 3 + }, + { + "characterID": 6, + "name": "Captain America", + "HP": 100, + "MP": 2, + "AP": 2, + "meleeDamage": 10, + "rangeCombatDamage": 30, + "rangeCombatReach": 5 + }, + { + "characterID": 7, + "name": "Spiderman", + "HP": 100, + "MP": 6, + "AP": 1, + "meleeDamage": 10, + "rangeCombatDamage": 10, + "rangeCombatReach": 3 + }, + { + "characterID": 8, + "name": "Dr. Strange", + "HP": 100, + "MP": 2, + "AP": 2, + "meleeDamage": 10, + "rangeCombatDamage": 30, + "rangeCombatReach": 5 + }, + { + "characterID": 9, + "name": "Iron Man", + "HP": 100, + "MP": 6, + "AP": 1, + "meleeDamage": 10, + "rangeCombatDamage": 10, + "rangeCombatReach": 3 + }, + { + "characterID": 10, + "name": "Black Panther", + "HP": 100, + "MP": 6, + "AP": 1, + "meleeDamage": 10, + "rangeCombatDamage": 10, + "rangeCombatReach": 3 + }, + { + "characterID": 11, + "name": "Thor", + "HP": 100, + "MP": 2, + "AP": 2, + "meleeDamage": 10, + "rangeCombatDamage": 30, + "rangeCombatReach": 5 + }, + { + "characterID": 12, + "name": "Captain Marvel", + "HP": 100, + "MP": 6, + "AP": 1, + "meleeDamage": 10, + "rangeCombatDamage": 10, + "rangeCombatReach": 3 + }, + { + "characterID": 13, + "name": "Groot", + "HP": 100, + "MP": 2, + "AP": 2, + "meleeDamage": 10, + "rangeCombatDamage": 30, + "rangeCombatReach": 5 + }, + { + "characterID": 14, + "name": "Starlord", + "HP": 100, + "MP": 6, + "AP": 1, + "meleeDamage": 10, + "rangeCombatDamage": 10, + "rangeCombatReach": 3 + }, + { + "characterID": 15, + "name": "Gamora", + "HP": 100, + "MP": 6, + "AP": 1, + "meleeDamage": 10, + "rangeCombatDamage": 10, + "rangeCombatReach": 3 + }, + { + "characterID": 16, + "name": "Ant Man", + "HP": 100, + "MP": 2, + "AP": 2, + "meleeDamage": 10, + "rangeCombatDamage": 30, + "rangeCombatReach": 5 + }, + { + "characterID": 17, + "name": "Vision", + "HP": 100, + "MP": 6, + "AP": 1, + "meleeDamage": 10, + "rangeCombatDamage": 10, + "rangeCombatReach": 3 + }, + { + "characterID": 18, + "name": "Deadpool", + "HP": 100, + "MP": 2, + "AP": 2, + "meleeDamage": 10, + "rangeCombatDamage": 30, + "rangeCombatReach": 5 + }, + { + "characterID": 19, + "name": "Loki", + "HP": 100, + "MP": 6, + "AP": 1, + "meleeDamage": 10, + "rangeCombatDamage": 10, + "rangeCombatReach": 3 + }, + { + "characterID": 20, + "name": "Silver Surfer", + "HP": 100, + "MP": 6, + "AP": 1, + "meleeDamage": 10, + "rangeCombatDamage": 10, + "rangeCombatReach": 3 + }, + { + "characterID": 21, + "name": "Mantis", + "HP": 100, + "MP": 2, + "AP": 2, + "meleeDamage": 10, + "rangeCombatDamage": 30, + "rangeCombatReach": 5 + }, + { + "characterID": 22, + "name": "Ghost Rider", + "HP": 100, + "MP": 6, + "AP": 1, + "meleeDamage": 10, + "rangeCombatDamage": 10, + "rangeCombatReach": 3 + }, + { + "characterID": 23, + "name": "Jesica Jones", + "HP": 100, + "MP": 2, + "AP": 2, + "meleeDamage": 10, + "rangeCombatDamage": 30, + "rangeCombatReach": 5 + }, + { + "characterID": 24, + "name": "Scarlet Witch", + "HP": 100, + "MP": 6, + "AP": 1, + "meleeDamage": 10, + "rangeCombatDamage": 10, + "rangeCombatReach": 3 + } + ] + } + """; + + ObjectMapper mapper; + + @BeforeProperty + void beforeProperty() { + mapper = new ObjectMapper(); + } + + @Property + void characterConfigsAreDeserializedProperly(@ForAll("CharacterConfigs") CharacterConfig config) + throws JsonProcessingException { + var jsonRepresentingCharacterConfig = getJsonOfCharacterConfig(config); + assertThat(mapper.readValue(jsonRepresentingCharacterConfig, CharacterConfig.class)) + .isEqualTo(config); + } + + + @Property + void characterConfigsAreSerializedProperly(@ForAll("CharacterConfigs") CharacterConfig config) + throws JsonProcessingException { + var jsonRepresentingCharacterConfig = getJsonOfCharacterConfig(config); + assertThat(mapper.writeValueAsString(config)) + .isEqualTo(jsonRepresentingCharacterConfig); + } + + @Provide("CharacterConfigs") + Arbitrary characterConfigs() { + HashSet usedIDs = new HashSet<>(); + HashSet usedNames = new HashSet<>(); + + return characterProperties() + .filter(property -> usedIDs.add(property.characterID)) + .filter(property -> usedNames.add(property.name)) + .collect(list -> list.size() >= ThreadLocalRandom.current().nextInt(1999) + 1) + .map(list -> { + var config = new CharacterConfig(); + config.characters = list.toArray(new CharacterProperties[0]); + return config; + }); + } + + + @Provide("CharacterProperties") + Arbitrary characterProperties() { + return Combinators.combine( + Arbitraries.integers() + .greaterOrEqual(0) + .tuple5(), + Arbitraries.integers() + .greaterOrEqual(0) + .tuple2(), + Arbitraries.strings() + .alpha() + .withChars(' ') + .ofMinLength(3) + .ofMaxLength(3)) + .as((fiveInts, twoInts, name) -> { + var properties = new CharacterProperties(); + properties.characterID = fiveInts.get1(); + properties.name = name; + properties.HP = fiveInts.get2(); + properties.MP = fiveInts.get3(); + properties.AP = fiveInts.get4(); + properties.meleeDamage = fiveInts.get5(); + properties.rangedDamage = twoInts.get1(); + properties.attackRange = twoInts.get2(); + return properties; + }); + } + + + private String getJsonOfProperties( + Integer id, + String name, + Integer HP, + Integer MP, + Integer AP, + Integer meleeDamage, + Integer rangeCombatDamage, + Integer rangeCombatReach + ) { + return String.format(""" + { + "characterID": %d, + "name": "%s", + "HP": %d, + "MP": %d, + "AP": %d, + "meleeDamage": %d, + "rangeCombatDamage": %d, + "rangeCombatReach": %d + } + """.replace(" ", ""), + id, + name, + HP, + MP, + AP, + meleeDamage, + rangeCombatDamage, + rangeCombatReach).replace("\n", ""); + } + + String getJsonOfCharacterConfig(CharacterConfig config) { + var jsonRepresentingCharacterConfig = new StringBuilder(""" + { + "characters":[ + """.replace("\n", "")); + + for (CharacterProperties prop: config.characters) { + jsonRepresentingCharacterConfig.append(getJsonOfProperties( + prop.characterID, + prop.name, + prop.HP, + prop.MP, + prop.AP, + prop.meleeDamage, + prop.rangedDamage, + prop.attackRange + )).append(','); + } + + jsonRepresentingCharacterConfig.setLength(jsonRepresentingCharacterConfig.length() - 1); + return jsonRepresentingCharacterConfig.append(']').append('}').toString(); + + + } +} diff --git a/src/test/java/uulm/teamname/marvelous/gamelibrary/json/config/CharacterPropertiesJSONTest.java b/src/test/java/uulm/teamname/marvelous/gamelibrary/json/config/CharacterPropertiesJSONTest.java new file mode 100644 index 0000000..10ab0d7 --- /dev/null +++ b/src/test/java/uulm/teamname/marvelous/gamelibrary/json/config/CharacterPropertiesJSONTest.java @@ -0,0 +1,124 @@ +package uulm.teamname.marvelous.gamelibrary.json.config; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import net.jqwik.api.*; +import net.jqwik.api.constraints.*; +import net.jqwik.api.lifecycle.BeforeProperty; + +import static org.mockito.Mockito.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.assertj.core.api.Assertions.*; + +class CharacterPropertiesJSONTest { + + ObjectMapper mapper; + + @BeforeProperty + void beforeProperty() { + mapper = new ObjectMapper(); + } + + @Property + void characterPropertiesGetDeserializedProperly( + @ForAll("Positive Integers") Integer id, + @ForAll @NotBlank @StringLength(min = 3, max = 50) @AlphaChars @Chars({' '}) String name, + @ForAll ("Positive Integers") Integer HP, + @ForAll ("Positive Integers") Integer MP, + @ForAll ("Positive Integers") Integer AP, + @ForAll ("Positive Integers") Integer meleeDamage, + @ForAll ("Positive Integers") Integer rangeCombatDamage, + @ForAll ("Positive Integers") Integer rangeCombatReach) throws JsonProcessingException { + + var values = getPropertiesAndJson( + id, + name, + HP, + MP, + AP, + meleeDamage, + rangeCombatDamage, + rangeCombatReach); + + + assertThat(mapper.readValue(values.get2(), CharacterProperties.class)) + .isEqualTo(values.get1()); + } + + + @Property + void characterPropertiesGetSerializedProperly( + @ForAll("Positive Integers") Integer id, + @ForAll @NotBlank @StringLength(min = 3, max = 50) @AlphaChars @Chars({' '}) String name, + @ForAll ("Positive Integers") Integer HP, + @ForAll ("Positive Integers") Integer MP, + @ForAll ("Positive Integers") Integer AP, + @ForAll ("Positive Integers") Integer meleeDamage, + @ForAll ("Positive Integers") Integer rangeCombatDamage, + @ForAll ("Positive Integers") Integer rangeCombatReach) throws JsonProcessingException { + + var values = getPropertiesAndJson( + id, + name, + HP, + MP, + AP, + meleeDamage, + rangeCombatDamage, + rangeCombatReach); + + + assertThat(mapper.writeValueAsString(values.get1())) + .isEqualTo(values.get2()); + } + + @Provide("Positive Integers") + Arbitrary positiveIntegers() { + return Arbitraries.integers().greaterOrEqual(0); + } + + private Tuple.Tuple2 getPropertiesAndJson( + Integer id, + String name, + Integer HP, + Integer MP, + Integer AP, + Integer meleeDamage, + Integer rangeCombatDamage, + Integer rangeCombatReach + ) { + var properties = new CharacterProperties(); + properties.characterID = id; + properties.name = name; + properties.HP = HP; + properties.MP = MP; + properties.AP = AP; + properties.meleeDamage = meleeDamage; + properties.rangedDamage = rangeCombatDamage; + properties.attackRange = rangeCombatReach; + + var jsonRepresentingProperties = String.format(""" + { + "characterID": %d, + "name": "%s", + "HP": %d, + "MP": %d, + "AP": %d, + "meleeDamage": %d, + "rangeCombatDamage": %d, + "rangeCombatReach": %d + } + """.replace(" ", ""), + id, + name, + HP, + MP, + AP, + meleeDamage, + rangeCombatDamage, + rangeCombatReach).replace("\n", ""); + + return Tuple.of(properties, jsonRepresentingProperties); + } + +}