|
14 | 14 | import java.io.IOException; |
15 | 15 | import java.nio.file.Files; |
16 | 16 | import java.nio.file.Path; |
| 17 | +import java.util.List; |
17 | 18 |
|
18 | 19 | import static io.github.cowwoc.requirements13.java.DefaultJavaValidators.requireThat; |
19 | 20 |
|
@@ -100,7 +101,10 @@ public void inProgressVersionIsIncluded() throws IOException |
100 | 101 | {"status":"in-progress"}"""); |
101 | 102 | Files.writeString(versionDir.resolve("plan.md"), |
102 | 103 | "# Plan\n\n## Goal\n\nTest version goal summary.\n"); |
103 | | - Files.createDirectories(versionDir.resolve("my-issue")); |
| 104 | + Path myIssueDir = versionDir.resolve("my-issue"); |
| 105 | + Files.createDirectories(myIssueDir); |
| 106 | + Files.writeString(myIssueDir.resolve("index.json"), """ |
| 107 | + {"status":"open"}"""); |
104 | 108 |
|
105 | 109 | GetAddOutput handler = new GetAddOutput(scope); |
106 | 110 | String result = handler.getOutput(new String[0]); |
@@ -323,7 +327,10 @@ public void regularFilesNotListedAsIssues() throws IOException |
323 | 327 | Files.writeString(versionDir.resolve("plan.md"), "# Plan\n\n## Goal\n\nGoal.\n"); |
324 | 328 | Files.writeString(versionDir.resolve("CHANGELOG.md"), "# Changelog\n"); |
325 | 329 | Files.writeString(versionDir.resolve("notes.txt"), "some notes"); |
326 | | - Files.createDirectories(versionDir.resolve("real-issue")); |
| 330 | + Path realIssueDir = versionDir.resolve("real-issue"); |
| 331 | + Files.createDirectories(realIssueDir); |
| 332 | + Files.writeString(realIssueDir.resolve("index.json"), """ |
| 333 | + {"status":"open"}"""); |
327 | 334 |
|
328 | 335 | GetAddOutput handler = new GetAddOutput(scope); |
329 | 336 | String result = handler.getOutput(new String[0]); |
@@ -354,8 +361,14 @@ public void issueNamesWithSpecialCharactersListed() throws IOException |
354 | 361 | Files.createDirectories(versionDir); |
355 | 362 | Files.writeString(versionDir.resolve("index.json"), """ |
356 | 363 | {"status":"open"}"""); |
357 | | - Files.createDirectories(versionDir.resolve("fix-bug-123")); |
358 | | - Files.createDirectories(versionDir.resolve("add-feature-abc")); |
| 364 | + Path fixBugDir = versionDir.resolve("fix-bug-123"); |
| 365 | + Files.createDirectories(fixBugDir); |
| 366 | + Files.writeString(fixBugDir.resolve("index.json"), """ |
| 367 | + {"status":"open"}"""); |
| 368 | + Path addFeatureDir = versionDir.resolve("add-feature-abc"); |
| 369 | + Files.createDirectories(addFeatureDir); |
| 370 | + Files.writeString(addFeatureDir.resolve("index.json"), """ |
| 371 | + {"status":"open"}"""); |
359 | 372 |
|
360 | 373 | GetAddOutput handler = new GetAddOutput(scope); |
361 | 374 | String result = handler.getOutput(new String[0]); |
@@ -388,9 +401,13 @@ public void issueCountEqualsExistingIssuesSize() throws IOException |
388 | 401 | Files.createDirectories(versionDir); |
389 | 402 | Files.writeString(versionDir.resolve("index.json"), """ |
390 | 403 | {"status":"open"}"""); |
391 | | - Files.createDirectories(versionDir.resolve("issue-a")); |
392 | | - Files.createDirectories(versionDir.resolve("issue-b")); |
393 | | - Files.createDirectories(versionDir.resolve("issue-c")); |
| 404 | + for (String issueName : List.of("issue-a", "issue-b", "issue-c")) |
| 405 | + { |
| 406 | + Path issueDir = versionDir.resolve(issueName); |
| 407 | + Files.createDirectories(issueDir); |
| 408 | + Files.writeString(issueDir.resolve("index.json"), """ |
| 409 | + {"status":"open"}"""); |
| 410 | + } |
394 | 411 |
|
395 | 412 | GetAddOutput handler = new GetAddOutput(scope); |
396 | 413 | String result = handler.getOutput(new String[0]); |
@@ -886,4 +903,117 @@ public void nullArgsThrowsNullPointerException() throws IOException |
886 | 903 | handler.getOutput(null); |
887 | 904 | } |
888 | 905 | } |
| 906 | + |
| 907 | + // ==================== open-only issue filtering ==================== |
| 908 | + |
| 909 | + /** |
| 910 | + * Verifies that closed issues are excluded from the existing_issues list, allowing new issues with the |
| 911 | + * same name to be created without a false duplicate error. |
| 912 | + * |
| 913 | + * @throws IOException if an I/O error occurs |
| 914 | + */ |
| 915 | + @Test |
| 916 | + @SuppressWarnings("try") |
| 917 | + public void closedIssueExcludedFromExistingIssues() throws IOException |
| 918 | + { |
| 919 | + try (TestClaudeTool scope = new TestClaudeTool()) |
| 920 | + { |
| 921 | + Path projectPath = scope.getProjectPath(); |
| 922 | + Path issuesDir = projectPath.resolve(".cat/issues"); |
| 923 | + Path versionDir = issuesDir.resolve("v2/v2.1"); |
| 924 | + Files.createDirectories(versionDir); |
| 925 | + Files.writeString(versionDir.resolve("index.json"), """ |
| 926 | + {"status":"open"}"""); |
| 927 | + |
| 928 | + Path closedIssueDir = versionDir.resolve("fix-bug"); |
| 929 | + Files.createDirectories(closedIssueDir); |
| 930 | + Files.writeString(closedIssueDir.resolve("index.json"), """ |
| 931 | + {"status":"closed","resolution":"implemented"}"""); |
| 932 | + |
| 933 | + GetAddOutput handler = new GetAddOutput(scope); |
| 934 | + String result = handler.getOutput(new String[0]); |
| 935 | + |
| 936 | + JsonMapper mapper = scope.getJsonMapper(); |
| 937 | + JsonNode version = mapper.readTree(result).get("versions").get(0); |
| 938 | + JsonNode existingIssues = version.get("existing_issues"); |
| 939 | + |
| 940 | + requireThat(existingIssues.size(), "existing_issues.size").isEqualTo(0); |
| 941 | + requireThat(version.get("issue_count").asInt(), "issue_count").isEqualTo(0); |
| 942 | + } |
| 943 | + } |
| 944 | + |
| 945 | + /** |
| 946 | + * Verifies that open issues are included and closed issues are excluded from existing_issues. |
| 947 | + * |
| 948 | + * @throws IOException if an I/O error occurs |
| 949 | + */ |
| 950 | + @Test |
| 951 | + @SuppressWarnings("try") |
| 952 | + public void openIssueIncludedClosedIssueExcluded() throws IOException |
| 953 | + { |
| 954 | + try (TestClaudeTool scope = new TestClaudeTool()) |
| 955 | + { |
| 956 | + Path projectPath = scope.getProjectPath(); |
| 957 | + Path issuesDir = projectPath.resolve(".cat/issues"); |
| 958 | + Path versionDir = issuesDir.resolve("v2/v2.1"); |
| 959 | + Files.createDirectories(versionDir); |
| 960 | + Files.writeString(versionDir.resolve("index.json"), """ |
| 961 | + {"status":"open"}"""); |
| 962 | + |
| 963 | + Path openIssueDir = versionDir.resolve("new-feature"); |
| 964 | + Files.createDirectories(openIssueDir); |
| 965 | + Files.writeString(openIssueDir.resolve("index.json"), """ |
| 966 | + {"status":"open"}"""); |
| 967 | + |
| 968 | + Path closedIssueDir = versionDir.resolve("fix-bug"); |
| 969 | + Files.createDirectories(closedIssueDir); |
| 970 | + Files.writeString(closedIssueDir.resolve("index.json"), """ |
| 971 | + {"status":"closed","resolution":"implemented"}"""); |
| 972 | + |
| 973 | + GetAddOutput handler = new GetAddOutput(scope); |
| 974 | + String result = handler.getOutput(new String[0]); |
| 975 | + |
| 976 | + JsonMapper mapper = scope.getJsonMapper(); |
| 977 | + JsonNode version = mapper.readTree(result).get("versions").get(0); |
| 978 | + JsonNode existingIssues = version.get("existing_issues"); |
| 979 | + |
| 980 | + requireThat(existingIssues.size(), "existing_issues.size").isEqualTo(1); |
| 981 | + requireThat(existingIssues.get(0).asString(), "existing_issues[0]").isEqualTo("new-feature"); |
| 982 | + requireThat(version.get("issue_count").asInt(), "issue_count").isEqualTo(1); |
| 983 | + } |
| 984 | + } |
| 985 | + |
| 986 | + /** |
| 987 | + * Verifies that an issue directory with no index.json is excluded from existing_issues, since its status |
| 988 | + * cannot be determined as open. |
| 989 | + * |
| 990 | + * @throws IOException if an I/O error occurs |
| 991 | + */ |
| 992 | + @Test |
| 993 | + @SuppressWarnings("try") |
| 994 | + public void issueWithMissingIndexJsonExcluded() throws IOException |
| 995 | + { |
| 996 | + try (TestClaudeTool scope = new TestClaudeTool()) |
| 997 | + { |
| 998 | + Path projectPath = scope.getProjectPath(); |
| 999 | + Path issuesDir = projectPath.resolve(".cat/issues"); |
| 1000 | + Path versionDir = issuesDir.resolve("v2/v2.1"); |
| 1001 | + Files.createDirectories(versionDir); |
| 1002 | + Files.writeString(versionDir.resolve("index.json"), """ |
| 1003 | + {"status":"open"}"""); |
| 1004 | + |
| 1005 | + Path noIndexIssueDir = versionDir.resolve("mystery-issue"); |
| 1006 | + Files.createDirectories(noIndexIssueDir); |
| 1007 | + |
| 1008 | + GetAddOutput handler = new GetAddOutput(scope); |
| 1009 | + String result = handler.getOutput(new String[0]); |
| 1010 | + |
| 1011 | + JsonMapper mapper = scope.getJsonMapper(); |
| 1012 | + JsonNode version = mapper.readTree(result).get("versions").get(0); |
| 1013 | + JsonNode existingIssues = version.get("existing_issues"); |
| 1014 | + |
| 1015 | + requireThat(existingIssues.size(), "existing_issues.size").isEqualTo(0); |
| 1016 | + requireThat(version.get("issue_count").asInt(), "issue_count").isEqualTo(0); |
| 1017 | + } |
| 1018 | + } |
889 | 1019 | } |
0 commit comments