diff --git a/.gitignore b/.gitignore index db44c8a723e017349e18633821c8ee475d15621c..e295b15b15444d4e6e163fb51a2edb17668c3383 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ .settings/ .project .classpath +*.mv.db +*.trace.db \ No newline at end of file diff --git a/pom.xml b/pom.xml index d79e6e3368a7a5ba056738f44e140b6a5f825931..a85853b9fa543fa3e0c9d8bd47a3a5502797f1ff 100644 --- a/pom.xml +++ b/pom.xml @@ -12,6 +12,12 @@ <maven.compiler.target>21</maven.compiler.target> </properties> <dependencies> + <!-- https://mvnrepository.com/artifact/com.h2database/h2 --> + <dependency> + <groupId>com.h2database</groupId> + <artifactId>h2</artifactId> + <version>2.3.232</version> + </dependency> <dependency> <groupId>org.openjfx</groupId> <artifactId>javafx-controls</artifactId> diff --git a/src/main/java/lab/DbConnector.java b/src/main/java/lab/DbConnector.java new file mode 100644 index 0000000000000000000000000000000000000000..9aba4e9d79f07386e26e3b024bde198495a235b2 --- /dev/null +++ b/src/main/java/lab/DbConnector.java @@ -0,0 +1,57 @@ +package lab; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.List; + +public class DbConnector { + + private static final String JDBC_CONECTIN_STRING = "jdbc:h2:file:./scoreDB"; + + public static List<Score> getAll() { + return queryScore("select * from scores;"); + } + + public static List<Score> getFirstTen() { + return queryScore("select * from scores order by points desc limit 10;"); + } + + private static List<Score> queryScore(String query) { + List<Score> result = new ArrayList<>(); + try (Connection con = DriverManager.getConnection(JDBC_CONECTIN_STRING); + Statement stm = con.createStatement(); + ResultSet rs = stm.executeQuery(query);) { + while (rs.next()) { + result.add(new Score(rs.getString("nick"), rs.getInt("points"))); + } + } catch (SQLException e) { + e.printStackTrace(); + } + return result; + } + + public static void createTable() { + try (Connection con = DriverManager.getConnection(JDBC_CONECTIN_STRING); + Statement stm = con.createStatement();) { + stm.executeUpdate("CREATE TABLE if not exists scores (nick VARCHAR(50) NOT NULL, points INT NOT NULL);"); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + public static void insertScore(Score score) { + try (Connection con = DriverManager.getConnection(JDBC_CONECTIN_STRING); + PreparedStatement stm = con.prepareStatement("INSERT INTO scores VALUES (?, ?)");) { + stm.setString(1, score.getName()); + stm.setInt(2, score.getPoints()); + stm.executeUpdate(); + } catch (SQLException e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/lab/GameController.java b/src/main/java/lab/GameController.java index bb85e3dd84562731ca9adc7e12ae8609c3213e62..d48fecd0a82017a82c5505f253decabd9bc3ae0e 100644 --- a/src/main/java/lab/GameController.java +++ b/src/main/java/lab/GameController.java @@ -1,18 +1,41 @@ package lab; +import java.util.List; + import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.scene.canvas.Canvas; +import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.control.Slider; +import javafx.scene.control.TableColumn; +import javafx.scene.control.TableView; public class GameController { private Scene scene; + @FXML + private Button btnGenerateScore; + + @FXML + private Button btnLoadAll; + + @FXML + private Button btnLoadFirstTen; + @FXML + private TableView<Score> scores; + + @FXML + private TableColumn<Score, String> nickColumn; + + @FXML + private TableColumn<Score, Integer> pointsColumn; + + @FXML private Slider boatPosition; private DrawingThread timer; @@ -46,6 +69,28 @@ public class GameController { playerName.setText(String.format("Number of dead lochnesses: %03d", deadLochNessCounter)); } + @FXML + void btnGenerateScoreAction(ActionEvent event) { + Score score = Score.generate(); + this.scores.getItems().add(score); + DbConnector.insertScore(score); + } + + @FXML + void btnLoadAllAction(ActionEvent event) { + updateScoreTable(DbConnector.getAll()); + } + + @FXML + void btnLoadFirstTenAction(ActionEvent event) { + updateScoreTable(DbConnector.getFirstTen()); + } + + private void updateScoreTable(List<Score> scores) { + this.scores.getItems().clear(); + this.scores.getItems().addAll(scores); + } + @FXML void initialize() { assert boatPosition != null : "fx:id=\"angle\" was not injected: check your FXML file 'gameWindow.fxml'."; diff --git a/src/main/java/lab/MainScreenController.java b/src/main/java/lab/MainScreenController.java index 0dec5be7b1aa951966086b353c060841bab53d4d..5f844a1ec66882498838666957b2adc919268a5b 100644 --- a/src/main/java/lab/MainScreenController.java +++ b/src/main/java/lab/MainScreenController.java @@ -1,46 +1,90 @@ package lab; import java.io.IOException; +import java.util.List; import javafx.event.ActionEvent; import javafx.fxml.FXML; -import javafx.scene.control.RadioButton; +import javafx.scene.control.Button; +import javafx.scene.control.TableColumn; +import javafx.scene.control.TableView; import javafx.scene.control.TextField; import javafx.scene.control.ToggleButton; import javafx.scene.control.ToggleGroup; +import javafx.scene.control.cell.PropertyValueFactory; /** * */ public class MainScreenController { + @FXML + private Button btnGenerateScore; + + @FXML + private Button btnLoadAll; + + @FXML + private Button btnLoadFirstTen; + + @FXML + private TableView<Score> scores; + + @FXML + private TableColumn<Score, String> nickColumn; + + @FXML + private TableColumn<Score, Integer> pointsColumn; + @FXML private ToggleGroup difficult; - @FXML - private ToggleButton easy; + @FXML + private ToggleButton easy; - @FXML - private ToggleButton hard; + @FXML + private ToggleButton hard; - @FXML - private ToggleButton medium; + @FXML + private ToggleButton medium; - @FXML + @FXML private TextField name; private App app; - + @FXML void play(ActionEvent event) throws IOException { - Difficult dif = (Difficult)difficult.getSelectedToggle().getProperties().get(Difficult.class); + Difficult dif = (Difficult) difficult.getSelectedToggle().getProperties().get(Difficult.class); app.switchToGame(name.getText(), dif.getNumberOfMonsters()); } - + public void setApp(App app) { this.app = app; } + @FXML + void btnGenerateScoreAction(ActionEvent event) { + Score score = Score.generate(); + this.scores.getItems().add(score); + DbConnector.insertScore(score); + } + + @FXML + void btnLoadAllAction(ActionEvent event) { + updateScoreTable(DbConnector.getAll()); + } + + @FXML + void btnLoadFirstTenAction(ActionEvent event) { + updateScoreTable(DbConnector.getFirstTen()); + } + + private void updateScoreTable(List<Score> scores) { + this.scores.getItems().clear(); + this.scores.getItems().addAll(scores); + } + @FXML void initialize() { assert difficult != null : "fx:id=\"difficult\" was not injected: check your FXML file 'mainScreen.fxml'."; @@ -48,6 +92,17 @@ public class MainScreenController { easy.getProperties().put(Difficult.class, Difficult.EASY); medium.getProperties().put(Difficult.class, Difficult.MEDIUM); hard.getProperties().put(Difficult.class, Difficult.HARD); + + nickColumn.setCellValueFactory(new PropertyValueFactory<>("name")); + pointsColumn.setCellValueFactory(new PropertyValueFactory<>("points")); + + initDB(); + } + + private void initDB() { + // Stream.generate(Score::generate).limit(10).toList(); + DbConnector.createTable(); + scores.getItems().addAll(DbConnector.getAll()); } } diff --git a/src/main/java/lab/Score.java b/src/main/java/lab/Score.java new file mode 100644 index 0000000000000000000000000000000000000000..70d137ac13f30db887a2a8be3cbfafd2ff41ee73 --- /dev/null +++ b/src/main/java/lab/Score.java @@ -0,0 +1,64 @@ +package lab; + +import java.util.Random; + +public class Score { + + private static final Random RANDOM = new Random(); + + 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 String toString() { + return "Score [name=" + name + ", points=" + points + "]"; + } + + public static Score generate() { + return new Score(getRandomNick(), RANDOM.nextInt(50, 300)); + } + + public static final String[] nicks = { "CyberSurfer", "PixelPioneer", "SocialSavvy", "DigitalDynamo", "ByteBuddy", "InstaGuru", + "TikTokTornado", "SnapMaster", "TweetTrendsetter", "ChatChampion", "HashtagHero", "EmojiEnthusiast", + "StoryStylist", "SelfieStar", "FilterFanatic", "VlogVirtuoso", "Memelord", "InfluencerInsider", + "StreamSupreme", "GeekyGizmo", "CodeCommander", "JavaJuggernaut", "ByteNinja", "SyntaxSamurai", + "ClassyCoder", "ObjectOmnipotent", "LoopLegend", "VariableVirtuoso", "DebugDemon", "CompilerCrusader", + "PixelProdigy", "VirtualVoyager", "AlgorithmAce", "DataDynamo", "ExceptionExpert", "BugBuster", + "SyntaxSorcerer", "CodeCrusader", "JavaJester", "NerdyNavigator", "CryptoCaptain", "SocialButterfly", + "AppArchitect", "WebWizard", "FunctionFreak", "PixelArtist", "CyberPhantom", "HackHero", "CacheChampion", + "ScreenSage", "WebWeaver", "LogicLover", "BitBlazer", "NetworkNomad", "ProtocolPioneer", "BinaryBoss", + "StackSultan", "SocialScribe", "RenderRuler", "ScriptSorcerer", "HTMLHero", "PixelProwler", "FrameFreak", + "DataDreamer", "BotBuilder", "ByteBishop", "KeyboardKnight", "DesignDaredevil", "JavaJuggler", + "SyntaxStrategist", "TechTactician", "ProgramProdigy", "BinaryBard", "PixelPoet", "GigabyteGuru", + "TechTrekker", "NetworkNinja", "DataDetective", "MatrixMaster", "CodeConductor", "AppAlchemist", + "ServerSage", "ClusterChampion", "ScriptSensei", "KeyboardKicker", "CacheCrafter", "SocialSpark", + "BinaryBeast", "CodeConnoisseur", "BitBrain", "VirtualVanguard", "SystemSculptor", "RenderRogue", + "CryptoConqueror", "MachineMonarch", "PixelPal", "CompilerCaptain", "BitBuilder", "TechTitan", + "CloudConqueror", "EchoExplorer", "FunctionFanatic", "RobotRanger" }; + + public static String getRandomNick() { + return nicks[RANDOM.nextInt(nicks.length)]; + } + +} diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 736971c46e3a0601a2db674231080b0e8f886cc0..51b9b1c06e53e56d996d38195f8a878b7315b6db 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -2,6 +2,7 @@ module lab01 { requires transitive javafx.controls; requires javafx.fxml; requires javafx.base; + requires java.sql; opens lab to javafx.fxml; exports lab; } \ No newline at end of file diff --git a/src/main/resources/lab/mainScreen.fxml b/src/main/resources/lab/mainScreen.fxml index 4f2bc2fa0f4c22443a8f5dc1ba6daaeac0f3bcf9..69c55644281846932963325b133d7b89e288934a 100644 --- a/src/main/resources/lab/mainScreen.fxml +++ b/src/main/resources/lab/mainScreen.fxml @@ -4,13 +4,16 @@ <?import javafx.scene.control.Button?> <?import javafx.scene.control.Label?> <?import javafx.scene.control.RadioButton?> +<?import javafx.scene.control.TableColumn?> +<?import javafx.scene.control.TableView?> <?import javafx.scene.control.TextField?> <?import javafx.scene.control.ToggleGroup?> <?import javafx.scene.layout.BorderPane?> <?import javafx.scene.layout.HBox?> +<?import javafx.scene.layout.VBox?> <?import javafx.scene.text.Font?> -<BorderPane fx:id="menuPanel" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1" fx:controller="lab.MainScreenController"> +<BorderPane fx:id="menuPanel" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="436.0" prefWidth="660.0" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1" fx:controller="lab.MainScreenController"> <top> <HBox prefWidth="200.0" BorderPane.alignment="CENTER"> <children> @@ -49,4 +52,22 @@ </children> </HBox> </center> + <right> + <VBox prefHeight="267.0" prefWidth="156.0" BorderPane.alignment="CENTER"> + <children> + <TableView fx:id="scores" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"> + <columns> + <TableColumn fx:id="nickColumn" prefWidth="75.0" text="Nick" /> + <TableColumn fx:id="pointsColumn" prefWidth="75.0" text="Points" /> + </columns> + <columnResizePolicy> + <TableView fx:constant="CONSTRAINED_RESIZE_POLICY" /> + </columnResizePolicy> + </TableView> + <Button fx:id="btnGenerateScore" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#btnGenerateScoreAction" text="Generate new score" /> + <Button fx:id="btnLoadAll" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#btnLoadAllAction" text="Load all from DB" /> + <Button fx:id="btnLoadFirstTen" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#btnLoadFirstTenAction" text="Load first 10 from DB" /> + </children> + </VBox> + </right> </BorderPane> diff --git a/src/test/java/jez04/structure/test/ClassStructureTest.java b/src/test/java/jez04/structure/test/ClassStructureTest.java index eac591813e14f9f137c253acbfc4cc0d6d026c70..2a0188eb4c25e03557033ed5d4c8897d58fb2ee7 100644 --- a/src/test/java/jez04/structure/test/ClassStructureTest.java +++ b/src/test/java/jez04/structure/test/ClassStructureTest.java @@ -2,142 +2,100 @@ 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.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; 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; -import java.util.stream.Collectors; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import org.reflections.Configuration; -import org.reflections.Reflections; -import org.reflections.scanners.Scanners; -import org.reflections.util.ConfigurationBuilder; import javafx.event.ActionEvent; import javafx.fxml.FXML; +import javafx.scene.control.TableColumn; +import javafx.scene.control.TableView; class ClassStructureTest { StructureHelper helper = new StructureHelper(); @Test - void detectNioPackageTest() { - assertTrue(helper.getNameOfAllClasses().stream().anyMatch(name -> name.contains("java.nio")), - "Usage of NIO package not detected."); + void mainScreenControllerExistenceTest() { + helper.classExist("MainScreenController"); } @Test - void detectUsageOfIoPackageTest() { - assertTrue(helper.getNameOfAllClasses().stream().anyMatch(name -> name.contains("java.io")), - "Usage of java IO package not detected."); + void mainScreenControllerFxmlTest() { + helper.classExist("MainScreenController"); + Class<?> c = helper.getClass("MainScreenController"); + helper.hasPropertyWithAnnotation(c, ".*", FXML.class); } @Test - void detectUsageOfPathClassTest() { - assertTrue(helper.getNameOfAllClasses().stream().anyMatch(name -> name.contains("java.nio.file.Path")), - "Usage of Path not detected."); + void mainScreenControllerButtonActionMethodTest() { + helper.classExist("MainScreenController"); + Class<?> c = helper.getClass("MainScreenController"); + long count = helper.countMethodRegexp(c, ".*", void.class, ActionEvent.class); + assertTrue(count > 1, "Only " + count+ " method handling button click found. Expected more then 1"); } @Test - void detectUsageOfFileClassTest() { - assertTrue(helper.getNameOfAllClasses().stream().anyMatch(name -> name.contains("java.nio.file.File")), - "Usage of NIO File not detected."); + void mainScreenControllerTableViewTest() { + helper.classExist("MainScreenController"); + Class<?> c = helper.getClass("MainScreenController"); + helper.hasProperty(c, ".*", TableView.class, false); } - + @Test - 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."); + void mainScreenControllerTableColumnTest() { + helper.classExist("MainScreenController"); + Class<?> c = helper.getClass("MainScreenController"); + helper.hasProperty(c, ".*", TableColumn.class, false); } @Test - 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."); + void dbConnectorTest() { + helper.classExistRegexp(".*[Dd][Bb][cC]on.*"); } @Test - 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."); + void dbConnectorGetAllTest() { + helper.classExistRegexp(".*[Dd][Bb][cC]on.*"); + Class<?> scoreClass = helper.getClassRegexp(".*[sS]core.*"); + Class<?> c = helper.getClassRegexp(".*[Dd][Bb][cC]on.*"); + helper.hasMethodRegexp(c, ".*[aA]ll.*", List.class); + helper.hasMethodRegexp(c, ".*[iI]nsert.*", void.class, scoreClass); + } + @Test + void dbConnectorInsertTest() { + helper.classExistRegexp(".*[Dd][Bb][cC]on.*"); + Class<?> scoreClass = helper.getClassRegexp(".*[sS]core.*"); + Class<?> c = helper.getClassRegexp(".*[Dd][Bb][cC]on.*"); + helper.hasMethodRegexp(c, ".*[iI]nsert.*", void.class, scoreClass); } - @Test - 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."); + void dbConnectorContainsJdbcTest() throws URISyntaxException, IOException { + helper.classExistRegexp(".*[Dd][Bb][cC]on.*"); + Class<?> c = helper.getClassRegexp(".*[Dd][Bb][cC]on.*"); + String src = helper.getSourceCode(c); + assertTrue(src.contains("jdbc:"), "No usage of jdbc detect."); } + @Test - 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."); + void dbConnectorContainsDriverManagerTest() throws URISyntaxException, IOException { + helper.classExistRegexp(".*[Dd][Bb][cC]on.*"); + Class<?> c = helper.getClassRegexp(".*[Dd][Bb][cC]on.*"); + String src = helper.getSourceCode(c); + assertTrue(src.contains("DriverManager"), "No usage of DriverManager detect."); } + @Test - 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."); + void dbConnectorContainsSqlTest() throws URISyntaxException, IOException { + helper.classExistRegexp(".*[Dd][Bb][cC]on.*"); + Class<?> c = helper.getClassRegexp(".*[Dd][Bb][cC]on.*"); + String src = helper.getSourceCode(c).toLowerCase(); + assertTrue(src.contains("create "), "No usage of SQL create."); + assertTrue(src.contains("select "), "No usage of SQL select."); + assertTrue(src.contains("insert "), "No usage of SQL table."); + assertTrue(src.contains(" from "), "No usage of SQL from."); + assertTrue(src.contains(" table"), "No usage of SQL table."); } } diff --git a/src/test/java/jez04/structure/test/StructureHelper.java b/src/test/java/jez04/structure/test/StructureHelper.java index 7e10c4548338227a501380ffd9d7a67d8214a6cc..f3aed5d82d5483fad6c3733ace46c8ce5c29e785 100644 --- a/src/test/java/jez04/structure/test/StructureHelper.java +++ b/src/test/java/jez04/structure/test/StructureHelper.java @@ -1,11 +1,13 @@ 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; @@ -24,6 +26,8 @@ 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 org.junit.jupiter.api.Assertions; @@ -44,20 +48,20 @@ class StructureHelper { assertTrue(allClasses.stream().anyMatch(c -> c.endsWith(name)), "Class/Interface " + name + " not found"); } + public void classExistRegexp(String name) { + assertTrue(allClasses.stream().anyMatch(c -> c.matches(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; + return loadClass(name, name); + } + + public Class<?> getClassRegexp(String name) { + String className = allClasses.stream().filter(c -> c.matches(name)).findAny().orElse(null); + if (className == null) { + Assertions.fail("Class " + name + " not found."); } + return loadClass(name, className); } public Class<?> getClass(String name) { @@ -65,6 +69,10 @@ class StructureHelper { 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) { @@ -125,15 +133,66 @@ class StructureHelper { + Arrays.asList(params).stream().map(Class::getName).collect(Collectors.joining(", "))); } + public Method getMethod(Class<?> interfaceDef, String methodName, Class<?> returnType, Class<?>... params) { + List<Method> methods = Arrays.asList(interfaceDef.getDeclaredMethods()); + List<Method> foundMethods = methods.stream().filter(m -> m.getName().contains(methodName)) + .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) { List<Method> methods = Arrays.asList(interfaceDef.getDeclaredMethods()); return methods.stream().filter(m -> m.getName().matches(methodNameRegexp)).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 getNameOfAllClasses().stream().filter(className -> className.matches(classNameRegexp)).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) { List<Method> methods = Arrays.asList(interfaceDef.getDeclaredMethods()); @@ -147,6 +206,16 @@ class StructureHelper { + Arrays.asList(params).stream().map(Class::getName).collect(Collectors.joining(", "))); } + public long countMethodRegexp(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); + return methods.stream().filter(m -> m.getName().matches(methodNameRegexp)) + .filter(m -> m.getReturnType().equals(returnType)) + .filter(m -> Arrays.asList(m.getParameterTypes()).containsAll(Arrays.asList(params))).count(); + } + public void hasMethod(Class<?> interfaceDef, boolean finalTag, boolean abstractTag, String methodName, Class<?> returnType, Class<?>... params) { List<Method> methods = Arrays.asList(interfaceDef.getDeclaredMethods()); @@ -184,9 +253,22 @@ class StructureHelper { assertTrue(methods.stream().anyMatch(m -> m.getName().contains(methodName)), "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<>(); - dynamicaliFoundSomeClass(allClassesName); + dynamicalyFoundSomeClass(allClassesName); // allClassesName.addAll(List.of("cz.vsb.fei.lab.App", "lab.Routines", "lab.App", "lab.DrawingThread")); for (String className : allClassesName) { try { @@ -203,27 +285,23 @@ class StructureHelper { || p.getName().startsWith("javassist")) { continue; } - System.out.println(p.getName()); +// 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); +// System.out.println(">>> " + c); return true; }))); } - for (String string : allClassesName) { - System.out.println(string); - } 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 dynamicaliFoundSomeClass(Set<String> allClassesName) { - URL myClassUrl = StructureHelper.class.getResource("ClassStructureTest.class"); - myClassUrl.getFile(); + 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()) @@ -233,7 +311,7 @@ class StructureHelper { if ("test-classes".equals(classRoot.getFileName().toString())) { classRoot = classRoot.getParent().resolve("classes"); } - System.out.println("class root: " + classRoot); +// System.out.println("class root: " + classRoot); final Path classRootFinal = classRoot; Files.walkFileTree(classRoot, new FileVisitor<Path>() { @@ -285,20 +363,22 @@ class StructureHelper { 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); + .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); + .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) { + .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) {