From 8495cebec5504058cdf8e03c49c79c7f533719c4 Mon Sep 17 00:00:00 2001 From: jez04 <david.jezek@post.cz> Date: Sun, 16 Mar 2025 23:54:55 +0100 Subject: [PATCH] feat: :tada: solution --- pom.xml | 44 ++--- scores.csv | 11 +- src/main/java/lab/data/Level.java | 5 + src/main/java/lab/data/Score.java | 6 +- src/main/java/lab/gui/App.java | 26 ++- src/main/java/lab/gui/GameController.java | 27 ++- src/main/java/lab/storage/DbConnector.java | 25 ++- src/main/java/lab/storage/FileStorage.java | 25 ++- src/main/java/lab/storage/JpaConnector.java | 54 ++++++ .../lab/storage/ScoreStorageInterface.java | 7 +- src/main/java/module-info.java | 5 +- src/main/resources/lab/gui/gameWindow.fxml | 3 +- .../structure/test/ClassStructureTest.java | 177 +++++++++++++++--- 13 files changed, 341 insertions(+), 74 deletions(-) create mode 100644 src/main/java/lab/data/Level.java create mode 100644 src/main/java/lab/storage/JpaConnector.java diff --git a/pom.xml b/pom.xml index 67e399c..8f66f11 100644 --- a/pom.xml +++ b/pom.xml @@ -3,10 +3,10 @@ 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-lab04-v1</artifactId> + <artifactId>java2-lab05-v1</artifactId> <version>0.0.1-SNAPHOST</version> - <name>java2-lab04-v1</name> + <name>java2-lab05-v1</name> <packaging>jar</packaging> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> @@ -14,24 +14,8 @@ <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> @@ -59,7 +43,6 @@ <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <version>2.3.232</version> - <scope>runtime</scope> </dependency> <dependency> @@ -96,7 +79,13 @@ <version>5.11.0</version> <scope>test</scope> </dependency> - <!-- https://mvnrepository.com/artifact/org.reflections/reflections --> + <dependency> + <groupId>cz.vsb.fei</groupId> + <artifactId>kelvin-java-unittest-support</artifactId> + <version>[0.1.4,)</version> + <scope>test</scope> + </dependency> + </dependencies> <build> <plugins> @@ -114,6 +103,7 @@ </annotationProcessorPaths> </configuration> </plugin> + <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> @@ -151,6 +141,7 @@ </plugin> </plugins> + <pluginManagement> <plugins> <!-- Ignore/Execute plugin execution in Eclipse (error of m2e @@ -183,4 +174,15 @@ </plugins> </pluginManagement> </build> + + <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> </project> diff --git a/scores.csv b/scores.csv index c7f3e2f..310f42d 100644 --- a/scores.csv +++ b/scores.csv @@ -5,12 +5,13 @@ WebWizard;262 ScreenSage;95 CodeCommander;276 FunctionFanatic;288 -LogicLover;289 DataDetective;112 ScreenSage;181 -BitBuilder;51 PixelArtist;242 RenderRogue;62 -AppArchitect;225 -DataDreamer;62 -EmojiEnthusiast;101 +siast;101 +ByteBishop;53 +PixelProdigy;196 +PixelArtist;70 +AppAlchemist;106 +ScriptSensei;283 diff --git a/src/main/java/lab/data/Level.java b/src/main/java/lab/data/Level.java new file mode 100644 index 0000000..fc4e031 --- /dev/null +++ b/src/main/java/lab/data/Level.java @@ -0,0 +1,5 @@ +package lab.data; + +public enum Level { + EASY, MEDIUM, HARD; +} diff --git a/src/main/java/lab/data/Score.java b/src/main/java/lab/data/Score.java index 1c64263..435a6c2 100644 --- a/src/main/java/lab/data/Score.java +++ b/src/main/java/lab/data/Score.java @@ -3,6 +3,7 @@ package lab.data; import java.util.Random; import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Setter; @@ -13,16 +14,19 @@ import lombok.ToString; @AllArgsConstructor @EqualsAndHashCode @ToString +@Builder(toBuilder = true) public class Score { private static final Random RANDOM = new Random(); + private Long id; private String name; private int points; + private Level level; public static Score generate() { - return new Score(getRandomNick(), RANDOM.nextInt(50, 300)); + return new Score(null, getRandomNick(), RANDOM.nextInt(50, 300), Level.values()[RANDOM.nextInt(Level.values().length)]); } public static final String[] nicks = { "CyberSurfer", "PixelPioneer", "SocialSavvy", "DigitalDynamo", "ByteBuddy", "InstaGuru", diff --git a/src/main/java/lab/gui/App.java b/src/main/java/lab/gui/App.java index 4ea74e5..8381fc3 100644 --- a/src/main/java/lab/gui/App.java +++ b/src/main/java/lab/gui/App.java @@ -1,7 +1,8 @@ package lab.gui; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; +import java.sql.SQLException; + +import org.h2.tools.Server; import javafx.application.Application; import javafx.fxml.FXMLLoader; @@ -10,6 +11,8 @@ import javafx.scene.Scene; import javafx.stage.Stage; import javafx.stage.WindowEvent; import lab.Setting; +import lab.storage.JpaConnector; +import lombok.extern.log4j.Log4j2; /** * Class <b>App</b> - extends class Application and it is an entry point of the @@ -17,17 +20,31 @@ import lab.Setting; * * @author Java I */ +@Log4j2 public class App extends Application { - private static Logger log = LogManager.getLogger(App.class); private GameController gameController; public static void main(String[] args) { log.info("Application lauched"); - Setting.configure(Setting.getInstanceForHardcoreGame().toBuilder().ufoMinPercentageHeight(0.4).build()); + Setting.configure(Setting.builder().scoreStorageInterface(new JpaConnector()).build()); + + startH2WebServerToInspectDb(); + launch(args); } + private static void startH2WebServerToInspectDb() { + //Start HTTP server for access H2 DB for look inside + try { + Server server = Server.createWebServer(); + log.info(server.getURL()); + server.start(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + @Override public void start(Stage primaryStage) { try { @@ -57,6 +74,7 @@ public class App extends Application { if (gameController != null) { gameController.stop(); } + Setting.getInstance().getScoreStorageInterface().stop(); log.info("Exiting game"); System.exit(0); } diff --git a/src/main/java/lab/gui/GameController.java b/src/main/java/lab/gui/GameController.java index 0fc2551..6ee31ad 100644 --- a/src/main/java/lab/gui/GameController.java +++ b/src/main/java/lab/gui/GameController.java @@ -1,16 +1,19 @@ package lab.gui; +import java.util.ArrayList; import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import javafx.collections.ListChangeListener; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.geometry.Point2D; import javafx.scene.canvas.Canvas; import javafx.scene.control.Button; import javafx.scene.control.Label; +import javafx.scene.control.SelectionMode; import javafx.scene.control.Slider; import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; @@ -18,6 +21,7 @@ import javafx.scene.control.cell.PropertyValueFactory; import javafx.scene.input.KeyEvent; import javafx.scene.input.MouseEvent; import lab.Setting; +import lab.data.Level; import lab.data.Score; import lab.game.BulletAnimated; import lab.game.DrawingThread; @@ -57,6 +61,9 @@ public class GameController { @FXML private TableColumn<Score, Integer> pointsColumn; + @FXML + private TableColumn<Score, Level> levelColumn; + private DrawingThread timer; @FXML @@ -80,7 +87,7 @@ public class GameController { void btnGenerateScoreAction(ActionEvent event) { Score score = Score.generate(); this.scores.getItems().add(score); - Setting.getInstance().getScoreStorageInterface().insertScore(score); + Setting.getInstance().getScoreStorageInterface().save(score); } @FXML @@ -93,6 +100,13 @@ public class GameController { updateScoreTable(Setting.getInstance().getScoreStorageInterface().getFirstTen()); } + @FXML + void btnDeleteAction(ActionEvent event) { + List<Score> selectedScores = new ArrayList<>(scores.getSelectionModel().getSelectedItems()); + Setting.getInstance().getScoreStorageInterface().delete(selectedScores); + updateScoreTable(Setting.getInstance().getScoreStorageInterface().getAll()); + } + @FXML void keyPressed(KeyEvent event) { log.info(event.getCode()); @@ -100,9 +114,9 @@ public class GameController { } @FXML - void canvasClicked(MouseEvent event) { + void canvasClicked(MouseEvent event) { canvas.requestFocus(); - } + } @FXML void keyReleased(KeyEvent event) { @@ -137,6 +151,13 @@ public class GameController { nickColumn.setCellValueFactory(new PropertyValueFactory<>("name")); pointsColumn.setCellValueFactory(new PropertyValueFactory<>("points")); + levelColumn.setCellValueFactory(new PropertyValueFactory<>("level")); + + btnDelete.setDisable(true); + scores.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); + scores.getSelectionModel().getSelectedItems() + .addListener((ListChangeListener.Change<? extends Score> change) -> + btnDelete.setDisable(change.getList().isEmpty())); initStorage(); log.info("Screeen initialized."); diff --git a/src/main/java/lab/storage/DbConnector.java b/src/main/java/lab/storage/DbConnector.java index 7511c9a..4b1e190 100644 --- a/src/main/java/lab/storage/DbConnector.java +++ b/src/main/java/lab/storage/DbConnector.java @@ -31,7 +31,7 @@ public class DbConnector implements ScoreStorageInterface { Statement stm = con.createStatement(); ResultSet rs = stm.executeQuery(query);) { while (rs.next()) { - result.add(new Score(rs.getString("nick"), rs.getInt("points"))); + result.add(new Score(null, rs.getString("nick"), rs.getInt("points"), null)); } } catch (SQLException e) { e.printStackTrace(); @@ -50,7 +50,7 @@ public class DbConnector implements ScoreStorageInterface { } @Override - public void insertScore(Score score) { + public Score save(Score score) { try (Connection con = DriverManager.getConnection(JDBC_CONECTIN_STRING); PreparedStatement stm = con.prepareStatement("INSERT INTO scores VALUES (?, ?)");) { stm.setString(1, score.getName()); @@ -59,5 +59,26 @@ public class DbConnector implements ScoreStorageInterface { } catch (SQLException e) { e.printStackTrace(); } + return score; } + + @Override + public void delete(List<Score> scores) { + try (Connection con = DriverManager.getConnection(JDBC_CONECTIN_STRING); + PreparedStatement stm = con.prepareStatement("DELETE FROM scores WHERE nick=? AND points=?");) { + for (Score score : scores) { + stm.setString(1, score.getName()); + stm.setInt(2, score.getPoints()); + stm.executeUpdate(); + } + } catch (SQLException e) { + e.printStackTrace(); + } + } + + @Override + public void stop() { + /*nothing to do*/ + } + } diff --git a/src/main/java/lab/storage/FileStorage.java b/src/main/java/lab/storage/FileStorage.java index a3228c1..828ca06 100644 --- a/src/main/java/lab/storage/FileStorage.java +++ b/src/main/java/lab/storage/FileStorage.java @@ -21,7 +21,7 @@ public class FileStorage implements ScoreStorageInterface { if (Files.exists(Paths.get(SCORE_FILE_NAME))) { try (Stream<String> lines = Files.lines(Paths.get(SCORE_FILE_NAME))) { List<Score> result = lines.map(line -> line.split(";")) - .map(parts -> new Score(parts[0], Integer.parseInt(parts[1]))).toList(); + .map(parts -> new Score(null, parts[0], Integer.parseInt(parts[1]), null)).toList(); return new ArrayList<>(result); } catch (IOException e) { e.printStackTrace(); @@ -43,14 +43,33 @@ public class FileStorage implements ScoreStorageInterface { } @Override - public void insertScore(Score score) { + public Score save(Score score) { List<Score> all = getAll(); all.add(score); + storeAll(all); + return score; + } + + private void storeAll(List<Score> all) { List<String> lines = all.stream().map(s -> String.format("%s;%d", s.getName(), s.getPoints())).toList(); try { - Files.write(Paths.get(SCORE_FILE_NAME), lines, StandardOpenOption.CREATE); + Files.write(Paths.get(SCORE_FILE_NAME), lines, StandardOpenOption.TRUNCATE_EXISTING); } catch (IOException e) { e.printStackTrace(); } } + + @Override + public void delete(List<Score> scores) { + List<Score> all = getAll(); + all.removeAll(scores); + storeAll(all); + + } + + @Override + public void stop() { + /*nothing to do*/ + } + } diff --git a/src/main/java/lab/storage/JpaConnector.java b/src/main/java/lab/storage/JpaConnector.java new file mode 100644 index 0000000..b1f5bf1 --- /dev/null +++ b/src/main/java/lab/storage/JpaConnector.java @@ -0,0 +1,54 @@ +package lab.storage; + +import java.util.Collections; +import java.util.List; +import java.util.function.Consumer; + +import lab.data.Score; + +public class JpaConnector implements ScoreStorageInterface { + + + public JpaConnector() { + } + + @Override + public List<Score> getAll() { + return Collections.emptyList(); + } + + @Override + public List<Score> getFirstTen() { + return Collections.emptyList(); + } + + @Override + public void init() { + } + + @Override + public Score save(Score score) { + return null; + } + + @Override + public void delete(List<Score> scores) { + } + + @Override + public void stop() { + } + + public Object getEntityManager() { + //return entity manager. Type Object is there because of compilation of empty task assignment + return null; + } + + public Score find(long id) { + return null; + } + + public void modifyNoPersistOrMerge(long id, Consumer<Score> motificator) { + } + +} diff --git a/src/main/java/lab/storage/ScoreStorageInterface.java b/src/main/java/lab/storage/ScoreStorageInterface.java index c7664c2..af8932e 100644 --- a/src/main/java/lab/storage/ScoreStorageInterface.java +++ b/src/main/java/lab/storage/ScoreStorageInterface.java @@ -1,6 +1,5 @@ package lab.storage; -import java.util.Collection; import java.util.List; import lab.data.Score; @@ -13,6 +12,10 @@ public interface ScoreStorageInterface { void init(); - void insertScore(Score score); + Score save(Score score); + + void delete(List<Score> scores); + + void stop(); } \ No newline at end of file diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 3f19883..d40f0a8 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -1,11 +1,12 @@ -module cz.vsb.fei.java2.lab03_module { +module cz.vsb.fei.java2.lab05_module { requires transitive javafx.controls; requires javafx.fxml; requires javafx.base; requires java.sql; requires org.apache.logging.log4j; requires static lombok; - + requires com.h2database; + opens lab.gui to javafx.fxml; opens lab.data to javafx.base; diff --git a/src/main/resources/lab/gui/gameWindow.fxml b/src/main/resources/lab/gui/gameWindow.fxml index e0d12e5..3aea4d0 100644 --- a/src/main/resources/lab/gui/gameWindow.fxml +++ b/src/main/resources/lab/gui/gameWindow.fxml @@ -59,6 +59,7 @@ <columns> <TableColumn fx:id="nickColumn" prefWidth="75.0" text="Nick" /> <TableColumn fx:id="pointsColumn" prefWidth="75.0" text="Points" /> + <TableColumn fx:id="levelColumn" prefWidth="75.0" text="ĂšroveĹ" /> </columns> <columnResizePolicy> <TableView fx:constant="CONSTRAINED_RESIZE_POLICY" /> @@ -67,7 +68,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" /> + <Button fx:id="btnDelete" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#btnDeleteAction" text="Delete score" /> </children> </VBox> </center> diff --git a/src/test/java/jez04/structure/test/ClassStructureTest.java b/src/test/java/jez04/structure/test/ClassStructureTest.java index 43e2f1c..21c3023 100644 --- a/src/test/java/jez04/structure/test/ClassStructureTest.java +++ b/src/test/java/jez04/structure/test/ClassStructureTest.java @@ -2,59 +2,176 @@ package jez04.structure.test; import static org.hamcrest.MatcherAssert.assertThat; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; import java.net.URISyntaxException; +import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.Objects; +import java.util.regex.Pattern; +import org.hamcrest.Matchers; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.MethodOrderer.OrderAnnotation; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.api.TestMethodOrder; +import cz.vsb.fei.kelvin.unittest.ProjectContains; import cz.vsb.fei.kelvin.unittest.StructureHelper; import cz.vsb.fei.kelvin.unittest.TextFileContains; import cz.vsb.fei.kelvin.unittest.XmlFileContains; +import lab.data.Level; +import lab.data.Score; +import lab.storage.JpaConnector; class ClassStructureTest { 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); + void jakartaAndHibernateAsDependencyTest() throws URISyntaxException { + assertThat(TextFileContains.getProjectRoot(getClass()), new XmlFileContains("pom.xml", + "/project/dependencies/dependency/artifactId[text() = 'jakarta.persistence-api']")); + assertThat(TextFileContains.getProjectRoot(getClass()), new XmlFileContains("pom.xml", + "/project/dependencies/dependency/artifactId[text() = 'hibernate-core']")); } @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']")); + void jakartaInModulInfoTest() throws URISyntaxException { + assertThat(TextFileContains.getProjectRoot(getClass()), + new TextFileContains("module-info.java", "jakarta.persistence;")); + assertThat(TextFileContains.getProjectRoot(getClass()), + new TextFileContains("module-info.java", "opens\\slab.data;")); } @Test - void moduleInfoTest() throws URISyntaxException { - assertThat(TextFileContains.getProjectRoot(getClass()), new TextFileContains("module-info.java", "lombok;")); + void pesistenceXmlTest() throws URISyntaxException { + ProjectContains projectContains = new ProjectContains("persistence.xml"); + assertThat(TextFileContains.getProjectRoot(getClass()), projectContains); + assertThat(projectContains.getFoundFiles(), Matchers.not(Matchers.hasSize(0))); + Path persistenceXml = projectContains.getFoundFiles().getFirst(); + assertThat(persistenceXml.toAbsolutePath().toString(), + Matchers.endsWith(Paths.get("resources", "META-INF", "persistence.xml").toString())); } - @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 { + @Test + void useEnumeratedTest() throws URISyntaxException { assertThat(TextFileContains.getProjectRoot(getClass()), - new TextFileContains(".*\\.java", text).count(count).useRegExpForName(true)); + new TextFileContains("Score.java", "@Enumerated\\(\\s*EnumType.STRING\\s*\\)")); } + @TestMethodOrder(OrderAnnotation.class) + @Nested + class JpaConnectorTests { + + private Score template = new Score(null, "Tester", 100, Level.EASY); + private JpaConnector connector; + + @BeforeEach + void init() { + connector = new JpaConnector(); + } + + @AfterEach + void cleanUp() { + connector.stop(); + } + + boolean same(Score s1, Score s2) { + return s1.getLevel() == s2.getLevel() && s1.getPoints() == s2.getPoints() + && Objects.equals(s1.getName(), s2.getName()); + } + + @Test + @Order(100) + void jpaScoreInsertTest() { + Score savedScore = connector.save(template); + assertThat(savedScore.getId(), Matchers.notNullValue()); + } + + @Test + @Order(200) + void jpaScoreReadTest() { + List<Score> savedScores = connector.getAll().stream().filter(s -> same(s, template)).toList(); + assertThat(savedScores, Matchers.not(Matchers.hasSize(0))); + } + + @Test + @Order(250) + void jpaReadSortedTest() { + for (int i = 0; i < 20; i++) { + connector.save(template.toBuilder().points(i).build()); + } + List<Score> result = connector.getFirstTen(); + assertThat(result, Matchers.hasSize(10)); + for (int i = 0; i < result.size()-1; i++) { + assertThat(result.get(i).getPoints(), Matchers.greaterThanOrEqualTo(result.get(i+1).getPoints())); + } + } + + @Test + @Order(300) + void jpaScoreModifyTest() { + List<Score> savedScores = connector.getAll().stream().filter(s -> same(s, template)).toList(); + List<Long> savedIds = savedScores.stream().map(Score::getId).toList(); + assertThat(savedScores, Matchers.not(Matchers.hasSize(0))); + for (Score score : savedScores) { + score.setLevel(Level.HARD); + connector.save(score); + } + List<Score> modifiedScores = connector.getAll().stream().filter(s -> savedIds.contains(s.getId())).toList(); + assertThat(modifiedScores, Matchers.not(Matchers.hasSize(0))); + List<Score> originalDataScores = connector.getAll().stream().filter(s -> same(s, template)).toList(); + assertThat(originalDataScores, Matchers.hasSize(0)); + } + + @Test + @Order(400) + void jpaScoreDeleteTest() { + template.setLevel(Level.HARD); + List<Score> savedScores = connector.getAll().stream().filter(s -> same(s, template)).toList(); + List<Long> savedIds = savedScores.stream().map(Score::getId).toList(); + assertThat(savedScores, Matchers.not(Matchers.hasSize(0))); + connector.delete(savedScores); + List<Score> modifiedScores = connector.getAll().stream().filter(s -> savedIds.contains(s.getId())).toList(); + assertThat(modifiedScores, Matchers.hasSize(0)); + List<Score> originalDataScores = connector.getAll().stream().filter(s -> same(s, template)).toList(); + assertThat(originalDataScores, Matchers.hasSize(0)); + } + + @Test + @Order(400) + void jpaMergeTest() { + connector.save(template); + connector.find(template.getId()); + Score copy = template.toBuilder().points(500).build(); + Score result = connector.save(copy); + assertThat(result, Matchers.not(Matchers.sameInstance(copy))); + } + + @Test + @Order(500) + void jpamodifyNoPersistNoMergeTest() throws URISyntaxException, IOException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, SecurityException { + template.setName("aaa"); + connector.save(template); + connector.modifyNoPersistOrMerge(template.getId(), score -> score.setName("ok")); + Object em = connector.getEntityManager(); + em.getClass().getMethod("clear").invoke(em); + + assertThat(connector.find(template.getId()).getName(), Matchers.equalTo("ok")); + TextFileContains textFileContains = new TextFileContains("JpaConnector.java", + "void\\s+modifyNoPersistOrMerge[\\s\\S]*}").multiline(true); + assertThat(TextFileContains.getProjectRoot(ClassStructureTest.class), textFileContains); + Path score = textFileContains.getFoundFiles().getFirst(); + String src = Files.readString(score); + String method = Pattern.compile("void\\s+modifyNoPersistOrMerge[\\s\\S]*}").matcher(src).results().findFirst().get().group(); + assertThat(method, Matchers.not(Matchers.containsString("persist"))); + assertThat(method, Matchers.not(Matchers.containsString("merge"))); + } + } } -- GitLab