Add test templates
This commit is contained in:
parent
38ea6a91fe
commit
94e81e5e08
@ -3,15 +3,33 @@
|
|||||||
# and
|
# and
|
||||||
# https://gitlab.stud.idi.ntnu.no/tdt4140-staff/examples/-/blob/master/.gitlab-ci.yml
|
# https://gitlab.stud.idi.ntnu.no/tdt4140-staff/examples/-/blob/master/.gitlab-ci.yml
|
||||||
|
|
||||||
image: maven:3.6.3-openjdk-15
|
image: maven:3-openjdk-15-slim
|
||||||
|
|
||||||
variables:
|
variables:
|
||||||
|
|
||||||
# This will suppress any download for dependencies and plugins or upload messages which would clutter the console log.
|
# This will suppress any download for dependencies and plugins or upload messages which would clutter the console log.
|
||||||
# `showDateTime` will show the passed time in milliseconds. You need to specify `--batch-mode` to make this work.
|
# `showDateTime` will show the passed time in milliseconds. You need to specify `--batch-mode` to make this work.
|
||||||
MAVEN_OPTS: "-Dhttps.protocols=TLSv1.2 -Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=WARN -Dorg.slf4j.simpleLogger.showDateTime=true -Djava.awt.headless=true"
|
MAVEN_OPTS: " \
|
||||||
|
-Dhttps.protocols=TLSv1.2 \
|
||||||
|
-Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository \
|
||||||
|
-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=WARN \
|
||||||
|
-Dorg.slf4j.simpleLogger.showDateTime=true \
|
||||||
|
-Djava.awt.headless=true"
|
||||||
|
|
||||||
# As of Maven 3.3.0 instead of this you may define these options in `.mvn/maven.config` so the same config is used
|
# As of Maven 3.3.0 instead of this you may define these options in `.mvn/maven.config` so the same config is used
|
||||||
# when running from the command line.
|
# when running from the command line.
|
||||||
MAVEN_CLI_OPTS: "--batch-mode --errors --fail-at-end --show-version"
|
MAVEN_CLI_OPTS: " \
|
||||||
|
--batch-mode \
|
||||||
|
--errors \
|
||||||
|
--fail-at-end \
|
||||||
|
--show-version \
|
||||||
|
-Dprism.verbose=true \
|
||||||
|
-Dtestfx.robot=glass \
|
||||||
|
-Dtestfx.headless=true \
|
||||||
|
-Dglass.platform=Monocle \
|
||||||
|
-Dprism.order=sw \
|
||||||
|
-Dprism.text=t2k \
|
||||||
|
-Dtestfx.setup.timeout=60000"
|
||||||
|
|
||||||
# Cache downloaded dependencies and plugins between builds.
|
# Cache downloaded dependencies and plugins between builds.
|
||||||
# To keep cache across branches add 'key: "$CI_JOB_NAME"'
|
# To keep cache across branches add 'key: "$CI_JOB_NAME"'
|
||||||
@ -38,6 +56,8 @@ unittest:
|
|||||||
stage: test
|
stage: test
|
||||||
needs: [build]
|
needs: [build]
|
||||||
script:
|
script:
|
||||||
|
- "apt update"
|
||||||
|
- "apt install -y openjfx"
|
||||||
- "mvn package $MAVEN_CLI_OPTS"
|
- "mvn package $MAVEN_CLI_OPTS"
|
||||||
artifacts:
|
artifacts:
|
||||||
paths:
|
paths:
|
||||||
@ -46,12 +66,15 @@ unittest:
|
|||||||
reports:
|
reports:
|
||||||
junit:
|
junit:
|
||||||
- target/surefire-reports/TEST-*.xml
|
- target/surefire-reports/TEST-*.xml
|
||||||
- target/failsafe-reports/TEST-*.xml
|
# TODO: Separate unit tests and integration tests
|
||||||
|
# - target/failsafe-reports/TEST-*.xml
|
||||||
|
|
||||||
generate-coverage:
|
generate-coverage:
|
||||||
stage: docs
|
stage: docs
|
||||||
script:
|
script:
|
||||||
- 'mvn clean jacoco:prepare-agent test jacoco:report'
|
- "apt update"
|
||||||
|
- "apt install -y openjfx"
|
||||||
|
- 'mvn clean jacoco:prepare-agent test $MAVEN_CLI_OPTS jacoco:report'
|
||||||
- 'cat target/site/jacoco/index.html'
|
- 'cat target/site/jacoco/index.html'
|
||||||
coverage: '/Total.*?([0-9]{1,3})%/'
|
coverage: '/Total.*?([0-9]{1,3})%/'
|
||||||
artifacts:
|
artifacts:
|
||||||
|
32
pom.xml
32
pom.xml
@ -42,7 +42,6 @@
|
|||||||
<version>3.2.0-01</version>
|
<version>3.2.0-01</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
<!-- JUnit 5 -->
|
<!-- JUnit 5 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.junit.jupiter</groupId>
|
<groupId>org.junit.jupiter</groupId>
|
||||||
@ -65,6 +64,36 @@
|
|||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Hamcrest - Matchers to help testing the JavaFX UI -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.hamcrest</groupId>
|
||||||
|
<artifactId>hamcrest</artifactId>
|
||||||
|
<version>2.1</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Monocle - Headless UI testing in CI -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.testfx</groupId>
|
||||||
|
<artifactId>openjfx-monocle</artifactId>
|
||||||
|
<version>jdk-12.0.1+2</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Mockito - Mocking Library for performing isolated unit tests -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mockito</groupId>
|
||||||
|
<artifactId>mockito-inline</artifactId>
|
||||||
|
<version>3.8.0</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mockito</groupId>
|
||||||
|
<artifactId>mockito-junit-jupiter</artifactId>
|
||||||
|
<version>2.23.0</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- JavaDoc -->
|
<!-- JavaDoc -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
@ -133,7 +162,6 @@
|
|||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
|
||||||
|
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
</project>
|
</project>
|
||||||
|
@ -35,7 +35,8 @@ public class Main extends Application {
|
|||||||
*/
|
*/
|
||||||
private void setupWindow(Stage window) {
|
private void setupWindow(Stage window) {
|
||||||
window.setTitle(TITLE);
|
window.setTitle(TITLE);
|
||||||
window.getIcons().add(new Image(getClass().getResourceAsStream(ICON_PATH)));
|
if (window.getIcons().isEmpty())
|
||||||
|
window.getIcons().add(new Image(getClass().getResourceAsStream(ICON_PATH)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -53,6 +54,7 @@ public class Main extends Application {
|
|||||||
*/
|
*/
|
||||||
private void createScene() {
|
private void createScene() {
|
||||||
this.scene = new Scene(fxmlRoot);
|
this.scene = new Scene(fxmlRoot);
|
||||||
|
this.scene.setUserData(this.fxmlLoader);
|
||||||
Model.setScene(scene);
|
Model.setScene(scene);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,6 +66,16 @@ public class MainController implements Initializable {
|
|||||||
return hostServices;
|
return hostServices;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO: Document
|
||||||
|
public List<Controller> getInnerControllers() {
|
||||||
|
return List.of(
|
||||||
|
editorController,
|
||||||
|
filetreeController,
|
||||||
|
modelineController,
|
||||||
|
menubarController
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a reference to the global Host Services API
|
* Set a reference to the global Host Services API
|
||||||
*
|
*
|
||||||
|
@ -66,6 +66,11 @@ public class EditorController implements Initializable, Controller, FileManageme
|
|||||||
this.eventBus.register(this);
|
this.eventBus.register(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: document
|
||||||
|
public CodeArea getEditor() {
|
||||||
|
return editor;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Applies highlighting to the editor.
|
* Applies highlighting to the editor.
|
||||||
*
|
*
|
||||||
@ -146,21 +151,20 @@ public class EditorController implements Initializable, Controller, FileManageme
|
|||||||
* @throws FileNotFoundException
|
* @throws FileNotFoundException
|
||||||
*/
|
*/
|
||||||
public void setEditorContent(String filePath) {
|
public void setEditorContent(String filePath) {
|
||||||
if (filePath == null) {
|
// if (filePath == null) {
|
||||||
editor.clear();
|
// editor.clear();
|
||||||
editor.appendText("// New File");
|
// editor.appendText("// New File");
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
try (Scanner sc = new Scanner(new File(filePath))) {
|
try (Scanner sc = new Scanner(new File(filePath))) {
|
||||||
if (filePath.endsWith(".java") || filePath.endsWith(".md")) {
|
// if (filePath.endsWith(".java") || filePath.endsWith(".md")) {
|
||||||
editor.clear();
|
editor.clear();
|
||||||
while (sc.hasNextLine()) {
|
while (sc.hasNextLine()) {
|
||||||
editor.appendText(sc.nextLine());
|
editor.appendText(sc.nextLine() + "\n");
|
||||||
editor.appendText("\n");
|
|
||||||
}
|
}
|
||||||
} else {
|
// } else {
|
||||||
throw new FileNotFoundException();
|
// throw new FileNotFoundException();
|
||||||
}
|
// }
|
||||||
|
|
||||||
} catch (FileNotFoundException ex) {
|
} catch (FileNotFoundException ex) {
|
||||||
Alert error = new Alert(AlertType.ERROR);
|
Alert error = new Alert(AlertType.ERROR);
|
||||||
@ -208,8 +212,8 @@ public class EditorController implements Initializable, Controller, FileManageme
|
|||||||
* Updates Code Area (read from file) whenever the FileSelected is changed
|
* Updates Code Area (read from file) whenever the FileSelected is changed
|
||||||
*/
|
*/
|
||||||
@Subscribe
|
@Subscribe
|
||||||
private void handle(FileSelectedEvent event) {
|
public void handle(FileSelectedEvent event) {
|
||||||
this.setEditorContent(event.getPath());
|
this.setEditorContent(event.getPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -226,7 +230,7 @@ public class EditorController implements Initializable, Controller, FileManageme
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
private void handle(ToggleCommentEvent event) {
|
public void handle(ToggleCommentEvent event) {
|
||||||
this.toggleComment();
|
this.toggleComment();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ import javafx.scene.image.ImageView;
|
|||||||
import javafx.scene.input.MouseEvent;
|
import javafx.scene.input.MouseEvent;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
@ -124,12 +125,26 @@ public class FiletreeController implements Initializable, Controller {
|
|||||||
String name = file.getName();
|
String name = file.getName();
|
||||||
String ext = (name.substring(file.getName().lastIndexOf(".") + 1, file.getName().length()));
|
String ext = (name.substring(file.getName().lastIndexOf(".") + 1, file.getName().length()));
|
||||||
|
|
||||||
if ("java".equals(ext))
|
try {
|
||||||
createExtension(name, java, parent);
|
createExtension(name, getIconForFile(file), parent);
|
||||||
else if ("md".equals(ext))
|
} catch (Exception e) {
|
||||||
createExtension(name, md, parent);
|
System.err.println("ICON NOT FOUND: " + file.getPath());
|
||||||
else
|
}
|
||||||
createExtension(name, placeholder, parent);
|
|
||||||
|
// if ("java".equals(ext))
|
||||||
|
// createExtension(name, java, parent);
|
||||||
|
// else if ("md".equals(ext))
|
||||||
|
// createExtension(name, md, parent);
|
||||||
|
// else
|
||||||
|
// createExtension(name, placeholder, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Image getIconForFile(File file) throws IOException {
|
||||||
|
String mimeType = Files.probeContentType(file.toPath()).replace('/', '-');
|
||||||
|
String iconPath = (mimeType != null)
|
||||||
|
? "/graphics/filetreeicons/" + mimeType + ".png"
|
||||||
|
: "/graphics/filetreeicons/file.png";
|
||||||
|
return new Image(getClass().getResourceAsStream(iconPath));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createExtension(String name, Image image, CheckBoxTreeItem<String> parent) {
|
private void createExtension(String name, Image image, CheckBoxTreeItem<String> parent) {
|
||||||
|
@ -3,4 +3,4 @@ package app.events;
|
|||||||
/**
|
/**
|
||||||
* Base class for any type of event of the eventbus
|
* Base class for any type of event of the eventbus
|
||||||
*/
|
*/
|
||||||
abstract class Event {}
|
public abstract class Event {}
|
||||||
|
@ -13,7 +13,7 @@ import app.model.ProgrammingLanguage;
|
|||||||
* Common static operations that can be executed on any class
|
* Common static operations that can be executed on any class
|
||||||
* that implements {@link app.model.ProgrammingLanguage ProgrammingLanguage}
|
* that implements {@link app.model.ProgrammingLanguage ProgrammingLanguage}
|
||||||
*/
|
*/
|
||||||
public class LanguageOperations {
|
public final class LanguageOperations {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use a matcher to find the styleclass of the next match
|
* Use a matcher to find the styleclass of the next match
|
||||||
|
@ -10,7 +10,8 @@
|
|||||||
prefHeight="400"
|
prefHeight="400"
|
||||||
xmlns="http://javafx.com/javafx/8.0.65"
|
xmlns="http://javafx.com/javafx/8.0.65"
|
||||||
xmlns:fx="http://javafx.com/fxml/1"
|
xmlns:fx="http://javafx.com/fxml/1"
|
||||||
fx:controller="app.MainController">
|
fx:controller="app.MainController"
|
||||||
|
fx:id="root">
|
||||||
|
|
||||||
<top>
|
<top>
|
||||||
<!-- Menubar -->
|
<!-- Menubar -->
|
||||||
|
44
src/test/java/app/FxTestTemplate.java
Normal file
44
src/test/java/app/FxTestTemplate.java
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
package app;
|
||||||
|
|
||||||
|
import javafx.scene.Node;
|
||||||
|
import javafx.stage.Stage;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.testfx.api.FxToolkit;
|
||||||
|
import org.testfx.framework.junit5.ApplicationTest;
|
||||||
|
import org.testfx.util.WaitForAsyncUtils;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
public class FxTestTemplate extends ApplicationTest {
|
||||||
|
|
||||||
|
private Stage stage;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void runAppToTests() throws Exception {
|
||||||
|
FxToolkit.registerPrimaryStage();
|
||||||
|
FxToolkit.setupApplication(Main::new);
|
||||||
|
FxToolkit.showStage();
|
||||||
|
WaitForAsyncUtils.waitForFxEvents(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public void stopApp() throws TimeoutException {
|
||||||
|
FxToolkit.cleanupStages();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start(Stage primaryStage){
|
||||||
|
this.stage = primaryStage;
|
||||||
|
primaryStage.toFront();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Stage getStage() {
|
||||||
|
return stage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T extends Node> T find(final String query) {
|
||||||
|
/** TestFX provides many operations to retrieve elements from the loaded GUI. */
|
||||||
|
return lookup(query).query();
|
||||||
|
}
|
||||||
|
}
|
@ -1,16 +1,74 @@
|
|||||||
package app;
|
package app;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.junit.jupiter.api.DisplayName;
|
import org.junit.jupiter.api.DisplayName;
|
||||||
|
import org.junit.jupiter.api.Order;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.platform.commons.annotation.Testable;
|
||||||
|
|
||||||
public class MainTest {
|
import app.controllers.*;
|
||||||
|
|
||||||
@Test
|
import java.util.List;
|
||||||
@DisplayName("Temp Test")
|
import java.util.stream.Collectors;
|
||||||
public void tempTest() {
|
|
||||||
assertEquals(1, 1);
|
import javafx.scene.layout.BorderPane;
|
||||||
}
|
|
||||||
|
import app.testing.FxTestTemplate;
|
||||||
}
|
|
||||||
|
|
||||||
|
@Testable
|
||||||
|
public class MainTest extends FxTestTemplate {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Check that the stage title is correct")
|
||||||
|
public void should_have_stage_title() {
|
||||||
|
assertEquals("Banana Editor", this.getStage().getTitle());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(1)
|
||||||
|
@DisplayName("Check that the stage has an icon")
|
||||||
|
public void should_have_stage_icon() {
|
||||||
|
assertEquals(1, this.getStage().getIcons().size());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(2)
|
||||||
|
@DisplayName("Check that the root element is present")
|
||||||
|
public void should_have_root() {
|
||||||
|
BorderPane app = (BorderPane) find("#root");
|
||||||
|
assertNotNull(app);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(3)
|
||||||
|
@DisplayName("Check that all subcontrollers are present")
|
||||||
|
public void should_have_subcontrollers() {
|
||||||
|
this
|
||||||
|
.getMainController()
|
||||||
|
.getInnerControllers()
|
||||||
|
.forEach((Controller controller) -> assertNotNull(controller));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Check that the scene is correct")
|
||||||
|
public void should_have_scene() throws IOException {
|
||||||
|
assertNotNull(this.getStage().getScene());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Check that the CSS is set")
|
||||||
|
public void should_have_css() {
|
||||||
|
List<String> expectedCSS =
|
||||||
|
List.of("/styling/themes/monokai.css", "/styling/languages/java.css")
|
||||||
|
.stream()
|
||||||
|
.map(p -> getClass().getResource(p).toExternalForm())
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
assertEquals(expectedCSS, this.getStage().getScene().getStylesheets());
|
||||||
|
}
|
||||||
|
}
|
238
src/test/java/app/controllers/EditorControllerTest.java
Normal file
238
src/test/java/app/controllers/EditorControllerTest.java
Normal file
@ -0,0 +1,238 @@
|
|||||||
|
package app.controllers;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.fxmisc.richtext.CodeArea;
|
||||||
|
import org.fxmisc.richtext.model.StyleSpans;
|
||||||
|
|
||||||
|
import com.google.common.eventbus.EventBus;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.DisplayName;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.mockStatic;
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.Captor;
|
||||||
|
import org.mockito.InjectMocks;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockedStatic;
|
||||||
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
|
||||||
|
import app.testing.FxTestTemplate;
|
||||||
|
import app.model.Model;
|
||||||
|
import app.model.ProgrammingLanguage;
|
||||||
|
import app.service.LanguageOperations;
|
||||||
|
import app.events.CopyEvent;
|
||||||
|
import app.events.CutEvent;
|
||||||
|
import app.events.FileSelectedEvent;
|
||||||
|
import app.events.LanguageChangedEvent;
|
||||||
|
import app.events.PasteEvent;
|
||||||
|
import app.events.RedoEvent;
|
||||||
|
import app.events.ToggleCommentEvent;
|
||||||
|
import app.events.ToggleWrapTextEvent;
|
||||||
|
import app.events.UndoEvent;
|
||||||
|
|
||||||
|
@ExtendWith(MockitoExtension.class)
|
||||||
|
public class EditorControllerTest extends FxTestTemplate {
|
||||||
|
|
||||||
|
|
||||||
|
@Captor
|
||||||
|
private ArgumentCaptor<String> captor;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private CodeArea editor;
|
||||||
|
|
||||||
|
private EventBus eventBus;
|
||||||
|
|
||||||
|
@InjectMocks
|
||||||
|
private EditorController controller;
|
||||||
|
|
||||||
|
private String mockContent = """
|
||||||
|
class HelloWorld {
|
||||||
|
private String message = "Hello world";
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
|
private String mockLine = "private String message = \"Hello world\";";
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void insertEventBus() {
|
||||||
|
this.eventBus = new EventBus();
|
||||||
|
this.controller.setEventBus(eventBus);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Test handling of FileSelectedEvent with a real file")
|
||||||
|
public void testFileSelectedEventWithRealFile() throws IOException {
|
||||||
|
|
||||||
|
String resourcePath = "/testfile.txt";
|
||||||
|
String filePath = getClass().getResource(resourcePath).getPath();
|
||||||
|
File file = new File(filePath);
|
||||||
|
List<String> content =
|
||||||
|
Files.readAllLines(file.toPath())
|
||||||
|
.stream()
|
||||||
|
.map(s -> s + "\n")
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
eventBus.post(new FileSelectedEvent(filePath));
|
||||||
|
verify(editor, times(content.size())).appendText(captor.capture());
|
||||||
|
|
||||||
|
assertEquals(content, captor.getAllValues());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Test handling of FileSelectedEvent with a file that doesn't exist")
|
||||||
|
public void testFileSelectedEventWithUnrealFile() throws IOException {
|
||||||
|
|
||||||
|
String brokenFilePath = "/doesNotExist.txt";
|
||||||
|
eventBus.post(new FileSelectedEvent(brokenFilePath));
|
||||||
|
|
||||||
|
verify(editor, never()).clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Test handling of LanguageChangedEvent")
|
||||||
|
public void testLanguageChangedEvent(){
|
||||||
|
|
||||||
|
when(editor.getText()).thenReturn(mockContent);
|
||||||
|
|
||||||
|
try (MockedStatic<LanguageOperations> mocked = mockStatic(LanguageOperations.class)) {
|
||||||
|
mocked.when(() -> LanguageOperations.syntaxHighlight(anyString(), any()))
|
||||||
|
.thenReturn(StyleSpans.singleton(null, 0));
|
||||||
|
|
||||||
|
eventBus.post(new LanguageChangedEvent("markdown"));
|
||||||
|
mocked.verify(() -> LanguageOperations.syntaxHighlight(anyString(), any()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Test handling of ToggleCommentEvent when not selected")
|
||||||
|
public void testToggleCommentEventNotSelect(){
|
||||||
|
|
||||||
|
ProgrammingLanguage lang = mock(ProgrammingLanguage.class);
|
||||||
|
when(editor.getSelectedText()).thenReturn("");
|
||||||
|
when(editor.getText(anyInt())).thenReturn(mockLine);
|
||||||
|
|
||||||
|
try (MockedStatic<Model> mocked = mockStatic(Model.class)) {
|
||||||
|
mocked.when(() -> Model.getLanguage()).thenReturn(lang);
|
||||||
|
|
||||||
|
when(lang.isCommentedLine(anyString())).thenReturn(false);
|
||||||
|
eventBus.post(new ToggleCommentEvent());
|
||||||
|
verify(lang).commentLine(anyString());
|
||||||
|
|
||||||
|
when(lang.isCommentedLine(anyString())).thenReturn(true);
|
||||||
|
eventBus.post(new ToggleCommentEvent());
|
||||||
|
verify(lang).unCommentLine(anyString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Test handling of ToggleCommentEvent when selected")
|
||||||
|
public void testToggleCommentEventSelect(){
|
||||||
|
|
||||||
|
ProgrammingLanguage lang = mock(ProgrammingLanguage.class);
|
||||||
|
when(editor.getSelectedText()).thenReturn("Selected Text");
|
||||||
|
|
||||||
|
try (MockedStatic<Model> mocked = mockStatic(Model.class)) {
|
||||||
|
mocked.when(() -> Model.getLanguage()).thenReturn(lang);
|
||||||
|
|
||||||
|
when(lang.isCommentedSelection(anyString())).thenReturn(false);
|
||||||
|
eventBus.post(new ToggleCommentEvent());
|
||||||
|
verify(lang).commentSelection(anyString());
|
||||||
|
|
||||||
|
when(lang.isCommentedSelection(anyString())).thenReturn(true);
|
||||||
|
eventBus.post(new ToggleCommentEvent());
|
||||||
|
verify(lang).unCommentSelection(anyString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Test handling of ToggleWrapTextEvent")
|
||||||
|
public void testToggleWrapTextEvent(){
|
||||||
|
eventBus.post(new ToggleWrapTextEvent(true));
|
||||||
|
verify(editor).setWrapText(true);
|
||||||
|
eventBus.post(new ToggleWrapTextEvent(false));
|
||||||
|
verify(editor).setWrapText(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Test handling of UndoEvent")
|
||||||
|
public void testUndoEvent(){
|
||||||
|
when(editor.isFocused()).thenReturn(true);
|
||||||
|
eventBus.post(new UndoEvent());
|
||||||
|
verify(editor, times(1)).undo();
|
||||||
|
|
||||||
|
when(editor.isFocused()).thenReturn(false);
|
||||||
|
eventBus.post(new UndoEvent());
|
||||||
|
// Should not have been called one more time
|
||||||
|
verify(editor, times(1)).undo();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Test handling of RedoEvent")
|
||||||
|
public void testRedoEvent(){
|
||||||
|
when(editor.isFocused()).thenReturn(true);
|
||||||
|
eventBus.post(new RedoEvent());
|
||||||
|
verify(editor, times(1)).redo();
|
||||||
|
|
||||||
|
when(editor.isFocused()).thenReturn(false);
|
||||||
|
eventBus.post(new RedoEvent());
|
||||||
|
verify(editor, times(1)).redo();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Test handling of CopyEvent")
|
||||||
|
public void testCopyEvent(){
|
||||||
|
when(editor.isFocused()).thenReturn(true);
|
||||||
|
eventBus.post(new CopyEvent());
|
||||||
|
verify(editor, times(1)).copy();
|
||||||
|
|
||||||
|
when(editor.isFocused()).thenReturn(false);
|
||||||
|
eventBus.post(new CopyEvent());
|
||||||
|
verify(editor, times(1)).copy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Test handling of CutEvent")
|
||||||
|
public void testCutEvent(){
|
||||||
|
when(editor.isFocused()).thenReturn(true);
|
||||||
|
eventBus.post(new CutEvent());
|
||||||
|
verify(editor, times(1)).cut();
|
||||||
|
|
||||||
|
when(editor.isFocused()).thenReturn(false);
|
||||||
|
eventBus.post(new CutEvent());
|
||||||
|
verify(editor, times(1)).cut();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Test handling of PasteEvent")
|
||||||
|
public void testPasteEvent(){
|
||||||
|
when(editor.isFocused()).thenReturn(true);
|
||||||
|
eventBus.post(new PasteEvent());
|
||||||
|
verify(editor, times(1)).paste();
|
||||||
|
|
||||||
|
when(editor.isFocused()).thenReturn(false);
|
||||||
|
eventBus.post(new PasteEvent());
|
||||||
|
verify(editor, times(1)).paste();
|
||||||
|
}
|
||||||
|
}
|
18
src/test/java/app/events/FileSaveStateChangedEventTest.java
Normal file
18
src/test/java/app/events/FileSaveStateChangedEventTest.java
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package app.events;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.DisplayName;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import app.model.Model;
|
||||||
|
import app.testing.EventTestTemplate;
|
||||||
|
|
||||||
|
public class FileSaveStateChangedEventTest extends EventTestTemplate {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Check that model gets changed on constructor")
|
||||||
|
public void checkModel() {
|
||||||
|
new FileSaveStateChangedEvent(true);
|
||||||
|
this.mockModel.verify(() -> Model.setFileIsSaved(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
5
src/test/java/app/testing/ControllerTestTemplate.java
Normal file
5
src/test/java/app/testing/ControllerTestTemplate.java
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package app.testing;
|
||||||
|
|
||||||
|
public class ControllerTestTemplate extends FxTestTemplate {
|
||||||
|
|
||||||
|
}
|
25
src/test/java/app/testing/EventTestTemplate.java
Normal file
25
src/test/java/app/testing/EventTestTemplate.java
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package app.testing;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.mockStatic;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.mockito.MockedStatic;
|
||||||
|
|
||||||
|
import app.model.Model;
|
||||||
|
|
||||||
|
public class EventTestTemplate extends FxTestTemplate {
|
||||||
|
|
||||||
|
public MockedStatic<Model> mockModel;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void openModel() {
|
||||||
|
mockModel = mockStatic(Model.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public void closeModel() {
|
||||||
|
mockModel.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
56
src/test/java/app/testing/FxTestTemplate.java
Normal file
56
src/test/java/app/testing/FxTestTemplate.java
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
package app.testing;
|
||||||
|
|
||||||
|
import javafx.application.Application;
|
||||||
|
import javafx.fxml.FXMLLoader;
|
||||||
|
import javafx.scene.Node;
|
||||||
|
import javafx.stage.Stage;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.testfx.api.FxToolkit;
|
||||||
|
import org.testfx.framework.junit5.ApplicationTest;
|
||||||
|
import org.testfx.util.WaitForAsyncUtils;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
import app.Main;
|
||||||
|
import app.MainController;
|
||||||
|
|
||||||
|
public class FxTestTemplate extends ApplicationTest {
|
||||||
|
|
||||||
|
private Stage stage;
|
||||||
|
private Application application;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void runAppToTests() throws Exception {
|
||||||
|
FxToolkit.registerPrimaryStage();
|
||||||
|
this.application = FxToolkit.setupApplication(Main::new);
|
||||||
|
|
||||||
|
FxToolkit.showStage();
|
||||||
|
WaitForAsyncUtils.waitForFxEvents(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public void stopApp() throws TimeoutException {
|
||||||
|
FxToolkit.cleanupStages();
|
||||||
|
FxToolkit.cleanupApplication(this.application);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start(Stage primaryStage){
|
||||||
|
this.stage = primaryStage;
|
||||||
|
primaryStage.toFront();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Stage getStage() {
|
||||||
|
return stage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MainController getMainController() {
|
||||||
|
return ((FXMLLoader) this.stage.getScene().getUserData()).getController();
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T extends Node> T find(final String query) {
|
||||||
|
/** TestFX provides many operations to retrieve elements from the loaded GUI. */
|
||||||
|
return lookup(query).query();
|
||||||
|
}
|
||||||
|
}
|
3
src/test/resources/testfile.txt
Normal file
3
src/test/resources/testfile.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
public class testfile {
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user