From 3047924784e9c930e8f4605a14f8c2c8984ece8f Mon Sep 17 00:00:00 2001 From: jez04 <david.jezek@post.cz> Date: Mon, 24 Feb 2025 01:11:13 +0100 Subject: [PATCH] feat: base changes for java2 --- pom.xml | 10 +- src/main/java/lab/App.java | 7 +- src/main/java/lab/BulletAnimated.java | 2 +- src/main/java/lab/DataImporter.java | 69 ++++++ src/main/java/lab/Person.java | 57 +++++ src/main/resources/lab/gameWindow.fxml | 26 +- .../jez04/structure/test/AllOfContinue.java | 39 +++ .../java/jez04/structure/test/ClassExist.java | 44 ++++ .../structure/test/ClassStructureTest.java | 161 +++++++----- .../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 | 229 ++++++++++++++++-- .../structure/test/StructureMatcher.java | 7 + 18 files changed, 1002 insertions(+), 108 deletions(-) create mode 100644 src/main/java/lab/DataImporter.java create mode 100644 src/main/java/lab/Person.java create mode 100644 src/test/java/jez04/structure/test/AllOfContinue.java create mode 100644 src/test/java/jez04/structure/test/ClassExist.java create mode 100644 src/test/java/jez04/structure/test/ContainsInnerClasses.java create mode 100644 src/test/java/jez04/structure/test/HasMethod.java create mode 100644 src/test/java/jez04/structure/test/HasProperty.java create mode 100644 src/test/java/jez04/structure/test/IsDescendatOf.java create mode 100644 src/test/java/jez04/structure/test/IsInterface.java create mode 100644 src/test/java/jez04/structure/test/ResourceContains.java create mode 100644 src/test/java/jez04/structure/test/SrcContains.java create mode 100644 src/test/java/jez04/structure/test/StructureMatcher.java diff --git a/pom.xml b/pom.xml index 98920e8..f9a7995 100644 --- a/pom.xml +++ b/pom.xml @@ -2,8 +2,8 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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>lab11v1</artifactId> + <groupId>vsb-cs-java2</groupId> + <artifactId>java2lab02v1</artifactId> <version>0.0.1-SNAPHOST</version> <packaging>jar</packaging> <properties> @@ -60,6 +60,12 @@ <version>0.10.2</version> <scope>test</scope> </dependency> + <dependency> + <groupId>org.hamcrest</groupId> + <artifactId>hamcrest</artifactId> + <version>3.0</version> + <scope>test</scope> + </dependency> </dependencies> <build> <plugins> diff --git a/src/main/java/lab/App.java b/src/main/java/lab/App.java index 9543b11..ec8e126 100644 --- a/src/main/java/lab/App.java +++ b/src/main/java/lab/App.java @@ -15,9 +15,6 @@ import javafx.stage.WindowEvent; */ public class App extends Application { - static { - System.out.println("aaa"); - } private GameController gameController; public static void main(String[] args) { launch(args); @@ -32,8 +29,8 @@ public class App extends Application { GameController gameController = gameLoader.getController(); Scene scene = new Scene(root); primaryStage.setScene(scene); - primaryStage.resizableProperty().set(false); - primaryStage.setTitle("Java 1 - 1th laboratory"); +// primaryStage.resizableProperty().set(false); + primaryStage.setTitle("Java 2 - 2nd laboratory"); primaryStage.show(); // Exit program when main window is closed primaryStage.setOnCloseRequest(this::exitProgram); diff --git a/src/main/java/lab/BulletAnimated.java b/src/main/java/lab/BulletAnimated.java index e0de237..8274916 100644 --- a/src/main/java/lab/BulletAnimated.java +++ b/src/main/java/lab/BulletAnimated.java @@ -13,7 +13,7 @@ public class BulletAnimated extends Bullet { private static final double SIZE = 40; private final Point2D initVelocity; private Cannon cannon; - private Image image = new Image(this.getClass().getResourceAsStream("fireball-transparent.gif")); + private static Image image = new Image(BulletAnimated.class.getResourceAsStream("fireball-transparent.gif")); private List<HitListener> hitListeners = new ArrayList<>(); diff --git a/src/main/java/lab/DataImporter.java b/src/main/java/lab/DataImporter.java new file mode 100644 index 0000000..735c61e --- /dev/null +++ b/src/main/java/lab/DataImporter.java @@ -0,0 +1,69 @@ +package lab; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.regex.MatchResult; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +public class DataImporter { + private static final Pattern personTextPattern = Pattern.compile("\\{[^\\{\\}]*address"); + private static final Pattern firstNamePattern = Pattern.compile("\"firstname\":\"([\\p{IsAlphabetic}']+)\""); + private static final Pattern lastNamePattern = Pattern.compile("\"lastname\":\"([\\p{IsAlphabetic}']+)\""); + private static final Pattern datePattern = Pattern.compile("\"birthday\":\"(\\d{4}-\\d{2}-\\d{2})\""); + private static final DateTimeFormatter czechDate = DateTimeFormatter.ofPattern("dd. MM. YYYY"); + + public static void main(String[] args) { + importPlayers(); + } + + public static void importPlayers() { + List<Person> persons = parseData(downloadText()).stream().map(DataImporter::parsePerson).toList(); + + for (Person person : persons) { + System.out.printf("%s %s (%s): age=%d, 50th: %s , next in: %d%n" + , person.getFirstName(), person.getLastName() + , person.getDayOfBirth().format(czechDate) + , person.getAge() + , person.get50thBirthDay().format(czechDate) + , person.getDaysToBirthday()); + } + } + + public static String downloadText() { + try { + URL url = new URI("https://fakerapi.it/api/v2/persons?_quantity=20").toURL(); + try (InputStream is = url.openStream()) { + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is)); + return bufferedReader.lines().collect(Collectors.joining("\n")); + } + } catch (URISyntaxException | IOException e) { + e.printStackTrace(); + return ""; + } + } + + public static List<String> parseData(String data) { + Matcher matcher = personTextPattern.matcher(data); + return matcher.results().map(MatchResult::group).toList(); + } + + public static Person parsePerson(String personText) { + String firstName = firstNamePattern.matcher(personText).results().map(result -> result.group(1)).findAny() + .orElse(""); + String lastName = lastNamePattern.matcher(personText).results().map(result -> result.group(1)).findAny() + .orElse(""); + LocalDate date = datePattern.matcher(personText).results().map(result -> result.group(1)).map(text -> LocalDate.parse(text, DateTimeFormatter.ISO_DATE)).findAny() + .orElse(LocalDate.EPOCH); + return new Person(firstName, lastName, date); + } +} diff --git a/src/main/java/lab/Person.java b/src/main/java/lab/Person.java new file mode 100644 index 0000000..3694c1e --- /dev/null +++ b/src/main/java/lab/Person.java @@ -0,0 +1,57 @@ +package lab; + +import java.time.Duration; +import java.time.LocalDate; +import java.time.Period; +import java.time.temporal.ChronoUnit; + +public class Person { + + private String firstName; + private String lastName; + private LocalDate dayOfBirth; + + public Person(String firstName, String lastName, LocalDate dayOfBirth) { + super(); + this.firstName = firstName; + this.lastName = lastName; + this.dayOfBirth = dayOfBirth; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getFirstName() { + return firstName; + } + + public LocalDate getDayOfBirth() { + return dayOfBirth; + } + + public int getAge() { + return Period.between(dayOfBirth, LocalDate.now()).getYears(); + } + + public static void main(String[] args) { + Person p = new Person("", "", LocalDate.now().minusDays(3700)); + System.out.println(p.getAge()); + System.out.println(p.getDaysToBirthday()); + } + public LocalDate get50thBirthDay() { + return dayOfBirth.plusYears(50); + } + + public long getDaysToBirthday() { + LocalDate nextBirthday = dayOfBirth.withYear(LocalDate.now().getYear()); + if(nextBirthday.isBefore(LocalDate.now())){ + nextBirthday = nextBirthday.plusYears(1); + } + return ChronoUnit.DAYS.between(LocalDate.now(), nextBirthday); + } +} diff --git a/src/main/resources/lab/gameWindow.fxml b/src/main/resources/lab/gameWindow.fxml index 7fc092a..33be739 100644 --- a/src/main/resources/lab/gameWindow.fxml +++ b/src/main/resources/lab/gameWindow.fxml @@ -4,18 +4,18 @@ <?import javafx.scene.Cursor?> <?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?> <?import javafx.scene.layout.BorderPane?> <?import javafx.scene.layout.HBox?> +<?import javafx.scene.layout.StackPane?> <?import javafx.scene.layout.VBox?> <?import javafx.scene.text.Font?> -<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="471.0" prefWidth="901.0" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1" fx:controller="lab.GameController"> +<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="421.0" prefWidth="849.0" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1" fx:controller="lab.GameController"> <bottom> - <HBox alignment="TOP_CENTER" prefHeight="100.0" prefWidth="200.0" BorderPane.alignment="CENTER"> + <HBox alignment="TOP_CENTER" prefHeight="66.0" prefWidth="866.0" BorderPane.alignment="CENTER"> <children> <Slider fx:id="angle" majorTickUnit="15.0" max="90.0" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minorTickCount="5" showTickLabels="true" showTickMarks="true" HBox.hgrow="ALWAYS" /> <Button mnemonicParsing="false" onAction="#fire" style="-fx-background-color: RED;" text="Fire" textAlignment="CENTER"> @@ -36,18 +36,18 @@ </children> </HBox> </bottom> - <center> - <Canvas fx:id="canvas" height="306.0" width="582.0" BorderPane.alignment="CENTER"> + <left> + <StackPane style="-fx-border-image-width: 3px; -fx-border-style: SOLID;" BorderPane.alignment="CENTER"> <BorderPane.margin> <Insets /> </BorderPane.margin> - </Canvas> - </center> - <top> - <Label fx:id="hits" text="Hit count: 0" textAlignment="CENTER" BorderPane.alignment="CENTER" /> - </top> - <right> - <VBox maxHeight="1.7976931348623157E308" maxWidth="-Infinity" BorderPane.alignment="CENTER"> + <children> + <Canvas fx:id="canvas" height="306.0" style="-fx-border-width: 3px; -fx-border-style: SOLID; -fx-border-color: RGB(100.0,0.0,0.0);" width="582.0" StackPane.alignment="TOP_LEFT" /> + </children> + </StackPane> + </left> + <center> + <VBox maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" BorderPane.alignment="CENTER"> <children> <TableView fx:id="scores" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"> <columns> @@ -63,5 +63,5 @@ <Button fx:id="btnLoadFirstTen" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#btnLoadFirstTenAction" text="Load First 10 from DB" /> </children> </VBox> - </right> + </center> </BorderPane> diff --git a/src/test/java/jez04/structure/test/AllOfContinue.java b/src/test/java/jez04/structure/test/AllOfContinue.java new file mode 100644 index 0000000..8eb250b --- /dev/null +++ b/src/test/java/jez04/structure/test/AllOfContinue.java @@ -0,0 +1,39 @@ +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 new file mode 100644 index 0000000..7e1f9b7 --- /dev/null +++ b/src/test/java/jez04/structure/test/ClassExist.java @@ -0,0 +1,44 @@ +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 b54aa04..1e4cce5 100644 --- a/src/test/java/jez04/structure/test/ClassStructureTest.java +++ b/src/test/java/jez04/structure/test/ClassStructureTest.java @@ -1,101 +1,132 @@ package jez04.structure.test; -import static org.junit.jupiter.api.Assertions.assertTrue; +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 org.junit.jupiter.api.Test; -import javafx.event.ActionEvent; -import javafx.fxml.FXML; -import javafx.scene.control.TableColumn; -import javafx.scene.control.TableView; - class ClassStructureTest { - StructureHelper helper = new StructureHelper(); + StructureHelper helper = StructureHelper.getInstance(); @Test - void gameControllerExistenceTest() { - helper.classExist("GameController"); + void dataImporterTest() throws URISyntaxException, IOException, IllegalAccessException, InvocationTargetException { + assertThat("", new ClassExist(".*Data.*", false, true)); + Class<?> c = helper.getClassRegexp(".*Data.*"); } @Test - void gameControllerFxmlTest() { - helper.classExist("GameController"); - Class<?> c = helper.getClass("GameController"); - helper.hasPropertyWithAnnotation(c, ".*", FXML.class); + void dataImporterDownloadTest() throws URISyntaxException, IOException, IllegalAccessException, InvocationTargetException { + assertThat("", new ClassExist(".*Data.*", false, true)); + Class<?> d = helper.getClassRegexp(".*Data.*"); + assertThat(d, new HasMethod(".*down.*", String.class).useRegExp(true).caseSensitive(false)); + Method download = helper.getMethod(d, ".*down.*", false, String.class); + String downloadedText = (String) download.invoke(null); + assertThat(downloadedText, allOf( + endsWith("}]}"), + startsWith("{\"status\":\"OK\""), + stringContainsInOrder("firstname"), + stringContainsInOrder("lastname"), + stringContainsInOrder("birthday") + )); + } @Test - void gameControllerButtonActionMethodTest() { - helper.classExist("GameController"); - Class<?> c = helper.getClass("GameController"); - long count = helper.countMethodRegexp(c, ".*", void.class, ActionEvent.class); - assertTrue(count > 1, "Only " + count+ " method handling button click found. Expected more then 1"); + void dataImporterParseAllTest() throws URISyntaxException, IOException, IllegalAccessException, InvocationTargetException { + assertThat("", new ClassExist(".*Data.*", false, true)); + Class<?> d = helper.getClassRegexp(".*Data.*"); + helper.hasMethod(d, ".*parse.*", false, List.class, String.class); + Method parse = helper.getMethod(d, ".*parse.*", false, List.class, String.class); + List<String> texts = (List<String>) parse.invoke(null, "{\"id\":1,\"firstname\":\"Tatum\",\"lastname\":\"Block\",\"email\":\"lonnie.bergstrom@stoltenberg.com\",\"phone\":\"+12397191764\",\"birthday\":\"1946-11-06\",\"gender\":\"male\",\"address\":{"); + assertThat(texts, not(empty())); } @Test - void gameControllerTableViewTest() { - helper.classExist("GameController"); - Class<?> c = helper.getClass("GameController"); - helper.hasProperty(c, ".*", TableView.class, false); - } - - @Test - void gameControllerTableColumnTest() { - helper.classExist("GameController"); - Class<?> c = helper.getClass("GameController"); - helper.hasProperty(c, ".*", TableColumn.class, false); + void personTest() throws URISyntaxException, IOException, IllegalAccessException, InvocationTargetException { + assertThat("", new ClassExist("Person", false, false)); + Class<?> p = helper.getClass("Person", false); } @Test - void dbConnectorTest() { - helper.classExistRegexp(".*[Dd][Bb][cC]on.*"); - } + void dataImporterParsePersonTest() throws URISyntaxException, IOException, IllegalAccessException, InvocationTargetException { + assertThat("", new ClassExist(".*Data.*", false, true)); + Class<?> d = helper.getClassRegexp(".*Data.*"); - @Test - 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); + assertThat("", new ClassExist("Person", false, false)); + Class<?> p = helper.getClass("Person", false); + helper.hasMethod(d, ".*parse.*", false, p, String.class); + Method parsePerson = helper.getMethod(d, ".*parse.*", false, p, String.class); + Object person = parsePerson.invoke(null, "{\"id\":1,\"firstname\":\"Tatum\",\"lastname\":\"Block\",\"email\":\"lonnie.bergstrom@stoltenberg.com\",\"phone\":\"+12397191764\",\"birthday\":\"1946-11-06\",\"gender\":\"male\",\"address\":{"); + assertThat(person, notNullValue()); } + @Test - 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."); + void personAgeTest() throws URISyntaxException, IOException, IllegalAccessException, InvocationTargetException { + assertThat("", new ClassExist(".*Data.*", false, true)); + Class<?> d = helper.getClassRegexp(".*Data.*"); + + assertThat("", new ClassExist("Person", false, false)); + Class<?> p = helper.getClass("Person", false); + helper.hasMethod(d, ".*parse.*", false, p, String.class); + Method parsePerson = helper.getMethod(d, ".*parse.*", false, p, String.class); + Object person = parsePerson.invoke(null, "{\"id\":1,\"firstname\":\"Tatum\",\"lastname\":\"Block\",\"email\":\"lonnie.bergstrom@stoltenberg.com\",\"phone\":\"+12397191764\",\"birthday\":\"1946-11-06\",\"gender\":\"male\",\"address\":{"); + assertThat(person, notNullValue()); + + Method age = helper.getMethod(p, ".*age.*", false, int.class); + int result = (int)age.invoke(person); + assertEquals(78, result , "Calculate wrong age."); } @Test - 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."); + void person50birthdayTest() throws URISyntaxException, IOException, IllegalAccessException, InvocationTargetException { + assertThat("", new ClassExist(".*Data.*", false, true)); + Class<?> d = helper.getClassRegexp(".*Data.*"); + + assertThat("", new ClassExist("Person", false, false)); + Class<?> p = helper.getClass("Person", false); + helper.hasMethod(d, ".*parse.*", false, p, String.class); + Method parsePerson = helper.getMethod(d, ".*parse.*", false, p, String.class); + Object person = parsePerson.invoke(null, "{\"id\":1,\"firstname\":\"Tatum\",\"lastname\":\"Block\",\"email\":\"lonnie.bergstrom@stoltenberg.com\",\"phone\":\"+12397191764\",\"birthday\":\"1946-11-06\",\"gender\":\"male\",\"address\":{"); + assertThat(person, notNullValue()); + + Method birth50 = helper.getMethod(p, ".*50.*", false, LocalDate.class); + LocalDate ldBirth50 = (LocalDate)birth50.invoke(person); + assertEquals(LocalDate.of(1996, 11, 06), ldBirth50 , "Calculate wrong 50th birthday."); + } @Test - 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."); + void personNextBirthdayTest() throws URISyntaxException, IOException, IllegalAccessException, InvocationTargetException { + assertThat("", new ClassExist(".*Data.*", false, true)); + Class<?> d = helper.getClassRegexp(".*Data.*"); + + assertThat("", new ClassExist("Person", false, false)); + Class<?> p = helper.getClass("Person", false); + helper.hasMethod(d, ".*parse.*", false, p, String.class); + Method parsePerson = helper.getMethod(d, ".*parse.*", false, p, String.class); + LocalDate bod =LocalDate.now().plusDays(338).minusYears(10); + Object person = parsePerson.invoke(null, "{\"id\":1,\"firstname\":\"Tatum\",\"lastname\":\"Block\",\"email\":\"lonnie.bergstrom@stoltenberg.com\",\"phone\":\"+12397191764\",\"birthday\":\""+ bod.format(DateTimeFormatter.ISO_DATE) +"\",\"gender\":\"male\",\"address\":{"); + assertThat(person, notNullValue()); + + Method daysM = helper.getMethod(p, ".*days.*", false, long.class); + long days= (long)daysM.invoke(person); + assertEquals(338, days , "Calculate wrong days to next birthday."); } + } diff --git a/src/test/java/jez04/structure/test/ContainsInnerClasses.java b/src/test/java/jez04/structure/test/ContainsInnerClasses.java new file mode 100644 index 0000000..5c79529 --- /dev/null +++ b/src/test/java/jez04/structure/test/ContainsInnerClasses.java @@ -0,0 +1,70 @@ +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 new file mode 100644 index 0000000..142fec8 --- /dev/null +++ b/src/test/java/jez04/structure/test/HasMethod.java @@ -0,0 +1,95 @@ +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 new file mode 100644 index 0000000..0e7098d --- /dev/null +++ b/src/test/java/jez04/structure/test/HasProperty.java @@ -0,0 +1,91 @@ +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 new file mode 100644 index 0000000..a202faa --- /dev/null +++ b/src/test/java/jez04/structure/test/IsDescendatOf.java @@ -0,0 +1,24 @@ +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 new file mode 100644 index 0000000..2abdee2 --- /dev/null +++ b/src/test/java/jez04/structure/test/IsInterface.java @@ -0,0 +1,23 @@ +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 new file mode 100644 index 0000000..e7d9277 --- /dev/null +++ b/src/test/java/jez04/structure/test/ResourceContains.java @@ -0,0 +1,102 @@ +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 new file mode 100644 index 0000000..4ed7d6c --- /dev/null +++ b/src/test/java/jez04/structure/test/SrcContains.java @@ -0,0 +1,54 @@ +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 index f3aed5d..6ccabb4 100644 --- a/src/test/java/jez04/structure/test/StructureHelper.java +++ b/src/test/java/jez04/structure/test/StructureHelper.java @@ -29,7 +29,10 @@ 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; @@ -38,18 +41,49 @@ 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) { - assertTrue(allClasses.stream().anyMatch(c -> c.endsWith(name)), "Class/Interface " + name + " not found"); + 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) { - assertTrue(allClasses.stream().anyMatch(c -> c.matches(name)), "Class/Interface " + name + " not found"); + 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) { @@ -57,7 +91,13 @@ class StructureHelper { } public Class<?> getClassRegexp(String name) { - String className = allClasses.stream().filter(c -> c.matches(name)).findAny().orElse(null); + 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."); } @@ -65,7 +105,13 @@ class StructureHelper { } public Class<?> getClass(String name) { - String className = allClasses.stream().filter(c -> c.endsWith(name)).findAny().orElse(null); + 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."); } @@ -88,10 +134,27 @@ class StructureHelper { } } + 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()); - assertTrue(fields.stream().anyMatch(f -> { - if (f.getName().matches(propertyNameRegexp)) { + 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 { @@ -99,14 +162,20 @@ class StructureHelper { } } 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) { + 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 -> f.getName().matches(propertyNameRegexp)) + 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 " @@ -114,19 +183,36 @@ class StructureHelper { } 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 -> m.getName().contains(methodName)) + 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 -> m.getName().contains(methodName)), "No method " + methodName); assertTrue( - methods.stream().filter(m -> m.getName().contains(methodName)) + 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:" @@ -134,8 +220,15 @@ class StructureHelper { } 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 -> m.getName().contains(methodName)) + 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()) { @@ -148,8 +241,13 @@ class StructureHelper { } 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 -> m.getName().matches(methodNameRegexp)).count(); + 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 { @@ -170,7 +268,12 @@ class StructureHelper { } public long countClassesRegexp(String classNameRegexp) { - return getNameOfAllClasses().stream().filter(className -> className.matches(classNameRegexp)).count(); + 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) { @@ -195,33 +298,103 @@ class StructureHelper { 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 -> m.getName().matches(methodNameRegexp)), + assertTrue( + methods.stream() + .anyMatch(m -> caseSensitive ? m.getName().matches(methodNameRegexp) + : m.getName().toLowerCase().matches(methodNameRegexp.toLowerCase())), "No method " + methodNameRegexp); assertTrue( - methods.stream().filter(m -> m.getName().matches(methodNameRegexp)) + 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 -> m.getName().matches(methodNameRegexp)), + assertTrue( + methods.stream() + .anyMatch(m -> caseSensitive ? m.getName().matches(methodNameRegexp) + : m.getName().toLowerCase().matches(methodNameRegexp.toLowerCase())), "No method " + methodNameRegexp); - return methods.stream().filter(m -> m.getName().matches(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 -> m.getName().contains(methodName)), "No method " + methodName); assertTrue( - methods.stream().filter(m -> m.getName().contains(methodName)) + 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)) @@ -230,6 +403,10 @@ class StructureHelper { + 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)); @@ -249,8 +426,16 @@ class StructureHelper { } 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 -> m.getName().contains(methodName)), "No method " + methodName); + 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 { diff --git a/src/test/java/jez04/structure/test/StructureMatcher.java b/src/test/java/jez04/structure/test/StructureMatcher.java new file mode 100644 index 0000000..6b8bc25 --- /dev/null +++ b/src/test/java/jez04/structure/test/StructureMatcher.java @@ -0,0 +1,7 @@ +package jez04.structure.test; + +public abstract class StructureMatcher<T> extends org.hamcrest.BaseMatcher<T>{ + + protected StructureHelper structureHelper = StructureHelper.getInstance(); + +} -- GitLab