Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,19 @@ dependencies {

testImplementation(mn.junit.jupiter.api)
testImplementation(mn.junit.jupiter.params)
testRuntimeOnly(mn.junit.jupiter.engine)
testImplementation(mn.testcontainers.core)
testImplementation(mn.testcontainers.mariadb)
testImplementation(mn.micronaut.test.rest.assured)
testImplementation(mn.micronaut.validation)
testImplementation(mn.micronaut.test.resources.extensions.core)
testImplementation(mn.micronaut.test.resources.extensions.junit.platform)
// Faker library for JUnit tests
testImplementation(libs.testcontainers.junit)
testImplementation(libs.datafaker)
testImplementation(libs.hibernate.validator)
testImplementation(libs.jakarta.validation)

testRuntimeOnly(mn.junit.jupiter.engine)
}

application {
Expand Down
5 changes: 5 additions & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,18 @@ dependencyResolutionManagement {
version("uuid.creator", "6.1.1")
version("datafaker", "2.4.2")
version("jetbrains.annotation", "26.0.2")
version("hibernate.validator", "9.0.1.Final")
version("jakarta.validation", "3.1.1")

library("uuid.creator", "com.github.f4b6a3", "uuid-creator").versionRef("uuid.creator")
library("vulpes.api", "net.onelitefeather", "vulpes-model").versionRef("vulpes.model")
library("jetbrains.annotation", "org.jetbrains", "annotations").versionRef("jetbrains.annotation")
library("datafaker", "net.datafaker", "datafaker").versionRef("datafaker")
library("testcontainers.junit", "org.testcontainers", "junit-jupiter").withoutVersion()

library("hibernate.validator", "org.hibernate.validator", "hibernate-validator").versionRef("hibernate.validator")
library("jakarta.validation", "jakarta.validation", "jakarta.validation-api").versionRef("jakarta.validation")

plugin("micronaut.application", "io.micronaut.application").versionRef("micronaut")
plugin("micronaut.aot", "io.micronaut.aot").versionRef("micronaut")
plugin("micronaut.test-resources", "io.micronaut.test-resources").versionRef("micronaut")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
import io.micronaut.core.annotation.Introspected;
import io.micronaut.serde.annotation.Serdeable;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Positive;
import jakarta.validation.constraints.PositiveOrZero;
import net.onelitefeather.vulpes.api.model.AttributeEntity;

import java.util.UUID;
Expand All @@ -12,10 +15,10 @@
@Introspected
public record AttributeModelDTO(
@Schema(description = "ID of the attribute", requiredMode = Schema.RequiredMode.NOT_REQUIRED) UUID id,
@Schema(description = "The name for the ui", requiredMode = Schema.RequiredMode.REQUIRED) String uiName,
@Schema(description = "The name which represents the variable after the generation", requiredMode = Schema.RequiredMode.REQUIRED) String variableName,
@Schema(description = "Default value of the attribute", requiredMode = Schema.RequiredMode.REQUIRED) double defaultValue,
@Schema(description = "Maximum value of the attribute", requiredMode = Schema.RequiredMode.REQUIRED) double maximumValue
@Schema(description = "The name for the ui", requiredMode = Schema.RequiredMode.REQUIRED) @NotBlank String uiName,
@Schema(description = "The name which represents the variable after the generation", requiredMode = Schema.RequiredMode.REQUIRED) @NotBlank String variableName,
@Schema(description = "Default value of the attribute", requiredMode = Schema.RequiredMode.REQUIRED) @PositiveOrZero double defaultValue,
@Schema(description = "Maximum value of the attribute", requiredMode = Schema.RequiredMode.REQUIRED) @Positive double maximumValue
) {
public AttributeEntity toAttributeModel() {
return new AttributeEntity(id, uiName, variableName, defaultValue, maximumValue);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

import io.micronaut.serde.annotation.Serdeable;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.annotation.Nullable;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.PositiveOrZero;
import net.onelitefeather.vulpes.api.model.FontEntity;

import java.util.List;
Expand All @@ -12,14 +15,14 @@
@Serdeable
public record FontModelDTO(
@Schema(description = "ID of the mode", requiredMode = Schema.RequiredMode.NOT_REQUIRED) UUID id,
@Schema(description = "Model Name for the ui", requiredMode = Schema.RequiredMode.REQUIRED) String uiName,
@Schema(description = "Name in the UI", requiredMode = Schema.RequiredMode.REQUIRED) String variableName,
@Schema(description = "Which provider should be used", requiredMode = Schema.RequiredMode.REQUIRED) String provider,
@Schema(description = "Internal mapper variable", requiredMode = Schema.RequiredMode.REQUIRED) String mapper,
@Schema(description = "The path to the texture", requiredMode = Schema.RequiredMode.REQUIRED) String texturePath,
@Schema(description = "The comment", requiredMode = Schema.RequiredMode.REQUIRED) String comment,
@Schema(description = "The ascent property", requiredMode = Schema.RequiredMode.REQUIRED) int ascent,
@Schema(description = "The height property", requiredMode = Schema.RequiredMode.REQUIRED) int height,
@Schema(description = "Model Name for the ui", requiredMode = Schema.RequiredMode.REQUIRED) @NotBlank String uiName,
@Schema(description = "Name in the UI", requiredMode = Schema.RequiredMode.REQUIRED) @NotBlank String variableName,
@Schema(description = "Which provider should be used", requiredMode = Schema.RequiredMode.REQUIRED) @NotBlank String provider,
@Schema(description = "Internal mapper variable", requiredMode = Schema.RequiredMode.REQUIRED) @NotBlank String mapper,
@Schema(description = "The path to the texture", requiredMode = Schema.RequiredMode.REQUIRED) @NotBlank String texturePath,
@Schema(description = "The comment", requiredMode = Schema.RequiredMode.REQUIRED) @Nullable String comment,
@Schema(description = "The ascent property", requiredMode = Schema.RequiredMode.REQUIRED) @PositiveOrZero int ascent,
@Schema(description = "The height property", requiredMode = Schema.RequiredMode.REQUIRED) @PositiveOrZero int height,
@Schema(description = "The chars which are overwritten", requiredMode = Schema.RequiredMode.NOT_REQUIRED) List<String> chars
) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
import io.micronaut.core.annotation.Introspected;
import io.micronaut.serde.annotation.Serdeable;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Positive;
import jakarta.validation.constraints.PositiveOrZero;
import net.onelitefeather.vulpes.api.model.ItemEntity;

import java.util.List;
Expand All @@ -26,14 +29,14 @@
@Serdeable
public record ItemModelDTO(
@Schema(description = "ID of the Model", requiredMode = Schema.RequiredMode.NOT_REQUIRED) UUID id,
@Schema(description = "Name in the UI", requiredMode = Schema.RequiredMode.REQUIRED) String uiName,
@Schema(description = "Variable name for the entity", requiredMode = Schema.RequiredMode.REQUIRED) String variableName,
@Schema(description = "Name in the UI", requiredMode = Schema.RequiredMode.REQUIRED) @NotBlank String uiName,
@Schema(description = "Variable name for the entity", requiredMode = Schema.RequiredMode.REQUIRED) @NotBlank String variableName,
@Schema(description = "Internal description of the item", requiredMode = Schema.RequiredMode.REQUIRED) String comment,
@Schema(description = "The display name of the item", requiredMode = Schema.RequiredMode.REQUIRED) String displayName,
@Schema(description = "The material from the item", requiredMode = Schema.RequiredMode.REQUIRED) String material,
@Schema(description = "The group to identify their basic usage", requiredMode = Schema.RequiredMode.REQUIRED) String group,
@Schema(description = "Integer which refers to the customModelData index", requiredMode = Schema.RequiredMode.REQUIRED) int customModelData,
@Schema(description = "The amount of the item", requiredMode = Schema.RequiredMode.REQUIRED) int amount,
@Schema(description = "The display name of the item", requiredMode = Schema.RequiredMode.REQUIRED) @NotBlank String displayName,
@Schema(description = "The material from the item", requiredMode = Schema.RequiredMode.REQUIRED) @NotBlank String material,
@Schema(description = "The group to identify their basic usage", requiredMode = Schema.RequiredMode.REQUIRED) @NotBlank String group,
@Schema(description = "Integer which refers to the customModelData index", requiredMode = Schema.RequiredMode.REQUIRED) @PositiveOrZero int customModelData,
@Schema(description = "The amount of the item", requiredMode = Schema.RequiredMode.REQUIRED) @Positive int amount,
@Schema(description = "The given enchantments", requiredMode = Schema.RequiredMode.NOT_REQUIRED) Map<String, Short> enchantments,
@Schema(description = "The given lore from the item", requiredMode = Schema.RequiredMode.NOT_REQUIRED) List<String> lore,
@Schema(description = "The flags which the item should have", requiredMode = Schema.RequiredMode.NOT_REQUIRED) List<String> flags
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@
import io.micronaut.core.annotation.Introspected;
import io.micronaut.serde.annotation.Serdeable;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import net.onelitefeather.vulpes.api.model.NotificationEntity;

@Schema(requiredProperties = {
"uiName",
"variableName",
"description",
"comment",
"material",
"frameType",
"title"
Expand All @@ -20,24 +22,25 @@
@Serdeable
public record NotificationModelDTO(
@Schema(description = "ID of the notification", requiredMode = Schema.RequiredMode.NOT_REQUIRED) UUID id,
@Schema(description = "Model variableName for the UI", requiredMode = Schema.RequiredMode.REQUIRED) String uiName,
@Schema(description = "Name in the UI", requiredMode = Schema.RequiredMode.REQUIRED) String variableName,
@Schema(description = "Description of the notification", requiredMode = Schema.RequiredMode.REQUIRED) String description,
@Schema(description = "Material identifier", requiredMode = Schema.RequiredMode.REQUIRED) String material,
@Schema(description = "Type of frame", requiredMode = Schema.RequiredMode.REQUIRED) String frameType,
@Schema(description = "Title of the notification", requiredMode = Schema.RequiredMode.REQUIRED) String title
@Schema(description = "Model variableName for the UI", requiredMode = Schema.RequiredMode.REQUIRED) @NotBlank String uiName,
@Schema(description = "Name in the UI", requiredMode = Schema.RequiredMode.REQUIRED) @NotBlank String variableName,
@Schema(description = "Comment of the notification", requiredMode = Schema.RequiredMode.REQUIRED) String comment,
@Schema(description = "Material identifier", requiredMode = Schema.RequiredMode.REQUIRED) @NotBlank String material,
@Schema(description = "Type of frame", requiredMode = Schema.RequiredMode.REQUIRED) @NotBlank String frameType,
@Schema(description = "Title of the notification", requiredMode = Schema.RequiredMode.REQUIRED) @NotBlank String title
) {

/**
* Converts this DTO to a {@link NotificationEntity}.
*
* @return a new {@link NotificationEntity} instance with the data from this DTO
*/
public @NotNull NotificationEntity toNotificationModel() {
return new NotificationEntity(
this.id,
uiName,
variableName,
description,
comment,
material,
frameType,
title
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import io.micronaut.serde.annotation.Serdeable;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.media.Schema.RequiredMode;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import net.onelitefeather.vulpes.api.model.sound.SoundEventEntity;

Expand Down Expand Up @@ -37,10 +38,10 @@
@Serdeable
public record SoundEventDTO(
@Schema(description = "Id of the Model", requiredMode = RequiredMode.REQUIRED) UUID id,
@Schema(description = "Name to display it in the ui", requiredMode = RequiredMode.REQUIRED) String uiName,
@Schema(description = "The name which is used for the variable generation", requiredMode = RequiredMode.REQUIRED) String variableName,
@Schema(description = "They key of the sound", requiredMode = RequiredMode.REQUIRED) String keyName,
@Schema(description = "The subtitle which is display when the sound is played", requiredMode = RequiredMode.REQUIRED) String subTitle
@Schema(description = "Name to display it in the ui", requiredMode = RequiredMode.REQUIRED) @NotBlank String uiName,
@Schema(description = "The name which is used for the variable generation", requiredMode = RequiredMode.REQUIRED) @NotBlank String variableName,
@Schema(description = "They key of the sound", requiredMode = RequiredMode.REQUIRED) @NotBlank String keyName,
@Schema(description = "The subtitle which is display when the sound is played", requiredMode = RequiredMode.REQUIRED) @NotBlank String subTitle
) {
/**
* Converts this DTO to a {@link SoundEventEntity}.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,38 @@
import io.micronaut.core.annotation.Introspected;
import io.micronaut.serde.annotation.Serdeable;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Positive;
import jakarta.validation.constraints.PositiveOrZero;
import net.onelitefeather.vulpes.api.model.sound.SoundFileSource;

import java.util.UUID;

@Schema(
requiredProperties = {
"name",
"volume",
"pitch",
"weight",
"stream",
"attenuationDistance",
"preload",
"type"
}
)
@Introspected
@Serdeable
public record SoundFileSourceDTO(
UUID id,
String name,
float volume,
float pitch,
int weight,
@NotBlank String name,
@PositiveOrZero float volume,
@PositiveOrZero float pitch,
@Positive int weight,
boolean stream,
int attenuationDistance,
@Positive int attenuationDistance,
boolean preload,
String type
@NotBlank String type
) {

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package net.onelitefeather.vulpes.backend.domain;

import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validation;
import jakarta.validation.Validator;
import jakarta.validation.ValidatorFactory;
import org.hibernate.validator.messageinterpolation.ParameterMessageInterpolator;
import org.junit.jupiter.api.BeforeAll;

import java.util.Set;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

public abstract class ValidationTestBase<T> {

protected static Validator validator;

@BeforeAll
static void setupValidator() {
try (ValidatorFactory factory = Validation.byDefaultProvider()
.configure()
.messageInterpolator(new ParameterMessageInterpolator())
.buildValidatorFactory()) {
validator = factory.getValidator();
}
}

/**
* Helper method to validate a DTO and assert that it has a violation on a specific property
*
* @param dto the DTO to validate
* @param propertyName the name of the property to validate
*/
protected void assertViolation(T dto, String propertyName) {
Set<ConstraintViolation<T>> violations = validator.validate(dto);
assertFalse(violations.isEmpty(), "Expected violations for property: " + propertyName);
boolean found = violations.stream().anyMatch(v -> v.getPropertyPath().toString().equals(propertyName));
if (!found) {
throw new AssertionError("No violation found for property: " + propertyName);
}
}

/**
* Helper method to validate a DTO and assert that it has no violations on a specific property
*
* @param dto the DTO to validate
* @param propertyName the name of the property to validate
*/
protected void assertNoViolation(T dto, String propertyName) {
Set<ConstraintViolation<T>> violations = validator.validate(dto);
assertTrue(violations.isEmpty(), "Expected no violations for property: " + propertyName);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package net.onelitefeather.vulpes.backend.domain.attribute.validation;

import net.onelitefeather.vulpes.backend.domain.ValidationTestBase;
import net.onelitefeather.vulpes.backend.domain.attribute.AttributeModelDTO;
import org.junit.jupiter.api.Test;

import java.util.UUID;

class AttributeModelDTOValidationTest extends ValidationTestBase<AttributeModelDTO> {

@Test
void testEmptyUiNameValidationFail() {
AttributeModelDTO dto = new AttributeModelDTO(
UUID.randomUUID(),
"",
"empty_value", // invalid
1.0,
5.0
);

assertViolation(dto, "uiName");
}

@Test
void testDefaultValueValidationFail() {
AttributeModelDTO dto = new AttributeModelDTO(
UUID.randomUUID(),
"Speed",
"playerSpeed",
-1.0,
5.0
);

assertViolation(dto, "defaultValue");
}

@Test
void testMaxValueValidationFail() {
AttributeModelDTO dto = new AttributeModelDTO(
UUID.randomUUID(),
"Speed",
"playerSpeed",
0.0,
0.0 // must be strictly positive
);

assertViolation(dto, "maximumValue");
}

@Test
void testEmptyVariableNameValidationFail() {
AttributeModelDTO dto = new AttributeModelDTO(
UUID.randomUUID(),
"Speed",
"",
0.0,
5.0
);

assertViolation(dto, "variableName");
}
}
Loading
Loading