Skip to content

Commit

Permalink
Feature/tests (#4)
Browse files Browse the repository at this point in the history
* Add criteria

* H13_Tests base class

* Criterion 1

* Criterion 2

* Improve context information

* Change run to onError

* Criterion 3

* Fix gradient domain

* Fix javadoc

* Update createGradient

* Fix javadoc

* Fix H1.1 tests

* H1.2 Tests

* H1.3 Tests

* H1.3 Tests

* H1.3 Tests

* Tests for H2.1

* Tests for H2.2

* Tests for H3.1

* Tests for H3.2

* Increase memory or else tests won't run

* Improve comments

* Tests H4.1

* Fix rubric title

* Draft H4.2

* Tests H4.2

* Fix display name of tests classes

* Tests H4.3

* Tests H5.1

* Improve test cases using mockito

* Tests H6

* Change test package structure to match src code

* Finish H5.2 Tests

* Improve H5.2 and add headless testing

* Split tests into private and public tests

* Update public-tests.yml

* Update privatec-tests.yml

* Fix rubric title and increase timeout for linux

* Add information to not move mouse for test criterion 1 in H5.2

* Remove CI

---------

Co-authored-by: zentox <[email protected]>
  • Loading branch information
zentox and zentox authored Feb 7, 2024
1 parent db27d84 commit ace6bbe
Show file tree
Hide file tree
Showing 54 changed files with 12,137 additions and 48 deletions.
38 changes: 37 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import org.sourcegrade.jagr.launcher.env.Config
import org.sourcegrade.jagr.launcher.env.Executor

plugins {
alias(libs.plugins.jagr)
alias(libs.plugins.algomate)
Expand Down Expand Up @@ -42,6 +45,21 @@ javafx {
modules("javafx.controls", "javafx.graphics", "javafx.base", "javafx.swing")
}

tasks {
test {
jvmArgs(
"-Djava.awt.headless=true",
"-Dtestfx.robot=glass",
"-Dtestfx.headless=true",
"-Dprism.order=sw",
"-Dprism.lcdtext=false",
"-Dprism.subpixeltext=false",
"-Dglass.win.uiScale=100%",
"-Dprism.text=t2k"
)
}
}

jagr {
graders {
val graderPublic by getting {
Expand All @@ -50,11 +68,29 @@ jagr {
configureDependencies {
implementation(libs.bundles.testfx)
}
config.set(
Config(
executor = Executor(
timeoutIndividual = 20000,
timeoutTotal = 300000,
jvmArgs = listOf(
"-Djava.awt.headless=true",
"-Dtestfx.robot=glass",
"-Dtestfx.headless=true",
"-Dprism.order=sw",
"-Dprism.lcdtext=false",
"-Dprism.subpixeltext=false",
"-Dglass.win.uiScale=100%",
"-Dprism.text=t2k"
)
)
)
)
}
val graderPrivate by creating {
parent(graderPublic)
graderName.set("H13-Private")
rubricProviderName.set("h13.H13_RubricProviderPrivate")
rubricProviderName.set("h13.H13_RubricProviderPrivate")
}
}
}
2 changes: 2 additions & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
org.gradle.daemon=false
org.gradle.jvmargs=-Xmx1G
4 changes: 3 additions & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ algoutils-tutor = { module = "org.tudalgo:algoutils-tutor", version.ref = "algou
junit-pioneer = { module = "org.junit-pioneer:junit-pioneer", version = "2.2.0" }
testfx-core = { module = "org.testfx:testfx-core", version.ref = "testfx" }
testfx-junit5 = { module = "org.testfx:testfx-junit5", version.ref = "testfx" }
openjfx-monocle = { module = "org.testfx:openjfx-monocle", version = "jdk-12.0.1+2" }
hamcrest = { module = "org.hamcrest:hamcrest", version = "2.2" }

[bundles]
testfx = ["testfx-core", "testfx-junit5"]
testfx = ["testfx-core", "testfx-junit5", "openjfx-monocle", "hamcrest"]
107 changes: 107 additions & 0 deletions src/graderPrivate/java/h13/noise/H1_2_TestsPrivate.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package h13.noise;

import com.fasterxml.jackson.databind.JsonNode;
import h13.rubric.TutorAssertions;
import h13.util.Links;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.params.ParameterizedTest;
import org.mockito.Mockito;
import org.sourcegrade.jagr.api.rubric.TestForSubmission;
import org.tudalgo.algoutils.tutor.general.assertions.Context;
import org.tudalgo.algoutils.tutor.general.json.JsonParameterSet;
import org.tudalgo.algoutils.tutor.general.json.JsonParameterSetTest;
import org.tudalgo.algoutils.tutor.general.reflections.BasicTypeLink;
import org.tudalgo.algoutils.tutor.general.reflections.MethodLink;
import org.tudalgo.algoutils.tutor.general.reflections.TypeLink;

import java.util.Map;
import java.util.function.Function;

@DisplayName("H1.2 | Lineare Interpolation und Fading-Funktion")
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@TestForSubmission
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class H1_2_TestsPrivate extends H1_Tests {

private SimplePerlinNoise noise;

public static final Map<String, Function<JsonNode, ?>> CONVERTERS = Map.ofEntries(
Map.entry("x1", JsonNode::asDouble),
Map.entry("x2", JsonNode::asDouble),
Map.entry("alpha", JsonNode::asDouble),
Map.entry("t", JsonNode::asDouble),
Map.entry("expectedInterpolate", JsonNode::asDouble),
Map.entry("expectedFade", JsonNode::asDouble)
);

@BeforeAll
public void globalSetup() {
noise = Mockito.mock(SimplePerlinNoise.class, Mockito.CALLS_REAL_METHODS);
}

@Override
public Map<String, String> getContextInformation() {
return Map.ofEntries(
Map.entry("x1", "The first value to interpolate"),
Map.entry("x2", "The second value to interpolate"),
Map.entry("alpha", "The interpolation factor"),
Map.entry("t", "The value to which the fade function will be applied"),
Map.entry("expectedInterpolate", "The expected interpolated value"),
Map.entry("expectedFade", "The expected fading factor")
);
}

@Override
public TypeLink getTypeLink() {
return BasicTypeLink.of(SimplePerlinNoise.class);
}

@DisplayName("Die Methoden interpolate(double, double, double) und fade(double) geben die korrekten Ergebnisse "
+ "zurück.")
@Order(4)
@ParameterizedTest
@JsonParameterSetTest(value = "H1_2_Criterion.json", customConverters = CONVERTERS_FIELD_NAME)
public void testFunctions(JsonParameterSet parameters) {
testInterpolate(parameters);
testFade(parameters);
}

@JsonParameterSetTest(value = "H1_2_Criterion.json", customConverters = CONVERTERS_FIELD_NAME)
private void testInterpolate(JsonParameterSet parameters) {
double x1 = parameters.get("x1");
double x2 = parameters.get("x2");
double alpha = parameters.get("alpha");
double expected = parameters.get("expectedInterpolate");
double actual = noise.interpolate(x1, x2, alpha);

MethodLink methodLink = Links.getMethod(getTypeLink(), "interpolate");
Context context = contextBuilder(methodLink, "testInterpolate")
.add("x1", x1)
.add("x2", x2)
.add("alpha", alpha)
.add("Expected result", expected)
.add("Actual result", actual)
.build();
TutorAssertions.assertEquals(expected, actual, context);
}

@JsonParameterSetTest(value = "H1_2_Criterion.json", customConverters = CONVERTERS_FIELD_NAME)
private void testFade(JsonParameterSet parameters) {
double t = parameters.get("t");
double expected = parameters.get("expectedFade");
double actual = noise.fade(t);

MethodLink methodLink = Links.getMethod(getTypeLink(), "fade");
Context context = contextBuilder(methodLink, "testFade")
.add("t", t)
.add("Expected result", expected)
.add("Actual result", actual)
.build();
TutorAssertions.assertEquals(expected, actual, context);
}
}
136 changes: 136 additions & 0 deletions src/graderPrivate/java/h13/noise/H2_1_TestsPrivate.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package h13.noise;

import com.fasterxml.jackson.databind.JsonNode;
import h13.json.JsonConverters;
import h13.rubric.TutorUtils;
import h13.util.Links;
import javafx.geometry.Point2D;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.params.ParameterizedTest;
import org.mockito.Mockito;
import org.sourcegrade.jagr.api.rubric.TestForSubmission;
import org.tudalgo.algoutils.tutor.general.assertions.Assertions2;
import org.tudalgo.algoutils.tutor.general.assertions.Context;
import org.tudalgo.algoutils.tutor.general.json.JsonParameterSet;
import org.tudalgo.algoutils.tutor.general.json.JsonParameterSetTest;
import org.tudalgo.algoutils.tutor.general.reflections.BasicTypeLink;
import org.tudalgo.algoutils.tutor.general.reflections.FieldLink;
import org.tudalgo.algoutils.tutor.general.reflections.MethodLink;
import org.tudalgo.algoutils.tutor.general.reflections.TypeLink;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.function.Function;

@DisplayName("H2.1 | Permutationstabelle")
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@TestForSubmission
public class H2_1_TestsPrivate extends H2_Tests {

public static final Map<String, Function<JsonNode, ?>> CONVERTERS = Map.ofEntries(
Map.entry("width", JsonNode::asInt),
Map.entry("height", JsonNode::asInt),
Map.entry("gradients", JsonConverters::toGradients),
Map.entry("permutation", JsonConverters::toPermutation),
Map.entry("x", JsonNode::asInt),
Map.entry("y", JsonNode::asInt),
Map.entry("expected", JsonConverters::toGradient)
);

@Override
public Map<String, String> getContextInformation() {
return Map.ofEntries(
Map.entry("width", "The width of the noise domain"),
Map.entry("height", "The height of the noise domain"),
Map.entry("gradients", "The gradients of a noise domain"),
Map.entry("permutation", "The permutation of the improved algorithm"),
Map.entry("x", "The x-coordinate of the gradient"),
Map.entry("y", "The y-coordinate of the gradient"),
Map.entry("expected", "The expected result of the compute method")
);
}

@Override
public TypeLink getTypeLink() {
return BasicTypeLink.of(ImprovedPerlinNoise.class);
}

private ImprovedPerlinNoise createNoise(JsonParameterSet parameters) {
PerlinNoise delegate = Mockito.mock(PerlinNoise.class);
Mockito.when(delegate.getRandomGenerator()).thenReturn(new Random(0));
Mockito.when(delegate.getWidth()).thenReturn(parameters.get("width"));
Mockito.when(delegate.getHeight()).thenReturn(parameters.get("height"));
return new ImprovedPerlinNoise(delegate);
}

@DisplayName("Die Methode createPermutation(Random seed) erstellt eine korrekte Permutationstabelle.")
@Order(8)
@ParameterizedTest
@JsonParameterSetTest(value = "H2_1_Criterion_01.json", customConverters = CONVERTERS_FIELD_NAME)
public void testCreatePermutation(JsonParameterSet parameters) throws Throwable {
ImprovedPerlinNoise noise = createNoise(parameters);
MethodLink methodLink = Links.getMethod(getTypeLink(), "createPermutation");
int[] p = methodLink.invoke(noise, new Random(0));

Context context = contextBuilder(methodLink, "testCreatePermutation")
.build();

Assertions2.assertEquals(ImprovedPerlinNoise.PERMUTATION_SIZE * 2, p.length, context,
result -> "Permutation size is incorrect.");

int[] first = Arrays.copyOf(p, ImprovedPerlinNoise.PERMUTATION_SIZE);

for (int i = 0; i < ImprovedPerlinNoise.PERMUTATION_SIZE; i++) {
Assertions2.assertEquals(i, first[i], context,
result -> "First half is not sorted.");
}
List<Integer> second = Arrays.stream(Arrays.copyOfRange(p, ImprovedPerlinNoise.PERMUTATION_SIZE, p.length))
.boxed()
.toList();
Assertions2.assertTrue(Arrays.stream(first).boxed().toList().containsAll(second), context,
result -> "Second does not contain all elements from 0 to 255.");
List<Integer> secondSorted = new ArrayList<>(second);
secondSorted.sort(Comparator.naturalOrder());
Assertions2.assertNotEquals(secondSorted, second, context,
result -> "Second half is not shuffled.");
}

@DisplayName("Die Methode getGradient(int, int) gibt den korrekten Gradienten an der Koordinate (x, y) zurück.")
@Order(9)
@ParameterizedTest
@JsonParameterSetTest(value = "H2_1_Criterion_02.json", customConverters = CONVERTERS_FIELD_NAME)
public void testGetGradient(JsonParameterSet parameters) {
ImprovedPerlinNoise noise = createNoise(parameters);
MethodLink methodLink = Links.getMethod(getTypeLink(), "getGradient");
Point2D[] gradients = parameters.get("gradients");
FieldLink gradientsLink = Links.getField(getTypeLink().superType().superType(), "gradients");
gradientsLink.set(noise, gradients);
int[] permutation = parameters.get("permutation");
FieldLink permutationLink = Links.getField(getTypeLink(), "p");
permutationLink.set(noise, permutation);

int x = parameters.get("x");
int y = parameters.get("y");

Context context = contextBuilder(methodLink, "testGetGradient")
.add("width", noise.getWidth())
.add("height", noise.getHeight())
.add("gradients", TutorUtils.toString(gradients))
.add("p", Arrays.toString(permutation))
.add("x", x)
.add("y", y)
.build();

Point2D expected = parameters.get("expected");
Point2D actual = noise.getGradient(x, y);
Assertions2.assertEquals(expected, actual, context,
result -> "The gradient g(%s, %s) is incorrect.".formatted(x, y));
}
}
Loading

0 comments on commit ace6bbe

Please sign in to comment.