From f9fe3fa0823a94ba3819453e513836e0f2fecf90 Mon Sep 17 00:00:00 2001
From: jez04 <david.jezek@post.cz>
Date: Fri, 14 Mar 2025 18:53:24 +0100
Subject: [PATCH] feat: :tada: solution

---
 pom.xml                                       |  32 +-
 src/main/java/lab/Setup.java                  | 167 +----
 src/main/java/lab/data/Score.java             |  55 +-
 src/main/java/lab/game/DeadListener.java      |   2 +-
 src/main/java/lab/game/LochNess.java          |   2 +-
 src/main/java/lab/game/Scene.java             |  19 +-
 src/main/java/lab/gui/App.java                |   5 +-
 src/main/java/lab/gui/GameController.java     |   5 +-
 src/main/java/module-info.java                |   3 +-
 .../jez04/structure/test/AllOfContinue.java   |  39 --
 .../java/jez04/structure/test/ClassExist.java |  44 --
 .../structure/test/ClassStructureTest.java    |  91 ++-
 .../structure/test/ContainsInnerClasses.java  |  70 ---
 .../java/jez04/structure/test/HasMethod.java  |  95 ---
 .../jez04/structure/test/HasProperty.java     |  91 ---
 .../jez04/structure/test/IsDescendatOf.java   |  24 -
 .../jez04/structure/test/IsInterface.java     |  23 -
 .../structure/test/ResourceContains.java      | 102 ----
 .../jez04/structure/test/SrcContains.java     |  54 --
 .../jez04/structure/test/StructureHelper.java | 573 ------------------
 .../structure/test/StructureMatcher.java      |   7 -
 21 files changed, 172 insertions(+), 1331 deletions(-)
 delete mode 100644 src/test/java/jez04/structure/test/AllOfContinue.java
 delete mode 100644 src/test/java/jez04/structure/test/ClassExist.java
 delete mode 100644 src/test/java/jez04/structure/test/ContainsInnerClasses.java
 delete mode 100644 src/test/java/jez04/structure/test/HasMethod.java
 delete mode 100644 src/test/java/jez04/structure/test/HasProperty.java
 delete mode 100644 src/test/java/jez04/structure/test/IsDescendatOf.java
 delete mode 100644 src/test/java/jez04/structure/test/IsInterface.java
 delete mode 100644 src/test/java/jez04/structure/test/ResourceContains.java
 delete mode 100644 src/test/java/jez04/structure/test/SrcContains.java
 delete mode 100644 src/test/java/jez04/structure/test/StructureHelper.java
 delete mode 100644 src/test/java/jez04/structure/test/StructureMatcher.java

diff --git a/pom.xml b/pom.xml
index 59a8ae7..b593796 100644
--- a/pom.xml
+++ b/pom.xml
@@ -11,8 +11,32 @@
 		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 		<maven.compiler.source>21</maven.compiler.source>
 		<maven.compiler.target>21</maven.compiler.target>
+		<lombok.version>1.18.36</lombok.version>
 	</properties>
+	<repositories>
+		<repository>
+			<id>vsb-education-release</id>
+			<url>https://artifactory.cs.vsb.cz/repository/education-releases/</url>
+		</repository>
+		<repository>
+			<id>vsb-education-snapshot</id>
+			<url>https://artifactory.cs.vsb.cz/repository/education-snapshot/</url>
+		</repository>
+	</repositories>
 	<dependencies>
+		<dependency>
+			<groupId>cz.vsb.fei</groupId>
+			<artifactId>kelvin-java-unittest-support</artifactId>
+			<version>[0.0.1-SNAPSHOT,)</version>
+			<scope>test</scope>
+		</dependency>
+		<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
+		<dependency>
+			<groupId>org.projectlombok</groupId>
+			<artifactId>lombok</artifactId>
+			<version>${lombok.version}</version>
+			<scope>provided</scope>
+		</dependency>
 		<!--
 		https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
 		<dependency>
@@ -102,7 +126,13 @@
 				<artifactId>maven-compiler-plugin</artifactId>
 				<version>3.13.0</version>
 				<configuration>
-					<failOnError>false</failOnError>
+					<annotationProcessorPaths>
+						<path>
+							<groupId>org.projectlombok</groupId>
+							<artifactId>lombok</artifactId>
+							<version>${lombok.version}</version>
+						</path>
+					</annotationProcessorPaths>
 				</configuration>
 			</plugin>
 			<plugin>
diff --git a/src/main/java/lab/Setup.java b/src/main/java/lab/Setup.java
index 6716305..9f5e5ed 100644
--- a/src/main/java/lab/Setup.java
+++ b/src/main/java/lab/Setup.java
@@ -2,161 +2,46 @@ package lab;
 
 import lab.storage.DbConnector;
 import lab.storage.ScoreStorageInterface;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Builder.Default;
 
+@Getter
+@AllArgsConstructor
+@lombok.Builder(toBuilder = true)
 public class Setup {
 
+	@Getter
 	private static Setup instance;
 
+	@Default
 	private ScoreStorageInterface scoreStorageInterface = new DbConnector();
-	private double lochnessMinXPopsition;
-	private double lochnessMinYPopsition;
-	private double lochnessMinSpeed;
-	private double lochnessMaxSpeed;
-	private int lochnessMultiplier;
-	private double boatCollisionHeight;
-	private double boatHitPulseX;
-	private double boatHitPulseYMin;
-	private double boatHitPulseYMax;
-
-	private Setup(ScoreStorageInterface scoreStorageInterface, double lochnessMinXPopsition,
-			double lochnessMinYPopsition, double lochnessMinSpeed, double lochnessMaxSpeed, int lochnessMultiplier,
-			double boatCollisionHeight, double boatHitPulseX, double boatHitPulseYMin, double boatHitPulseYMax) {
-		this.scoreStorageInterface = scoreStorageInterface;
-		this.lochnessMinXPopsition = lochnessMinXPopsition;
-		this.lochnessMinYPopsition = lochnessMinYPopsition;
-		this.lochnessMinSpeed = lochnessMinSpeed;
-		this.lochnessMaxSpeed = lochnessMaxSpeed;
-		this.lochnessMultiplier = lochnessMultiplier;
-		this.boatCollisionHeight = boatCollisionHeight;
-		this.boatHitPulseX = boatHitPulseX;
-		this.boatHitPulseYMin = boatHitPulseYMin;
-		this.boatHitPulseYMax = boatHitPulseYMax;
-	}
+	@Default
+	private double lochnessMinXPopsition = 0.5;
+	@Default
+	private double lochnessMinYPopsition = 0.5;
+	@Default
+	private double lochnessMinSpeed = 50;
+	@Default
+	private double lochnessMaxSpeed = 150;
+	@Default
+	private int lochnessMultiplier = 1;
+	@Default
+	private double boatCollisionHeight = 0.25;
+	@Default
+	private double boatHitPulseX = 20;
+	@Default
+	private double boatHitPulseYMin = 50;
+	@Default
+	private double boatHitPulseYMax = 100;
 
 	public static void configure(Setup setting) {
 		instance = setting;
 	}
 
-	public static Setup getInstance() {
-		return instance;
-	}
-
-	public ScoreStorageInterface getScoreStorageInterface() {
-		return scoreStorageInterface;
-	}
-
-	public double getBoatCollisionHeight() {
-		return boatCollisionHeight;
-	}
-
-	public double getBoatHitPulseX() {
-		return boatHitPulseX;
-	}
-
-	public double getBoatHitPulseYMin() {
-		return boatHitPulseYMin;
-	}
-
-	public double getBoatHitPulseYMax() {
-		return boatHitPulseYMax;
-	}
-
-	public int getLochnessMultiplier() {
-		return lochnessMultiplier;
-	}
-
-	public double getLochnessMinXPopsition() {
-		return lochnessMinXPopsition;
-	}
-
-	public double getLochnessMinYPopsition() {
-		return lochnessMinYPopsition;
-	}
-
-	public double getLochnessMinSpeed() {
-		return lochnessMinSpeed;
-	}
-
-	public double getLochnessMaxSpeed() {
-		return lochnessMaxSpeed;
-	}
-
-	public static Builder builder() {
-		return new Builder();
-	}
-
 	public static Setup getInstanceForHardcoreGame() {
 		return builder().lochnessMaxSpeed(500).lochnessMinSpeed(200).lochnessMultiplier(10).lochnessMinYPopsition(0.1)
 				.build();
 	}
 
-	public static class Builder {
-		private ScoreStorageInterface scoreStorageInterface = new DbConnector();
-		private double lochnessMinXPopsition = 0.5;
-		private double lochnessMinYPopsition = 0.5;
-		private double lochnessMinSpeed = 50;
-		private double lochnessMaxSpeed = 150;
-		private int lochnessMultiplier = 1;
-		private double boatCollisionHeight = 0.25;
-		private double boatHitPulseX = 20;
-		private double boatHitPulseYMin = 50;
-		private double boatHitPulseYMax = 100;
-
-		public Builder scoreStorageInterface(ScoreStorageInterface scoreStorageInterface) {
-			this.scoreStorageInterface = scoreStorageInterface;
-			return this;
-		}
-
-		public Builder lochnessMinXPopsition(double lochnessMinXPopsition) {
-			this.lochnessMinXPopsition = lochnessMinXPopsition;
-			return this;
-		}
-
-		public Builder lochnessMinYPopsition(double lochnessMinYPopsition) {
-			this.lochnessMinYPopsition = lochnessMinYPopsition;
-			return this;
-		}
-
-		public Builder lochnessMinSpeed(double lochnessMinSpeed) {
-			this.lochnessMinSpeed = lochnessMinSpeed;
-			return this;
-		}
-
-		public Builder lochnessMaxSpeed(double lochnessMaxSpeed) {
-			this.lochnessMaxSpeed = lochnessMaxSpeed;
-			return this;
-		}
-
-		public Builder lochnessMultiplier(int lochnessMultiplier) {
-			this.lochnessMultiplier = lochnessMultiplier;
-			return this;
-		}
-
-		public Builder boatCollisionHeight(double boatCollisionHeight) {
-			this.boatCollisionHeight = boatCollisionHeight;
-			return this;
-		}
-
-		public Builder boatHitPulseX(double boatHitPulseX) {
-			this.boatHitPulseX = boatHitPulseX;
-			return this;
-		}
-
-		public Builder boatHitPulseYMin(double boatHitPulseYMin) {
-			this.boatHitPulseYMin = boatHitPulseYMin;
-			return this;
-		}
-
-		public Builder boatHitPulseYMax(double boatHitPulseYMax) {
-			this.boatHitPulseYMax = boatHitPulseYMax;
-			return this;
-		}
-
-		public Setup build() {
-			return new Setup(scoreStorageInterface, lochnessMinXPopsition, lochnessMinYPopsition, lochnessMinSpeed,
-					lochnessMaxSpeed, lochnessMultiplier, boatCollisionHeight, boatHitPulseX, boatHitPulseYMin,
-					boatHitPulseYMax);
-		}
-	}
-
 }
diff --git a/src/main/java/lab/data/Score.java b/src/main/java/lab/data/Score.java
index a9993a9..7101102 100644
--- a/src/main/java/lab/data/Score.java
+++ b/src/main/java/lab/data/Score.java
@@ -1,8 +1,18 @@
 package lab.data;
 
-import java.util.Objects;
 import java.util.Random;
 
+import lombok.AllArgsConstructor;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+@Getter
+@Setter
+@AllArgsConstructor
+@EqualsAndHashCode
+@ToString
 public class Score {
 
 	private static final Random RANDOM = new Random();
@@ -10,49 +20,6 @@ public class Score {
 	private String name;
 	private int points;
 	
-	public Score(String name, int points) {
-		this.name = name;
-		this.points = points;
-	}
-
-	public String getName() {
-		return name;
-	}
-
-	public void setName(String name) {
-		this.name = name;
-	}
-
-	public int getPoints() {
-		return points;
-	}
-
-	public void setPoints(int points) {
-		this.points = points;
-	}
-
-	@Override
-	public int hashCode() {
-		return Objects.hash(name, points);
-	}
-
-	@Override
-	public boolean equals(Object obj) {
-		if (this == obj)
-			return true;
-		if (obj == null)
-			return false;
-		if (getClass() != obj.getClass())
-			return false;
-		Score other = (Score) obj;
-		return Objects.equals(name, other.name) && points == other.points;
-	}
-
-	@Override
-	public String toString() {
-		return "Score [name=" + name + ", points=" + points + "]";
-	}
-	
 	public static Score generate() {
 		return new Score(getRandomNick(), RANDOM.nextInt(50, 300));
 	}
diff --git a/src/main/java/lab/game/DeadListener.java b/src/main/java/lab/game/DeadListener.java
index b6c163f..950a557 100644
--- a/src/main/java/lab/game/DeadListener.java
+++ b/src/main/java/lab/game/DeadListener.java
@@ -1,5 +1,5 @@
 package lab.game;
 
 public interface DeadListener {
-	void lochnessDead();
+	void lochnessDead(LochNess lochNess);
 }
diff --git a/src/main/java/lab/game/LochNess.java b/src/main/java/lab/game/LochNess.java
index a9904f6..0766013 100644
--- a/src/main/java/lab/game/LochNess.java
+++ b/src/main/java/lab/game/LochNess.java
@@ -91,7 +91,7 @@ public class LochNess extends WorldEntity implements Collisionable {
 
 	private void fireLochNessDead() {
 		for (DeadListener deadListener : deadListeners) {
-			deadListener.lochnessDead();
+			deadListener.lochnessDead(this);
 		}
 	}
 }
diff --git a/src/main/java/lab/game/Scene.java b/src/main/java/lab/game/Scene.java
index edf26a0..a5481b1 100644
--- a/src/main/java/lab/game/Scene.java
+++ b/src/main/java/lab/game/Scene.java
@@ -1,20 +1,25 @@
 package lab.game;
 
+import java.time.LocalDateTime;
 import java.util.ArrayList;
 import java.util.Comparator;
+import java.util.LinkedList;
 import java.util.List;
 
 import javafx.geometry.Dimension2D;
 import javafx.geometry.Point2D;
 import javafx.scene.canvas.GraphicsContext;
 import lab.Setup;
+import lombok.extern.log4j.Log4j2;
 
+@Log4j2
 public class Scene {
 
 	private Dimension2D size;
 	private List<DrawableSimulable> sceneEntitites;
 	private List<DrawableSimulable> entititesToAdd = new ArrayList<>();
 	private List<DrawableSimulable> entititesToRemove = new ArrayList<>();
+	private List<LochNessDeadLog> lochNessDeadLogs = new LinkedList<>();
 
 	private Boat boat;
 	private Rock rock;
@@ -30,10 +35,22 @@ public class Scene {
 		sceneEntitites.add(rock);
 		sceneEntitites.add(boat);
 		for (int i = 0; i < numberOfMonsters * Setup.getInstance().getLochnessMultiplier(); i++) {
-			sceneEntitites.add(new LochNess(this));
+			LochNess lochNess = new LochNess(this);
+			lochNess.addDeadListener(ln -> lochNessDeadLogs.add(new LochNessDeadLog(LocalDateTime.now(), ln.getPosition())));
+			sceneEntitites.add(lochNess);
 		}
 	}
+	
+	record LochNessDeadLog(LocalDateTime time, Point2D position) {}
 
+	
+	public void printDeadLog() {
+		for (LochNessDeadLog lochNessDeadLog : lochNessDeadLogs) {
+			log.info(lochNessDeadLog);
+		}
+	}
+	
+	
 	public Dimension2D getSize() {
 		return size;
 	}
diff --git a/src/main/java/lab/gui/App.java b/src/main/java/lab/gui/App.java
index 40859ad..ec45080 100644
--- a/src/main/java/lab/gui/App.java
+++ b/src/main/java/lab/gui/App.java
@@ -30,7 +30,7 @@ public class App extends Application {
 	
 	public static void main(String[] args) {
 		log.info("Application lauched");
-		Setup.configure(Setup.getInstanceForHardcoreGame());
+		Setup.configure(Setup.getInstanceForHardcoreGame().toBuilder().boatHitPulseX(-20).build());
 		launch(args);
 	}
 
@@ -81,6 +81,9 @@ public class App extends Application {
 	}
 
 	private void exitProgram(WindowEvent evt) {
+		if(gameController != null) {
+			gameController.stop();
+		}
 		log.info("Exiting game");
 		System.exit(0);
 	}
diff --git a/src/main/java/lab/gui/GameController.java b/src/main/java/lab/gui/GameController.java
index 863489a..9bf7ece 100644
--- a/src/main/java/lab/gui/GameController.java
+++ b/src/main/java/lab/gui/GameController.java
@@ -64,13 +64,13 @@ public class GameController {
 	@FXML
 	void changePosition(ActionEvent event) {
 		LochNess lochNess = new LochNess(scene);
-		lochNess.addDeadListener(() -> log.info("LochNess dead!"));
+		lochNess.addDeadListener(ln -> log.info("LochNess dead!"));
 		lochNess.addDeadListener(this::addDead);
 		scene.add(lochNess);
 
 	}
 	
-	private void addDead() {
+	private void addDead(LochNess lochNess) {
 		deadLochNessCounter++;
 		updateDeadLabel();
 	}
@@ -131,6 +131,7 @@ public class GameController {
 
 	public void stop() {
 		timer.stop();
+		scene.printDeadLog();
 	}
 
 }
diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java
index 0206796..cfa87d7 100644
--- a/src/main/java/module-info.java
+++ b/src/main/java/module-info.java
@@ -4,7 +4,8 @@ module lab04_module {
 	requires javafx.base;
 	requires java.sql;
 	requires org.apache.logging.log4j;
-
+	requires static lombok;
+	
 	opens lab.gui to javafx.fxml;
 	opens lab.data to javafx.base;
 
diff --git a/src/test/java/jez04/structure/test/AllOfContinue.java b/src/test/java/jez04/structure/test/AllOfContinue.java
deleted file mode 100644
index 8eb250b..0000000
--- a/src/test/java/jez04/structure/test/AllOfContinue.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package jez04.structure.test;
-
-import java.util.Arrays;
-import java.util.List;
-
-import org.hamcrest.BaseMatcher;
-import org.hamcrest.Description;
-import org.hamcrest.Matcher;
-
-public class AllOfContinue<T> extends BaseMatcher<T> {
-
-	private final List<Matcher<? super T>> matchers;
-
-    @SafeVarargs
-	public AllOfContinue(Matcher<? super T> ... matchers) {
-        this(Arrays.asList(matchers));
-    }
-
-    public AllOfContinue(List<Matcher<? super T>> matchers) {
-        this.matchers = matchers;
-    }
-
-    @Override
-    public boolean matches(Object o) {
-        for (Matcher<? super T> matcher : matchers) {
-            if (!matcher.matches(o)) {
-//                matcher.describeMismatch(o, mismatch);
-              return false;
-            }
-        }
-        return true;
-    }
-
-    @Override
-    public void describeTo(Description description) {
-        description.appendList("(", " " + "and" + " ", ")", matchers);
-    }
-
-}
diff --git a/src/test/java/jez04/structure/test/ClassExist.java b/src/test/java/jez04/structure/test/ClassExist.java
deleted file mode 100644
index 7e1f9b7..0000000
--- a/src/test/java/jez04/structure/test/ClassExist.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package jez04.structure.test;
-
-import org.hamcrest.Description;
-
-public class ClassExist extends StructureMatcher<String> {
-
-	private String className;
-	private boolean useRegExp;
-	private boolean caseSensitive;
-
-	public ClassExist(String className) {
-		this(className, true, false);
-	}
-
-	public ClassExist(String className, boolean caseSensitive, boolean useRegExp) {
-		this.className = className;
-		this.useRegExp = useRegExp;
-		this.caseSensitive = caseSensitive;
-	}
-
-	@Override
-	public boolean matches(Object actual) {
-		if (useRegExp) {
-			return structureHelper.getAllClasses().stream().anyMatch(
-					c -> caseSensitive ? c.matches(className) : c.toLowerCase().matches(className.toLowerCase()));
-		} else {
-			return structureHelper.getAllClasses().stream().anyMatch(
-					c -> caseSensitive ? c.endsWith(className) : c.toLowerCase().endsWith(className.toLowerCase()));
-		}
-
-	}
-
-	@Override
-	public void describeTo(Description description) {
-		description.appendText(String.format("class/interface with name '%s' comparsion params(%s %s)  exists", className,
-				caseSensitive ? "" : "no case sensitive", useRegExp ? "using regexp" : ""));
-	}
-
-	@Override
-	public void describeMismatch(Object item, Description description) {
-		description.appendValueList("no class match from:\n      ", "\n      ", "", structureHelper.getAllClasses());
-	}
-
-}
diff --git a/src/test/java/jez04/structure/test/ClassStructureTest.java b/src/test/java/jez04/structure/test/ClassStructureTest.java
index 7eb5fb7..95bab29 100644
--- a/src/test/java/jez04/structure/test/ClassStructureTest.java
+++ b/src/test/java/jez04/structure/test/ClassStructureTest.java
@@ -1,27 +1,86 @@
 package jez04.structure.test;
 
 import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.allOf;
-import static org.hamcrest.Matchers.empty;
-import static org.hamcrest.Matchers.endsWith;
-import static org.hamcrest.Matchers.not;
-import static org.hamcrest.Matchers.notNullValue;
-import static org.hamcrest.Matchers.startsWith;
-import static org.hamcrest.Matchers.stringContainsInOrder;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-import java.io.IOException;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
+
 import java.net.URISyntaxException;
-import java.time.LocalDate;
-import java.time.format.DateTimeFormatter;
-import java.util.List;
+import java.nio.file.Path;
+import java.util.Objects;
+import java.util.stream.Stream;
 
+import org.hamcrest.Matchers;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+
+import cz.vsb.fei.kelvin.unittest.SrcContains;
+import cz.vsb.fei.kelvin.unittest.StructureHelper;
+import cz.vsb.fei.kelvin.unittest.TextFileContains;
+import cz.vsb.fei.kelvin.unittest.XmlFileContains;
 
 class ClassStructureTest {
 
-	StructureHelper helper = StructureHelper.getInstance();
+	StructureHelper helper = StructureHelper.getInstance(ClassStructureTest.class);
+	
+	@Test
+	void lombokAsDependencyTest() throws URISyntaxException {
+		XmlFileContains xmlFileContains = new XmlFileContains("pom.xml", "/project/dependencies/dependency/artifactId[text() = 'lombok']");
+		Path root = TextFileContains.getProjectRoot(getClass()); 
+		assertThat(root, xmlFileContains);
+	}
+
+	@Test
+	void lombokAsAnnotationProcessorTest() throws URISyntaxException {
+		assertThat(TextFileContains.getProjectRoot(getClass()), new XmlFileContains("pom.xml", "/project/build/plugins/plugin/artifactId[text() = 'maven-compiler-plugin']"));
+		assertThat(TextFileContains.getProjectRoot(getClass()), new XmlFileContains("pom.xml", "/project/build/plugins/plugin/configuration/annotationProcessorPaths/path/artifactId[text() = 'lombok']"));
+	}
+
+	@Test
+	void moduleInfoTest() throws URISyntaxException {
+		assertThat(TextFileContains.getProjectRoot(getClass()), new TextFileContains("module-info.java", "lombok;"));
+	}
+
+	@CsvSource({
+		"Setup,@Getter,1",
+		"Setup,@.*Builder,1",
+		"Setup,@.*Default,3"
+		})
+	@ParameterizedTest(name = "useLombokTest in {1} annotation {2}")
+	void useLombokConfigTest(String className, String text, int count) throws URISyntaxException, ClassNotFoundException {
+		Class<?> config = helper.getClass(className);
+		assertThat(config, new SrcContains(text).count(count));
+	}
+
+	@CsvSource({
+		"Score,@Setter,1",
+		"Score,@Getter,1",
+		"Score,@AllArgsConstructor,1",
+		"Score,@EqualsAndHashCode,1",
+		"Score,@ToString,1"
+		})
+	@ParameterizedTest(name = "useLombokTest in {1} annotation {2}")
+	void useLombokOrDataTest(String className, String text, int count) throws URISyntaxException, ClassNotFoundException {
+		Class<?> config = helper.getClass(className);
+		assertThat(config, Matchers.anyOf(new SrcContains(text).count(count),
+				new SrcContains("@Data").count(1)));
+	}
+	
+	@Test
+	void recordTest() throws URISyntaxException {
+		
+		long recordCount = Stream.concat(
+				helper.getAllNonInnerClasses().stream(),
+				helper.getAllInnerClasses().stream())
+				.filter(className -> !className.startsWith("javafx")).map(className -> {
+					try {
+						return helper.getClassDirectly(className);
+					} catch (ClassNotFoundException e) {
+						e.printStackTrace();
+						return null;
+					}
+				}).filter(Objects::nonNull).filter(clazz -> clazz.isRecord()).count();
+		assertThat(recordCount, Matchers.greaterThanOrEqualTo(1L));
+		
+	}
+	
 
 }
diff --git a/src/test/java/jez04/structure/test/ContainsInnerClasses.java b/src/test/java/jez04/structure/test/ContainsInnerClasses.java
deleted file mode 100644
index 5c79529..0000000
--- a/src/test/java/jez04/structure/test/ContainsInnerClasses.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package jez04.structure.test;
-
-import java.io.IOException;
-import java.net.URISyntaxException;
-import java.util.List;
-import java.util.stream.Collectors;
-
-import org.hamcrest.Description;
-
-public class ContainsInnerClasses extends StructureMatcher<Class<?>> {
-
-	private String methodNameRegexp;
-	private boolean caseSensitive = true;
-	private boolean useRegExp = false;
-	private int count = 1;
-	private List<Class<?>> params;
-
-	public ContainsInnerClasses(String methodNameRegexp) {
-		this.methodNameRegexp = methodNameRegexp;
-	}
-
-	public ContainsInnerClasses caseSensitive(boolean caseSensitive) {
-		this.caseSensitive = caseSensitive;
-		return this;
-	}
-
-	public ContainsInnerClasses count(int count) {
-		this.count = count;
-		return this;
-	}
-
-	public ContainsInnerClasses useRegExp(boolean useRegExp) {
-		this.useRegExp = useRegExp;
-		return this;
-	}
-
-	@Override
-	public boolean matches(Object actual) {
-		if (actual instanceof Class c) {
-			long lamdaCount = structureHelper.countMethodRegexp(c, "lambda\\$.*");
-			long innerClassCount = structureHelper.countClassesRegexp(c.getCanonicalName()+"\\$.*");
-			long methodRefCount = 0;
-			try {
-				methodRefCount = structureHelper.countMethodReference(c);
-			} catch (URISyntaxException  | IOException e) {
-				System.out.println("Cannot count method references");
-				e.printStackTrace();
-			}
-			return lamdaCount + innerClassCount+methodRefCount >= count;
-		}
-		return false;
-	}
-
-	@Override
-	public void describeTo(Description description) {
-		params.stream().map(Class::getName).collect(Collectors.joining(", "));
-		description.appendText(
-				String.format("Class should have inner classses or lambdas name (regexp) of type %s %s %s with params types %s",
-						methodNameRegexp, caseSensitive ? "" : "ignore case", ""));
-	}
-
-	@Override
-	public void describeMismatch(Object item, Description description) {
-		if (item instanceof Class c) {
-			description.appendValueList("no method match from:\n      ", "\n      ", "", c.getDeclaredMethods());
-		} else {
-			description.appendText("mismatched item is not class type");
-		}
-	}
-}
diff --git a/src/test/java/jez04/structure/test/HasMethod.java b/src/test/java/jez04/structure/test/HasMethod.java
deleted file mode 100644
index 142fec8..0000000
--- a/src/test/java/jez04/structure/test/HasMethod.java
+++ /dev/null
@@ -1,95 +0,0 @@
-package jez04.structure.test;
-
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.Arrays;
-import java.util.List;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import org.hamcrest.Description;
-
-public class HasMethod extends StructureMatcher<Class<?>> {
-
-	private String methodNameRegexp;
-	private Class<?> returnType;
-	private boolean caseSensitive = true;
-	private boolean useRegExp = false;
-	private Boolean abstractTag = null;
-	private Boolean finalTag = null;
-	private int count = 1;
-	private List<Class<?>> params;
-
-	public HasMethod(String methodNameRegexp, Class<?> returnType, Class<?>... params) {
-		this.methodNameRegexp = methodNameRegexp;
-		this.returnType = returnType;
-		this.params = List.of(params);
-	}
-
-	public HasMethod caseSensitive(boolean caseSensitive) {
-		this.caseSensitive = caseSensitive;
-		return this;
-	}
-
-	public HasMethod abstractTag(Boolean abstractTag) {
-		this.abstractTag = abstractTag;
-		return this;
-	}
-
-	public HasMethod finalTag(Boolean finalTag) {
-		this.finalTag = finalTag;
-		return this;
-	}
-
-	public HasMethod count(int count) {
-		this.count = count;
-		return this;
-	}
-
-	public HasMethod useRegExp(boolean useRegExp) {
-		this.useRegExp = useRegExp;
-		return this;
-	}
-
-	@Override
-	public boolean matches(Object actual) {
-		if (actual instanceof Class c) {
-			List<Method> methods = Arrays.asList(c.getDeclaredMethods());
-			Stream<Method> streamOfMethods;
-			if (useRegExp) {
-				streamOfMethods = methods.stream().filter(m -> caseSensitive ? m.getName().matches(methodNameRegexp)
-						: m.getName().toLowerCase().matches(methodNameRegexp.toLowerCase()));
-
-			} else {
-				streamOfMethods = methods.stream().filter(m -> caseSensitive ? m.getName().endsWith(methodNameRegexp)
-						: m.getName().toLowerCase().endsWith(methodNameRegexp.toLowerCase()));
-			}
-			streamOfMethods = streamOfMethods
-					.filter(m -> returnType != null ? returnType.equals(m.getReturnType()) : true)
-					.filter(m -> finalTag != null ? Modifier.isAbstract(m.getModifiers()) == abstractTag.booleanValue()
-							: true)
-					.filter(m -> abstractTag != null ? Modifier.isFinal(m.getModifiers()) == finalTag.booleanValue()
-							: true);
-			long co = streamOfMethods.count(); 
-			return co >= count;
-		}
-		return false;
-	}
-
-	@Override
-	public void describeTo(Description description) {
-		params.stream().map(Class::getName).collect(Collectors.joining(", "));
-		description.appendText(
-				String.format("Class should have method name (regexp) of type %s %s %s with params types %s",
-						returnType, methodNameRegexp, caseSensitive ? "" : "ignore case", ""));
-	}
-
-	@Override
-	public void describeMismatch(Object item, Description description) {
-		if (item instanceof Class c) {
-			description.appendValueList("no method match from:\n      ", "\n      ", "", c.getDeclaredMethods());
-		} else {
-			description.appendText("mismatched item is not class type");
-		}
-	}
-}
diff --git a/src/test/java/jez04/structure/test/HasProperty.java b/src/test/java/jez04/structure/test/HasProperty.java
deleted file mode 100644
index 0e7098d..0000000
--- a/src/test/java/jez04/structure/test/HasProperty.java
+++ /dev/null
@@ -1,91 +0,0 @@
-package jez04.structure.test;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.Type;
-import java.util.Arrays;
-import java.util.List;
-import java.util.function.Predicate;
-import java.util.stream.Stream;
-
-import org.hamcrest.Description;
-
-public class HasProperty extends StructureMatcher<Class<?>> {
-
-	private String propertyNameRegexp;
-	private Class<?> type;
-	private Predicate<Type> genericTypeFilter;
-	private Predicate<Class<?>> typeFilter;
-	private Boolean array = false;
-	private boolean caseSensitive;
-	private Class<?> annotation = null;
-	private int count = 1;
-
-	public HasProperty(String propertyNameRegexp, Class<?> type, Boolean array) {
-		this(propertyNameRegexp, type, array, true);
-	}
-
-	public HasProperty(String propertyNameRegexp, Class<?> type, Boolean array, boolean caseSensitive) {
-		this.propertyNameRegexp = propertyNameRegexp;
-		this.type = type;
-		this.array = array;
-		this.caseSensitive = caseSensitive;
-	}
-
-	public HasProperty annotation(Class<?> annotation) {
-		this.annotation = annotation;
-		return this;
-	}
-
-	public HasProperty typeFilter(Predicate<Class<?>> typeFilter) {
-		this.typeFilter = typeFilter;
-		return this;
-	}
-
-	public HasProperty genericTypeFilter(Predicate<Type> genericTypeFilter) {
-		this.genericTypeFilter = genericTypeFilter;
-		return this;
-	}
-
-	public HasProperty count(int count) {
-		this.count = count;
-		return this;
-	}
-
-	@Override
-	public boolean matches(Object actual) {
-		if (actual instanceof Class c) {
-			Stream<?> streamOfResults;
-			List<Field> fields = Arrays.asList(c.getDeclaredFields());
-			Stream<Field> streamOfFields = fields.stream()
-					.filter(f -> caseSensitive ? f.getName().matches(propertyNameRegexp)
-							: f.getName().toLowerCase().matches(propertyNameRegexp.toLowerCase()))
-					.filter(f -> type != null ? f.getType().equals(type) : true)
-					.filter(f -> array != null ? f.getType().isAnnotation() == array.booleanValue() : true)
-					.filter(f -> genericTypeFilter != null ? genericTypeFilter.test(f.getGenericType()) : true)
-					.filter(f -> typeFilter != null ? typeFilter.test(f.getType()) : true);
-			streamOfResults = streamOfFields;
-			if (annotation != null) {
-				streamOfResults = streamOfFields.flatMap(f -> Arrays.asList(f.getAnnotations()).stream())
-						.map(a -> a.annotationType()).filter(a -> a.equals(annotation));
-			}
-			long actualCount = streamOfResults.count();
-			return this.count <= actualCount;
-		}
-		return false;
-	}
-
-	@Override
-	public void describeTo(Description description) {
-		description.appendText(String.format("Class should have field of type %s%s with name match regexp '%s'%s", type,
-				array != null && array ? "[]" : "", propertyNameRegexp, caseSensitive ? "" : "ignore case"));
-	}
-
-	@Override
-	public void describeMismatch(Object item, Description description) {
-		if (item instanceof Class c) {
-			description.appendValueList("none of", ", ", "match", c.getDeclaredFields());
-		} else {
-			description.appendText("mismatched item is not class type");
-		}
-	}
-}
diff --git a/src/test/java/jez04/structure/test/IsDescendatOf.java b/src/test/java/jez04/structure/test/IsDescendatOf.java
deleted file mode 100644
index a202faa..0000000
--- a/src/test/java/jez04/structure/test/IsDescendatOf.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package jez04.structure.test;
-
-import org.hamcrest.Description;
-
-public class IsDescendatOf extends StructureMatcher<Class<?>> {
-
-	private String className;
-	public IsDescendatOf(String className) {
-		this.className = className;
-	}
-	@Override
-	public boolean matches(Object actual) {
-		if(actual instanceof Class c) {
-			return structureHelper.getClass(className).isAssignableFrom(c);
-		}
-		return false;
-	}
-
-	@Override
-	public void describeTo(Description description) {
-		description.appendText(String.format("cass shoud be descendant of %s", className));
-	}
-	
-}
diff --git a/src/test/java/jez04/structure/test/IsInterface.java b/src/test/java/jez04/structure/test/IsInterface.java
deleted file mode 100644
index 2abdee2..0000000
--- a/src/test/java/jez04/structure/test/IsInterface.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package jez04.structure.test;
-
-import org.hamcrest.Description;
-
-public class IsInterface extends StructureMatcher<Class<?>> {
-
-	public IsInterface() {
-	}
-
-	@Override
-	public boolean matches(Object actual) {
-		if (actual instanceof Class c) {
-			return c.isInterface();
-		}
-		return false;
-	}
-
-	@Override
-	public void describeTo(Description description) {
-		description.appendText(String.format("value should be interface"));
-	}
-
-}
diff --git a/src/test/java/jez04/structure/test/ResourceContains.java b/src/test/java/jez04/structure/test/ResourceContains.java
deleted file mode 100644
index e7d9277..0000000
--- a/src/test/java/jez04/structure/test/ResourceContains.java
+++ /dev/null
@@ -1,102 +0,0 @@
-package jez04.structure.test;
-
-import java.io.IOException;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.nio.file.FileVisitResult;
-import java.nio.file.FileVisitor;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.attribute.BasicFileAttributes;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.regex.Pattern;
-
-import org.hamcrest.Description;
-
-public class ResourceContains extends StructureMatcher<String> {
-	private String regexp;
-	private boolean caseInsensitive;
-	private boolean srcFound;
-	private int count = 1;
-
-	public ResourceContains(String regexp, boolean caseInsensitive) {
-		this.regexp = regexp;
-		this.caseInsensitive = caseInsensitive;
-	}
-
-	public ResourceContains count(int count) {
-		this.count = count;
-		return this;
-	}
-
-	@Override
-	public boolean matches(Object actual) {
-		srcFound = true;
-		List<Path> foundResources = new LinkedList<>();
-		Pattern p;
-		if (caseInsensitive) {
-			p = Pattern.compile(regexp, Pattern.CASE_INSENSITIVE);
-		} else {
-			p = Pattern.compile(regexp);
-		}
-		try {
-			URL myClassUrl = StructureHelper.class.getResource(this.getClass().getSimpleName() + ".class");
-			Path classRoot = Paths.get(myClassUrl.toURI());
-			while (!"test-classes".equals(classRoot.getFileName().toString())
-					&& !"classes".equals(classRoot.getFileName().toString())) {
-				classRoot = classRoot.getParent();
-			}
-			Path resourcesRoot = classRoot.getParent().getParent().resolve(Paths.get("src", "main", "resources"));
-			System.out.println("resources root: " + resourcesRoot);
-			Files.walkFileTree(resourcesRoot, new FileVisitor<Path>() {
-
-				@Override
-				public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
-					return FileVisitResult.CONTINUE;
-				}
-
-				@Override
-				public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
-					if (p.matcher(file.getFileName().toString()).matches()) {
-						foundResources.add(file);
-					}
-					return FileVisitResult.CONTINUE;
-				}
-
-				@Override
-				public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
-					return FileVisitResult.CONTINUE;
-				}
-
-				@Override
-				public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
-					return FileVisitResult.CONTINUE;
-				}
-			});
-			return foundResources.size() >= count;
-		} catch (URISyntaxException | IOException e) {
-			srcFound = false;
-			e.printStackTrace();
-			return false;
-		}
-	}
-
-	@Override
-	public void describeTo(Description description) {
-		description.appendText(String.format("Source code of class shoud contains regexp '%s'%s", regexp,
-				caseInsensitive ? " in case insensitive mode" : ""));
-	}
-
-	@Override
-	public void describeMismatch(Object item, Description description) {
-		if (srcFound) {
-			description
-					.appendText(String.format("source code of class %s do not contains substring that match reg exp"));
-		} else {
-			description.appendText(String.format("source code of class %s was not found"));
-		}
-	}
-
-}
diff --git a/src/test/java/jez04/structure/test/SrcContains.java b/src/test/java/jez04/structure/test/SrcContains.java
deleted file mode 100644
index 4ed7d6c..0000000
--- a/src/test/java/jez04/structure/test/SrcContains.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package jez04.structure.test;
-
-import java.io.IOException;
-import java.net.URISyntaxException;
-import java.util.regex.Pattern;
-
-import org.hamcrest.Description;
-
-public class SrcContains extends StructureMatcher<Class<?>> {
-	private String regexp;
-	private boolean caseInsensitive;
-	private boolean srcFound;
-
-	public SrcContains(String regexp, boolean caseInsensitive) {
-		this.regexp = regexp;
-		this.caseInsensitive = caseInsensitive;
-	}
-
-	@Override
-	public boolean matches(Object actual) {
-		srcFound = true;
-		if (actual instanceof Class c) {
-			Pattern p = Pattern.compile(regexp);
-			if (caseInsensitive) {
-				p = Pattern.compile(regexp, Pattern.CASE_INSENSITIVE);
-			}
-			try {
-				return p.matcher(structureHelper.getSourceCode(c)).find();
-			} catch (URISyntaxException | IOException e) {
-				srcFound = false;
-				e.printStackTrace();
-				return false;
-			}
-		}
-		return false;
-	}
-
-	@Override
-	public void describeTo(Description description) {
-		description.appendText(String.format("Source code of class shoud contains regexp '%s'%s", regexp,
-				caseInsensitive ? " in case insensitive mode" : ""));
-	}
-
-	@Override
-	public void describeMismatch(Object item, Description description) {
-		if (srcFound) {
-			description
-					.appendText(String.format("source code of class %s do not contains substring that match reg exp", item));
-		} else {
-			description.appendText(String.format("source code of class %s was not found"));
-		}
-	}
-
-}
diff --git a/src/test/java/jez04/structure/test/StructureHelper.java b/src/test/java/jez04/structure/test/StructureHelper.java
deleted file mode 100644
index 6ccabb4..0000000
--- a/src/test/java/jez04/structure/test/StructureHelper.java
+++ /dev/null
@@ -1,573 +0,0 @@
-package jez04.structure.test;
-
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.junit.jupiter.api.Assertions.fail;
-
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.IOException;
-import java.io.PrintStream;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.lang.reflect.Parameter;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.nio.file.FileVisitResult;
-import java.nio.file.FileVisitor;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.attribute.BasicFileAttributes;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Set;
-import java.util.TreeSet;
-import java.util.function.Predicate;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import org.hamcrest.BaseMatcher;
-import org.hamcrest.Description;
-import org.junit.jupiter.api.Assertions;
-import org.reflections.Configuration;
-import org.reflections.Reflections;
-import org.reflections.scanners.Scanners;
-import org.reflections.util.ConfigurationBuilder;
-
-class StructureHelper {
-
-	private static StructureHelper singeltonInstance;
-
-	public static StructureHelper getInstance() {
-		if (singeltonInstance == null) {
-			singeltonInstance = new StructureHelper();
-		}
-		return singeltonInstance;
-	}
-
-	Set<String> allClasses = getNameOfAllClasses();
-
-	private StructureHelper() {
-		/* hide public one */
-	}
-
-	public Set<String> getAllClasses() {
-		return allClasses;
-	}
-
-	public void isInterface(Class<?> c) {
-		assertTrue(c.isInterface(), c.getName() + " have to be interface.");
-	}
-
-	public void classExist(String name) {
-		classExist(name, true);
-	}
-
-	public void classExist(String name, boolean caseSensitive) {
-		assertTrue(
-				allClasses.stream()
-						.anyMatch(c -> caseSensitive ? c.endsWith(name) : c.toLowerCase().endsWith(name.toLowerCase())),
-				"Class/Interface " + name + " not found");
-	}
-
-	public void classExistRegexp(String name) {
-		classExistRegexp(name, true);
-	}
-
-	public void classExistRegexp(String name, boolean caseSensitive) {
-		assertTrue(
-				allClasses.stream()
-						.anyMatch(c -> caseSensitive ? c.matches(name) : c.toLowerCase().matches(name.toLowerCase())),
-				"Class/Interface " + name + " not found");
-	}
-
-	public Class<?> getClassDirectly(String name) {
-		return loadClass(name, name);
-	}
-
-	public Class<?> getClassRegexp(String name) {
-		return getClassRegexp(name, true);
-	}
-
-	public Class<?> getClassRegexp(String name, boolean caseSensitive) {
-		String className = allClasses.stream()
-				.filter(c -> caseSensitive ? c.matches(name) : c.toLowerCase().matches(name.toLowerCase())).findAny()
-				.orElse(null);
-		if (className == null) {
-			Assertions.fail("Class " + name + " not found.");
-		}
-		return loadClass(name, className);
-	}
-
-	public Class<?> getClass(String name) {
-		return getClass(name, true);
-	}
-
-	public Class<?> getClass(String name, boolean caseSensitive) {
-		String className = allClasses.stream()
-				.filter(c -> caseSensitive ? c.endsWith(name) : c.toLowerCase().endsWith(name.toLowerCase())).findAny()
-				.orElse(null);
-		if (className == null) {
-			Assertions.fail("Class " + name + " not found.");
-		}
-		return loadClass(name, className);
-	}
-
-	private Class<?> loadClass(String name, String className) {
-		try {
-			return Class.forName(className);
-		} catch (ClassNotFoundException e) {
-			final ByteArrayOutputStream baos = new ByteArrayOutputStream();
-			try (PrintStream ps = new PrintStream(baos, true)) {
-				e.printStackTrace(ps);
-			} catch (Exception e2) {
-				Assertions.fail(e2.getMessage());
-			}
-			String stackTrace = baos.toString();
-			Assertions.fail("Class " + name + " not found.\n" + stackTrace);
-			return null;
-		}
-	}
-
-	public org.hamcrest.Matcher<Class<?>> hasProperty(String propertyNameRegexp, Class<?> type, boolean array) {
-		return new HasProperty(propertyNameRegexp, type, array);
-	}
-
-	public void hasProperty(Class<?> classDef, String propertyNameRegexp, Class<?> type, boolean array) {
-		hasProperty(classDef, propertyNameRegexp, type, array, true);
-	}
-
-	public void hasProperty(Class<?> classDef, String propertyNameRegexp, Class<?> type, boolean array,
-			boolean caseSensitive) {
-		assertTrue(hasPropertyB(classDef, propertyNameRegexp, type, array, caseSensitive),
-				"No field " + propertyNameRegexp + " of type " + type.getName() + " (is array " + array + ") in class "
-						+ classDef.getName());
-	}
-
-	public boolean hasPropertyB(Class<?> classDef, String propertyNameRegexp, Class<?> type, boolean array,
-			boolean caseSensitive) {
-		List<Field> fields = Arrays.asList(classDef.getDeclaredFields());
-		return fields.stream().anyMatch(f -> {
-			if (caseSensitive ? f.getName().matches(propertyNameRegexp)
-					: f.getName().toLowerCase().matches(propertyNameRegexp.toLowerCase())) {
-				if (array) {
-					return f.getType().isArray() && f.getType().getComponentType().equals(type);
-				} else {
-					return f.getType().equals(type);
-				}
-			}
-			return false;
-		});
-	}
-
-	public void hasPropertyWithAnnotation(Class<?> classDef, String propertyNameRegexp, Class<?> annotation) {
-		hasPropertyWithAnnotation(classDef, propertyNameRegexp, annotation, true);
-	}
-
-	public void hasPropertyWithAnnotation(Class<?> classDef, String propertyNameRegexp, Class<?> annotation,
-			boolean caseSensitive) {
-		List<Field> fields = Arrays.asList(classDef.getDeclaredFields());
-		assertTrue(
-				fields.stream()
-						.filter(f -> caseSensitive ? f.getName().matches(propertyNameRegexp)
-								: f.getName().toLowerCase().matches(propertyNameRegexp.toLowerCase()))
-						.flatMap(f -> Arrays.asList(f.getAnnotations()).stream()).map(a -> a.annotationType())
-						.anyMatch(a -> a.equals(annotation)),
-				"No field " + propertyNameRegexp + " with annotation " + annotation.getName() + " in class "
-						+ classDef.getName());
-	}
-
-	public void hasMethod(Class<?> interfaceDef, String methodName, Class<?> returnType) {
-		hasMethod(interfaceDef, methodName, returnType, true);
-	}
-
-	public void hasMethod(Class<?> interfaceDef, String methodName, Class<?> returnType, boolean caseSensitive) {
-		List<Method> methods = Arrays.asList(interfaceDef.getDeclaredMethods());
-		assertTrue(methods.stream().anyMatch(m -> m.getName().contains(methodName)), "No method " + methodName);
-		assertTrue(
-				methods.stream()
-						.filter(m -> caseSensitive ? m.getName().matches(methodName)
-								: m.getName().toLowerCase().matches(methodName.toLowerCase()))
-						.anyMatch(m -> m.getReturnType().equals(returnType)),
-				"Method " + methodName + " not return " + returnType.getName());
-	}
-
-	public void hasMethod(Class<?> interfaceDef, String methodName, Class<?> returnType, Class<?>... params) {
-		hasMethod(interfaceDef, methodName, true, returnType, params);
-	}
-
-	public void hasMethod(Class<?> interfaceDef, String methodName, boolean caseSensitive, Class<?> returnType,
-			Class<?>... params) {
-		List<Method> methods = Arrays.asList(interfaceDef.getDeclaredMethods());
-		assertTrue(
-				methods.stream()
-						.anyMatch(m -> caseSensitive ? m.getName().matches(methodName)
-								: m.getName().toLowerCase().matches(methodName.toLowerCase())),
-				"No method " + methodName);
-		assertTrue(
-				methods.stream()
-						.filter(m -> caseSensitive ? m.getName().matches(methodName)
-								: m.getName().toLowerCase().matches(methodName.toLowerCase()))
-						.filter(m -> m.getReturnType().equals(returnType))
-						.anyMatch(m -> Arrays.asList(m.getParameterTypes()).containsAll(Arrays.asList(params))),
-				"Method " + methodName + " has no all parrams:"
-						+ Arrays.asList(params).stream().map(Class::getName).collect(Collectors.joining(", ")));
-	}
-
-	public Method getMethod(Class<?> interfaceDef, String methodName, Class<?> returnType, Class<?>... params) {
-		return getMethod(interfaceDef, methodName, true, returnType, params);
-	}
-
-	public Method getMethod(Class<?> interfaceDef, String methodName, boolean caseSensitive, Class<?> returnType,
-			Class<?>... params) {
-		List<Method> methods = Arrays.asList(interfaceDef.getDeclaredMethods());
-		List<Method> foundMethods = methods.stream()
-				.filter(m -> caseSensitive ? m.getName().matches(methodName)
-						: m.getName().toLowerCase().matches(methodName.toLowerCase()))
-				.filter(m -> m.getReturnType().equals(returnType))
-				.filter(m -> Arrays.asList(m.getParameterTypes()).containsAll(Arrays.asList(params))).toList();
-		if (foundMethods.isEmpty()) {
-			fail("No method " + methodName + " found");
-		}
-		if (foundMethods.size() > 1) {
-			fail("More then one method " + methodName + " found");
-		}
-		return foundMethods.get(0);
-	}
-
-	public long countMethodRegexp(Class<?> interfaceDef, String methodNameRegexp) {
-		return countMethodRegexp(interfaceDef, methodNameRegexp, true);
-	}
-
-	public long countMethodRegexp(Class<?> interfaceDef, String methodNameRegexp, boolean caseSensitive) {
-		List<Method> methods = Arrays.asList(interfaceDef.getDeclaredMethods());
-		return methods.stream().filter(m -> caseSensitive ? m.getName().matches(methodNameRegexp)
-				: m.getName().toLowerCase().matches(methodNameRegexp.toLowerCase())).count();
-	}
-
-	public long countMethodReference(Class<?> interfaceDef) throws URISyntaxException, IOException {
-		Pattern p = Pattern.compile("::");
-		Matcher m = p.matcher(getSourceCode(interfaceDef));
-		return m.results().count();
-	}
-
-	public long countMethodReferenceOn(Class<?> interfaceDef, String to) {
-		try {
-			Pattern p = Pattern.compile(to + "::");
-			Matcher m = p.matcher(getSourceCode(interfaceDef));
-			return m.results().count();
-		} catch (URISyntaxException | IOException e) {
-			e.printStackTrace();
-			return 0;
-		}
-	}
-
-	public long countClassesRegexp(String classNameRegexp) {
-		return countClassesRegexp(classNameRegexp, true);
-	}
-
-	public long countClassesRegexp(String classNameRegexp, boolean caseSensitive) {
-		return getNameOfAllClasses().stream().filter(className -> caseSensitive ? className.matches(classNameRegexp)
-				: className.toLowerCase().matches(classNameRegexp.toLowerCase())).count();
-	}
-
-	public void hasConstructor(Class<?> classDef, Class<?>... params) {
-		getConstructor(classDef, params);
-	}
-
-	public Constructor<?> getConstructor(Class<?> classDef, Class<?>... params) {
-		List<Constructor<?>> constructors = Arrays.asList(classDef.getConstructors());
-		List<Constructor<?>> foundConstructors = constructors.stream()
-				.filter(m -> m.getParameterCount() == params.length)
-				.filter(m -> Arrays.asList(m.getParameterTypes()).containsAll(Arrays.asList(params))).toList();
-		if (foundConstructors.isEmpty()) {
-			fail("No constructor found with parameters: "
-					+ Arrays.asList(params).stream().map(Class::getName).collect(Collectors.joining(", ")));
-		}
-		if (foundConstructors.size() > 1) {
-			fail("More then one constructor found with parameters: "
-					+ Arrays.asList(params).stream().map(Class::getName).collect(Collectors.joining(", ")));
-		}
-		return foundConstructors.get(0);
-	}
-
-	public void hasMethodRegexp(Class<?> interfaceDef, String methodNameRegexp, Class<?> returnType,
-			Class<?>... params) {
-		hasMethodRegexp(interfaceDef, methodNameRegexp, true, returnType, params);
-	}
-
-	public void hasMethodRegexp(Class<?> interfaceDef, String methodNameRegexp, boolean caseSensitive,
-			Class<?> returnType, Class<?>... params) {
-		List<Method> methods = Arrays.asList(interfaceDef.getDeclaredMethods());
-		assertTrue(
-				methods.stream()
-						.anyMatch(m -> caseSensitive ? m.getName().matches(methodNameRegexp)
-								: m.getName().toLowerCase().matches(methodNameRegexp.toLowerCase())),
-				"No method " + methodNameRegexp);
-		assertTrue(
-				methods.stream()
-						.filter(m -> caseSensitive ? m.getName().matches(methodNameRegexp)
-								: m.getName().toLowerCase().matches(methodNameRegexp.toLowerCase()))
-						.filter(m -> m.getReturnType().equals(returnType))
-						.anyMatch(m -> Arrays.asList(m.getParameterTypes()).containsAll(Arrays.asList(params))),
-				"Method " + methodNameRegexp + " has no all parrams:"
-						+ Arrays.asList(params).stream().map(Class::getName).collect(Collectors.joining(", ")));
-	}
-
-	public boolean hasMethodRegexpTest(Class<?> interfaceDef, String methodNameRegexp, boolean caseSensitive,
-			Class<?> returnType, Class<?>... params) {
-		return hasMethodRegexpTest(interfaceDef, methodNameRegexp, caseSensitive, returnType, List.of(params));
-	}
-
-	public boolean hasMethodRegexpTest(Class<?> interfaceDef, String methodNameRegexp, boolean caseSensitive,
-			Class<?> returnType, List<Class<?>> params) {
-		List<Method> methods = Arrays.asList(interfaceDef.getDeclaredMethods());
-		if (!methods.stream().anyMatch(m -> caseSensitive ? m.getName().matches(methodNameRegexp)
-				: m.getName().toLowerCase().matches(methodNameRegexp.toLowerCase()))) {
-			return false;
-		}
-		return methods.stream()
-				.filter(m -> caseSensitive ? m.getName().matches(methodNameRegexp)
-						: m.getName().toLowerCase().matches(methodNameRegexp.toLowerCase()))
-				.filter(m -> m.getReturnType().equals(returnType))
-				.anyMatch(m -> Arrays.asList(m.getParameterTypes()).containsAll(params));
-	}
-
-	public long countMethodRegexp(Class<?> interfaceDef, String methodNameRegexp, Class<?> returnType,
-			Class<?>... params) {
-		return countMethodRegexp(interfaceDef, methodNameRegexp, true, returnType, params);
-	}
-
-	public long countMethodRegexp(Class<?> interfaceDef, String methodNameRegexp, boolean caseSensitive,
-			Class<?> returnType, Class<?>... params) {
-		List<Method> methods = Arrays.asList(interfaceDef.getDeclaredMethods());
-		assertTrue(
-				methods.stream()
-						.anyMatch(m -> caseSensitive ? m.getName().matches(methodNameRegexp)
-								: m.getName().toLowerCase().matches(methodNameRegexp.toLowerCase())),
-				"No method " + methodNameRegexp);
-		return methods.stream()
-				.filter(m -> caseSensitive ? m.getName().matches(methodNameRegexp)
-						: m.getName().toLowerCase().matches(methodNameRegexp.toLowerCase()))
-				.filter(m -> m.getReturnType().equals(returnType))
-				.filter(m -> Arrays.asList(m.getParameterTypes()).containsAll(Arrays.asList(params))).count();
-	}
-
-	public boolean hasMethodTest(Class<?> interfaceDef, boolean finalTag, boolean abstractTag, String methodName,
-			boolean caseSensitive, Class<?> returnType, Class<?>... params) {
-		return hasMethodTest(interfaceDef, finalTag, abstractTag, methodName, caseSensitive, returnType, List.of(params));
-	}
-	public boolean hasMethodTest(Class<?> interfaceDef, boolean finalTag, boolean abstractTag, String methodName,
-			boolean caseSensitive, Class<?> returnType, List<Class<?>> params) {
-		List<Method> methods = Arrays.asList(interfaceDef.getDeclaredMethods());
-		if (!methods.stream().anyMatch(m -> caseSensitive ? m.getName().matches(methodName)
-				: m.getName().toLowerCase().matches(methodName.toLowerCase()))) {
-			return false;
-		}
-		return methods.stream()
-				.filter(m -> caseSensitive ? m.getName().matches(methodName)
-						: m.getName().toLowerCase().matches(methodName.toLowerCase()))
-				.filter(m -> m.getReturnType().equals(returnType)
-						&& (Modifier.isAbstract(m.getModifiers()) == abstractTag)
-						&& (Modifier.isFinal(m.getModifiers()) == finalTag))
-				.anyMatch(m -> Arrays.asList(m.getParameterTypes()).containsAll(params));
-	}
-
-	public void hasMethod(Class<?> interfaceDef, boolean finalTag, boolean abstractTag, String methodName,
-			Class<?> returnType, Class<?>... params) {
-		hasMethod(interfaceDef, finalTag, abstractTag, methodName, true, returnType, params);
-	}
-
-	public void hasMethod(Class<?> interfaceDef, boolean finalTag, boolean abstractTag, String methodName,
-			boolean caseSensitive, Class<?> returnType, Class<?>... params) {
-		List<Method> methods = Arrays.asList(interfaceDef.getDeclaredMethods());
-		assertTrue(
-				methods.stream()
-						.anyMatch(m -> caseSensitive ? m.getName().matches(methodName)
-								: m.getName().toLowerCase().matches(methodName.toLowerCase())),
-				"No method " + methodName);
-		assertTrue(
-				methods.stream()
-						.filter(m -> caseSensitive ? m.getName().matches(methodName)
-								: m.getName().toLowerCase().matches(methodName.toLowerCase()))
-						.filter(m -> m.getReturnType().equals(returnType)
-								&& (Modifier.isAbstract(m.getModifiers()) == abstractTag)
-								&& (Modifier.isFinal(m.getModifiers()) == finalTag))
-						.anyMatch(m -> Arrays.asList(m.getParameterTypes()).containsAll(Arrays.asList(params))),
-				"Method " + methodName + " has no all params:"
-						+ Arrays.asList(params).stream().map(Class::getName).collect(Collectors.joining(", ")));
-	}
-
-	public boolean isDescendatOf(Class<?> clazz, String interfaceName) {
-		return getClass(interfaceName).isAssignableFrom(clazz);
-	}
-
-	public void hasImplements(Class<?> clazz, String... interfaceNames) {
-		List<Class<?>> interfaces = new ArrayList<>();
-		Arrays.asList(interfaceNames).stream().map(name -> getClass(name)).forEach(c -> interfaces.add(c));
-		assertTrue(Arrays.asList(clazz.getInterfaces()).containsAll(interfaces), "Class not implements all interfaces:"
-				+ interfaces.stream().map(Class::getName).collect(Collectors.joining(", ")));
-	}
-
-	public void hasExtends(Class<?> clazz, String parentName) {
-		Class<?> parent = getClass(parentName);
-		assertTrue(clazz.getSuperclass().equals(parent),
-				"Class " + clazz.getName() + " not extends class " + parentName);
-	}
-
-	public void hasExtends(Class<?> clazz, Class<?> parent) {
-		assertTrue(clazz.getSuperclass().equals(parent),
-				"Class " + clazz.getName() + " not extends class " + parent.getCanonicalName());
-	}
-
-	public void hasMethod(Class<?> interfaceDef, String methodName) {
-		hasMethod(interfaceDef, methodName, true);
-	}
-
-	public void hasMethod(Class<?> interfaceDef, String methodName, boolean caseSensitive) {
-		List<Method> methods = Arrays.asList(interfaceDef.getMethods());
-		assertTrue(
-				methods.stream()
-						.anyMatch(m -> caseSensitive ? m.getName().matches(methodName)
-								: m.getName().toLowerCase().matches(methodName.toLowerCase())),
-				"No method " + methodName);
-	}
-
-	public String getSourceCode(Class<?> clazz) throws URISyntaxException, IOException {
-		URL myClassUrl = StructureHelper.class.getResource(this.getClass().getSimpleName() + ".class");
-		Path classRoot = Paths.get(myClassUrl.toURI());
-		while (!"test-classes".equals(classRoot.getFileName().toString())
-				&& !"classes".equals(classRoot.getFileName().toString())) {
-			classRoot = classRoot.getParent();
-		}
-		Path srcRoot = classRoot.getParent().getParent().resolve(Paths.get("src", "main", "java"));
-		System.out.println("class root: " + classRoot);
-		Path srcPath = srcRoot.resolve(clazz.getCanonicalName().replace(".", File.separator) + ".java");
-		return Files.readString(srcPath);
-	}
-
-	public Set<String> getNameOfAllClasses() {
-		Set<String> allClassesName = new TreeSet<>();
-		dynamicalyFoundSomeClass(allClassesName);
-//		allClassesName.addAll(List.of("cz.vsb.fei.lab.App", "lab.Routines", "lab.App", "lab.DrawingThread"));
-		for (String className : allClassesName) {
-			try {
-				Class.forName(className);
-				break;
-			} catch (ClassNotFoundException e) {
-				System.out.println(String.format("Class '%s' cannot be loaded: %s", className, e.getMessage()));
-			}
-		}
-		for (Package p : Package.getPackages()) {
-			if (p.getName().startsWith("java.") || p.getName().startsWith("com.") || p.getName().startsWith("jdk.")
-					|| p.getName().startsWith("javafx.") || p.getName().startsWith("org.")
-					|| p.getName().startsWith("sun.") || p.getName().startsWith("javax.")
-					|| p.getName().startsWith("javassist")) {
-				continue;
-			}
-//			System.out.println(p.getName());
-			Configuration conf = new ConfigurationBuilder().addScanners(Scanners.SubTypes.filterResultsBy(pc -> true))
-					.forPackages(p.getName());
-			Reflections reflections = new Reflections(conf);
-			allClassesName.addAll(reflections.getAll(Scanners.SubTypes.filterResultsBy(c -> {
-//				System.out.println(">>> " + c);
-				return true;
-			})));
-		}
-		return allClassesName;
-	}
-
-	private static final List<String> dirsToSkip = List.of("jez04", "META-INF");
-	private static final List<String> filesToSkip = List.of("module-info.class");
-
-	public void dynamicalyFoundSomeClass(Set<String> allClassesName) {
-		URL myClassUrl = StructureHelper.class.getResource(this.getClass().getSimpleName() + ".class");
-		try {
-			Path classRoot = Paths.get(myClassUrl.toURI());
-			while (!"test-classes".equals(classRoot.getFileName().toString())
-					&& !"classes".equals(classRoot.getFileName().toString())) {
-				classRoot = classRoot.getParent();
-			}
-			if ("test-classes".equals(classRoot.getFileName().toString())) {
-				classRoot = classRoot.getParent().resolve("classes");
-			}
-//			System.out.println("class root: " + classRoot);
-			final Path classRootFinal = classRoot;
-			Files.walkFileTree(classRoot, new FileVisitor<Path>() {
-
-				@Override
-				public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
-					if (dirsToSkip.contains(dir.getFileName().toString())) {
-						return FileVisitResult.SKIP_SUBTREE;
-					}
-					return FileVisitResult.CONTINUE;
-				}
-
-				@Override
-				public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
-					if (filesToSkip.contains(file.getFileName().toString())) {
-						return FileVisitResult.CONTINUE;
-					}
-					if (!file.getFileName().toString().endsWith(".class")) {
-						return FileVisitResult.CONTINUE;
-					}
-					if (file.getFileName().toString().contains("$")) {
-						return FileVisitResult.CONTINUE;
-					}
-					String foundClassName = classRootFinal.relativize(file).toString();
-					foundClassName = foundClassName.substring(0, foundClassName.length() - 6)
-							.replace(File.separatorChar, '.');
-					addClassAndAllRef(allClassesName, foundClassName);
-					return FileVisitResult.CONTINUE;
-				}
-
-				@Override
-				public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
-					return FileVisitResult.CONTINUE;
-				}
-
-				@Override
-				public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
-					return FileVisitResult.CONTINUE;
-				}
-			});
-		} catch (URISyntaxException | IOException e) {
-			e.printStackTrace();
-		}
-	}
-
-	private void addClassAndAllRef(Set<String> allClassesName, String foundClassName) {
-		allClassesName.add(foundClassName);
-		try {
-			Class<?> foundClass = Class.forName(foundClassName);
-			List.of(foundClass.getInterfaces()).stream().map(Class::getCanonicalName).forEach(allClassesName::add);
-			List.of(foundClass.getDeclaredClasses()).stream().map(Class::getCanonicalName).forEach(allClassesName::add);
-			List.of(foundClass.getDeclaredFields()).stream().map(Field::getType)
-					.map(clazz -> clazz.isArray() ? clazz.componentType() : clazz)
-					.filter(Predicate.not(Class::isPrimitive)).map(Class::getCanonicalName)
-					.forEach(allClassesName::add);
-			List.of(foundClass.getDeclaredMethods()).stream().map(Method::getReturnType)
-					.map(clazz -> clazz.isArray() ? clazz.componentType() : clazz)
-					.filter(Predicate.not(Class::isPrimitive)).map(Class::getCanonicalName)
-					.forEach(allClassesName::add);
-			List.of(foundClass.getDeclaredMethods()).stream().flatMap(m -> List.of(m.getParameters()).stream())
-					.map(Parameter::getType).map(clazz -> clazz.isArray() ? clazz.componentType() : clazz)
-					.filter(Predicate.not(Class::isPrimitive)).map(Class::getCanonicalName)
-					.forEach(allClassesName::add);
-			List.of(foundClass.getDeclaredMethods()).stream().flatMap(m -> List.of(m.getExceptionTypes()).stream())
-					.map(clazz -> clazz.isArray() ? clazz.componentType() : clazz)
-					.filter(Predicate.not(Class::isPrimitive)).map(Class::getCanonicalName)
-					.forEach(allClassesName::add);
-			if (foundClass.getSuperclass() != null) {
-				allClassesName.add(foundClass.getSuperclass().getCanonicalName());
-			}
-		} catch (ClassNotFoundException e) {
-			e.printStackTrace();
-		}
-	}
-}
diff --git a/src/test/java/jez04/structure/test/StructureMatcher.java b/src/test/java/jez04/structure/test/StructureMatcher.java
deleted file mode 100644
index 6b8bc25..0000000
--- a/src/test/java/jez04/structure/test/StructureMatcher.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package jez04.structure.test;
-
-public abstract class StructureMatcher<T> extends org.hamcrest.BaseMatcher<T>{
-		
-		protected StructureHelper  structureHelper = StructureHelper.getInstance();
-		
-}
-- 
GitLab