code: package com.beijunyi.parallelgit.filesystem;
  
  import java.io.IOException;
  import java.nio.ByteBuffer;
  import java.nio.channels.SeekableByteChannel;
  import java.nio.file.*;
  import javax.annotation.Nonnull;
  
  import org.junit.After;
  import org.junit.Before;
  import org.junit.Test;
  
  import static java.lang.System.arraycopy;
  import static java.nio.file.Files.*;
  import static java.nio.file.StandardOpenOption.*;
  import static org.eclipse.jgit.lib.Constants.encodeASCII;
  import static org.junit.Assert.*;
  
  public class FilesNewByteChannelTest extends AbstractGitFileSystemTest {
  
    private static final byte[] TEST_DATA = someBytes();
  
    private SeekableByteChannel channel;
  
    @Before
    public void setUp() throws IOException {
      initRepository();
      writeToCache("/dir/file.txt", TEST_DATA);
      commitToMaster();
      initGitFileSystem();
    }
  
    @After
    public void tearDown() throws IOException {
      if(channel != null) {
        channel.close();
        channel = null;
      }
    }
  
    @Test
    public void createNewReadOnlyChannelFromExistingFile_resultChannelShouldAllowReadAccess() throws IOException {
      channel = newByteChannel(gfs.getPath("/dir/file.txt"), READ);
      assertArrayEquals(TEST_DATA, readChannel(channel));
    }
  
    @Test(expected = NoSuchFileException.class)
    public void createNewReadOnlyChannelFromNonExistentFile_shouldThrowNoSuchFileException() throws IOException {
      newByteChannel(gfs.getPath("/non_existent_file.txt"), READ);
    }
  
    @Test(expected = AccessDeniedException.class)
    public void createNewReadOnlyChannelFromDirectory_shouldThrowAccessDeniedException() throws IOException {
      newByteChannel(gfs.getPath("/dir"), READ);
    }
  
    @Test
    public void createNewWriteOnlyChannelFromExistingFile_resultChannelShouldAllowWriteAccess() throws IOException {
      channel = newByteChannel(gfs.getPath("/dir/file.txt"), WRITE);
      writeChannel(channel, someBytes());
    }
  
    @Test
    public void writeToWritableChannel_shouldOverwriteFileDataFromBeginning() throws IOException {
      channel = newByteChannel(gfs.getPath("/dir/file.txt"), WRITE);
      byte[] overwrite = encodeASCII("!!!");
      writeChannel(channel, overwrite);
      byte[] expected = new byte[TEST_DATA.length];
      arraycopy(TEST_DATA, 0, expected, 0, TEST_DATA.length);
      arraycopy(overwrite, 0, expected, 0, overwrite.length);
      assertArrayEquals(expected, readAllBytes(gfs.getPath("/dir/file.txt")));
    }
  
    @Test
    public void writeToWritableChannelWithTruncateExistingOption_shouldOverwriteEntireFileData() throws IOException {
      channel = newByteChannel(gfs.getPath("/dir/file.txt"), WRITE, TRUNCATE_EXISTING);
      byte[] overwrite = encodeASCII("!!!");
      writeChannel(channel, overwrite);
      channel.close();
      assertArrayEquals(overwrite, readAllBytes(gfs.getPath("/dir/file.txt")));
    }
  
    @Test
    public void writeToWritableChannelWithAppendOption_shouldAppendDataToTheEndOfTheFile() throws IOException {
      channel = newByteChannel(gfs.getPath("/dir/file.txt"), WRITE, APPEND);
      byte[] append = encodeASCII("!!!");
      writeChannel(channel, append);
      channel.close();
      byte[] expected = new byte[TEST_DATA.length + append.length];
      arraycopy(TEST_DATA, 0, expected, 0, TEST_DATA.length);
      arraycopy(append, 0, expected, TEST_DATA.length, append.length);
      assertArrayEquals(expected, readAllBytes(gfs.getPath("/dir/file.txt")));
    }
  
    @Test(expected = NoSuchFileException.class)
    public void createNewWriteOnlyChannelFromNonExistentFile_shouldThrowNoSuchFileException() throws IOException {
      newByteChannel(gfs.getPath("/non_existent_file.txt"), WRITE);
    }
  
    @Test(expected = AccessDeniedException.class)
    public void createNewWriteOnlyChannelFromDirectory_shouldThrowAccessDeniedException() throws IOException {
      newByteChannel(gfs.getPath("/dir"), WRITE);
    }
  
    @Test
    public void createReadWriteChannel_resultChannelShouldAllowReadWriteAccess() throws IOException {
      channel = newByteChannel(gfs.getPath("/dir/file.txt"), READ, WRITE);
      byte[] overwrite = encodeASCII("!!!");
      writeChannel(channel, overwrite);
      byte[] expected = new byte[TEST_DATA.length];
      arraycopy(TEST_DATA, 0, expected, 0, TEST_DATA.length);
      arraycopy(overwrite, 0, expected, 0, overwrite.length);
      channel.position(0);
      assertArrayEquals(expected, readChannel(channel));
    }
  
    @Test
    public void createChannelWithNoExplicitOption_resultChannelShouldAllowReadAccess() throws IOException {
      channel = newByteChannel(gfs.getPath("/dir/file.txt"));
      assertArrayEquals(TEST_DATA, readChannel(channel));
    }
  
    @Test
    public void createChannelWithReadOption_positionShouldBeTheEndOfTheFile() throws IOException {
      channel = newByteChannel(gfs.getPath("/dir/file.txt"), READ);
      assertEquals(0, channel.position());
    }
  
    @Test
    public void createChannelWithWriteOption_positionShouldBeTheEndOfTheFile() throws IOException {
      channel = newByteChannel(gfs.getPath("/dir/file.txt"), WRITE);
      assertEquals(0, channel.position());
    }
  
    @Test
    public void createChannelWithAppendOption_resultChannelShouldAllowWriteAccess() throws IOException {
      channel = newByteChannel(gfs.getPath("/dir/file.txt"), APPEND);
      writeChannel(channel, someBytes());
    }
  
    @Test
    public void createChannelWithAppendOption_positionShouldBeTheEndOfTheFile() throws IOException {
      channel = newByteChannel(gfs.getPath("/dir/file.txt"), APPEND);
      assertEquals(channel.size(), channel.position());
    }
  
    @Test
    public void createChannelWithTruncateExistingOption_sizeShouldBecomeZero() throws IOException {
      channel = newByteChannel(gfs.getPath("/dir/file.txt"), WRITE, TRUNCATE_EXISTING);
      assertEquals(0, channel.size());
    }
  
    @Test
    public void createChannelWithCreateOptionFromExistingFile_shouldReturnReadableChannel() throws IOException {
      channel = newByteChannel(gfs.getPath("/dir/file.txt"), CREATE);
      assertArrayEquals(TEST_DATA, readChannel(channel));
    }
  
    @Test
    public void createChannelWithCreateOptionFromNonExistentFile_shouldReturnEmptyReadableChannel() throws IOException {
      channel = newByteChannel(gfs.getPath("/non_existent_file.txt"), CREATE);
      assertArrayEquals(new byte[0], readChannel(channel));
    }
  
    @Test
    public void createChannelWithCreateOptionFromNonExistentFile_fileShouldBeCreated() throws IOException {
      Path newFile = gfs.getPath("/new_file.txt");
      channel = newByteChannel(newFile, CREATE);
      exists(newFile);
    }
  
    @Test(expected = FileAlreadyExistsException.class)
    public void createChannelWithCreateNewOptionFromExistingFile_shouldThrowFileAlreadyExistsException() throws IOException {
      newByteChannel(gfs.getPath("/dir/file.txt"), CREATE_NEW);
    }
  
    @Test
    public void createChannelWithCreateNewOptionFromNonExistentFile_shouldReturnEmptyReadableChannel() throws IOException {
      channel = newByteChannel(gfs.getPath("/non_existent_file.txt"), CREATE_NEW);
      assertArrayEquals(new byte[0], readChannel(channel));
    }
  
    @Test
    public void createChannelWithCreateNewOptionFromNonExistentFile_fileShouldBeCreated() throws IOException {
      Path newFile = gfs.getPath("/new_file.txt");
      channel = newByteChannel(newFile, CREATE_NEW);
      exists(newFile);
    }
  
    @Test(expected = UnsupportedOperationException.class)
    public void createChannelWitUnsupportedOption_shouldThrowUnsupportedOperationException() throws IOException {
      newByteChannel(gfs.getPath("/dir"), DELETE_ON_CLOSE);
    }
  
    @Nonnull
    private static byte[] readChannel(SeekableByteChannel channel) throws IOException {
      ByteBuffer buffer = ByteBuffer.allocate((int) channel.size());
      channel.read(buffer);
      return buffer.array();
    }
  
    private static void writeChannel(SeekableByteChannel channel, byte[] bytes) throws IOException {
      ByteBuffer buffer = ByteBuffer.wrap(bytes);
      channel.write(buffer);
    }
  
  }
  