package com.beijunyi.parallelgit.filesystem.io; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import javax.annotation.Nonnull; import com.beijunyi.parallelgit.filesystem.AbstractGitFileSystemTest; import com.beijunyi.parallelgit.filesystem.exceptions.GfsCheckoutConflictException; import com.beijunyi.parallelgit.filesystem.test.NioUtils; import com.beijunyi.parallelgit.utils.BlobUtils; import com.beijunyi.parallelgit.utils.CacheUtils; import org.eclipse.jgit.dircache.DirCache; import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.ObjectId; import org.junit.Test; import static java.nio.file.Files.createDirectories; import static org.eclipse.jgit.lib.FileMode.REGULAR_FILE; import static org.junit.Assert.*; /** * Scenarios: * * TABLE 1: * H -> HEAD; T -> TARGET; W -> WORKTREE * Y -> YES; N -> NO * CASE H==T T==W H==W RESULT * 1 N N N CHECK TYPE (GO TO TABLE 2) * 2 N N Y USE T * 3 N Y N USE W (NO CHANGE) * 4* N Y Y IMPOSSIBLE * 5 Y N N USE W (NO CHANGE) * 6* Y N Y IMPOSSIBLE * 7* Y Y N IMPOSSIBLE * 8 Y Y Y OK (NO CHANGE) * * TABLE 2: * F -> FILE && NON-EXISTENT; D -> DIRECTORY * CASE HEAD TARGET WORKTREE RESULT * 1-1 F F F CONFLICT * 1-2 F F D CONFLICT * 1-3 F D F CONFLICT * 1-4 F D D ENTER SUBTREE (GO TO TABLE 1) * 1-5 D F F CONFLICT * 1-6 D F D CONFLICT * 1-7 D D F CONFLICT * 1-8 D D D ENTER SUBTREE (GO TO TABLE 1) */ public class GfsDefaultCheckoutTreeTest extends AbstractGitFileSystemTest { @Test(expected = GfsCheckoutConflictException.class) public void case11_allTreesHaveDifferentFiles_shouldThrowGfsCheckoutConflictException() throws IOException { initGitFileSystem("/test_file.txt"); clearWorktreeAndWrite("/test_file.txt", someBytes()); AnyObjectId target = createTreeWithFile("/test_file.txt", someBytes()); new GfsDefaultCheckout(gfs).checkout(target); } @Test(expected = GfsCheckoutConflictException.class) public void case12_headHasFile_targetHasDirectory_worktreeHasFile_shouldThrowGfsCheckoutConflictException() throws IOException { initGitFileSystem("/test_target"); clearWorktreeAndWrite("/test_target/some_file.txt", someBytes()); AnyObjectId target = createTreeWithFile("/test_target", someBytes()); new GfsDefaultCheckout(gfs).checkout(target); } @Test(expected = GfsCheckoutConflictException.class) public void case13_headHasFile_targetHasFile_worktreeHasDirectory_shouldThrowGfsCheckoutConflictException() throws IOException { initGitFileSystem("/test_target"); clearWorktreeAndWrite("/test_target", someBytes()); AnyObjectId target = createTreeWithFile("/test_target/some_file.txt", someBytes()); new GfsDefaultCheckout(gfs).checkout(target); } @Test public void case14_targetAndWorktreeHaveNonConflictingDirectories_theFilesFromBothDirectoriesShouldBePresentAfterTheOperation() throws IOException { initGitFileSystem("/test_target"); clearWorktreeAndWrite("/test_target/some_file1.txt", someBytes()); AnyObjectId target = createTreeWithFile("/test_target/some_file2.txt", someBytes()); new GfsDefaultCheckout(gfs).checkout(target); assertTrue(Files.exists(gfs.getPath("/test_target/some_file1.txt"))); assertTrue(Files.exists(gfs.getPath("/test_target/some_file2.txt"))); } @Test(expected = GfsCheckoutConflictException.class) public void case15_headHasDirectory_targetAndWorktreeHaveDifferentFiles_shouldThrowGfsCheckoutConflictException() throws IOException { initGitFileSystem("/test_target/some_file.txt"); clearWorktreeAndWrite("/test_target", someBytes()); AnyObjectId target = createTreeWithFile("/test_target", someBytes()); new GfsDefaultCheckout(gfs).checkout(target); } @Test(expected = GfsCheckoutConflictException.class) public void case16_headHasDirectory_targetHasFile_worktreeHasDirectory_shouldThrowGfsCheckoutConflictException() throws IOException { initGitFileSystem("/test_target/some_file.txt"); clearWorktreeAndWrite("/test_target", someBytes()); AnyObjectId target = createTreeWithFile("/test_target/some_file.txt", someBytes()); new GfsDefaultCheckout(gfs).checkout(target); } @Test(expected = GfsCheckoutConflictException.class) public void case17_headHasDirectory_targetHasDirectory_worktreeHasFile_shouldThrowGfsCheckoutConflictException() throws IOException { initGitFileSystem("/test_target/some_file.txt"); clearWorktreeAndWrite("/test_target/some_file.txt", someBytes()); AnyObjectId target = createTreeWithFile("/test_target", someBytes()); new GfsDefaultCheckout(gfs).checkout(target); } @Test public void case18_allTreesHaveDifferentButNonConflictingDirectories_theFilesFromTargetAndDirectoryShouldBePresentAfterTheOperation() throws IOException { initGitFileSystem("/test_target/some_file1.txt"); clearWorktreeAndWrite("/test_target/some_file2.txt", someBytes()); AnyObjectId target = createTreeWithFile("/test_target/some_file3.txt", someBytes()); new GfsDefaultCheckout(gfs).checkout(target); assertFalse(Files.exists(gfs.getPath("/test_target/some_file1.txt"))); assertTrue(Files.exists(gfs.getPath("/test_target/some_file2.txt"))); assertTrue(Files.exists(gfs.getPath("/test_target/some_file3.txt"))); } @Test public void case2_headNotEqualTarget_headEqualWorktree_targetFileShouldBeUsed() throws IOException { initGitFileSystem("/test_file.txt"); byte[] expected = someBytes(); AnyObjectId target = createTreeWithFile("/test_file.txt", expected); new GfsDefaultCheckout(gfs).checkout(target); assertArrayEquals(expected, Files.readAllBytes(gfs.getPath("/test_file.txt"))); } @Test public void case3_headNotEqualTarget_targetEqualWorktree_worktreeFileShouldRemainTheSame() throws IOException { initGitFileSystem("/test_file.txt"); byte[] expected = someBytes(); clearWorktreeAndWrite("/test_file.txt", expected); AnyObjectId target = createTreeWithFile("/test_file.txt", expected); new GfsDefaultCheckout(gfs).checkout(target); assertArrayEquals(expected, Files.readAllBytes(gfs.getPath("/test_file.txt"))); } @Test public void case5_headEqualTarget_targetNotEqualWorktree_worktreeFileShouldRemainTheSame() throws IOException { initRepository(); byte[] someBytes = someBytes(); writeToCache("/test_file.txt", someBytes); commitToMaster(); initGitFileSystem(); byte[] expected = someBytes(); clearWorktreeAndWrite("/test_file.txt", expected); AnyObjectId target = createTreeWithFile("/test_file.txt", someBytes); new GfsDefaultCheckout(gfs).checkout(target); assertArrayEquals(expected, Files.readAllBytes(gfs.getPath("/test_file.txt"))); } @Test public void case8_allTreesEqual_worktreeFileShouldRemainTheSame() throws IOException { initRepository(); byte[] expected = someBytes(); writeToCache("/test_file.txt", expected); commitToMaster(); initGitFileSystem(); AnyObjectId target = createTreeWithFile("/test_file.txt", expected); new GfsDefaultCheckout(gfs).checkout(target); assertArrayEquals(expected, Files.readAllBytes(gfs.getPath("/test_file.txt"))); } private void clearWorktree() throws IOException { Files.walkFileTree(gfs.getRootPath(), NioUtils.RECURSIVE_DELETE); } private void clearWorktreeAndWrite(String path, byte[] bytes) throws IOException { clearWorktree(); Path file = gfs.getPath(path); Path parent = file.getParent(); if(parent != null) createDirectories(parent); Files.write(file, bytes); } @Nonnull private ObjectId createTreeWithFile(String path, byte[] bytes) throws IOException { DirCache cache = DirCache.newInCore(); CacheUtils.addFile(path, REGULAR_FILE, BlobUtils.insertBlob(bytes, repo), cache); return CacheUtils.writeTree(cache, repo); } }