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

feat: :tada: solution

parent 4ef5be7b
No related merge requests found
Pipeline #2572 canceled with stages
Showing
with 169 additions and 747 deletions
......@@ -11,8 +11,33 @@
<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.36</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.0.3-SNAPSHOT,)</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<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>
......@@ -70,19 +95,6 @@
<version>5.11.0</version>
<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,6 +104,13 @@
<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,138 +2,42 @@ package lab;
import lab.storage.DbConnector;
import lab.storage.ScoreStorageInterface;
import lombok.AllArgsConstructor;
import lombok.Builder.Default;
import lombok.Getter;
@Getter
@AllArgsConstructor
@lombok.Builder(toBuilder = true)
public class Config {
@Getter
private static Config instance;
private ScoreStorageInterface scoreStorageInterface;
private double monsterMinXPopsition;
private double monsterMinSpeed;
private double monsterMaxSpeed;
private double obstacleWidth;
private double obstacleHeight;
private double playerStartSpeed;
private int monsterMultiplier;
@Default
private ScoreStorageInterface scoreStorageInterface = new DbConnector();
@Default
private double monsterMinXPopsition = 0.5;
@Default
private double monsterMinSpeed = 50;
@Default
private double monsterMaxSpeed = 150;
@Default
private double obstacleWidth = 30;
@Default
private double obstacleHeight = 20;
@Default
private double playerStartSpeed = 50;
@Default
private int monsterMultiplier = 1;
public static void configure(Config setting) {
instance = setting;
}
private Config(ScoreStorageInterface scoreStorageInterface, double monsterMinXPopsition, double monsterMinSpeed,
double monsterMaxSpeed, double obstacleWidth, double obstacleHeight, double playerStartSpeed,
int monsterMultiplier) {
super();
this.scoreStorageInterface = scoreStorageInterface;
this.monsterMinXPopsition = monsterMinXPopsition;
this.monsterMinSpeed = monsterMinSpeed;
this.monsterMaxSpeed = monsterMaxSpeed;
this.obstacleWidth = obstacleWidth;
this.obstacleHeight = obstacleHeight;
this.playerStartSpeed = playerStartSpeed;
this.monsterMultiplier = monsterMultiplier;
}
public static Config getInstance() {
return instance;
}
public ScoreStorageInterface getScoreStorageInterface() {
return scoreStorageInterface;
}
public double getMonsterMinXPopsition() {
return monsterMinXPopsition;
}
public double getMonsterMinSpeed() {
return monsterMinSpeed;
}
public double getMonsterMaxSpeed() {
return monsterMaxSpeed;
}
public double getObstacleHeight() {
return obstacleHeight;
}
public double getObstacleWidth() {
return obstacleWidth;
}
public double getPlayerStartSpeed() {
return playerStartSpeed;
}
public int getMonsterMultiplier() {
return monsterMultiplier;
}
public static Builder builder() {
return new Builder();
}
public static Config getInstanceForHardcoreGame() {
return builder().monsterMinSpeed(150).monsterMaxSpeed(500).monsterMultiplier(5).monsterMinXPopsition(0.2)
.build();
}
public static class Builder {
private ScoreStorageInterface scoreStorageInterface = new DbConnector();
private double monsterMinXPopsition = 0.5;
private double monsterMinSpeed = 50;
private double monsterMaxSpeed = 150;
private double obstacleWidth = 30;
private double obstacleHeight = 20;
private double playerStartSpeed = 50;
private int monsterMultiplier = 1;
public Builder scoreStorageInterface(ScoreStorageInterface scoreStorageInterface) {
this.scoreStorageInterface = scoreStorageInterface;
return this;
}
public Builder monsterMinXPopsition(double monsterMinXPopsition) {
this.monsterMinXPopsition = monsterMinXPopsition;
return this;
}
public Builder monsterMinSpeed(double monsterMinSpeed) {
this.monsterMinSpeed = monsterMinSpeed;
return this;
}
public Builder monsterMaxSpeed(double monsterMaxSpeed) {
this.monsterMaxSpeed = monsterMaxSpeed;
return this;
}
public Builder obstacleWidth(double obstacleWidth) {
this.obstacleWidth = obstacleWidth;
return this;
}
public Builder obstacleHeight(double obstacleHeight) {
this.obstacleHeight = obstacleHeight;
return this;
}
public Builder playerStartSpeed(double playerStartSpeed) {
this.playerStartSpeed = playerStartSpeed;
return this;
}
public Builder monsterMultiplier(int monsterMultiplier) {
this.monsterMultiplier = monsterMultiplier;
return this;
}
public Config build() {
return new Config(scoreStorageInterface, monsterMinXPopsition, monsterMinSpeed, monsterMaxSpeed,
obstacleWidth, obstacleHeight, playerStartSpeed, monsterMultiplier);
}
}
}
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));
}
......
......@@ -2,5 +2,5 @@ package lab.game;
@FunctionalInterface
public interface DeadListener {
void monsterDead();
void monsterDead(Monster monster);
}
package lab.game;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import javafx.geometry.Dimension2D;
......@@ -9,7 +11,9 @@ import javafx.geometry.Point2D;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.paint.Color;
import lab.Config;
import lombok.extern.log4j.Log4j2;
@Log4j2
public class Level {
private double width;
......@@ -18,6 +22,7 @@ public class Level {
private List<DrawableSimulable> entitiesToAdd = new ArrayList<>();
private List<DrawableSimulable> entitiesToRemove = new ArrayList<>();
private Player player;
private List<MonsterDeadLog> deadLogs = new LinkedList<>();
public Level(double width, double height, int monsterCount) {
this.width = width;
......@@ -29,10 +34,19 @@ public class Level {
entities.add(new Obstacle(this));
entities.add(player);
for (int i = 0; i < monsterCount*Config.getInstance().getMonsterMultiplier(); i++) {
entities.add(new Monster(this));
Monster monster = new Monster(this);
monster.addDeadListener(m -> deadLogs.add(new MonsterDeadLog(LocalDateTime.now(), m.getPosition())));
entities.add(monster);
}
}
record MonsterDeadLog(LocalDateTime time, Point2D position) {}
public void printDeadLog() {
for (MonsterDeadLog monsterDeadLog : deadLogs) {
log.info(monsterDeadLog);
}
}
public void draw(GraphicsContext gc) {
gc.setFill(Color.WHITE);
gc.clearRect(0, 0, width, height);
......
......@@ -87,7 +87,7 @@ public class Monster extends WorldEntity implements Collisionable {
public void fireMonsterDead() {
for (DeadListener deadListener : deadListeners) {
deadListener.monsterDead();
deadListener.monsterDead(this);
}
}
}
......@@ -3,7 +3,7 @@ package lab.game;
public class MujListener implements DeadListener {
@Override
public void monsterDead() {
public void monsterDead(Monster monster) {
System.out.println("AAAAhh!!!!");
}
......
......@@ -80,6 +80,9 @@ public class App extends Application {
}
private void exitProgram(WindowEvent evt) {
if(gameController != null) {
gameController.stop();
}
log.info("Exiting game");
System.exit(0);
}
......
package lab.gui;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import javafx.animation.AnimationTimer;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
......@@ -15,11 +12,11 @@ import lab.game.DrawingThread;
import lab.game.Level;
import lab.game.Monster;
import lab.game.MujListener;
import lombok.extern.log4j.Log4j2;
@Log4j2
public class GameController {
private static Logger log = LogManager.getLogger(GameController.class);
private AnimationTimer timer;
private Level level;
......@@ -42,13 +39,13 @@ public class GameController {
Monster monster = new Monster(level);
monster.addDeadListener(new MujListener());
monster.addDeadListener(new Dead());
monster.addDeadListener(() -> System.out.println("another lambda dead"));
monster.addDeadListener(m -> log.info("another lambda dead"));
monster.addDeadListener(this::updateDeadLabel);
level.add(monster);
}
private void updateDeadLabel() {
private void updateDeadLabel(Monster monster) {
deadCount++;
playerName.setText(String.format("Deads: %03d", deadCount));
}
......@@ -77,13 +74,14 @@ public class GameController {
}
public void stop() {
level.printDeadLog();
timer.stop();
}
private class Dead implements DeadListener {
@Override
public void monsterDead() {
System.out.println("Named dead");
public void monsterDead(Monster monster) {
log.info("Named dead");
}
}
}
......@@ -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;
......
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 java.util.Objects;
import java.util.stream.Stream;
import org.hamcrest.Matchers;
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.SrcContains;
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({
"Config,@Getter,1",
"Config,@.*Builder,1",
"Config,@.*Default,3"
})
@ParameterizedTest(name = "useLombokTest in {1} annotation {2}")
void useLombokConfigTest(String className, String text, int count) throws URISyntaxException, ClassNotFoundException {
Class<?> config = helper.getClass(className);
assertThat(config, new SrcContains(text).count(count));
}
@CsvSource({
"Score,@Setter,1",
"Score,@Getter,1",
"Score,@AllArgsConstructor,1",
"Score,@EqualsAndHashCode,1",
"Score,@ToString,1"
})
@ParameterizedTest(name = "useLombokTest in {1} annotation {2}")
void useLombokOrDataTest(String className, String text, int count) throws URISyntaxException, ClassNotFoundException {
Class<?> config = helper.getClass(className);
assertThat(config, Matchers.anyOf(new SrcContains(text).count(count),
new SrcContains("@Data").count(1)));
}
@Test
void recordTest() throws URISyntaxException {
long recordCount = Stream.concat(
helper.getAllNonInnerClasses().stream(),
helper.getAllInnerClasses().stream())
.filter(className -> !className.startsWith("javafx")).map(className -> {
try {
return helper.getClassDirectly(className);
} catch (ClassNotFoundException e) {
e.printStackTrace();
return null;
}
}).filter(Objects::nonNull).filter(clazz -> clazz.isRecord()).count();
assertThat(recordCount, Matchers.greaterThanOrEqualTo(1L));
}
}
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"));
}
}
}
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"));
}
}
}
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