From 233a0643e0dc083d63c246458b496de0e2fd48d8 Mon Sep 17 00:00:00 2001 From: jez04 <david.jezek@post.cz> Date: Fri, 8 Nov 2024 11:30:42 +0100 Subject: [PATCH] =?UTF-8?q?feat:=20=F0=9F=8E=89=20solution?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/lab/Background.java | 2 +- src/main/java/lab/Boat.java | 2 +- src/main/java/lab/DeadListener.java | 5 + src/main/java/lab/DrawableSimulable.java | 1 + src/main/java/lab/GameController.java | 16 +- src/main/java/lab/LochNess.java | 24 +- src/main/java/lab/Rock.java | 2 +- src/main/java/lab/Scene.java | 40 ++- src/main/java/lab/WorldEntity.java | 9 +- .../structure/test/ClassStructureTest.java | 245 ++++++----------- .../jez04/structure/test/StructureHelper.java | 248 ++++++++++++++++++ 11 files changed, 414 insertions(+), 180 deletions(-) create mode 100644 src/main/java/lab/DeadListener.java create mode 100644 src/test/java/jez04/structure/test/StructureHelper.java diff --git a/src/main/java/lab/Background.java b/src/main/java/lab/Background.java index d31af4b..295f423 100644 --- a/src/main/java/lab/Background.java +++ b/src/main/java/lab/Background.java @@ -13,7 +13,7 @@ public class Background extends WorldEntity { private static final double[] speedMultiplier = new double[] { 0.6, 0.8, 1, 1 }; public Background(Scene scene) { - super(scene, new Point2D(0, 0)); + super(scene, new Point2D(0, 0), 0); image = new Image[4]; imagePosition = new Point2D[4]; image[0] = new Image(Background.class.getResourceAsStream("cityfar400.png")); diff --git a/src/main/java/lab/Boat.java b/src/main/java/lab/Boat.java index 73597b7..b39b834 100644 --- a/src/main/java/lab/Boat.java +++ b/src/main/java/lab/Boat.java @@ -14,7 +14,7 @@ public class Boat extends WorldEntity implements Collisionable { private Image image; public Boat(Scene scene, Point2D position) { - super(scene, position); + super(scene, position, 100); image = new Image(Boat.class.getResourceAsStream("ship-boat.gif")); speed = new Point2D(0, 0); } diff --git a/src/main/java/lab/DeadListener.java b/src/main/java/lab/DeadListener.java new file mode 100644 index 0000000..e1e00b1 --- /dev/null +++ b/src/main/java/lab/DeadListener.java @@ -0,0 +1,5 @@ +package lab; + +public interface DeadListener { + void lochnessDead(); +} diff --git a/src/main/java/lab/DrawableSimulable.java b/src/main/java/lab/DrawableSimulable.java index 9930e7e..7f8c22a 100644 --- a/src/main/java/lab/DrawableSimulable.java +++ b/src/main/java/lab/DrawableSimulable.java @@ -6,4 +6,5 @@ public interface DrawableSimulable { void draw(GraphicsContext gc); void simulate(double deltaTime); + int getZIndex(); } diff --git a/src/main/java/lab/GameController.java b/src/main/java/lab/GameController.java index 6d13ce1..bb85e3d 100644 --- a/src/main/java/lab/GameController.java +++ b/src/main/java/lab/GameController.java @@ -26,11 +26,25 @@ public class GameController { @FXML private Label playerName; + private int deadLochNessCounter = 0; + @FXML void changePosition(ActionEvent event) { - scene.getRock().changePosition(); + LochNess lochNess = new LochNess(scene); + lochNess.addDeadListener(() -> System.out.println("LochNess dead!")); + lochNess.addDeadListener(this::addDead); + scene.add(lochNess); } + + private void addDead() { + deadLochNessCounter++; + updateDeadLabel(); + } + + private void updateDeadLabel() { + playerName.setText(String.format("Number of dead lochnesses: %03d", deadLochNessCounter)); + } @FXML void initialize() { diff --git a/src/main/java/lab/LochNess.java b/src/main/java/lab/LochNess.java index 79edf18..ccf4850 100644 --- a/src/main/java/lab/LochNess.java +++ b/src/main/java/lab/LochNess.java @@ -1,7 +1,10 @@ package lab; +import java.util.ArrayList; +import java.util.List; import java.util.Random; +import javafx.geometry.Dimension2D; import javafx.geometry.Point2D; import javafx.geometry.Rectangle2D; import javafx.scene.canvas.GraphicsContext; @@ -13,9 +16,10 @@ public class LochNess extends WorldEntity implements Collisionable { private Point2D speed; private Image image; + private List<DeadListener> deadListeners = new ArrayList<>(); public LochNess(Scene scene) { - super(scene, new Point2D(0, 0)); + super(scene, new Point2D(0, 0), 90); this.scene = scene; image = new Image(LochNess.class.getResourceAsStream("LochNess.gif")); position = new Point2D(RANDOM.nextDouble(scene.getSize().getWidth() * 0.3, scene.getSize().getWidth()), @@ -58,8 +62,24 @@ public class LochNess extends WorldEntity implements Collisionable { @Override public void hitBy(Collisionable another) { if (another instanceof Boat) { - changeDirection(); + scene.remove(this); + scene.add(new Rock(scene, getPosition(), new Dimension2D(10, 10))); + fireLochNessDead(); } } + + public boolean addDeadListener(DeadListener e) { + return deadListeners.add(e); + } + + public boolean removeDeadListener(DeadListener o) { + return deadListeners.remove(o); + } + + private void fireLochNessDead() { + for (DeadListener deadListener : deadListeners) { + deadListener.lochnessDead(); + } + } } diff --git a/src/main/java/lab/Rock.java b/src/main/java/lab/Rock.java index 0162301..1998785 100644 --- a/src/main/java/lab/Rock.java +++ b/src/main/java/lab/Rock.java @@ -20,7 +20,7 @@ public class Rock extends WorldEntity { } public Rock(Scene scene, Point2D position, Dimension2D size) { - super(scene, position); + super(scene, position, 50); this.size = size; } diff --git a/src/main/java/lab/Scene.java b/src/main/java/lab/Scene.java index 0b45059..96eefa9 100644 --- a/src/main/java/lab/Scene.java +++ b/src/main/java/lab/Scene.java @@ -1,5 +1,9 @@ package lab; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + import javafx.geometry.Dimension2D; import javafx.geometry.Point2D; import javafx.scene.canvas.GraphicsContext; @@ -7,7 +11,9 @@ import javafx.scene.canvas.GraphicsContext; public class Scene { private Dimension2D size; - private DrawableSimulable[] sceneEntitites; + private List<DrawableSimulable> sceneEntitites; + private List<DrawableSimulable> entititesToAdd = new ArrayList<>(); + private List<DrawableSimulable> entititesToRemove = new ArrayList<>(); private Boat boat; private Rock rock; @@ -15,15 +21,15 @@ public class Scene { public Scene(double width, double height, int numberOfMonsters) { size = new Dimension2D(width, height); - sceneEntitites = new DrawableSimulable[3+numberOfMonsters]; + sceneEntitites = new ArrayList<>(); background = new Background(this); rock = new Rock(this, new Point2D(300, 300), new Dimension2D(30, 50)); boat = new Boat(this, new Point2D(20, 200)); - sceneEntitites[0] = background; - sceneEntitites[1] = rock; - sceneEntitites[2] = boat; - for (int i = 3; i < sceneEntitites.length; i++) { - sceneEntitites[i] = new LochNess(this); + sceneEntitites.add(background); + sceneEntitites.add(rock); + sceneEntitites.add(boat); + for (int i = 0; i < numberOfMonsters; i++) { + sceneEntitites.add(new LochNess(this)); } } @@ -41,10 +47,10 @@ public class Scene { for (DrawableSimulable drawableSimulable : sceneEntitites) { drawableSimulable.simulate(deltaTime); } - for (int i = 0; i < sceneEntitites.length; i++) { - if (sceneEntitites[i] instanceof Collisionable c1) { - for (int j = i + 1; j < sceneEntitites.length; j++) { - if (sceneEntitites[j] instanceof Collisionable c2) { + for (int i = 0; i < sceneEntitites.size(); i++) { + if (sceneEntitites.get(i) instanceof Collisionable c1) { + for (int j = i + 1; j < sceneEntitites.size(); j++) { + if (sceneEntitites.get(j) instanceof Collisionable c2) { if (c1.intersect(c2.getBoundingBox())) { c1.hitBy(c2); c2.hitBy(c1); @@ -53,6 +59,11 @@ public class Scene { } } } + sceneEntitites.removeAll(entititesToRemove); + sceneEntitites.addAll(entititesToAdd); + entititesToAdd.clear(); + entititesToRemove.clear(); + sceneEntitites.sort(Comparator.comparing(DrawableSimulable::getZIndex)); } public Boat getBoat() { @@ -66,5 +77,12 @@ public class Scene { public Background getBackground() { return background; } + + public void add(DrawableSimulable entity) { + entititesToAdd.add(entity); + } + public void remove(DrawableSimulable entity) { + entititesToRemove.add(entity); + } } diff --git a/src/main/java/lab/WorldEntity.java b/src/main/java/lab/WorldEntity.java index b5ae6f5..926a7da 100644 --- a/src/main/java/lab/WorldEntity.java +++ b/src/main/java/lab/WorldEntity.java @@ -7,10 +7,12 @@ public abstract class WorldEntity implements DrawableSimulable { protected Scene scene; protected Point2D position; + private int zIndex; - public WorldEntity(Scene scene, Point2D position) { + public WorldEntity(Scene scene, Point2D position, int zIndex) { this.scene = scene; this.position = position; + this.zIndex = zIndex; } public Point2D getPosition() { @@ -28,5 +30,10 @@ public abstract class WorldEntity implements DrawableSimulable { gc.restore(); } + + public int getZIndex() { + return zIndex; + } + public abstract void drawInternal(GraphicsContext gc); } diff --git a/src/test/java/jez04/structure/test/ClassStructureTest.java b/src/test/java/jez04/structure/test/ClassStructureTest.java index fa5f2e5..a1a6b0d 100644 --- a/src/test/java/jez04/structure/test/ClassStructureTest.java +++ b/src/test/java/jez04/structure/test/ClassStructureTest.java @@ -3,12 +3,23 @@ package jez04.structure.test; import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; import java.io.PrintStream; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +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.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -26,198 +37,108 @@ import javafx.fxml.FXML; class ClassStructureTest { - private static final String drawableSimulableName = "DrawableSimulable"; - private static final String collisionableName = "Collisionable"; - - Set<String> allClasses = getNameOfAllClasses(); + StructureHelper helper = new StructureHelper(); @Test void gameControllerExistenceTest() { - classExist("GameController"); - Class<?> c = getClass("GameController"); - hasPropertyWithAnnotation(c, ".*", FXML.class); - hasMethodRegexp(c, ".*", void.class, ActionEvent.class); + helper.classExist("GameController"); } + @Test void gameControllerFxmlTest() { - classExist("GameController"); - Class<?> c = getClass("GameController"); - hasPropertyWithAnnotation(c, ".*", FXML.class); - } - @Test - void gameControllerActionEventTest() { - classExist("GameController"); - Class<?> c = getClass("GameController"); - hasMethodRegexp(c, ".*", void.class, ActionEvent.class); - } - @Test - void gameControllerLambdaTest() { - classExist("GameController"); - Class<?> c = getClass("GameController"); - hasMethodRegexp(c, "lambda$.*", void.class, ActionEvent.class); + helper.classExist("GameController"); + Class<?> c = helper.getClass("GameController"); + helper.hasPropertyWithAnnotation(c, ".*", FXML.class); } @Test - void cannonExistenceTest() { - classExist("Player"); - } - @Test - void cannonExistenceSetAngleTest() { - classExist("Player"); - Class<?> c = getClass("Player"); - hasMethod(c, "setAngle"); - } - @Test - void cannonExistenceSetSpeedTest() { - classExist("Player"); - Class<?> c = getClass("Player"); - hasMethod(c, "setSpeed"); - } - - - private void isInterface(Class<?> c) { - assertTrue(c.isInterface(), c.getName() + " have to be interface."); + void gameControllerActionMethodTest() { + helper.classExist("GameController"); + Class<?> c = helper.getClass("GameController"); + helper.hasMethodRegexp(c, ".*", void.class, ActionEvent.class); } - private void classExist(String name) { - assertTrue(allClasses.stream().anyMatch(c -> c.endsWith(name)), "Interface " + name + " not found"); + @Test + void gameControllerLambdasTest() { + helper.classExist("GameController"); + Class<?> c = helper.getClass("GameController"); + long lamdaCount = helper.countMethodRegexp(c, "lambda\\$.*"); + long innerClasscount = helper.countClassesRegexp(".*GameController\\$.*"); + assertTrue(lamdaCount + innerClasscount >= 3, + "At least 3 inner classes or lamdas required for GameController but only " + + (lamdaCount + innerClasscount) + " found."); } - private Class<?> getClass(String name) { - String className = allClasses.stream().filter(c -> c.endsWith(name)).findAny().orElse(null); - if (className == null) { - Assertions.fail("Class " + name + " not found."); - } - 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; - } + @Test + void deadListenerExistenceTest() { + helper.classExist("DeadListener"); } - private void hasProperty(Class<?> classDef, String propertyNameRegexp, Class<?> type, boolean array) { - List<Field> fields = Arrays.asList(classDef.getDeclaredFields()); - assertTrue(fields.stream().anyMatch(f -> { - if (f.getName().matches(propertyNameRegexp)) { - if (array) { - return f.getType().isArray() && f.getType().getComponentType().equals(type); - } else { - return f.getType().equals(type); - } - } - return false; - }), "No field " + propertyNameRegexp + " of type " + type.getName() + " (is array " + array + ") in class " - + classDef.getName()); + @Test + void deadListenerEventMethodTest() { + helper.classExist("DeadListener"); + Class<?> c = helper.getClass("DeadListener"); + helper.hasMethod(c, "lochnessDead"); } - private void hasPropertyWithAnnotation(Class<?> classDef, String propertyNameRegexp, Class<?> annotation) { - List<Field> fields = Arrays.asList(classDef.getDeclaredFields()); - assertTrue( - fields.stream().filter(f -> f.getName().matches(propertyNameRegexp)) - .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()); + @Test + void sceneCollectionTest() { + helper.classExist("lab.Scene"); + Class<?> c = helper.getClass("lab.Scene"); + long collectionCount = Arrays.asList(c.getDeclaredFields()).stream() + .filter(f -> Collection.class.isAssignableFrom(f.getType())).count(); + assertTrue(collectionCount >= 3, "lab.Scene require atleast 3 filed of type/subtype Collection, but only " + + collectionCount + " found."); } - private void hasMethod(Class<?> interfaceDef, String methodName, Class<?> returnType) { - List<Method> methods = Arrays.asList(interfaceDef.getDeclaredMethods()); - assertTrue(methods.stream().anyMatch(m -> m.getName().contains(methodName)), "No method " + methodName); - assertTrue( - methods.stream().filter(m -> m.getName().contains(methodName)) - .anyMatch(m -> m.getReturnType().equals(returnType)), - "Method " + methodName + " not return " + returnType.getName()); + @Test + void sceneMethodAddTest() { + helper.classExist("lab.Scene"); + Class<?> c = helper.getClass("lab.Scene"); + helper.hasMethod(c, "add", void.class, helper.getClass("DrawableSimulable")); + ; } - private void hasMethod(Class<?> interfaceDef, String methodName, Class<?> returnType, Class<?>... params) { - List<Method> methods = Arrays.asList(interfaceDef.getDeclaredMethods()); - assertTrue(methods.stream().anyMatch(m -> m.getName().contains(methodName)), "No method " + methodName); - assertTrue( - methods.stream().filter(m -> m.getName().contains(methodName)) - .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(", "))); + @Test + void sceneMethodRemoveTest() { + helper.classExist("lab.Scene"); + Class<?> c = helper.getClass("lab.Scene"); + helper.hasMethod(c, "remove", void.class, helper.getClass("DrawableSimulable")); + ; } - private void hasMethodRegexp(Class<?> interfaceDef, String methodNameRegexp, Class<?> returnType, Class<?>... params) { - List<Method> methods = Arrays.asList(interfaceDef.getDeclaredMethods()); - assertTrue(methods.stream().anyMatch(m -> m.getName().matches(methodNameRegexp)), "No method " + methodNameRegexp); - assertTrue( - methods.stream().filter(m -> m.getName().matches(methodNameRegexp)) - .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(", "))); - } - private void hasMethod(Class<?> interfaceDef, boolean finalTag, boolean abstractTag, String methodName, - Class<?> returnType, Class<?>... params) { - List<Method> methods = Arrays.asList(interfaceDef.getDeclaredMethods()); - assertTrue(methods.stream().anyMatch(m -> m.getName().contains(methodName)), "No method " + methodName); - assertTrue( - methods.stream().filter(m -> m.getName().contains(methodName)) - .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(", "))); + @Test + void lochnessMethodAddTest() { + helper.classExist("LochNess"); + Class<?> c = helper.getClass("LochNess"); + helper.hasMethod(c, "addDeadListener"); } - private 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(", "))); + @Test + void lochnessMethodRemoveTest() { + helper.classExist("LochNess"); + Class<?> c = helper.getClass("LochNess"); + helper.hasMethod(c, "removeDeadListener"); } - private void hasExtends(Class<?> clazz, String parentName) { - Class<?> parent = getClass(parentName); - assertTrue(clazz.getSuperclass().equals(parent), - "Class " + clazz.getName() + " not extends class " + parentName); + @Test + void lochnessMethodFireTest() { + helper.classExist("LochNess"); + Class<?> c = helper.getClass("LochNess"); + assertTrue(helper.countMethodRegexp(c, "fire.*") > 0, "Method fire.* in LochNess not found."); } - private void hasMethod(Class<?> interfaceDef, String methodName) { - List<Method> methods = Arrays.asList(interfaceDef.getMethods()); - assertTrue(methods.stream().anyMatch(m -> m.getName().contains(methodName)), "No method " + methodName); + @Test + void zIndexMethodTest() { + helper.classExist("DrawableSimulable"); + Class<?> c = helper.getClass("DrawableSimulable"); + helper.hasMethodRegexp(c, "get[zZ][iI]ndex", int.class, new Class[0]); } - private Set<String> getNameOfAllClasses() { - List<String> initClassesName = Arrays.asList("lab.Routines", "lab.App", "lab.DrawingThread", "project.loderunner.Game", "cz.vsb.fei.java1.gravityhook.App"); - for (String className : initClassesName) { - try { - Class.forName(className); - } catch (ClassNotFoundException e) { - System.out.println(String.format("Class '%s' cannot be loaded: %s", className, e.getMessage())); - } - } - Set<String> allClasses = new HashSet<>(); - 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); - allClasses.addAll(reflections.getAll(Scanners.SubTypes.filterResultsBy(c -> { - System.out.println(c); - return true; - }))); - } - return allClasses; + @Test + void zIndexFieldTest() { + helper.classExist("WorldEntity"); + Class<?> c = helper.getClass("WorldEntity"); + helper.hasProperty(c, "[zZ][iI]ndex", int.class, false); } } diff --git a/src/test/java/jez04/structure/test/StructureHelper.java b/src/test/java/jez04/structure/test/StructureHelper.java new file mode 100644 index 0000000..aef0cd0 --- /dev/null +++ b/src/test/java/jez04/structure/test/StructureHelper.java @@ -0,0 +1,248 @@ +package jez04.structure.test; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.PrintStream; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +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.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +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 { + + Set<String> allClasses = getNameOfAllClasses(); + + public void isInterface(Class<?> c) { + assertTrue(c.isInterface(), c.getName() + " have to be interface."); + } + + public void classExist(String name) { + assertTrue(allClasses.stream().anyMatch(c -> c.endsWith(name)), "Class/Interface " + name + " not found"); + } + + public Class<?> getClass(String name) { + String className = allClasses.stream().filter(c -> c.endsWith(name)).findAny().orElse(null); + if (className == null) { + Assertions.fail("Class " + name + " not found."); + } + 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 void hasProperty(Class<?> classDef, String propertyNameRegexp, Class<?> type, boolean array) { + List<Field> fields = Arrays.asList(classDef.getDeclaredFields()); + assertTrue(fields.stream().anyMatch(f -> { + if (f.getName().matches(propertyNameRegexp)) { + if (array) { + return f.getType().isArray() && f.getType().getComponentType().equals(type); + } else { + return f.getType().equals(type); + } + } + return false; + }), "No field " + propertyNameRegexp + " of type " + type.getName() + " (is array " + array + ") in class " + + classDef.getName()); + } + + public void hasPropertyWithAnnotation(Class<?> classDef, String propertyNameRegexp, Class<?> annotation) { + List<Field> fields = Arrays.asList(classDef.getDeclaredFields()); + assertTrue( + fields.stream().filter(f -> f.getName().matches(propertyNameRegexp)) + .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) { + List<Method> methods = Arrays.asList(interfaceDef.getDeclaredMethods()); + assertTrue(methods.stream().anyMatch(m -> m.getName().contains(methodName)), "No method " + methodName); + assertTrue( + methods.stream().filter(m -> m.getName().contains(methodName)) + .anyMatch(m -> m.getReturnType().equals(returnType)), + "Method " + methodName + " not return " + returnType.getName()); + } + + public void hasMethod(Class<?> interfaceDef, String methodName, Class<?> returnType, Class<?>... params) { + List<Method> methods = Arrays.asList(interfaceDef.getDeclaredMethods()); + assertTrue(methods.stream().anyMatch(m -> m.getName().contains(methodName)), "No method " + methodName); + assertTrue( + methods.stream().filter(m -> m.getName().contains(methodName)) + .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 long countMethodRegexp(Class<?> interfaceDef, String methodNameRegexp) { + List<Method> methods = Arrays.asList(interfaceDef.getDeclaredMethods()); + return methods.stream().filter(m -> m.getName().matches(methodNameRegexp)).count(); + } + public long countClassesRegexp(String classNameRegexp) { + return getNameOfAllClasses().stream().filter(className -> className.matches(classNameRegexp)).count(); + } + + public void hasMethodRegexp(Class<?> interfaceDef, String methodNameRegexp, Class<?> returnType, + Class<?>... params) { + List<Method> methods = Arrays.asList(interfaceDef.getDeclaredMethods()); + assertTrue(methods.stream().anyMatch(m -> m.getName().matches(methodNameRegexp)), + "No method " + methodNameRegexp); + assertTrue( + methods.stream().filter(m -> m.getName().matches(methodNameRegexp)) + .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 void hasMethod(Class<?> interfaceDef, boolean finalTag, boolean abstractTag, String methodName, + Class<?> returnType, Class<?>... params) { + List<Method> methods = Arrays.asList(interfaceDef.getDeclaredMethods()); + assertTrue(methods.stream().anyMatch(m -> m.getName().contains(methodName)), "No method " + methodName); + assertTrue( + methods.stream().filter(m -> m.getName().contains(methodName)) + .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 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 hasMethod(Class<?> interfaceDef, String methodName) { + List<Method> methods = Arrays.asList(interfaceDef.getMethods()); + assertTrue(methods.stream().anyMatch(m -> m.getName().contains(methodName)), "No method " + methodName); + } + + public Set<String> getNameOfAllClasses() { + List<String> initClassesName = new ArrayList<>(); + dynamicaliFoundSomeClass(initClassesName); + initClassesName.addAll(List.of("lab.Routines", "lab.App", "lab.DrawingThread")); + for (String className : initClassesName) { + try { + Class.forName(className); + break; + } catch (ClassNotFoundException e) { + System.out.println(String.format("Class '%s' cannot be loaded: %s", className, e.getMessage())); + } + } + Set<String> allClasses = new HashSet<>(); + 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); + allClasses.addAll(reflections.getAll(Scanners.SubTypes.filterResultsBy(c -> { + System.out.println(c); + return true; + }))); + } + for (String string : allClasses) { + System.out.println(string); + } + return allClasses; + } + + public void dynamicaliFoundSomeClass(List<String> initClassesName) { + URL myClassUrl = StructureHelper.class.getResource("ClassStructureTest.class"); + myClassUrl.getFile(); + try { + Path classRoot = Paths.get(myClassUrl.toURI()).getParent().getParent().getParent().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 (List.of("jez04", "META-INF").contains(dir.getFileName().toString())) { + return FileVisitResult.SKIP_SUBTREE; + } + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + System.out.println("VISIT: " + file); + if ("module-info.class".equals(file.getFileName().toString())) { + return FileVisitResult.CONTINUE; + } + if (!file.getFileName().toString().endsWith(".class")) { + return FileVisitResult.CONTINUE; + } + String foundClassName = classRootFinal.relativize(file).toString(); + foundClassName = foundClassName.substring(0, foundClassName.length() - 6) + .replace(File.separatorChar, '.'); + initClassesName.add(foundClassName); + return FileVisitResult.TERMINATE; + } + + @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(); + } + } +} -- GitLab