diff --git a/build.gradle.kts b/build.gradle.kts index 6831e03..ea0b293 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,5 +1,6 @@ plugins { java + jacoco id("org.springframework.boot") version "4.0.3" id("io.spring.dependency-management") version "1.1.7" } @@ -41,4 +42,12 @@ dependencies { tasks.withType { useJUnitPlatform() + finalizedBy(tasks.jacocoTestReport) +} + +tasks.jacocoTestReport { + dependsOn(tasks.test) + reports { + csv.required = true + } } diff --git a/src/test/java/be/seeseepuff/webgit/WebgitApplicationTests.java b/src/test/java/be/seeseepuff/webgit/WebgitApplicationTests.java index 2c38a47..ed8e998 100644 --- a/src/test/java/be/seeseepuff/webgit/WebgitApplicationTests.java +++ b/src/test/java/be/seeseepuff/webgit/WebgitApplicationTests.java @@ -10,4 +10,9 @@ class WebgitApplicationTests { void contextLoads() { } + @Test + void mainMethodRuns() { + WebgitApplication.main(new String[]{}); + } + } diff --git a/src/test/java/be/seeseepuff/webgit/telnet/TelnetServerTest.java b/src/test/java/be/seeseepuff/webgit/telnet/TelnetServerTest.java index 747211b..626a47d 100644 --- a/src/test/java/be/seeseepuff/webgit/telnet/TelnetServerTest.java +++ b/src/test/java/be/seeseepuff/webgit/telnet/TelnetServerTest.java @@ -22,17 +22,15 @@ class TelnetServerTest WebgitProperties props = new WebgitProperties(); props.setWorktreePath(tempDir.resolve("worktrees")); props.setGitDirPath(tempDir.resolve("gitdirs")); - props.setTelnetPort(0); // use any free port - GitService gitService = new GitService(props); - - // We'll test with a real server socket but use port 0 for a random free port - // Since the TelnetServer uses PostConstruct, we'll test the component manually - var serverSocket = new java.net.ServerSocket(0); - int port = serverSocket.getLocalPort(); - serverSocket.close(); + // First find a free port + var tmpSocket = new java.net.ServerSocket(0); + int port = tmpSocket.getLocalPort(); + tmpSocket.close(); props.setTelnetPort(port); + GitService gitService = new GitService(props); + TelnetServer server = new TelnetServer(gitService, props); server.start(); @@ -40,14 +38,11 @@ class TelnetServerTest BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); PrintWriter out = new PrintWriter(socket.getOutputStream(), true)) { - // Read the welcome message String line = in.readLine(); assertTrue(line.contains("Welcome to WebGit")); - // Send quit out.println("q"); - // Read until we see Goodbye String response = ""; String l; while ((l = in.readLine()) != null) @@ -61,4 +56,49 @@ class TelnetServerTest server.stop(); } } + + @Test + void serverUsesDefaultPortWhenNull() throws Exception + { + WebgitProperties props = new WebgitProperties(); + props.setWorktreePath(tempDir.resolve("worktrees")); + props.setGitDirPath(tempDir.resolve("gitdirs")); + props.setTelnetPort(null); + + GitService gitService = new GitService(props); + TelnetServer server = new TelnetServer(gitService, props); + + // The default port is 2323; this tests the null branch + // We can't easily test this without port conflicts, so just verify + // it starts and stops without error (port 2323 may be in use) + try + { + server.start(); + server.stop(); + } + catch (java.net.BindException e) + { + // Port 2323 already in use is acceptable for this test + } + } + + @Test + void serverStopIsIdempotent() throws Exception + { + WebgitProperties props = new WebgitProperties(); + props.setWorktreePath(tempDir.resolve("worktrees")); + props.setGitDirPath(tempDir.resolve("gitdirs")); + + var tmpSocket = new java.net.ServerSocket(0); + int port = tmpSocket.getLocalPort(); + tmpSocket.close(); + props.setTelnetPort(port); + + GitService gitService = new GitService(props); + TelnetServer server = new TelnetServer(gitService, props); + server.start(); + server.stop(); + // Second stop should not throw + server.stop(); + } } diff --git a/src/test/java/be/seeseepuff/webgit/telnet/TelnetSessionTest.java b/src/test/java/be/seeseepuff/webgit/telnet/TelnetSessionTest.java index 058d52b..3482ef2 100644 --- a/src/test/java/be/seeseepuff/webgit/telnet/TelnetSessionTest.java +++ b/src/test/java/be/seeseepuff/webgit/telnet/TelnetSessionTest.java @@ -349,4 +349,90 @@ class TelnetSessionTest String output = runSession("3\n1\n6\nabc\nb\nq\n"); verify(gitService, never()).stageFiles(anyString(), anyList()); } + + @Test + void stageOutOfRangeNumbers() throws IOException, GitAPIException + { + when(gitService.listRepositories()).thenReturn(List.of("myrepo")); + when(gitService.getCurrentBranch("myrepo")).thenReturn("main"); + when(gitService.getModifiedFiles("myrepo")).thenReturn(List.of("a.txt")); + // Index 99 is out of range + String output = runSession("3\n1\n6\n99\nb\nq\n"); + verify(gitService, never()).stageFiles(anyString(), anyList()); + } + + @Test + void stageNegativeIndex() throws IOException, GitAPIException + { + when(gitService.listRepositories()).thenReturn(List.of("myrepo")); + when(gitService.getCurrentBranch("myrepo")).thenReturn("main"); + when(gitService.getModifiedFiles("myrepo")).thenReturn(List.of("a.txt")); + // Index 0 maps to -1 which is < 0 + String output = runSession("3\n1\n6\n0\nb\nq\n"); + verify(gitService, never()).stageFiles(anyString(), anyList()); + } + + @Test + void cloneNullUrl() + { + // Input ends after "2\n" prompt for URL — readLine returns null + String output = runSession("2\n"); + assertTrue(output.contains("Goodbye!")); + } + + @Test + void checkoutBranchNull() throws IOException, GitAPIException + { + when(gitService.listRepositories()).thenReturn(List.of("myrepo")); + when(gitService.getCurrentBranch("myrepo")).thenReturn("main"); + // Enter repo menu, choose checkout(2), then input stream ends + String output = runSession("3\n1\n2\n"); + verify(gitService, never()).checkoutBranch(anyString(), anyString()); + } + + @Test + void createBranchNull() throws IOException, GitAPIException + { + when(gitService.listRepositories()).thenReturn(List.of("myrepo")); + when(gitService.getCurrentBranch("myrepo")).thenReturn("main"); + String output = runSession("3\n1\n3\n"); + verify(gitService, never()).createAndCheckoutBranch(anyString(), anyString()); + } + + @Test + void commitNull() throws IOException, GitAPIException + { + when(gitService.listRepositories()).thenReturn(List.of("myrepo")); + when(gitService.getCurrentBranch("myrepo")).thenReturn("main"); + String output = runSession("3\n1\n7\n"); + verify(gitService, never()).commit(anyString(), anyString()); + } + + @Test + void stageFilesNull() throws IOException, GitAPIException + { + when(gitService.listRepositories()).thenReturn(List.of("myrepo")); + when(gitService.getCurrentBranch("myrepo")).thenReturn("main"); + when(gitService.getModifiedFiles("myrepo")).thenReturn(List.of("a.txt")); + // Input ends at the "enter numbers" prompt + String output = runSession("3\n1\n6\n"); + verify(gitService, never()).stageFiles(anyString(), anyList()); + } + + @Test + void openRepositoryNull() throws IOException + { + when(gitService.listRepositories()).thenReturn(List.of("myrepo")); + // Input ends at the "enter number" prompt + String output = runSession("3\n"); + assertTrue(output.contains("Goodbye!")); + } + + @Test + void cloneNullName() + { + // URL is provided but name input stream ends + String output = runSession("2\nhttps://example.com/repo.git\n"); + assertTrue(output.contains("Goodbye!")); + } }