feat: implemented proper CharacterConfig json stuff

This commit is contained in:
Yannik Bretschneider 2021-06-02 16:10:35 +02:00
parent ea6a178c82
commit b13a7db67b
4 changed files with 549 additions and 3 deletions

View File

@ -2,9 +2,7 @@ package uulm.teamname.marvelous.gamelibrary.json.config;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
import java.util.Collections; import java.util.*;
import java.util.HashMap;
import java.util.Map;
/** /**
* POJO describing the CharacterConfig as defined by the standard document. * 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. * @return a unmodifiable {@link Map}<{@link String}, {@link CharacterProperties}> containing all properties.
* If not yet existent, initialize the Map * If not yet existent, initialize the Map
*/ */
@JsonIgnore
public Map<String, CharacterProperties> getMap() { public Map<String, CharacterProperties> getMap() {
// lazy initialization // lazy initialization
if (propertyMap == null) { if (propertyMap == null) {
@ -31,4 +30,19 @@ public class CharacterConfig {
return unmodifiablePropertyMap; 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;
}
} }

View File

@ -1,11 +1,16 @@
package uulm.teamname.marvelous.gamelibrary.json.config; package uulm.teamname.marvelous.gamelibrary.json.config;
import com.fasterxml.jackson.annotation.JsonProperty; 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}. * Represents properties of a character in the {@link CharacterConfig}.
*/ */
public class CharacterProperties { public class CharacterProperties {
public int characterID;
public String name; public String name;
public int HP; public int HP;
public int MP; public int MP;
@ -15,4 +20,17 @@ public class CharacterProperties {
public int rangedDamage; public int rangedDamage;
@JsonProperty("rangeCombatReach") @JsonProperty("rangeCombatReach")
public int attackRange; 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);
}
} }

View File

@ -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<CharacterConfig> characterConfigs() {
HashSet<Integer> usedIDs = new HashSet<>();
HashSet<String> 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> 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();
}
}

View File

@ -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<Integer> positiveIntegers() {
return Arbitraries.integers().greaterOrEqual(0);
}
private Tuple.Tuple2<CharacterProperties, String> 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);
}
}