const path = require('path'); const fs = require('fs-plus'); const temp = require('temp').track(); const { Directory } = require('pathwatcher'); const GitRepository = require('../src/git-repository'); const GitRepositoryProvider = require('../src/git-repository-provider'); describe('GitRepositoryProvider', () => { let provider; beforeEach(() => { provider = new GitRepositoryProvider( atom.project, atom.config, atom.confirm ); }); afterEach(() => { if (provider) { Object.keys(provider.pathToRepository).forEach(key => { provider.pathToRepository[key].destroy(); }); } }); describe('.repositoryForDirectory(directory)', () => { describe('when specified a Directory with a Git repository', () => { it('resolves with a GitRepository', async () => { const directory = new Directory( path.join(__dirname, 'fixtures', 'git', 'master.git') ); const result = await provider.repositoryForDirectory(directory); expect(result).toBeInstanceOf(GitRepository); expect(provider.pathToRepository[result.getPath()]).toBeTruthy(); expect(result.getType()).toBe('git'); // Refresh should be started await new Promise(resolve => result.onDidChangeStatuses(resolve)); }); it('resolves with the same GitRepository for different Directory objects in the same repo', async () => { const firstRepo = await provider.repositoryForDirectory( new Directory(path.join(__dirname, 'fixtures', 'git', 'master.git')) ); const secondRepo = await provider.repositoryForDirectory( new Directory( path.join(__dirname, 'fixtures', 'git', 'master.git', 'objects') ) ); expect(firstRepo).toBeInstanceOf(GitRepository); expect(firstRepo).toBe(secondRepo); }); }); describe('when specified a Directory without a Git repository', () => { it('resolves with null', async () => { const directory = new Directory(temp.mkdirSync('dir')); const repo = await provider.repositoryForDirectory(directory); expect(repo).toBe(null); }); }); describe('when specified a Directory with an invalid Git repository', () => { it('resolves with null', async () => { const dirPath = temp.mkdirSync('dir'); fs.writeFileSync(path.join(dirPath, '.git', 'objects'), ''); fs.writeFileSync(path.join(dirPath, '.git', 'HEAD'), ''); fs.writeFileSync(path.join(dirPath, '.git', 'refs'), ''); const directory = new Directory(dirPath); const repo = await provider.repositoryForDirectory(directory); expect(repo).toBe(null); }); }); describe('when specified a Directory with a valid gitfile-linked repository', () => { it('returns a Promise that resolves to a GitRepository', async () => { const gitDirPath = path.join( __dirname, 'fixtures', 'git', 'master.git' ); const workDirPath = temp.mkdirSync('git-workdir'); fs.writeFileSync( path.join(workDirPath, '.git'), `gitdir: ${gitDirPath}\n` ); const directory = new Directory(workDirPath); const result = await provider.repositoryForDirectory(directory); expect(result).toBeInstanceOf(GitRepository); expect(provider.pathToRepository[result.getPath()]).toBeTruthy(); expect(result.getType()).toBe('git'); }); }); describe('when specified a Directory with a commondir file for a worktree', () => { it('returns a Promise that resolves to a GitRepository', async () => { const directory = new Directory( path.join( __dirname, 'fixtures', 'git', 'master.git', 'worktrees', 'worktree-dir' ) ); const result = await provider.repositoryForDirectory(directory); expect(result).toBeInstanceOf(GitRepository); expect(provider.pathToRepository[result.getPath()]).toBeTruthy(); expect(result.getType()).toBe('git'); }); }); describe('when specified a Directory without exists()', () => { let directory; beforeEach(() => { // An implementation of Directory that does not implement existsSync(). const subdirectory = {}; directory = { getSubdirectory() {}, isRoot() { return true; } }; spyOn(directory, 'getSubdirectory').andReturn(subdirectory); }); it('returns a Promise that resolves to null', async () => { const repo = await provider.repositoryForDirectory(directory); expect(repo).toBe(null); expect(directory.getSubdirectory).toHaveBeenCalledWith('.git'); }); }); }); describe('.repositoryForDirectorySync(directory)', () => { describe('when specified a Directory with a Git repository', () => { it('resolves with a GitRepository', async () => { const directory = new Directory( path.join(__dirname, 'fixtures', 'git', 'master.git') ); const result = provider.repositoryForDirectorySync(directory); expect(result).toBeInstanceOf(GitRepository); expect(provider.pathToRepository[result.getPath()]).toBeTruthy(); expect(result.getType()).toBe('git'); // Refresh should be started await new Promise(resolve => result.onDidChangeStatuses(resolve)); }); it('resolves with the same GitRepository for different Directory objects in the same repo', () => { const firstRepo = provider.repositoryForDirectorySync( new Directory(path.join(__dirname, 'fixtures', 'git', 'master.git')) ); const secondRepo = provider.repositoryForDirectorySync( new Directory( path.join(__dirname, 'fixtures', 'git', 'master.git', 'objects') ) ); expect(firstRepo).toBeInstanceOf(GitRepository); expect(firstRepo).toBe(secondRepo); }); }); describe('when specified a Directory without a Git repository', () => { it('resolves with null', () => { const directory = new Directory(temp.mkdirSync('dir')); const repo = provider.repositoryForDirectorySync(directory); expect(repo).toBe(null); }); }); describe('when specified a Directory with an invalid Git repository', () => { it('resolves with null', () => { const dirPath = temp.mkdirSync('dir'); fs.writeFileSync(path.join(dirPath, '.git', 'objects'), ''); fs.writeFileSync(path.join(dirPath, '.git', 'HEAD'), ''); fs.writeFileSync(path.join(dirPath, '.git', 'refs'), ''); const directory = new Directory(dirPath); const repo = provider.repositoryForDirectorySync(directory); expect(repo).toBe(null); }); }); describe('when specified a Directory with a valid gitfile-linked repository', () => { it('returns a Promise that resolves to a GitRepository', () => { const gitDirPath = path.join( __dirname, 'fixtures', 'git', 'master.git' ); const workDirPath = temp.mkdirSync('git-workdir'); fs.writeFileSync( path.join(workDirPath, '.git'), `gitdir: ${gitDirPath}\n` ); const directory = new Directory(workDirPath); const result = provider.repositoryForDirectorySync(directory); expect(result).toBeInstanceOf(GitRepository); expect(provider.pathToRepository[result.getPath()]).toBeTruthy(); expect(result.getType()).toBe('git'); }); }); describe('when specified a Directory with a commondir file for a worktree', () => { it('returns a Promise that resolves to a GitRepository', () => { const directory = new Directory( path.join( __dirname, 'fixtures', 'git', 'master.git', 'worktrees', 'worktree-dir' ) ); const result = provider.repositoryForDirectorySync(directory); expect(result).toBeInstanceOf(GitRepository); expect(provider.pathToRepository[result.getPath()]).toBeTruthy(); expect(result.getType()).toBe('git'); }); }); describe('when specified a Directory without existsSync()', () => { let directory; beforeEach(() => { // An implementation of Directory that does not implement existsSync(). const subdirectory = {}; directory = { getSubdirectory() {}, isRoot() { return true; } }; spyOn(directory, 'getSubdirectory').andReturn(subdirectory); }); it('returns null', () => { const repo = provider.repositoryForDirectorySync(directory); expect(repo).toBe(null); expect(directory.getSubdirectory).toHaveBeenCalledWith('.git'); }); }); }); });