code: package usecases;
  
  import java.io.IOException;
  import java.util.ArrayList;
  import java.util.List;
  import javax.annotation.Nonnull;
  
  import com.beijunyi.parallelgit.filesystem.AbstractGitFileSystemTest;
  import com.beijunyi.parallelgit.filesystem.io.GfsTreeIterator;
  import com.beijunyi.parallelgit.utils.TreeUtils;
  import org.eclipse.jgit.treewalk.TreeWalk;
  import org.eclipse.jgit.treewalk.filter.PathFilter;
  import org.junit.Before;
  import org.junit.Test;
  
  import static org.eclipse.jgit.lib.FileMode.*;
  import static org.junit.Assert.*;
  
  public class GfsTreeWalkTest extends AbstractGitFileSystemTest {
  
    @Before
    public void setUp() throws IOException {
      initRepository();
    }
  
    @Test
    public void walkGfsWhenThereAreOnlyRootLevelFiles_theFilesShouldBeIteratedInAlphabeticalOrder() throws IOException {
      String[] files = {
        "/a.txt",
        "/b.txt"
      };
      initGitFileSystem(files);
      assertWalk(false, files);
    }
  
    @Test
    public void walkGfsWhenThereAreFilesInRootLevelDirectory_theDirectoryShouldBeInTheResult() throws IOException {
      String[] files = {
        "/dir/a.txt",
        "/dir/b.txt"
      };
      initGitFileSystem(files);
      assertWalk(false, "/dir");
    }
  
    @Test
    public void walkGfsRecursivelyWhenThereAreFilesInDirectories_allTheFilesShouldBeIteratedInAlphabeticalOrder() throws IOException {
      String[] files = {
        "/dir1/a.txt",
        "/dir1/b.txt",
        "/dir2/c.txt",
        "/some_other_file.txt"
      };
      initGitFileSystem(files);
      assertWalk(true, files);
    }
  
    @Test
    public void getFileModeFromFileNode_shouldEqualRegularFile() throws IOException {
      initGitFileSystem("/test_file.txt");
      TreeWalk tw = forPath("/test_file.txt");
      assertEquals(REGULAR_FILE, tw.getFileMode(0));
    }
  
    @Test
    public void getFileModeFromDirectoryNode_shouldEqualTree() throws IOException {
      initGitFileSystem("/dir/some_file.txt");
      TreeWalk tw = forPath("/dir");
      assertEquals(TREE, tw.getFileMode(0));
      assertTrue(TreeUtils.isDirectory(tw));
    }
  
    @Test
    public void getObjectIdFromFileNode_shouldReturnTheBlobIdOfTheFile() throws IOException {
      initRepository();
      byte[] data = someBytes();
      writeToCache("/test_file.txt", data);
      commitToMaster();
      initGitFileSystem();
  
      TreeWalk tw = forPath("/test_file.txt");
      assertEquals(calculateBlobId(data), TreeUtils.getObjectId(tw));
    }
  
  
    @Nonnull
    private TreeWalk prepareTreeWalk(boolean recursive) throws IOException {
      GfsTreeIterator iterator = GfsTreeIterator.iterateRoot(gfs);
      TreeWalk ret = new TreeWalk(repo);
      ret.setRecursive(recursive);
      ret.addTree(iterator);
      return ret;
    }
  
    private void assertWalk(boolean recursive, String... expected) throws IOException {
      try(TreeWalk tw = prepareTreeWalk(recursive)) {
        assertWalk(tw, expected);
      }
    }
  
    private void assertWalk(TreeWalk tw, String... expected) throws IOException {
      assertArrayEquals(expected, toArrayWithLeadingSlash(tw));
    }
  
    @Nonnull
    private String[] toArrayWithLeadingSlash(TreeWalk tw) throws IOException {
      List<String> list = new ArrayList<>();
      while(tw.next())
        list.add("/" + tw.getPathString());
      String[] ret = new String[list.size()];
      return list.toArray(ret);
    }
  
    @Nonnull
    private TreeWalk forPath(String path) throws IOException {
      TreeWalk tw = prepareTreeWalk(false);
      PathFilter filter = PathFilter.create(path.charAt(0) == '/' ? path.substring(1) : path);
      tw.setFilter(filter);
      tw.setRecursive(false);
      while(tw.next()) {
        if(filter.isDone(tw))
          return tw;
        if(tw.isSubtree())
          tw.enterSubtree();
      }
      throw new IllegalStateException();
    }
  
  }
  