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

feat: :tada: solution

parent 4b682ad2
Branches
No related merge requests found
Showing
with 193 additions and 575 deletions
......@@ -3,17 +3,42 @@
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>cz.vsb.fei.java2</groupId>
<artifactId>java2-lab03-v1</artifactId>
<artifactId>java2-lab04-v1</artifactId>
<version>0.0.1-SNAPHOST</version>
<name>java2-lab03-v1</name>
<name>java2-lab04-v1</name>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<lombok.version>1.18.34</lombok.version>
</properties>
<repositories>
<repository>
<id>vsb-education-release</id>
<url>https://artifactory.cs.vsb.cz/repository/education-releases/</url>
</repository>
<repository>
<id>vsb-education-snapshot</id>
<url>https://artifactory.cs.vsb.cz/repository/education-snapshot/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>cz.vsb.fei</groupId>
<artifactId>kelvin-java-unittest-support</artifactId>
<version>[0.1.4,)</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
<!--
https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
<dependency>
......@@ -72,18 +97,6 @@
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.reflections/reflections -->
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<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>
......@@ -92,7 +105,13 @@
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<failOnError>false</failOnError>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
......
......@@ -2,147 +2,50 @@ package lab;
import lab.storage.DbConnector;
import lab.storage.ScoreStorageInterface;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Builder.Default;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
@Getter
@Builder(toBuilder = true)
@EqualsAndHashCode
@ToString
@AllArgsConstructor
public class Setting {
@Getter
private static Setting instance;
private ScoreStorageInterface scoreStorageInterface;
private double gravity;
private double normalBulletSpeed;
private int numberOfUfos;
private double ufoMinPercentageHeight;
private double ufoMinSpeed;
private double ufoMaxSpeed;
private double bulletMinSpeed;
private double bulletMaxSpeed;
@Default
private ScoreStorageInterface scoreStorageInterface = new DbConnector();
@Default
private double gravity = 9.81;
@Default
private double normalBulletSpeed = 30;
@Default
private int numberOfUfos = 3;
@Default
private double ufoMinPercentageHeight = 0.3;
@Default
private double ufoMinSpeed = 70;
@Default
private double ufoMaxSpeed = 150;
@Default
private double bulletMinSpeed = 30;
@Default
private double bulletMaxSpeed = 300;
public static void configure(Setting setting) {
instance = setting;
}
private Setting(ScoreStorageInterface scoreStorageInterface, double gravity, double normalBulletSpeed,
int numberOfUfos, double ufoMinPercentageHeight, double ufoMinSpeed, double ufoMaxSpeed,
double bulletMinSpeed, double bulletMaxSpeed) {
super();
this.scoreStorageInterface = scoreStorageInterface;
this.gravity = gravity;
this.normalBulletSpeed = normalBulletSpeed;
this.numberOfUfos = numberOfUfos;
this.ufoMinPercentageHeight = ufoMinPercentageHeight;
this.ufoMinSpeed = ufoMinSpeed;
this.ufoMaxSpeed = ufoMaxSpeed;
this.bulletMinSpeed = bulletMinSpeed;
this.bulletMaxSpeed = bulletMaxSpeed;
}
public static Setting getInstance() {
return instance;
}
public double getGravity() {
return gravity;
}
public double getNormalBulletSpeed() {
return normalBulletSpeed;
}
public int getNumberOfUfos() {
return numberOfUfos;
}
public ScoreStorageInterface getScoreStorageInterface() {
return scoreStorageInterface;
}
public double getUfoMinPercentageHeight() {
return ufoMinPercentageHeight;
}
public double getUfoMinSpeed() {
return ufoMinSpeed;
}
public double getUfoMaxSpeed() {
return ufoMaxSpeed;
}
public double getBulletMinSpeed() {
return bulletMinSpeed;
}
public double getBulletMaxSpeed() {
return bulletMaxSpeed;
}
public static Builder builder() {
return new Builder();
}
public static Setting getInstanceForHardcoreGame() {
return builder().numberOfUfos(50).ufoMinPercentageHeight(0.9).ufoMinSpeed(200).ufoMaxSpeed(500).build();
}
public static class Builder {
private ScoreStorageInterface scoreStorageInterface = new DbConnector();
private double gravity = 9.81;
private double normalBulletSpeed = 30;
private int numberOfUfos = 3;
private double ufoMinPercentageHeight = 0.3;
private double ufoMinSpeed = 70;
private double ufoMaxSpeed = 150;
private double bulletMinSpeed = 30;
private double bulletMaxSpeed = 300;
public Builder bulletMaxSpeed(double bulletMaxSpeed) {
this.bulletMaxSpeed = bulletMaxSpeed;
return this;
}
public Builder scoreStorageInterface(ScoreStorageInterface scoreStorageInterface) {
this.scoreStorageInterface = scoreStorageInterface;
return this;
}
public Builder gravity(double gravity) {
this.gravity = gravity;
return this;
}
public Builder normalBulletSpeed(double normalBulletSpeed) {
this.normalBulletSpeed = normalBulletSpeed;
return this;
}
public Builder numberOfUfos(int numberOfUfos) {
this.numberOfUfos = numberOfUfos;
return this;
}
public Builder ufoMinPercentageHeight(double ufoMinPercentageHeight) {
this.ufoMinPercentageHeight = ufoMinPercentageHeight;
return this;
}
public Builder ufoMinSpeed(double ufoMinSpeed) {
this.ufoMinSpeed = ufoMinSpeed;
return this;
}
public Builder ufoMaxSpeed(double ufoMaxSpeed) {
this.ufoMaxSpeed = ufoMaxSpeed;
return this;
}
public Builder bulletMinSpeed(double bulletMinSpeed) {
this.bulletMinSpeed = bulletMinSpeed;
return this;
}
public Setting build() {
return new Setting(scoreStorageInterface, gravity, normalBulletSpeed, numberOfUfos, ufoMinPercentageHeight,
ufoMinSpeed, ufoMaxSpeed, bulletMinSpeed, bulletMaxSpeed);
}
}
}
package lab.data;
import java.util.Objects;
import java.util.Random;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@AllArgsConstructor
@EqualsAndHashCode
@ToString
public class Score {
private static final Random RANDOM = new Random();
......@@ -10,49 +20,6 @@ public class Score {
private String name;
private int points;
public Score(String name, int points) {
this.name = name;
this.points = points;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPoints() {
return points;
}
public void setPoints(int points) {
this.points = points;
}
@Override
public 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
public String toString() {
return "Score [name=" + name + ", points=" + points + "]";
}
public static Score generate() {
return new Score(getRandomNick(), RANDOM.nextInt(50, 300));
......
package lab.game;
public enum AngleChange {
UP, DOWN;
}
......@@ -14,8 +14,8 @@ public class BulletAnimated extends Bullet {
private final Point2D initVelocity;
private Cannon cannon;
private static Image image = new Image(BulletAnimated.class.getResourceAsStream("fireball-transparent.gif"));
private List<HitListener> hitListeners =
new ArrayList<>();
private List<HitListener> hitListeners = new ArrayList<>();
public BulletAnimated(World world, Cannon cannon, Point2D position, Point2D velocity, Point2D acceleration) {
super(world, position, velocity, acceleration);
......@@ -49,11 +49,11 @@ public class BulletAnimated extends Bullet {
public boolean removeHitListener(HitListener o) {
return hitListeners.remove(o);
}
private void fireUfoDestroyed() {
for (HitListener hitListener : hitListeners) {
hitListener.ufoDestroyed();
}
}
}
\ No newline at end of file
package lab.game;
public enum ForceChange {
UP, DOWN;
}
package lab.game;
import java.time.LocalDateTime;
import java.util.Random;
import org.apache.logging.log4j.LogManager;
......@@ -18,7 +19,7 @@ public class Ufo extends WorldEntity implements Collisionable {
private static final Random RANDOM = new Random();
private Image image;
private Point2D velocity;
public Ufo(World world) {
this(world,
new Point2D(RANDOM.nextDouble(world.getWidth()),
......@@ -74,7 +75,11 @@ public class Ufo extends WorldEntity implements Collisionable {
public void hitBy(Collisionable another) {
log.trace("Ufo hitted by {}.", another);
if (another instanceof BulletAnimated || another instanceof Bullet) {
world.add(new UfoDestroyLog(LocalDateTime.now(), getPosition()));
world.remove(this);
}
}
record UfoDestroyLog(LocalDateTime time, Point2D position) {}
}
......@@ -8,7 +8,10 @@ import java.util.List;
import javafx.geometry.Point2D;
import javafx.scene.canvas.GraphicsContext;
import lab.Setting;
import lab.game.Ufo.UfoDestroyLog;
import lombok.extern.log4j.Log4j2;
@Log4j2
public class World {
public static final Point2D GRAVITY = new Point2D(0, Setting.getInstance().getGravity());
......@@ -19,6 +22,7 @@ public class World {
private List<DrawableSimulable> entities;
private Collection<DrawableSimulable> entitiesToRemove = new LinkedList<>();
private Collection<DrawableSimulable> entitiesToAdd = new LinkedList<>();
private List<UfoDestroyLog> destroyLogs = new LinkedList<>();
private Cannon cannon;
// private BulletAnimated bulletAnimated;
......@@ -37,6 +41,17 @@ public class World {
}
}
public void add(UfoDestroyLog ufoDestroyLog) {
destroyLogs.add(ufoDestroyLog);
}
public void pringDestroylog() {
for (UfoDestroyLog ufoDestroyLog : destroyLogs) {
log.info(ufoDestroyLog);
}
}
public void draw(GraphicsContext gc) {
gc.clearRect(0, 0, width, height);
......
......@@ -24,7 +24,7 @@ public class App extends Application {
public static void main(String[] args) {
log.info("Application lauched");
Setting.configure(Setting.getInstanceForHardcoreGame());
Setting.configure(Setting.getInstanceForHardcoreGame().toBuilder().ufoMinPercentageHeight(0.4).build());
launch(args);
}
......@@ -34,7 +34,7 @@ public class App extends Application {
// Construct a main window with a canvas.
FXMLLoader gameLoader = new FXMLLoader(getClass().getResource("/lab/gui/gameWindow.fxml"));
Parent root = gameLoader.load();
GameController gameController = gameLoader.getController();
gameController = gameLoader.getController();
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.setTitle("Java 2 - 2nd laboratory");
......@@ -54,6 +54,9 @@ public class App extends Application {
}
private void exitProgram(WindowEvent evt) {
if (gameController != null) {
gameController.stop();
}
log.info("Exiting game");
System.exit(0);
}
......
......@@ -15,6 +15,8 @@ import javafx.scene.control.Slider;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import lab.Setting;
import lab.data.Score;
import lab.game.BulletAnimated;
......@@ -34,6 +36,9 @@ public class GameController {
@FXML
private Button btnLoadFirstTen;
@FXML
private Button btnDelete;
@FXML
private Slider angle;
......@@ -88,6 +93,22 @@ public class GameController {
updateScoreTable(Setting.getInstance().getScoreStorageInterface().getFirstTen());
}
@FXML
void keyPressed(KeyEvent event) {
log.info(event.getCode());
event.consume();
}
@FXML
void canvasClicked(MouseEvent event) {
canvas.requestFocus();
}
@FXML
void keyReleased(KeyEvent event) {
}
private void updateScoreTable(List<Score> scores) {
this.scores.getItems().clear();
this.scores.getItems().addAll(scores);
......@@ -119,6 +140,7 @@ public class GameController {
initStorage();
log.info("Screeen initialized.");
canvas.requestFocus();
}
private void initStorage() {
......@@ -127,6 +149,7 @@ public class GameController {
}
public void stop() {
timer.getWorld().pringDestroylog();
timer.stop();
}
......
package lab.storage;
import java.util.Collection;
import java.util.List;
import lab.data.Score;
......
......@@ -4,6 +4,7 @@ module cz.vsb.fei.java2.lab03_module {
requires javafx.base;
requires java.sql;
requires org.apache.logging.log4j;
requires static lombok;
opens lab.gui to javafx.fxml;
opens lab.data to javafx.base;
......
......@@ -48,7 +48,7 @@
<Insets />
</BorderPane.margin>
<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" />
<Canvas fx:id="canvas" focusTraversable="true" height="306.0" onKeyPressed="#keyPressed" onKeyReleased="#keyReleased" onMouseClicked="#canvasClicked" 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>
......@@ -67,6 +67,7 @@
<Button fx:id="btnGenerateScore" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#btnGenerateScoreAction" text="Generate new score" />
<Button fx:id="btnLoadAll" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#btnLoadAllAction" text="Load all from DB" />
<Button fx:id="btnLoadFirstTen" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#btnLoadFirstTenAction" text="Load First 10 from DB" />
<Button fx:id="btnDelete" maxWidth="1.7976931348623157E308" mnemonicParsing="false" text="Delete score" />
</children>
</VBox>
</center>
......
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());
}
}
package jez04.structure.test;
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 java.nio.file.Path;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import cz.vsb.fei.kelvin.unittest.StructureHelper;
import cz.vsb.fei.kelvin.unittest.TextFileContains;
import cz.vsb.fei.kelvin.unittest.XmlFileContains;
class ClassStructureTest {
StructureHelper helper = StructureHelper.getInstance();
StructureHelper helper = StructureHelper.getInstance(ClassStructureTest.class);
@Test
void lombokAsDependencyTest() throws URISyntaxException {
XmlFileContains xmlFileContains = new XmlFileContains("pom.xml",
"/project/dependencies/dependency/artifactId[text() = 'lombok']");
Path root = TextFileContains.getProjectRoot(getClass());
assertThat(root, xmlFileContains);
}
@Test
void lombokAsAnnotationProcessorTest() throws URISyntaxException {
assertThat(TextFileContains.getProjectRoot(getClass()), new XmlFileContains("pom.xml",
"/project/build/plugins/plugin/artifactId[text() = 'maven-compiler-plugin']"));
assertThat(TextFileContains.getProjectRoot(getClass()), new XmlFileContains("pom.xml",
"/project/build/plugins/plugin/configuration/annotationProcessorPaths/path/artifactId[text() = 'lombok']"));
}
@Test
void moduleInfoTest() throws URISyntaxException {
assertThat(TextFileContains.getProjectRoot(getClass()), new TextFileContains("module-info.java", "lombok;"));
}
@CsvSource({
"@Getter,1",
"@Setter,1",
"@Log.*,1",
"@.*ArgsConstructor,1",
"@ToString,1",
"@Getter,3",
"@Setter,3",
"@Log.*,3",
"@.*ArgsConstructor,2",
"@ToString,3",
"@Log.*,5",
"@ToString,5" })
@ParameterizedTest(name = "use Lombok Annotation {0} {1} times")
void useLombokConfigTest(String text, int count) throws URISyntaxException, ClassNotFoundException {
assertThat(TextFileContains.getProjectRoot(getClass()),
new TextFileContains(".*\\.java", text).count(count).useRegExpForName(true));
}
}
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));
}
}
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