@@ -57,6 +57,54 @@ void test() throws IllegalStateException, GitAPIException, IOException {
5757 }
5858 }
5959
60+ @ Test
61+ void testGitIgnoredDirectory_ShouldNotThrowNPE () throws IllegalStateException , GitAPIException , IOException {
62+ try (Git git = initRepo ()) {
63+ // Create a directory with files and commit them
64+ setFile ("useless/Wow.java" ).toContent ("class Wow {}" );
65+ setFile ("useless/Another.java" ).toContent ("class Another {}" );
66+ addAndCommit (git , "Add useless package" );
67+
68+ // Now ignore the entire directory and commit
69+ setFile (".gitignore" ).toContent ("useless/" );
70+ addAndCommit (git , "Ignore useless directory" );
71+
72+ // The files in the useless directory are now committed but gitignored
73+ // This should not throw NPE
74+ ratchetFrom ("main" ).onlyDirty ("useless/Wow.java" , "useless/Another.java" );
75+ }
76+ }
77+
78+ @ Test
79+ void testNewUntrackedFile_ShouldBeDirty () throws IllegalStateException , GitAPIException , IOException {
80+ try (Git git = initRepo ()) {
81+ // Create and commit initial file
82+ setFile ("committed.java" ).toContent ("class Committed {}" );
83+ addAndCommit (git , "Initial commit" );
84+
85+ // Create a new file that's not tracked at all (not in gitignore either)
86+ setFile ("new_untracked.java" ).toContent ("class NewUntracked {}" );
87+
88+ // The new untracked file should be considered dirty
89+ ratchetFrom ("main" ).onlyDirty ("new_untracked.java" );
90+ }
91+ }
92+
93+ @ Test
94+ void testModifiedTrackedFile_ShouldBeDirty () throws IllegalStateException , GitAPIException , IOException {
95+ try (Git git = initRepo ()) {
96+ // Create and commit initial file
97+ setFile ("Main.java" ).toContent ("class Main { void old() {} }" );
98+ addAndCommit (git , "Initial commit" );
99+
100+ // Modify the file
101+ setFile ("Main.java" ).toContent ("class Main { void newMethod() {} }" );
102+
103+ // The modified file should be considered dirty
104+ ratchetFrom ("main" ).onlyDirty ("Main.java" );
105+ }
106+ }
107+
60108 static class GitRatchetSimple extends GitRatchet <File > {
61109 @ Override
62110 protected File getDir (File project ) {
@@ -81,14 +129,20 @@ class Asserter {
81129 Asserter (String ... ratchetFrom ) {
82130 this .ratchetFroms = ratchetFrom ;
83131 this .shas = Arrays .stream (ratchetFrom )
84- .map (from -> ratchet .rootTreeShaOf (rootFolder (), from ))
85- .toArray (ObjectId []::new );
132+ .map (from -> ratchet .rootTreeShaOf (rootFolder (), from ))
133+ .toArray (ObjectId []::new );
86134 }
87135
88136 private void assertClean (int i , String filename , boolean expected ) throws IOException {
89- boolean actual = ratchet .isClean (rootFolder (), shas [i ], newFile (filename ));
137+ File file = new File (rootFolder (), filename );
138+ if (!file .exists ()) {
139+ throw new AssertionError ("File " + filename + " does not exist" );
140+ }
141+
142+ boolean actual = ratchet .isClean (rootFolder (), shas [i ], file );
90143 if (actual != expected ) {
91- throw new AssertionError ("Expected " + filename + " to be " + (expected ? "clean" : "dirty" ) + " relative to " + ratchetFroms [i ]);
144+ throw new AssertionError ("Expected " + filename + " to be " + (expected ? "clean" : "dirty" ) +
145+ " relative to " + ratchetFroms [i ] + " but was " + (actual ? "clean" : "dirty" ));
92146 }
93147 }
94148
@@ -98,24 +152,31 @@ public void allClean() throws IOException {
98152
99153 public void allDirty () throws IOException {
100154 String [] filenames = Arrays .stream (rootFolder ().listFiles ())
101- .filter (File ::isFile )
102- .map (File ::getName )
103- .toArray (String []::new );
155+ .filter (File ::isFile )
156+ .map (File ::getName )
157+ .toArray (String []::new );
104158 onlyDirty (filenames );
105159 }
106160
107161 public void onlyDirty (String ... filenames ) throws IOException {
108162 List <String > dirtyFiles = Arrays .asList (filenames );
109- for (File file : rootFolder (). listFiles ( )) {
110- if (! file .isFile ()) {
163+ for (File file : getAllFilesRecursive ( rootFolder ())) {
164+ if (file .isDirectory ()) {
111165 continue ;
112166 }
113- boolean expectedClean = !dirtyFiles .contains (file .getName ());
167+ String relativePath = rootFolder ().toPath ().relativize (file .toPath ()).toString ();
168+ boolean expectedClean = !dirtyFiles .contains (relativePath );
114169 for (int i = 0 ; i < shas .length ; i ++) {
115- assertClean (i , file . getName () , expectedClean );
170+ assertClean (i , relativePath , expectedClean );
116171 }
117172 }
118173 }
174+
175+ private List <File > getAllFilesRecursive (File dir ) {
176+ return Arrays .stream (dir .listFiles ())
177+ .flatMap (file -> file .isDirectory () ? getAllFilesRecursive (file ).stream () : Arrays .stream (new File []{file }))
178+ .toList ();
179+ }
119180 }
120181
121182 private Git initRepo () throws IllegalStateException , GitAPIException , IOException {
0 commit comments