Skip to content
Snippets Groups Projects
Commit 7f714782 authored by jez04's avatar jez04
Browse files

feat: :tada: solution

parent 8e204918
No related merge requests found
Showing
with 709 additions and 131 deletions
/logs/
/target/ /target/
.settings/ .settings/
.project .project
......
...@@ -13,6 +13,22 @@ ...@@ -13,6 +13,22 @@
<maven.compiler.target>21</maven.compiler.target> <maven.compiler.target>21</maven.compiler.target>
</properties> </properties>
<dependencies> <dependencies>
<!--
https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.24.3</version>
</dependency>
<!--
https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-api -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.24.3</version>
</dependency>
<dependency> <dependency>
<groupId>com.h2database</groupId> <groupId>com.h2database</groupId>
<artifactId>h2</artifactId> <artifactId>h2</artifactId>
......
...@@ -8,15 +8,30 @@ public class Setup { ...@@ -8,15 +8,30 @@ public class Setup {
private static Setup instance; private static Setup instance;
private ScoreStorageInterface scoreStorageInterface = new DbConnector(); private ScoreStorageInterface scoreStorageInterface = new DbConnector();
private double lochnessMinXPopsition = 0.5; private double lochnessMinXPopsition;
private double lochnessMinYPopsition = 0.5; private double lochnessMinYPopsition;
private double lochnessMinSpeed = 50; private double lochnessMinSpeed;
private double lochnessMaxSpeed = 150; private double lochnessMaxSpeed;
private int lochnessMultiplier = 1; private int lochnessMultiplier;
private double boatCollisionHeight = 0.25; private double boatCollisionHeight;
private double boatHitPulseX = 20; private double boatHitPulseX;
private double boatHitPulseYMin = 50; private double boatHitPulseYMin;
private double boatHitPulseYMax = 100; private double boatHitPulseYMax;
private Setup(ScoreStorageInterface scoreStorageInterface, double lochnessMinXPopsition,
double lochnessMinYPopsition, double lochnessMinSpeed, double lochnessMaxSpeed, int lochnessMultiplier,
double boatCollisionHeight, double boatHitPulseX, double boatHitPulseYMin, double boatHitPulseYMax) {
this.scoreStorageInterface = scoreStorageInterface;
this.lochnessMinXPopsition = lochnessMinXPopsition;
this.lochnessMinYPopsition = lochnessMinYPopsition;
this.lochnessMinSpeed = lochnessMinSpeed;
this.lochnessMaxSpeed = lochnessMaxSpeed;
this.lochnessMultiplier = lochnessMultiplier;
this.boatCollisionHeight = boatCollisionHeight;
this.boatHitPulseX = boatHitPulseX;
this.boatHitPulseYMin = boatHitPulseYMin;
this.boatHitPulseYMax = boatHitPulseYMax;
}
public static void configure(Setup setting) { public static void configure(Setup setting) {
instance = setting; instance = setting;
...@@ -66,4 +81,82 @@ public class Setup { ...@@ -66,4 +81,82 @@ public class Setup {
return lochnessMaxSpeed; return lochnessMaxSpeed;
} }
public static Builder builder() {
return new Builder();
}
public static Setup getInstanceForHardcoreGame() {
return builder().lochnessMaxSpeed(500).lochnessMinSpeed(200).lochnessMultiplier(10).lochnessMinYPopsition(0.1)
.build();
}
public static class Builder {
private ScoreStorageInterface scoreStorageInterface = new DbConnector();
private double lochnessMinXPopsition = 0.5;
private double lochnessMinYPopsition = 0.5;
private double lochnessMinSpeed = 50;
private double lochnessMaxSpeed = 150;
private int lochnessMultiplier = 1;
private double boatCollisionHeight = 0.25;
private double boatHitPulseX = 20;
private double boatHitPulseYMin = 50;
private double boatHitPulseYMax = 100;
public Builder scoreStorageInterface(ScoreStorageInterface scoreStorageInterface) {
this.scoreStorageInterface = scoreStorageInterface;
return this;
}
public Builder lochnessMinXPopsition(double lochnessMinXPopsition) {
this.lochnessMinXPopsition = lochnessMinXPopsition;
return this;
}
public Builder lochnessMinYPopsition(double lochnessMinYPopsition) {
this.lochnessMinYPopsition = lochnessMinYPopsition;
return this;
}
public Builder lochnessMinSpeed(double lochnessMinSpeed) {
this.lochnessMinSpeed = lochnessMinSpeed;
return this;
}
public Builder lochnessMaxSpeed(double lochnessMaxSpeed) {
this.lochnessMaxSpeed = lochnessMaxSpeed;
return this;
}
public Builder lochnessMultiplier(int lochnessMultiplier) {
this.lochnessMultiplier = lochnessMultiplier;
return this;
}
public Builder boatCollisionHeight(double boatCollisionHeight) {
this.boatCollisionHeight = boatCollisionHeight;
return this;
}
public Builder boatHitPulseX(double boatHitPulseX) {
this.boatHitPulseX = boatHitPulseX;
return this;
}
public Builder boatHitPulseYMin(double boatHitPulseYMin) {
this.boatHitPulseYMin = boatHitPulseYMin;
return this;
}
public Builder boatHitPulseYMax(double boatHitPulseYMax) {
this.boatHitPulseYMax = boatHitPulseYMax;
return this;
}
public Setup build() {
return new Setup(scoreStorageInterface, lochnessMinXPopsition, lochnessMinYPopsition, lochnessMinSpeed,
lochnessMaxSpeed, lochnessMultiplier, boatCollisionHeight, boatHitPulseX, boatHitPulseYMin,
boatHitPulseYMax);
}
}
} }
package lab.data; package lab.data;
import java.util.Objects;
import java.util.Random; import java.util.Random;
public class Score { public class Score {
...@@ -30,6 +31,23 @@ public class Score { ...@@ -30,6 +31,23 @@ public class Score {
this.points = points; this.points = points;
} }
@Override
public int hashCode() {
return Objects.hash(name, points);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Score other = (Score) obj;
return Objects.equals(name, other.name) && points == other.points;
}
@Override @Override
public String toString() { public String toString() {
return "Score [name=" + name + ", points=" + points + "]"; return "Score [name=" + name + ", points=" + points + "]";
......
...@@ -4,6 +4,9 @@ import java.util.ArrayList; ...@@ -4,6 +4,9 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import javafx.geometry.Dimension2D; import javafx.geometry.Dimension2D;
import javafx.geometry.Point2D; import javafx.geometry.Point2D;
import javafx.geometry.Rectangle2D; import javafx.geometry.Rectangle2D;
...@@ -13,6 +16,8 @@ import lab.Setup; ...@@ -13,6 +16,8 @@ import lab.Setup;
public class LochNess extends WorldEntity implements Collisionable { public class LochNess extends WorldEntity implements Collisionable {
private static Logger log = LogManager.getLogger(LochNess.class);
private static final Random RANDOM = new Random(); private static final Random RANDOM = new Random();
private Point2D speed; private Point2D speed;
...@@ -48,6 +53,7 @@ public class LochNess extends WorldEntity implements Collisionable { ...@@ -48,6 +53,7 @@ public class LochNess extends WorldEntity implements Collisionable {
position = new Point2D(scene.getSize().getWidth(), position.getY()); position = new Point2D(scene.getSize().getWidth(), position.getY());
speed = speed.multiply(-1); speed = speed.multiply(-1);
} }
log.trace("LochNess position: {}", position);
} }
@Override @Override
...@@ -57,6 +63,7 @@ public class LochNess extends WorldEntity implements Collisionable { ...@@ -57,6 +63,7 @@ public class LochNess extends WorldEntity implements Collisionable {
public void changeDirection() { public void changeDirection() {
speed = speed.multiply(-1); speed = speed.multiply(-1);
log.debug("LochNess chaned direction.");
} }
@Override @Override
...@@ -66,6 +73,7 @@ public class LochNess extends WorldEntity implements Collisionable { ...@@ -66,6 +73,7 @@ public class LochNess extends WorldEntity implements Collisionable {
@Override @Override
public void hitBy(Collisionable another) { public void hitBy(Collisionable another) {
log.trace("LochNess hitted by {}.", another);
if (another instanceof Boat) { if (another instanceof Boat) {
scene.remove(this); scene.remove(this);
scene.add(new Rock(scene, getPosition(), new Dimension2D(10, 10))); scene.add(new Rock(scene, getPosition(), new Dimension2D(10, 10)));
......
...@@ -3,6 +3,9 @@ package lab.gui; ...@@ -3,6 +3,9 @@ package lab.gui;
import java.io.IOException; import java.io.IOException;
import java.net.URL; import java.net.URL;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import javafx.application.Application; import javafx.application.Application;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
import javafx.scene.Parent; import javafx.scene.Parent;
...@@ -19,12 +22,14 @@ import lab.Setup; ...@@ -19,12 +22,14 @@ import lab.Setup;
*/ */
public class App extends Application { public class App extends Application {
private static Logger log = LogManager.getLogger(App.class);
private GameController gameController; private GameController gameController;
private Stage primaryStage; private Stage primaryStage;
public static void main(String[] args) { public static void main(String[] args) {
Setup.configure(new Setup()); log.info("Application lauched");
Setup.configure(Setup.getInstanceForHardcoreGame());
launch(args); launch(args);
} }
...@@ -38,7 +43,7 @@ public class App extends Application { ...@@ -38,7 +43,7 @@ public class App extends Application {
// Exit program when main window is closed // Exit program when main window is closed
primaryStage.setOnCloseRequest(this::exitProgram); primaryStage.setOnCloseRequest(this::exitProgram);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); log.error("Error during game play.", e);
} }
} }
...@@ -71,9 +76,11 @@ public class App extends Application { ...@@ -71,9 +76,11 @@ public class App extends Application {
gameController.stop(); gameController.stop();
} }
super.stop(); super.stop();
log.info("Gamne stoped");
} }
private void exitProgram(WindowEvent evt) { private void exitProgram(WindowEvent evt) {
log.info("Exiting game");
System.exit(0); System.exit(0);
} }
} }
\ No newline at end of file
...@@ -2,6 +2,9 @@ package lab.gui; ...@@ -2,6 +2,9 @@ package lab.gui;
import java.util.List; import java.util.List;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import javafx.beans.value.ChangeListener; import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue; import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent; import javafx.event.ActionEvent;
...@@ -20,6 +23,8 @@ import lab.game.Scene; ...@@ -20,6 +23,8 @@ import lab.game.Scene;
public class GameController { public class GameController {
private static Logger log = LogManager.getLogger(GameController.class);
private Scene scene; private Scene scene;
@FXML @FXML
...@@ -101,19 +106,19 @@ public class GameController { ...@@ -101,19 +106,19 @@ public class GameController {
assert boatPosition != null : "fx:id=\"angle\" was not injected: check your FXML file 'gameWindow.fxml'."; assert boatPosition != null : "fx:id=\"angle\" was not injected: check your FXML file 'gameWindow.fxml'.";
assert canvas != null : "fx:id=\"canvas\" was not injected: check your FXML file 'gameWindow.fxml'."; assert canvas != null : "fx:id=\"canvas\" was not injected: check your FXML file 'gameWindow.fxml'.";
assert speed != null : "fx:id=\"speed\" was not injected: check your FXML file 'gameWindow.fxml'."; assert speed != null : "fx:id=\"speed\" was not injected: check your FXML file 'gameWindow.fxml'.";
boatPosition.valueProperty().addListener(new ChangeListener<Number>() { boatPosition.valueProperty().addListener(new ChangeListener<>() {
@Override @Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) { public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
scene.getBoat().setPosInPercentage(newValue.doubleValue()); scene.getBoat().setPosInPercentage(newValue.doubleValue());
} }
}); });
speed.valueProperty().addListener(new ChangeListener<Number>() { speed.valueProperty().addListener(new ChangeListener<>() {
@Override @Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) { public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
scene.getBackground().setSpeed(newValue.doubleValue()); scene.getBackground().setSpeed(newValue.doubleValue());
} }
}); });
log.info("Screeen initialized.");
} }
public void startGame(String name, int numberOfMonsters) { public void startGame(String name, int numberOfMonsters) {
......
...@@ -3,6 +3,9 @@ package lab.gui; ...@@ -3,6 +3,9 @@ package lab.gui;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import javafx.event.ActionEvent; import javafx.event.ActionEvent;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.scene.control.Button; import javafx.scene.control.Button;
...@@ -21,6 +24,8 @@ import lab.game.Difficult; ...@@ -21,6 +24,8 @@ import lab.game.Difficult;
*/ */
public class MainScreenController { public class MainScreenController {
private static Logger log = LogManager.getLogger(MainScreenController.class);
@FXML @FXML
private Button btnGenerateScore; private Button btnGenerateScore;
...@@ -100,6 +105,7 @@ public class MainScreenController { ...@@ -100,6 +105,7 @@ public class MainScreenController {
pointsColumn.setCellValueFactory(new PropertyValueFactory<>("points")); pointsColumn.setCellValueFactory(new PropertyValueFactory<>("points"));
initDB(); initDB();
log.info("Screeen initialized.");
} }
private void initDB() { private void initDB() {
......
...@@ -9,11 +9,17 @@ import java.sql.Statement; ...@@ -9,11 +9,17 @@ import java.sql.Statement;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import lab.data.Score; import lab.data.Score;
import lab.gui.GameController;
public class DbConnector implements ScoreStorageInterface { public class DbConnector implements ScoreStorageInterface {
private static Logger log = LogManager.getLogger(DbConnector.class);
private static final String JDBC_CONECTIN_STRING = "jdbc:h2:file:./scoreDB"; private static final String JDBC_CONECTIN_STRING = "jdbc:h2:file:./scoreDB";
@Override @Override
......
module lab02_module { module lab02_module {
requires transitive javafx.controls; requires transitive javafx.controls;
requires javafx.fxml; requires javafx.fxml;
requires javafx.base; requires javafx.base;
requires java.sql; requires java.sql;
opens lab.gui to javafx.fxml; requires org.apache.logging.log4j;
exports lab.gui to javafx.fxml,javafx.graphics;
opens lab.gui to javafx.fxml;
opens lab.data to javafx.base;
exports lab.gui to javafx.fxml, javafx.graphics;
} }
<?xml version="1.0" encoding="UTF-8"?>
<Configuration xmlns="https://logging.apache.org/xml/ns"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
https://logging.apache.org/xml/ns
https://logging.apache.org/xml/ns/log4j-config-2.xsd">
<Appenders>
<Console name="Console">
<PatternLayout
pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
</Console>
<RollingFile name="File" fileName="logs/app.log"
filePattern="logs/app.%d{yyyy-MM-dd}.%i.log.gz">
<PatternLayout
pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
<DefaultRolloverStrategy max="5">
<Delete basePath="logs">
<IfAccumulatedFileSize exceeds="2.2M" />
</Delete>
</DefaultRolloverStrategy>
<Policies>
<OnStartupTriggeringPolicy />
<SizeBasedTriggeringPolicy size="10M" />
<TimeBasedTriggeringPolicy interval="1" />
</Policies>
</RollingFile>
</Appenders>
<Loggers>
<Root level="INFO">
<AppenderRef ref="Console" level="INFO"/>
<AppenderRef ref="File" />
</Root>
<Logger name="lab.game" level="TRACE">
</Logger>
</Loggers>
</Configuration>
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);
}
}
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());
}
}
...@@ -22,116 +22,6 @@ import org.junit.jupiter.api.Test; ...@@ -22,116 +22,6 @@ import org.junit.jupiter.api.Test;
class ClassStructureTest { class ClassStructureTest {
StructureHelper helper = new StructureHelper(); StructureHelper helper = StructureHelper.getInstance();
@Test
void dataImporterTest() throws URISyntaxException, IOException, IllegalAccessException, InvocationTargetException {
helper.classExist("DataImporter", false);
Class<?> d = helper.getClass("DataImporter", false);
}
@Test
void dataImporterDownloadTest() throws URISyntaxException, IOException, IllegalAccessException, InvocationTargetException {
helper.classExist("DataImporter", false);
Class<?> d = helper.getClass("DataImporter", false);
String src = helper.getSourceCode(d);
helper.hasMethod(d, ".*down.*", false, String.class);
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 dataImporterParseAllTest() throws URISyntaxException, IOException, IllegalAccessException, InvocationTargetException {
helper.classExist("DataImporter", false);
Class<?> d = helper.getClass("DataImporter", false);
String src = helper.getSourceCode(d);
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 personTest() throws URISyntaxException, IOException, IllegalAccessException, InvocationTargetException {
helper.classExist("Person", false);
Class<?> p = helper.getClass("Person", false);
}
@Test
void dataImporterParsePersonTest() throws URISyntaxException, IOException, IllegalAccessException, InvocationTargetException {
helper.classExist("DataImporter", false);
Class<?> d = helper.getClass("DataImporter", false);
String src = helper.getSourceCode(d);
helper.classExist("Person", 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 personAgeTest() throws URISyntaxException, IOException, IllegalAccessException, InvocationTargetException {
helper.classExist("DataImporter", false);
Class<?> d = helper.getClass("DataImporter", false);
helper.classExist("Person", 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 person50birthdayTest() throws URISyntaxException, IOException, IllegalAccessException, InvocationTargetException {
helper.classExist("DataImporter", false);
Class<?> d = helper.getClass("DataImporter", false);
String src = helper.getSourceCode(d);
helper.classExist("Person", 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 personNextBirthdayTest() throws URISyntaxException, IOException, IllegalAccessException, InvocationTargetException {
helper.classExist("DataImporter", false);
Class<?> d = helper.getClass("DataImporter", false);
String src = helper.getSourceCode(d);
helper.classExist("Person", 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.");
}
} }
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");
}
}
}
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");
}
}
}
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");
}
}
}
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));
}
}
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"));
}
}
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"));
}
}
}
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment