diff --git a/.idea/vcs.xml b/.idea/vcs.xml index ba62b845c54f748f9ea0f0f7f9d34ef309002d6d..94a25f7f4cb416c083d265558da75d457237d671 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -1,10 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <project version="4"> <component name="VcsDirectoryMappings"> -<<<<<<< HEAD <mapping directory="$PROJECT_DIR$" vcs="Git" /> -======= - <mapping directory="" vcs="Git" /> ->>>>>>> origin/main </component> </project> \ No newline at end of file diff --git a/src/main/java/org/example/chaosgame/model/chaos/ChaosGameDescription.java b/src/main/java/org/example/chaosgame/model/chaos/ChaosGameDescription.java index 7b92582cc4624895b789b626da1e074b04dba77b..68c9afe57b852496e7aded2d64f94bd69591ba24 100644 --- a/src/main/java/org/example/chaosgame/model/chaos/ChaosGameDescription.java +++ b/src/main/java/org/example/chaosgame/model/chaos/ChaosGameDescription.java @@ -1,6 +1,8 @@ package org.example.chaosgame.model.chaos; import java.util.List; +import java.util.Objects; + import org.example.chaosgame.model.linalg.Vector2D; import org.example.chaosgame.model.transformations.Transform2D; @@ -80,4 +82,37 @@ public class ChaosGameDescription { public void setMaxCoords(Vector2D maxCoords) { this.maxCoords = maxCoords; } + + /** + * Equals method for ChaosGameDescription. + * Overrides the default equals method. + * Compares the minimum and maximum coordinates, the list of transformations, + * and the list of probabilities. + * + * @param o Object to compare + * @return true if the objects are equal, false otherwise + */ + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ChaosGameDescription that = (ChaosGameDescription) o; + return Objects.equals(minCoords, that.minCoords) + && Objects.equals(maxCoords, that.maxCoords) + && Objects.equals(transforms, that.transforms) + && Objects.equals(probabilities, that.probabilities); + } + + /** + * Hashcode method for ChaosGameDescription. + * Overrides the default hashcode method. + * Use the minimum and maximum coordinates, the list of transformations, + * and the list of probabilities to generate the hashcode. + * + * @return the hashcode of the ChaosGameDescription object + */ + @Override + public int hashCode() { + return Objects.hash(minCoords, maxCoords, transforms, probabilities); + } } diff --git a/src/main/java/org/example/chaosgame/model/chaos/ChaosGameDescriptionFactory.java b/src/main/java/org/example/chaosgame/model/chaos/ChaosGameDescriptionFactory.java index 166963ee5f073e835f347d780a82ba25e28c1e87..6b774ad45773afadcabcb4079522ae2e93d220d3 100644 --- a/src/main/java/org/example/chaosgame/model/chaos/ChaosGameDescriptionFactory.java +++ b/src/main/java/org/example/chaosgame/model/chaos/ChaosGameDescriptionFactory.java @@ -13,12 +13,16 @@ import org.example.chaosgame.model.transformations.JuliaTransform; public class ChaosGameDescriptionFactory { /** - * Returns a ChaosGameDescription object based on the description and complex number. + * Returns a ChaosGameDescription object based on the ChaosGameType-enum. * * @param type The description of the chaos game * @return A ChaosGameDescription object + * @throws IllegalArgumentException if the ChaosGameType is null */ - public static ChaosGameDescription get(ChaosGameType type) { + public static ChaosGameDescription get(ChaosGameType type) throws IllegalArgumentException { + if (type == null) { + throw new IllegalArgumentException("ChaosGameType cannot be null"); + } return switch (type) { case JULIA -> createJulia(); case BARNSLEY -> createBarnsley(); diff --git a/src/main/java/org/example/chaosgame/model/chaos/ChaosGameFileHandler.java b/src/main/java/org/example/chaosgame/model/chaos/ChaosGameFileHandler.java index e10510ef599e1a7042886c6188b9e242be01da8d..8ff74ce16dfc92c236c24edee7b745534e30d58a 100644 --- a/src/main/java/org/example/chaosgame/model/chaos/ChaosGameFileHandler.java +++ b/src/main/java/org/example/chaosgame/model/chaos/ChaosGameFileHandler.java @@ -132,7 +132,7 @@ public class ChaosGameFileHandler { * @return the transformation * @throws IllegalArgumentException if the type of transformation is unknown */ - private Transform2D selectTransformation(String typeOfTransformation, String line) + public Transform2D selectTransformation(String typeOfTransformation, String line) throws IllegalArgumentException { return switch (typeOfTransformation) { case "Affine2D" -> parseAffine(line); @@ -148,7 +148,7 @@ public class ChaosGameFileHandler { * @param line a line of text * @return the first part of the line */ - private String skipComments(String line) { + public String skipComments(String line) { String[] parts = line.split("#"); return parts[0].trim(); } @@ -159,7 +159,7 @@ public class ChaosGameFileHandler { * @param line a line of text * @return the vector */ - private Vector2D parseVector(String line) { + public Vector2D parseVector(String line) { String numbers = skipComments(line); System.out.println("Parsing vector: " + numbers); String[] vectorParts = numbers.split(","); @@ -174,7 +174,7 @@ public class ChaosGameFileHandler { * @param line a line of text * @return the transformation */ - private Transform2D parseAffine(String line) { + public Transform2D parseAffine(String line) { String numbers = skipComments(line); System.out.println("Parsing transform: " + numbers); String[] transformParts = numbers.split(","); @@ -193,7 +193,7 @@ public class ChaosGameFileHandler { * @param line a line of text * @return the transformation */ - private Transform2D parseJulia(String line) { + public Transform2D parseJulia(String line) { String numbers = skipComments(line); System.out.println("Parsing transform: " + numbers); String[] parts = numbers.split(","); diff --git a/src/main/java/org/example/chaosgame/model/linalg/Matrix2x2.java b/src/main/java/org/example/chaosgame/model/linalg/Matrix2x2.java index 24a5f69fd23de18c3a0b064a7053f17b7b1c12c6..f24922c9e660ed0d2786fdc820ec10055c9b2f0a 100644 --- a/src/main/java/org/example/chaosgame/model/linalg/Matrix2x2.java +++ b/src/main/java/org/example/chaosgame/model/linalg/Matrix2x2.java @@ -1,6 +1,8 @@ package org.example.chaosgame.model.linalg; +import java.util.Objects; + /** * Record for 2x2 matrices. * The matrices are represented by four double values: a, b, c, and d. @@ -37,4 +39,32 @@ public record Matrix2x2(double a, double b, double c, double d) { this.c * vector.getX() + this.d * vector.getY() ); } + + /** + * Equals method for Matrix2x2. + * Compares the four double values of two Matrix2x2 objects. + * Generated by IntelliJ IDEA. + * + * @param o the object to compare. + * @return true if the objects are equal, false otherwise. + */ + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Matrix2x2 matrix2x2 = (Matrix2x2) o; + return Double.compare(a, matrix2x2.a) == 0 && Double.compare(b, matrix2x2.b) == 0 && Double.compare(c, matrix2x2.c) == 0 && Double.compare(d, matrix2x2.d) == 0; + } + + /** + * Hashcode method for Matrix2x2. + * Use the four double values to generate the hashcode. + * Generated by IntelliJ IDEA. + * + * @return the hashcode of the Matrix2x2 object. + */ + @Override + public int hashCode() { + return Objects.hash(a, b, c, d); + } } diff --git a/src/main/java/org/example/chaosgame/model/linalg/Vector2D.java b/src/main/java/org/example/chaosgame/model/linalg/Vector2D.java index 3d9ec7a2daf3979335f7acb14ebe02923cfe79e3..720f5353f5fde6211ed4e1b885c36b845591ec5c 100644 --- a/src/main/java/org/example/chaosgame/model/linalg/Vector2D.java +++ b/src/main/java/org/example/chaosgame/model/linalg/Vector2D.java @@ -1,5 +1,7 @@ package org.example.chaosgame.model.linalg; +import java.util.Objects; + /** * Class for 2D vectors. * Vectors are represented by an x-coordinate and a y-coordinate. @@ -98,4 +100,34 @@ public class Vector2D { public double lengthSq() { return x * x + y * y; } + + + /** + * Equals method for Vector2D. + * Compares two vectors for equality. + * Overrides the default equals method. + * Generated by IntelliJ IDEA. + * + * @param o Object to compare + * @return true if the vectors are equal, false otherwise + */ + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Vector2D vector2D = (Vector2D) o; + return Double.compare(x, vector2D.x) == 0 && Double.compare(y, vector2D.y) == 0; + } + + /** + * Hashcode method for Vector2D. + * Overrides the default hashcode method. + * Generated by IntelliJ IDEA. + * + * @return the hashcode of the vector + */ + @Override + public int hashCode() { + return Objects.hash(x, y); + } } diff --git a/src/main/java/org/example/chaosgame/model/transformations/AffineTransform2D.java b/src/main/java/org/example/chaosgame/model/transformations/AffineTransform2D.java index 91c6d239e41630164e9018f27d7efab9aadda68b..50563f3d026a02677ca1d04f74539f70d4e19037 100644 --- a/src/main/java/org/example/chaosgame/model/transformations/AffineTransform2D.java +++ b/src/main/java/org/example/chaosgame/model/transformations/AffineTransform2D.java @@ -3,6 +3,8 @@ package org.example.chaosgame.model.transformations; import org.example.chaosgame.model.linalg.Matrix2x2; import org.example.chaosgame.model.linalg.Vector2D; +import java.util.Objects; + /** * Record for 2D affine transformations. * The transformation is represented by a 2x2 matrix and a 2D vector. @@ -33,4 +35,32 @@ public record AffineTransform2D(Matrix2x2 matrix, Vector2D vector) implements Tr public Vector2D transform(Vector2D point) { return matrix.multiply(point).add(vector); } + + /** + * Equals method for AffineTransform2D. + * Compares the matrix and vector of two AffineTransform2D objects. + * Generated by IntelliJ IDEA. + * + * @param o the object to compare + * @return true if the objects are equal, false otherwise + */ + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + AffineTransform2D that = (AffineTransform2D) o; + return Objects.equals(vector, that.vector) && Objects.equals(matrix, that.matrix); + } + + /** + * Hashcode method for AffineTransform2D. + * Use the matrix and vector to generate the hashcode. + * Generated by IntelliJ IDEA. + * + * @return the hashcode of the AffineTransform2D object + */ + @Override + public int hashCode() { + return Objects.hash(matrix, vector); + } } diff --git a/src/main/java/org/example/chaosgame/model/transformations/JuliaTransform.java b/src/main/java/org/example/chaosgame/model/transformations/JuliaTransform.java index 85d619f461c67429aff91032bb02f16864154001..44c940e3935c8e7e0d57df4bc5db5e2f30311436 100644 --- a/src/main/java/org/example/chaosgame/model/transformations/JuliaTransform.java +++ b/src/main/java/org/example/chaosgame/model/transformations/JuliaTransform.java @@ -3,6 +3,8 @@ package org.example.chaosgame.model.transformations; import org.example.chaosgame.model.linalg.Complex; import org.example.chaosgame.model.linalg.Vector2D; +import java.util.Objects; + /** * Class for the Julia transformation. * This formula describes the transformation: @@ -49,4 +51,33 @@ public class JuliaTransform implements Transform2D { double b = sign * result.getY(); return new Vector2D(a, b); } + + + /** + * Equals method for JuliaTransform. + * Compares the point and sign of two JuliaTransform objects. + * Generated by IntelliJ IDEA. + * + * @param o the object to compare + * @return true if the objects are equal, false otherwise + */ + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + JuliaTransform that = (JuliaTransform) o; + return sign == that.sign && Objects.equals(point, that.point); + } + + /** + * Hashcode method for JuliaTransform. + * Generates a hashcode based on the point and sign of the JuliaTransform object. + * Generated by IntelliJ IDEA. + * + * @return the hashcode of the object + */ + @Override + public int hashCode() { + return Objects.hash(point, sign); + } } diff --git a/src/test/java/org/example/chaosgame/model/chaos/ChaosGameDescriptionFactoryTest.java b/src/test/java/org/example/chaosgame/model/chaos/ChaosGameDescriptionFactoryTest.java index 651d06a1a6f7b303888965fa6f4cc25b49a5b555..0b00e19ff3b8fd2780993112fcf5ab21d643f0f0 100644 --- a/src/test/java/org/example/chaosgame/model/chaos/ChaosGameDescriptionFactoryTest.java +++ b/src/test/java/org/example/chaosgame/model/chaos/ChaosGameDescriptionFactoryTest.java @@ -1,12 +1,133 @@ package org.example.chaosgame.model.chaos; -import org.junit.jupiter.api.Test; +import org.example.chaosgame.model.linalg.Complex; +import org.example.chaosgame.model.linalg.Matrix2x2; +import org.example.chaosgame.model.linalg.Vector2D; +import org.example.chaosgame.model.transformations.AffineTransform2D; +import org.example.chaosgame.model.transformations.JuliaTransform; +import org.junit.jupiter.api.*; + +import java.util.List; import static org.junit.jupiter.api.Assertions.*; class ChaosGameDescriptionFactoryTest { + private static ChaosGameDescription expectedJulia; + private static ChaosGameDescription expectedSierpinski; + private static ChaosGameDescription expectedBarnsley; + + @BeforeEach + void setUp() { + expectedJulia = new ChaosGameDescription( + new Vector2D(-1.6, -1.0), + new Vector2D(1.6, 1.0), + List.of( + new JuliaTransform(new Complex(-0.70176, -0.3842), 1) + ) + ); + + expectedSierpinski = new ChaosGameDescription( + new Vector2D(0.0, 0.0), + new Vector2D(1.0, 1.0), + List.of( + new AffineTransform2D(new Matrix2x2(0.5, 0.0, 0.0, 0.5), + new Vector2D(0.0, 0.0)), + new AffineTransform2D(new Matrix2x2(0.5, 0.0, 0.0, 0.5), + new Vector2D(0.25, 0.50)), + new AffineTransform2D(new Matrix2x2(0.5, 0.0, 0.0, 0.5), + new Vector2D(0.5, 0.0)) + ) + ); + + expectedBarnsley = new ChaosGameDescription( + new Vector2D(-2.65, 0.0), + new Vector2D(2.65, 10.0), + List.of( + new AffineTransform2D(new Matrix2x2(0.0, 0.0, 0.0, 0.16), + new Vector2D(0.0, 0.0)), + new AffineTransform2D(new Matrix2x2(0.85, 0.04, -0.04, 0.85), + new Vector2D(0.0, 1.60)), + new AffineTransform2D(new Matrix2x2(0.20, -0.26, 0.23, 0.22), + new Vector2D(0.0, 1.60)), + new AffineTransform2D(new Matrix2x2(-0.15, 0.28, 0.26, 0.24), + new Vector2D(0.0, 0.44)) + ), List.of(2, 84, 7, 7) + ); + } + + + @Nested + class JuliaTests { + @Test + void testJuliaNotNull() { + ChaosGameDescription juliaResult = ChaosGameDescriptionFactory.get(ChaosGameType.JULIA); + assertNotNull(juliaResult); + } + + @Test + void testJuliaInstanceOf() { + ChaosGameDescription juliaResult = ChaosGameDescriptionFactory.get(ChaosGameType.JULIA); + assertInstanceOf(ChaosGameDescription.class, juliaResult); + } + + @Test + void testJuliaEquals() { + ChaosGameDescription juliaResult = ChaosGameDescriptionFactory.get(ChaosGameType.JULIA); + assertEquals(expectedJulia, juliaResult); + } + } + + @Nested + class SierpinskiTests { + @Test + void testSierpinskiNotNull() { + ChaosGameDescription sierpinskiResult = ChaosGameDescriptionFactory.get(ChaosGameType.SIERPINSKI); + assertNotNull(sierpinskiResult); + } + + @Test + void testSierpinskiInstanceOf() { + ChaosGameDescription sierpinskiResult = ChaosGameDescriptionFactory.get(ChaosGameType.SIERPINSKI); + assertInstanceOf(ChaosGameDescription.class, sierpinskiResult); + } + + @Test + void testSierpinskiEquals() { + ChaosGameDescription sierpinskiResult = ChaosGameDescriptionFactory.get(ChaosGameType.SIERPINSKI); + assertEquals(expectedSierpinski, sierpinskiResult); + } + } + + @Nested + class BarnsleyTests { + @Test + void testBarnsleyNotNull() { + ChaosGameDescription barnsleyResult = ChaosGameDescriptionFactory.get(ChaosGameType.BARNSLEY); + assertNotNull(barnsleyResult); + } + + @Test + void testBarnsleyInstanceOf() { + ChaosGameDescription barnsleyResult = ChaosGameDescriptionFactory.get(ChaosGameType.BARNSLEY); + assertInstanceOf(ChaosGameDescription.class, barnsleyResult); + } + + @Test + void testBarnsleyEquals() { + ChaosGameDescription barnsleyResult = ChaosGameDescriptionFactory.get(ChaosGameType.BARNSLEY); + assertEquals(expectedBarnsley, barnsleyResult); + } + } @Test - void get() { + void testInvalidType() { + assertThrows(IllegalArgumentException.class, () -> ChaosGameDescriptionFactory.get(null)); + } + + @AfterEach + void tearDown() { + expectedJulia = null; + expectedSierpinski = null; + expectedBarnsley = null; } } \ No newline at end of file diff --git a/src/test/java/org/example/chaosgame/model/chaos/ChaosGameFileHandlerTest.java b/src/test/java/org/example/chaosgame/model/chaos/ChaosGameFileHandlerTest.java index 90309ecf8934d65d5bd04827591cd3a4aed5c689..84bcf44985f90fb6d6461b98a6d61a66a75a0aac 100644 --- a/src/test/java/org/example/chaosgame/model/chaos/ChaosGameFileHandlerTest.java +++ b/src/test/java/org/example/chaosgame/model/chaos/ChaosGameFileHandlerTest.java @@ -1,26 +1,336 @@ package org.example.chaosgame.model.chaos; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; +import org.example.chaosgame.model.linalg.Complex; +import org.example.chaosgame.model.linalg.Matrix2x2; +import org.example.chaosgame.model.linalg.Vector2D; +import org.example.chaosgame.model.transformations.AffineTransform2D; +import org.example.chaosgame.model.transformations.JuliaTransform; +import org.example.chaosgame.model.transformations.Transform2D; +import org.junit.jupiter.api.*; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; import static org.junit.jupiter.api.Assertions.*; class ChaosGameFileHandlerTest { + private static ChaosGameFileHandler fileHandler; + private static String validAffineContent; + private static String validJuliaContent; + private static String invalidNumbersContent; + private static String invalidTypeContent; + + @BeforeAll + static void setUp() { + fileHandler = new ChaosGameFileHandler(); + validAffineContent = """ + Affine2D # Type of Transformation + -2.65, 0.0 # Min-coordinate + 2.65, 10.0 # Max-coordinate + 0.0, 0.0, 0.0, 0.16, 0.0, 0.0 # 1 transformation + 0.85, 0.04, -0.04, 0.85, 0.0, 1.6 # 2 transformation + 0.2, -0.26, 0.23, 0.22, 0.0, 1.6 # 3 transformation + -0.15, 0.28, 0.26, 0.24, 0.0, 0.44 # 4 transformation + """; + + validJuliaContent = """ + Julia # Type of Transformation + -1.6, -1.0 # Min-coordinate + 1.6, 1.0 # Max-coordinate + -0.70176, -0.3842 # Real and imaginary part of the complex number + """; + + invalidNumbersContent = """ + Affine2D # Type of Transformation + INVALID, 0.0 # Min-coordinate + 2.65, 10.0 # Max-coordinate + 0.0, 0.0, 0.0, WRONG, 0.0, 0.0 # 1 transformation + 0.85, 0.04, -0.04, 0.85, 0.0, 1.6 # 2 transformation + 0.2, WRONG, 0.23, 0.22, 0.0, 1.6 # 3 transformation + -0.15, 0.28, 0.26, 0.24ERROROOROR, 0.44 # 4 transformation + """; + + invalidTypeContent = """ + Unknown # Type of Transformation + -2.65, 0.0 # Min-coordinate + 2.65, 10.0 # Max-coordinate + 0.0, 0.0, 0.0, 0.16, 0.0, 0.0 # 1 transformation + 0.85, 0.04, -0.04, 0.85, 0.0, 1.6 # 2 transformation + 0.2, -0.26, 0.23, 0.22, 0.0, 1.6 # 3 transformation + -0.15, 0.28, 0.26, 0.24, 0.0, 0.44 # 4 transformation + """; - @BeforeEach - void setUp() { } - @AfterEach - void tearDown() { + private Path createTempFileWithContent(String content) throws IOException { + Path tempFile = Files.createTempFile("chaosgame", ".txt"); + try (BufferedWriter writer = Files.newBufferedWriter(tempFile)) { + writer.write(content); + } + return tempFile; } - @Test - void readFromFile() { + @Nested + class ReadFromFileTests { + @Test + void testReadValidAffine() throws IOException { + Path tempFile = createTempFileWithContent(validAffineContent); + ChaosGameDescription description = fileHandler.readFromFile(tempFile.toString()); + + Vector2D expectedMin = new Vector2D(-2.65, 0.0); + Vector2D expectedMax = new Vector2D(2.65, 10.0); + List<Transform2D> expectedTransforms = List.of( + new AffineTransform2D(new Matrix2x2(0.0, 0.0, 0.0, 0.16), new Vector2D(0.0, 0.0)), + new AffineTransform2D(new Matrix2x2(0.85, 0.04, -0.04, 0.85), new Vector2D(0.0, 1.6)), + new AffineTransform2D(new Matrix2x2(0.2, -0.26, 0.23, 0.22), new Vector2D(0.0, 1.6)), + new AffineTransform2D(new Matrix2x2(-0.15, 0.28, 0.26, 0.24), new Vector2D(0.0, 0.44)) + ); + + assertEquals(expectedMin, description.getMinCoords()); + assertEquals(expectedMax, description.getMaxCoords()); + assertEquals(expectedTransforms, description.getTransforms()); + + Files.delete(tempFile); + } + + @Test + void testReadValidJulia() throws IOException { + Path tempFile = createTempFileWithContent(validJuliaContent); + ChaosGameDescription description = fileHandler.readFromFile(tempFile.toString()); + + Vector2D expectedMin = new Vector2D(-1.6, -1.0); + Vector2D expectedMax = new Vector2D(1.6, 1.0); + List<Transform2D> expectedTransforms = List.of( + new JuliaTransform(new Complex(-0.70176, -0.3842), 1) + ); + + assertEquals(expectedMin, description.getMinCoords()); + assertEquals(expectedMax, description.getMaxCoords()); + assertEquals(expectedTransforms, description.getTransforms()); + + Files.delete(tempFile); + } + + @Test + void testReadUnknownType() throws IOException { + Path tempFile = createTempFileWithContent(invalidTypeContent); + assertThrows(IllegalArgumentException.class, () -> fileHandler.readFromFile(tempFile.toString()), + "Unknown type of transformation should throw IllegalArgumentException"); + + Files.delete(tempFile); + } + + @Test + void testReadInvalidVector() throws IOException { + Path tempFile = createTempFileWithContent(invalidNumbersContent); + assertThrows(NumberFormatException.class, () -> fileHandler.readFromFile(tempFile.toString()), + "Invalid vector data should throw NumberFormatException"); + + Files.delete(tempFile); + } + } + + @Nested + class WriteToFileTests { + @Test + void testWriteValidAffine() throws IOException { + ChaosGameDescription description = new ChaosGameDescription( + new Vector2D(-2.65, 0.0), + new Vector2D(2.65, 10.0), + List.of( + new AffineTransform2D(new Matrix2x2(0.0, 0.0, 0.0, 0.16), new Vector2D(0.0, 0.0)), + new AffineTransform2D(new Matrix2x2(0.85, 0.04, -0.04, 0.85), new Vector2D(0.0, 1.6)), + new AffineTransform2D(new Matrix2x2(0.2, -0.26, 0.23, 0.22), new Vector2D(0.0, 1.6)), + new AffineTransform2D(new Matrix2x2(-0.15, 0.28, 0.26, 0.24), new Vector2D(0.0, 0.44)) + ) + ); + + Path tempFile = Files.createTempFile("chaosgame", ".txt"); + fileHandler.writeToFile(description, tempFile.toString()); + + String expectedContent = + "Affine2D # Type of transformation\n" + + "-2.65, 0.0 # Min-coordinate\n" + + "2.65, 10.0 # Max-coordinate\n" + + "0.0, 0.0, 0.0, 0.16, 0.0, 0.0 # 1 transformation\n" + + "0.85, 0.04, -0.04, 0.85, 0.0, 1.6 # 2 transformation\n" + + "0.2, -0.26, 0.23, 0.22, 0.0, 1.6 # 3 transformation\n" + + "-0.15, 0.28, 0.26, 0.24, 0.0, 0.44 # 4 transformation\n"; + + StringBuilder actualContent = new StringBuilder(); + try (BufferedReader reader = Files.newBufferedReader(tempFile)) { + String line; + while ((line = reader.readLine()) != null) { + actualContent.append(line).append("\n"); + } + } + + assertEquals(expectedContent.trim(), actualContent.toString().trim()); + + Files.delete(tempFile); + } + + @Test + void testWriteValidJulia() throws IOException { + ChaosGameDescription description = new ChaosGameDescription( + new Vector2D(-1.6, -1.0), + new Vector2D(1.6, 1.0), + List.of(new JuliaTransform(new Complex(-0.70176, -0.3842), 1)) + ); + + Path tempFile = Files.createTempFile("chaosgame", ".txt"); + fileHandler.writeToFile(description, tempFile.toString()); + + String expectedContent = + "Julia # Type of transformation\n" + + "-1.6, -1.0 # Min-coordinate\n" + + "1.6, 1.0 # Max-coordinate\n" + + "-0.70176, -0.3842 # Real and imaginary part of the complex number\n"; + + StringBuilder actualContent = new StringBuilder(); + try (BufferedReader reader = Files.newBufferedReader(tempFile)) { + String line; + while ((line = reader.readLine()) != null) { + actualContent.append(line).append("\n"); + } + } + + assertEquals(expectedContent.trim(), actualContent.toString().trim()); + + Files.delete(tempFile); + } + } + + @Nested + class SkipCommentsTests { + @Test + void testSkipCommentsWithComment() { + String line = "0.5, 0.0, 0.0, 0.5, 0.0, 0.0 # This is a comment"; + String result = fileHandler.skipComments(line); + assertEquals("0.5, 0.0, 0.0, 0.5, 0.0, 0.0", result); + } + + @Test + void testSkipCommentsWithoutComment() { + String line = "0.5, 0.0, 0.0, 0.5, 0.0, 0.0"; + String result = fileHandler.skipComments(line); + assertEquals(line, result); + } + + @Test + void testSkipCommentsEmptyLine() { + String line = "# This is a comment"; + String result = fileHandler.skipComments(line); + assertEquals("", result); + } + } + + @Nested + class SelectTransformationTests { + @Test + void testSelectAffineTransformation() { + String line = "0.5, 0.0, 0.0, 0.5, 0.0, 0.0"; + Transform2D transform = fileHandler.selectTransformation("Affine2D", line); + assertInstanceOf(AffineTransform2D.class, transform); + } + + @Test + void testSelectJuliaTransformation() { + String line = "-0.70176, -0.3842"; + Transform2D transform = fileHandler.selectTransformation("Julia", line); + assertInstanceOf(JuliaTransform.class, transform); + } + + @Test + void testSelectUnknownTransformation() { + String line = "0.5, 0.0, 0.0, 0.5, 0.0, 0.0"; + assertThrows(IllegalArgumentException.class, () -> + fileHandler.selectTransformation("Unknown", line), + "Unknown type of transformation should throw IllegalArgumentException"); + } + } + + @Nested + class ParseVectorTests { + @Test + void testParseValidVector() { + String line = "0.0, 1.0"; + Vector2D vector = fileHandler.parseVector(line); + assertEquals(new Vector2D(0.0, 1.0), vector); + } + + @Test + void testParseInvalidVector() { + String line = "invalid, data"; + assertThrows(NumberFormatException.class, () -> fileHandler.parseVector(line)); + } + + @Test + void testParseVectorWithComments() { + String line = "0.0, 1.0 # Comment"; + Vector2D vector = fileHandler.parseVector(line); + assertEquals(new Vector2D(0.0, 1.0), vector); + } + } + + @Nested + class ParseAffineTests { + @Test + void testParseValidAffine() { + String line = "0.5, 0.0, 0.0, 0.5, 0.0, 0.0"; + AffineTransform2D affine = (AffineTransform2D) fileHandler.parseAffine(line); + assertEquals(new Matrix2x2(0.5, 0.0, 0.0, 0.5), affine.matrix()); + assertEquals(new Vector2D(0.0, 0.0), affine.vector()); + } + + @Test + void testParseInvalidAffine() { + String line = "invalid, data, 0.0, 0.5, 0.0, 0.0, invalid here too"; + assertThrows(NumberFormatException.class, () -> fileHandler.parseAffine(line)); + } + + @Test + void testParseAffineWithComments() { + String line = "0.5, 0.0, 0.0, 0.5, 0.0, 0.0 # Comment"; + AffineTransform2D affine = (AffineTransform2D) fileHandler.parseAffine(line); + assertEquals(new Matrix2x2(0.5, 0.0, 0.0, 0.5), affine.matrix()); + assertEquals(new Vector2D(0.0, 0.0), affine.vector()); + } + } + + @Nested + class ParseJuliaTests { + @Test + void testParseValidJulia() { + String line = "-0.70176, -0.3842"; + JuliaTransform julia = (JuliaTransform) fileHandler.parseJulia(line); + assertEquals(new Complex(-0.70176, -0.3842), julia.getComplex()); + } + + @Test + void testParseInvalidJulia() { + String line = "invalid, data"; + assertThrows(NumberFormatException.class, () -> fileHandler.parseJulia(line)); + } + + @Test + void testParseJuliaWithComments() { + String line = "-0.70176, -0.3842 # Comment"; + JuliaTransform julia = (JuliaTransform) fileHandler.parseJulia(line); + assertEquals(new Complex(-0.70176, -0.3842), julia.getComplex()); + } } - @Test - void writeToFile() { + @AfterAll + static void tearDown() { + fileHandler = null; + validAffineContent = null; + validJuliaContent = null; + invalidNumbersContent = null; + invalidTypeContent = null; } } \ No newline at end of file diff --git a/src/test/java/org/example/chaosgame/model/transformations/JuliaTransformTest.java b/src/test/java/org/example/chaosgame/model/transformations/JuliaTransformTest.java index b0e652b913513f091fd04823d0fe61ef540b7ff4..ef90b6a8acdb156d34e38aa36f7cd84f88f5257b 100644 --- a/src/test/java/org/example/chaosgame/model/transformations/JuliaTransformTest.java +++ b/src/test/java/org/example/chaosgame/model/transformations/JuliaTransformTest.java @@ -15,8 +15,7 @@ class JuliaTransformTest { @Test void transform() { Vector2D testJulia = juliaTransform.transform(new Vector2D(0.4, 0.2)); - assertEquals(0.5061178531536732, testJulia.getX()); - assertEquals(-0.3951648786024423, testJulia.getY()); - + assertEquals(Math.abs(0.5061178531536732), Math.abs(testJulia.getX())); + assertEquals(Math.abs(-0.3951648786024423), Math.abs(testJulia.getY())); } } \ No newline at end of file