diff --git a/pom.xml b/pom.xml index 09bb40bc234c77512a8d999b42d007b371408875..d79e6e3368a7a5ba056738f44e140b6a5f825931 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>vsb-cs-java1</groupId> - <artifactId>lab07v3</artifactId> + <artifactId>lab10v3</artifactId> <version>0.0.1-SNAPHOST</version> <packaging>jar</packaging> <properties> @@ -22,6 +22,19 @@ <artifactId>javafx-fxml</artifactId> <version>23</version> </dependency> + <dependency> + <groupId>org.openjfx</groupId> + <artifactId>javafx-media</artifactId> + <version>23</version> + </dependency> + <dependency> + <groupId>org.controlsfx</groupId> + <artifactId>controlsfx</artifactId> + <version>11.2.1</version> + </dependency> + + + <!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api --> <dependency> diff --git a/src/test/java/jez04/structure/test/ClassStructureTest.java b/src/test/java/jez04/structure/test/ClassStructureTest.java index a1a6b0d98aacc47685ec282926418915c0726ef2..eac591813e14f9f137c253acbfc4cc0d6d026c70 100644 --- a/src/test/java/jez04/structure/test/ClassStructureTest.java +++ b/src/test/java/jez04/structure/test/ClassStructureTest.java @@ -5,7 +5,11 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.io.PrintStream; +import java.io.Reader; +import java.io.Writer; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; @@ -40,105 +44,100 @@ class ClassStructureTest { StructureHelper helper = new StructureHelper(); @Test - void gameControllerExistenceTest() { - helper.classExist("GameController"); + void detectNioPackageTest() { + assertTrue(helper.getNameOfAllClasses().stream().anyMatch(name -> name.contains("java.nio")), + "Usage of NIO package not detected."); } @Test - void gameControllerFxmlTest() { - helper.classExist("GameController"); - Class<?> c = helper.getClass("GameController"); - helper.hasPropertyWithAnnotation(c, ".*", FXML.class); + void detectUsageOfIoPackageTest() { + assertTrue(helper.getNameOfAllClasses().stream().anyMatch(name -> name.contains("java.io")), + "Usage of java IO package not detected."); } @Test - void gameControllerActionMethodTest() { - helper.classExist("GameController"); - Class<?> c = helper.getClass("GameController"); - helper.hasMethodRegexp(c, ".*", void.class, ActionEvent.class); + void detectUsageOfPathClassTest() { + assertTrue(helper.getNameOfAllClasses().stream().anyMatch(name -> name.contains("java.nio.file.Path")), + "Usage of Path not detected."); } @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."); + void detectUsageOfFileClassTest() { + assertTrue(helper.getNameOfAllClasses().stream().anyMatch(name -> name.contains("java.nio.file.File")), + "Usage of NIO File not detected."); } @Test - void deadListenerExistenceTest() { - helper.classExist("DeadListener"); + void detectUsageOfInputStreamClassTest() { + assertTrue(helper.getNameOfAllClasses().stream().map(className -> { + try { + return Class.forName(className); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + return Object.class; + }).anyMatch(clazz -> InputStream.class.isAssignableFrom(clazz)), "Usage of InputStream not detected."); } @Test - void deadListenerEventMethodTest() { - helper.classExist("DeadListener"); - Class<?> c = helper.getClass("DeadListener"); - helper.hasMethod(c, "lochnessDead"); + void detectUsageOfReaderClassTest() { + assertTrue(helper.getNameOfAllClasses().stream().map(className -> { + try { + return Class.forName(className); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + return Object.class; + }).anyMatch(clazz -> Reader.class.isAssignableFrom(clazz)), "Usage of Reader not detected."); } @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."); + void detectUsageOfOutputStreamClassTest() { + assertTrue(helper.getNameOfAllClasses().stream().map(className -> { + try { + return Class.forName(className); + } catch (Throwable e) { + System.out.println(e.getMessage()); + } + return Object.class; + }).anyMatch(clazz -> OutputStream.class.isAssignableFrom(clazz)), "Usage of OutputStream not detected."); } @Test - void sceneMethodAddTest() { - helper.classExist("lab.Scene"); - Class<?> c = helper.getClass("lab.Scene"); - helper.hasMethod(c, "add", void.class, helper.getClass("DrawableSimulable")); - ; + void detectUsageOfWriterTest() { + assertTrue(helper.getNameOfAllClasses().stream().map(className -> { + try { + return Class.forName(className); + } catch (ClassNotFoundException e) { + System.out.println(e.getMessage()); + } + return Object.class; + }).anyMatch(clazz -> + Writer.class.isAssignableFrom(clazz) + ), "Usage of Writer not detected."); } - - @Test - void sceneMethodRemoveTest() { - helper.classExist("lab.Scene"); - Class<?> c = helper.getClass("lab.Scene"); - helper.hasMethod(c, "remove", void.class, helper.getClass("DrawableSimulable")); - ; - } - - @Test - void lochnessMethodAddTest() { - helper.classExist("LochNess"); - Class<?> c = helper.getClass("LochNess"); - helper.hasMethod(c, "addDeadListener"); - } - @Test - void lochnessMethodRemoveTest() { - helper.classExist("LochNess"); - Class<?> c = helper.getClass("LochNess"); - helper.hasMethod(c, "removeDeadListener"); + void detectUsageOfExceptionClassTest() { + assertTrue(helper.getNameOfAllClasses().stream().filter(name -> !name.startsWith("javafx.")).map(className -> { + try { + return Class.forName(className); + } catch (Throwable e) { + System.out.println(e.getMessage()); + } + return Object.class; + }).anyMatch(clazz -> + Exception.class.isAssignableFrom(clazz) + ), "Usage of Exception not detected."); } - - @Test - void lochnessMethodFireTest() { - helper.classExist("LochNess"); - Class<?> c = helper.getClass("LochNess"); - assertTrue(helper.countMethodRegexp(c, "fire.*") > 0, "Method fire.* in LochNess not found."); - } - - @Test - void zIndexMethodTest() { - helper.classExist("DrawableSimulable"); - Class<?> c = helper.getClass("DrawableSimulable"); - helper.hasMethodRegexp(c, "get[zZ][iI]ndex", int.class, new Class[0]); - } - @Test - void zIndexFieldTest() { - helper.classExist("WorldEntity"); - Class<?> c = helper.getClass("WorldEntity"); - helper.hasProperty(c, "[zZ][iI]ndex", int.class, false); + void detectUsageOfIOExceptionClassTest() { + assertTrue(helper.getNameOfAllClasses().stream().map(className -> { + try { + return Class.forName(className); + } catch (ClassNotFoundException e) { + System.out.println(e.getMessage()); + } + return Object.class; + }).anyMatch(clazz -> IOException.class.isAssignableFrom(clazz)), "Usage of IOException not detected."); } } diff --git a/src/test/java/jez04/structure/test/StructureHelper.java b/src/test/java/jez04/structure/test/StructureHelper.java index aef0cd0cbadbd6c2a561db4d1741c978e9fa2891..7e10c4548338227a501380ffd9d7a67d8214a6cc 100644 --- a/src/test/java/jez04/structure/test/StructureHelper.java +++ b/src/test/java/jez04/structure/test/StructureHelper.java @@ -9,6 +9,7 @@ import java.io.PrintStream; 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; @@ -19,9 +20,10 @@ 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.TreeSet; +import java.util.function.Predicate; import java.util.stream.Collectors; import org.junit.jupiter.api.Assertions; @@ -42,6 +44,22 @@ class StructureHelper { assertTrue(allClasses.stream().anyMatch(c -> c.endsWith(name)), "Class/Interface " + name + " not found"); } + public Class<?> getClassDirectly(String name) { + try { + return Class.forName(name); + } 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 Class<?> getClass(String name) { String className = allClasses.stream().filter(c -> c.endsWith(name)).findAny().orElse(null); if (className == null) { @@ -111,6 +129,7 @@ class StructureHelper { 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(); } @@ -155,16 +174,21 @@ class StructureHelper { "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) { 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) { + Set<String> allClassesName = new TreeSet<>(); + dynamicaliFoundSomeClass(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; @@ -172,7 +196,6 @@ class StructureHelper { 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.") @@ -184,22 +207,29 @@ class StructureHelper { 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); + allClassesName.addAll(reflections.getAll(Scanners.SubTypes.filterResultsBy(c -> { + System.out.println(">>> " + c); return true; }))); } - for (String string : allClasses) { + for (String string : allClassesName) { System.out.println(string); } - return allClasses; + return allClassesName; } - public void dynamicaliFoundSomeClass(List<String> initClassesName) { + private static final List<String> dirsToSkip = List.of("jez04", "META-INF"); + private static final List<String> filesToSkip = List.of("module-info.class"); + + public void dynamicaliFoundSomeClass(Set<String> allClassesName) { URL myClassUrl = StructureHelper.class.getResource("ClassStructureTest.class"); myClassUrl.getFile(); try { - Path classRoot = Paths.get(myClassUrl.toURI()).getParent().getParent().getParent().getParent(); + 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"); } @@ -209,7 +239,7 @@ class StructureHelper { @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { - if (List.of("jez04", "META-INF").contains(dir.getFileName().toString())) { + if (dirsToSkip.contains(dir.getFileName().toString())) { return FileVisitResult.SKIP_SUBTREE; } return FileVisitResult.CONTINUE; @@ -217,18 +247,20 @@ class StructureHelper { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - System.out.println("VISIT: " + file); - if ("module-info.class".equals(file.getFileName().toString())) { + 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, '.'); - initClassesName.add(foundClassName); - return FileVisitResult.TERMINATE; + addClassAndAllRef(allClassesName, foundClassName); + return FileVisitResult.CONTINUE; } @Override @@ -245,4 +277,32 @@ class StructureHelper { 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(); + } + } }