From 275fb0eb3645a883b5af0781f0137617f6867d7a Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 6 Nov 2017 10:25:31 -0800 Subject: [PATCH 1/2] Convert GitRepository spec to JS --- spec/git-repository-spec.coffee | 371 --------------------------- spec/git-repository-spec.js | 433 ++++++++++++++++++++++++++++++++ 2 files changed, 433 insertions(+), 371 deletions(-) delete mode 100644 spec/git-repository-spec.coffee create mode 100644 spec/git-repository-spec.js diff --git a/spec/git-repository-spec.coffee b/spec/git-repository-spec.coffee deleted file mode 100644 index e4d1e0c7f..000000000 --- a/spec/git-repository-spec.coffee +++ /dev/null @@ -1,371 +0,0 @@ -temp = require('temp').track() -GitRepository = require '../src/git-repository' -fs = require 'fs-plus' -path = require 'path' -Project = require '../src/project' - -copyRepository = -> - workingDirPath = temp.mkdirSync('atom-spec-git') - fs.copySync(path.join(__dirname, 'fixtures', 'git', 'working-dir'), workingDirPath) - fs.renameSync(path.join(workingDirPath, 'git.git'), path.join(workingDirPath, '.git')) - workingDirPath - -describe "GitRepository", -> - repo = null - - beforeEach -> - gitPath = path.join(temp.dir, '.git') - fs.removeSync(gitPath) if fs.isDirectorySync(gitPath) - - afterEach -> - repo.destroy() if repo?.repo? - try - temp.cleanupSync() # These tests sometimes lag at shutting down resources - - describe "@open(path)", -> - it "returns null when no repository is found", -> - expect(GitRepository.open(path.join(temp.dir, 'nogit.txt'))).toBeNull() - - describe "new GitRepository(path)", -> - it "throws an exception when no repository is found", -> - expect(-> new GitRepository(path.join(temp.dir, 'nogit.txt'))).toThrow() - - describe ".getPath()", -> - it "returns the repository path for a .git directory path with a directory", -> - repo = new GitRepository(path.join(__dirname, 'fixtures', 'git', 'master.git', 'objects')) - expect(repo.getPath()).toBe path.join(__dirname, 'fixtures', 'git', 'master.git') - - it "returns the repository path for a repository path", -> - repo = new GitRepository(path.join(__dirname, 'fixtures', 'git', 'master.git')) - expect(repo.getPath()).toBe path.join(__dirname, 'fixtures', 'git', 'master.git') - - describe ".isPathIgnored(path)", -> - it "returns true for an ignored path", -> - repo = new GitRepository(path.join(__dirname, 'fixtures', 'git', 'ignore.git')) - expect(repo.isPathIgnored('a.txt')).toBeTruthy() - - it "returns false for a non-ignored path", -> - repo = new GitRepository(path.join(__dirname, 'fixtures', 'git', 'ignore.git')) - expect(repo.isPathIgnored('b.txt')).toBeFalsy() - - describe ".isPathModified(path)", -> - [repo, filePath, newPath] = [] - - beforeEach -> - workingDirPath = copyRepository() - repo = new GitRepository(workingDirPath) - filePath = path.join(workingDirPath, 'a.txt') - newPath = path.join(workingDirPath, 'new-path.txt') - - describe "when the path is unstaged", -> - it "returns false if the path has not been modified", -> - expect(repo.isPathModified(filePath)).toBeFalsy() - - it "returns true if the path is modified", -> - fs.writeFileSync(filePath, "change") - expect(repo.isPathModified(filePath)).toBeTruthy() - - it "returns true if the path is deleted", -> - fs.removeSync(filePath) - expect(repo.isPathModified(filePath)).toBeTruthy() - - it "returns false if the path is new", -> - expect(repo.isPathModified(newPath)).toBeFalsy() - - describe ".isPathNew(path)", -> - [filePath, newPath] = [] - - beforeEach -> - workingDirPath = copyRepository() - repo = new GitRepository(workingDirPath) - filePath = path.join(workingDirPath, 'a.txt') - newPath = path.join(workingDirPath, 'new-path.txt') - fs.writeFileSync(newPath, "i'm new here") - - describe "when the path is unstaged", -> - it "returns true if the path is new", -> - expect(repo.isPathNew(newPath)).toBeTruthy() - - it "returns false if the path isn't new", -> - expect(repo.isPathNew(filePath)).toBeFalsy() - - describe ".checkoutHead(path)", -> - [filePath] = [] - - beforeEach -> - workingDirPath = copyRepository() - repo = new GitRepository(workingDirPath) - filePath = path.join(workingDirPath, 'a.txt') - - it "no longer reports a path as modified after checkout", -> - expect(repo.isPathModified(filePath)).toBeFalsy() - fs.writeFileSync(filePath, 'ch ch changes') - expect(repo.isPathModified(filePath)).toBeTruthy() - expect(repo.checkoutHead(filePath)).toBeTruthy() - expect(repo.isPathModified(filePath)).toBeFalsy() - - it "restores the contents of the path to the original text", -> - fs.writeFileSync(filePath, 'ch ch changes') - expect(repo.checkoutHead(filePath)).toBeTruthy() - expect(fs.readFileSync(filePath, 'utf8')).toBe '' - - it "fires a status-changed event if the checkout completes successfully", -> - fs.writeFileSync(filePath, 'ch ch changes') - repo.getPathStatus(filePath) - statusHandler = jasmine.createSpy('statusHandler') - repo.onDidChangeStatus statusHandler - repo.checkoutHead(filePath) - expect(statusHandler.callCount).toBe 1 - expect(statusHandler.argsForCall[0][0]).toEqual {path: filePath, pathStatus: 0} - - repo.checkoutHead(filePath) - expect(statusHandler.callCount).toBe 1 - - describe ".checkoutHeadForEditor(editor)", -> - [filePath, editor] = [] - - beforeEach -> - spyOn(atom, "confirm") - - workingDirPath = copyRepository() - repo = new GitRepository(workingDirPath, {project: atom.project, config: atom.config, confirm: atom.confirm}) - filePath = path.join(workingDirPath, 'a.txt') - fs.writeFileSync(filePath, 'ch ch changes') - - waitsForPromise -> - atom.workspace.open(filePath) - - runs -> - editor = atom.workspace.getActiveTextEditor() - - it "displays a confirmation dialog by default", -> - return if process.platform is 'win32' # Permissions issues with this test on Windows - - atom.confirm.andCallFake ({buttons}) -> buttons.OK() - atom.config.set('editor.confirmCheckoutHeadRevision', true) - - repo.checkoutHeadForEditor(editor) - - expect(fs.readFileSync(filePath, 'utf8')).toBe '' - - it "does not display a dialog when confirmation is disabled", -> - return if process.platform is 'win32' # Flakey EPERM opening a.txt on Win32 - atom.config.set('editor.confirmCheckoutHeadRevision', false) - - repo.checkoutHeadForEditor(editor) - - expect(fs.readFileSync(filePath, 'utf8')).toBe '' - expect(atom.confirm).not.toHaveBeenCalled() - - describe ".destroy()", -> - it "throws an exception when any method is called after it is called", -> - repo = new GitRepository(path.join(__dirname, 'fixtures', 'git', 'master.git')) - repo.destroy() - expect(-> repo.getShortHead()).toThrow() - - describe ".getPathStatus(path)", -> - [filePath] = [] - - beforeEach -> - workingDirectory = copyRepository() - repo = new GitRepository(workingDirectory) - filePath = path.join(workingDirectory, 'file.txt') - - it "trigger a status-changed event when the new status differs from the last cached one", -> - statusHandler = jasmine.createSpy("statusHandler") - repo.onDidChangeStatus statusHandler - fs.writeFileSync(filePath, '') - status = repo.getPathStatus(filePath) - expect(statusHandler.callCount).toBe 1 - expect(statusHandler.argsForCall[0][0]).toEqual {path: filePath, pathStatus: status} - - fs.writeFileSync(filePath, 'abc') - status = repo.getPathStatus(filePath) - expect(statusHandler.callCount).toBe 1 - - describe ".getDirectoryStatus(path)", -> - [directoryPath, filePath] = [] - - beforeEach -> - workingDirectory = copyRepository() - repo = new GitRepository(workingDirectory) - directoryPath = path.join(workingDirectory, 'dir') - filePath = path.join(directoryPath, 'b.txt') - - it "gets the status based on the files inside the directory", -> - expect(repo.isStatusModified(repo.getDirectoryStatus(directoryPath))).toBe false - fs.writeFileSync(filePath, 'abc') - repo.getPathStatus(filePath) - expect(repo.isStatusModified(repo.getDirectoryStatus(directoryPath))).toBe true - - describe ".refreshStatus()", -> - [newPath, modifiedPath, cleanPath, workingDirectory] = [] - - beforeEach -> - workingDirectory = copyRepository() - repo = new GitRepository(workingDirectory, {project: atom.project, config: atom.config}) - modifiedPath = path.join(workingDirectory, 'file.txt') - newPath = path.join(workingDirectory, 'untracked.txt') - cleanPath = path.join(workingDirectory, 'other.txt') - fs.writeFileSync(cleanPath, 'Full of text') - fs.writeFileSync(newPath, '') - newPath = fs.absolute newPath # specs could be running under symbol path. - - it "returns status information for all new and modified files", -> - fs.writeFileSync(modifiedPath, 'making this path modified') - statusHandler = jasmine.createSpy('statusHandler') - repo.onDidChangeStatuses statusHandler - repo.refreshStatus() - - waitsFor -> - statusHandler.callCount > 0 - - runs -> - expect(repo.getCachedPathStatus(cleanPath)).toBeUndefined() - expect(repo.isStatusNew(repo.getCachedPathStatus(newPath))).toBeTruthy() - expect(repo.isStatusModified(repo.getCachedPathStatus(modifiedPath))).toBeTruthy() - - it 'caches the proper statuses when a subdir is open', -> - subDir = path.join(workingDirectory, 'dir') - fs.mkdirSync(subDir) - - filePath = path.join(subDir, 'b.txt') - fs.writeFileSync(filePath, '') - - atom.project.setPaths([subDir]) - - waitsForPromise -> - atom.workspace.open('b.txt') - - statusHandler = null - runs -> - repo = atom.project.getRepositories()[0] - - statusHandler = jasmine.createSpy('statusHandler') - repo.onDidChangeStatuses statusHandler - repo.refreshStatus() - - waitsFor -> - statusHandler.callCount > 0 - - runs -> - status = repo.getCachedPathStatus(filePath) - expect(repo.isStatusModified(status)).toBe false - expect(repo.isStatusNew(status)).toBe false - - it "works correctly when the project has multiple folders (regression)", -> - atom.project.addPath(workingDirectory) - atom.project.addPath(path.join(__dirname, 'fixtures', 'dir')) - statusHandler = jasmine.createSpy('statusHandler') - repo.onDidChangeStatuses statusHandler - - repo.refreshStatus() - - waitsFor -> - statusHandler.callCount > 0 - - runs -> - expect(repo.getCachedPathStatus(cleanPath)).toBeUndefined() - expect(repo.isStatusNew(repo.getCachedPathStatus(newPath))).toBeTruthy() - expect(repo.isStatusModified(repo.getCachedPathStatus(modifiedPath))).toBeTruthy() - - it 'caches statuses that were looked up synchronously', -> - originalContent = 'undefined' - fs.writeFileSync(modifiedPath, 'making this path modified') - repo.getPathStatus('file.txt') - - fs.writeFileSync(modifiedPath, originalContent) - waitsForPromise -> repo.refreshStatus() - runs -> - expect(repo.isStatusModified(repo.getCachedPathStatus(modifiedPath))).toBeFalsy() - - describe "buffer events", -> - [editor] = [] - - beforeEach -> - statusRefreshed = false - atom.project.setPaths([copyRepository()]) - atom.project.getRepositories()[0].onDidChangeStatuses -> statusRefreshed = true - - waitsForPromise -> - atom.workspace.open('other.txt').then (o) -> editor = o - - waitsFor 'repo to refresh', -> statusRefreshed - - it "emits a status-changed event when a buffer is saved", -> - editor.insertNewline() - - statusHandler = jasmine.createSpy('statusHandler') - atom.project.getRepositories()[0].onDidChangeStatus statusHandler - - waitsForPromise -> - editor.save() - - runs -> - expect(statusHandler.callCount).toBe 1 - expect(statusHandler).toHaveBeenCalledWith {path: editor.getPath(), pathStatus: 256} - - it "emits a status-changed event when a buffer is reloaded", -> - fs.writeFileSync(editor.getPath(), 'changed') - - statusHandler = jasmine.createSpy('statusHandler') - atom.project.getRepositories()[0].onDidChangeStatus statusHandler - - waitsForPromise -> - editor.getBuffer().reload() - - runs -> - expect(statusHandler.callCount).toBe 1 - expect(statusHandler).toHaveBeenCalledWith {path: editor.getPath(), pathStatus: 256} - - waitsForPromise -> - editor.getBuffer().reload() - - runs -> - expect(statusHandler.callCount).toBe 1 - - it "emits a status-changed event when a buffer's path changes", -> - fs.writeFileSync(editor.getPath(), 'changed') - - statusHandler = jasmine.createSpy('statusHandler') - atom.project.getRepositories()[0].onDidChangeStatus statusHandler - editor.getBuffer().emitter.emit 'did-change-path' - expect(statusHandler.callCount).toBe 1 - expect(statusHandler).toHaveBeenCalledWith {path: editor.getPath(), pathStatus: 256} - editor.getBuffer().emitter.emit 'did-change-path' - expect(statusHandler.callCount).toBe 1 - - it "stops listening to the buffer when the repository is destroyed (regression)", -> - atom.project.getRepositories()[0].destroy() - expect(-> editor.save()).not.toThrow() - - describe "when a project is deserialized", -> - [buffer, project2, statusHandler] = [] - - afterEach -> - project2?.destroy() - - it "subscribes to all the serialized buffers in the project", -> - atom.project.setPaths([copyRepository()]) - - waitsForPromise -> - atom.workspace.open('file.txt') - - waitsForPromise -> - project2 = new Project({notificationManager: atom.notifications, packageManager: atom.packages, confirm: atom.confirm, applicationDelegate: atom.applicationDelegate}) - project2.deserialize(atom.project.serialize({isUnloading: false})) - - waitsFor -> - buffer = project2.getBuffers()[0] - - waitsForPromise -> - originalContent = buffer.getText() - buffer.append('changes') - - statusHandler = jasmine.createSpy('statusHandler') - project2.getRepositories()[0].onDidChangeStatus statusHandler - buffer.save() - - runs -> - expect(statusHandler.callCount).toBe 1 - expect(statusHandler).toHaveBeenCalledWith {path: buffer.getPath(), pathStatus: 256} diff --git a/spec/git-repository-spec.js b/spec/git-repository-spec.js new file mode 100644 index 000000000..1dfad182d --- /dev/null +++ b/spec/git-repository-spec.js @@ -0,0 +1,433 @@ +const path = require('path') +const fs = require('fs-plus') +const temp = require('temp').track() +const GitRepository = require('../src/git-repository') +const Project = require('../src/project') + +describe('GitRepository', () => { + let repo + + beforeEach(() => { + const gitPath = path.join(temp.dir, '.git') + if (fs.isDirectorySync(gitPath)) fs.removeSync(gitPath) + }) + + afterEach(() => { + if (repo && !repo.isDestroyed()) repo.destroy() + + // These tests sometimes lag at shutting down resources + try { + temp.cleanupSync() + } catch (error) {} + }) + + describe('@open(path)', () => { + it('returns null when no repository is found', () => { + expect(GitRepository.open(path.join(temp.dir, 'nogit.txt'))).toBeNull() + }) + }) + + describe('new GitRepository(path)', () => { + it('throws an exception when no repository is found', () => { + expect(() => new GitRepository(path.join(temp.dir, 'nogit.txt'))).toThrow() + }) + }) + + describe('.getPath()', () => { + it('returns the repository path for a .git directory path with a directory', () => { + repo = new GitRepository(path.join(__dirname, 'fixtures', 'git', 'master.git', 'objects')) + expect(repo.getPath()).toBe(path.join(__dirname, 'fixtures', 'git', 'master.git')) + }) + + it('returns the repository path for a repository path', () => { + repo = new GitRepository(path.join(__dirname, 'fixtures', 'git', 'master.git')) + expect(repo.getPath()).toBe(path.join(__dirname, 'fixtures', 'git', 'master.git')) + }) + }) + + describe('.isPathIgnored(path)', () => { + it('returns true for an ignored path', () => { + repo = new GitRepository(path.join(__dirname, 'fixtures', 'git', 'ignore.git')) + expect(repo.isPathIgnored('a.txt')).toBeTruthy() + }) + + it('returns false for a non-ignored path', () => { + repo = new GitRepository(path.join(__dirname, 'fixtures', 'git', 'ignore.git')) + expect(repo.isPathIgnored('b.txt')).toBeFalsy() + }) + }) + + describe('.isPathModified(path)', () => { + let filePath, newPath + + beforeEach(() => { + const workingDirPath = copyRepository() + repo = new GitRepository(workingDirPath) + filePath = path.join(workingDirPath, 'a.txt') + newPath = path.join(workingDirPath, 'new-path.txt') + }) + + describe('when the path is unstaged', () => { + it('returns false if the path has not been modified', () => { + expect(repo.isPathModified(filePath)).toBeFalsy() + }) + + it('returns true if the path is modified', () => { + fs.writeFileSync(filePath, 'change') + expect(repo.isPathModified(filePath)).toBeTruthy() + }) + + it('returns true if the path is deleted', () => { + fs.removeSync(filePath) + expect(repo.isPathModified(filePath)).toBeTruthy() + }) + + it('returns false if the path is new', () => { + expect(repo.isPathModified(newPath)).toBeFalsy() + }) + }) + }) + + describe('.isPathNew(path)', () => { + let filePath, newPath + + beforeEach(() => { + const workingDirPath = copyRepository() + repo = new GitRepository(workingDirPath) + filePath = path.join(workingDirPath, 'a.txt') + newPath = path.join(workingDirPath, 'new-path.txt') + fs.writeFileSync(newPath, "i'm new here") + }) + + describe('when the path is unstaged', () => { + it('returns true if the path is new', () => { + expect(repo.isPathNew(newPath)).toBeTruthy() + }) + + it("returns false if the path isn't new", () => { + expect(repo.isPathNew(filePath)).toBeFalsy() + }) + }) + }) + + describe('.checkoutHead(path)', () => { + let filePath + + beforeEach(() => { + const workingDirPath = copyRepository() + repo = new GitRepository(workingDirPath) + filePath = path.join(workingDirPath, 'a.txt') + }) + + it('no longer reports a path as modified after checkout', () => { + expect(repo.isPathModified(filePath)).toBeFalsy() + fs.writeFileSync(filePath, 'ch ch changes') + expect(repo.isPathModified(filePath)).toBeTruthy() + expect(repo.checkoutHead(filePath)).toBeTruthy() + expect(repo.isPathModified(filePath)).toBeFalsy() + }) + + it('restores the contents of the path to the original text', () => { + fs.writeFileSync(filePath, 'ch ch changes') + expect(repo.checkoutHead(filePath)).toBeTruthy() + expect(fs.readFileSync(filePath, 'utf8')).toBe('') + }) + + it('fires a status-changed event if the checkout completes successfully', () => { + fs.writeFileSync(filePath, 'ch ch changes') + repo.getPathStatus(filePath) + const statusHandler = jasmine.createSpy('statusHandler') + repo.onDidChangeStatus(statusHandler) + repo.checkoutHead(filePath) + expect(statusHandler.callCount).toBe(1) + expect(statusHandler.argsForCall[0][0]).toEqual({path: filePath, pathStatus: 0}) + + repo.checkoutHead(filePath) + expect(statusHandler.callCount).toBe(1) + }) + }) + + describe('.checkoutHeadForEditor(editor)', () => { + let filePath, editor + + beforeEach(() => { + spyOn(atom, 'confirm') + + const workingDirPath = copyRepository() + repo = new GitRepository(workingDirPath, {project: atom.project, config: atom.config, confirm: atom.confirm}) + filePath = path.join(workingDirPath, 'a.txt') + fs.writeFileSync(filePath, 'ch ch changes') + + waitsForPromise(() => atom.workspace.open(filePath)) + + runs(() => editor = atom.workspace.getActiveTextEditor()) + }) + + it('displays a confirmation dialog by default', () => { + // Permissions issues with this test on Windows + if (process.platform === 'win32') return + + atom.confirm.andCallFake(({buttons}) => buttons.OK()) + atom.config.set('editor.confirmCheckoutHeadRevision', true) + + repo.checkoutHeadForEditor(editor) + + expect(fs.readFileSync(filePath, 'utf8')).toBe('') + }) + + it('does not display a dialog when confirmation is disabled', () => { + // Flakey EPERM opening a.txt on Win32 + if (process.platform === 'win32') return + atom.config.set('editor.confirmCheckoutHeadRevision', false) + + repo.checkoutHeadForEditor(editor) + + expect(fs.readFileSync(filePath, 'utf8')).toBe('') + expect(atom.confirm).not.toHaveBeenCalled() + }) + }) + + describe('.destroy()', () => { + it('throws an exception when any method is called after it is called', () => { + repo = new GitRepository(path.join(__dirname, 'fixtures', 'git', 'master.git')) + repo.destroy() + expect(() => repo.getShortHead()).toThrow() + }) + }) + + describe('.getPathStatus(path)', () => { + let filePath + + beforeEach(() => { + const workingDirectory = copyRepository() + repo = new GitRepository(workingDirectory) + filePath = path.join(workingDirectory, 'file.txt') + }) + + it('trigger a status-changed event when the new status differs from the last cached one', () => { + const statusHandler = jasmine.createSpy('statusHandler') + repo.onDidChangeStatus(statusHandler) + fs.writeFileSync(filePath, '') + let status = repo.getPathStatus(filePath) + expect(statusHandler.callCount).toBe(1) + expect(statusHandler.argsForCall[0][0]).toEqual({path: filePath, pathStatus: status}) + + fs.writeFileSync(filePath, 'abc') + status = repo.getPathStatus(filePath) + expect(statusHandler.callCount).toBe(1) + }) + }) + + describe('.getDirectoryStatus(path)', () => { + let directoryPath, filePath + + beforeEach(() => { + const workingDirectory = copyRepository() + repo = new GitRepository(workingDirectory) + directoryPath = path.join(workingDirectory, 'dir') + filePath = path.join(directoryPath, 'b.txt') + }) + + it('gets the status based on the files inside the directory', () => { + expect(repo.isStatusModified(repo.getDirectoryStatus(directoryPath))).toBe(false) + fs.writeFileSync(filePath, 'abc') + repo.getPathStatus(filePath) + expect(repo.isStatusModified(repo.getDirectoryStatus(directoryPath))).toBe(true) + }) + }) + + describe('.refreshStatus()', () => { + let newPath, modifiedPath, cleanPath, workingDirectory + + beforeEach(() => { + workingDirectory = copyRepository() + repo = new GitRepository(workingDirectory, {project: atom.project, config: atom.config}) + modifiedPath = path.join(workingDirectory, 'file.txt') + newPath = path.join(workingDirectory, 'untracked.txt') + cleanPath = path.join(workingDirectory, 'other.txt') + fs.writeFileSync(cleanPath, 'Full of text') + fs.writeFileSync(newPath, '') + newPath = fs.absolute(newPath) + }) // specs could be running under symbol path. + + it('returns status information for all new and modified files', () => { + fs.writeFileSync(modifiedPath, 'making this path modified') + const statusHandler = jasmine.createSpy('statusHandler') + repo.onDidChangeStatuses(statusHandler) + repo.refreshStatus() + + waitsFor(() => statusHandler.callCount > 0) + + runs(() => { + expect(repo.getCachedPathStatus(cleanPath)).toBeUndefined() + expect(repo.isStatusNew(repo.getCachedPathStatus(newPath))).toBeTruthy() + expect(repo.isStatusModified(repo.getCachedPathStatus(modifiedPath))).toBeTruthy() + }) + }) + + it('caches the proper statuses when a subdir is open', () => { + const subDir = path.join(workingDirectory, 'dir') + fs.mkdirSync(subDir) + + const filePath = path.join(subDir, 'b.txt') + fs.writeFileSync(filePath, '') + + atom.project.setPaths([subDir]) + + waitsForPromise(() => atom.workspace.open('b.txt')) + + let statusHandler = null + runs(() => { + repo = atom.project.getRepositories()[0] + + statusHandler = jasmine.createSpy('statusHandler') + repo.onDidChangeStatuses(statusHandler) + repo.refreshStatus() + }) + + waitsFor(() => statusHandler.callCount > 0) + + runs(() => { + const status = repo.getCachedPathStatus(filePath) + expect(repo.isStatusModified(status)).toBe(false) + expect(repo.isStatusNew(status)).toBe(false) + }) + }) + + it('works correctly when the project has multiple folders (regression)', () => { + atom.project.addPath(workingDirectory) + atom.project.addPath(path.join(__dirname, 'fixtures', 'dir')) + const statusHandler = jasmine.createSpy('statusHandler') + repo.onDidChangeStatuses(statusHandler) + + repo.refreshStatus() + + waitsFor(() => statusHandler.callCount > 0) + + runs(() => { + expect(repo.getCachedPathStatus(cleanPath)).toBeUndefined() + expect(repo.isStatusNew(repo.getCachedPathStatus(newPath))).toBeTruthy() + expect(repo.isStatusModified(repo.getCachedPathStatus(modifiedPath))).toBeTruthy() + }) + }) + + it('caches statuses that were looked up synchronously', () => { + const originalContent = 'undefined' + fs.writeFileSync(modifiedPath, 'making this path modified') + repo.getPathStatus('file.txt') + + fs.writeFileSync(modifiedPath, originalContent) + waitsForPromise(() => repo.refreshStatus()) + runs(() => { + expect(repo.isStatusModified(repo.getCachedPathStatus(modifiedPath))).toBeFalsy() + }) + }) + }) + + describe('buffer events', () => { + let editor + + beforeEach(() => { + let statusRefreshed = false + atom.project.setPaths([copyRepository()]) + atom.project.getRepositories()[0].onDidChangeStatuses(() => statusRefreshed = true) + + waitsForPromise(() => atom.workspace.open('other.txt').then(o => editor = o)) + + waitsFor('repo to refresh', () => statusRefreshed) + }) + + it('emits a status-changed event when a buffer is saved', () => { + editor.insertNewline() + + const statusHandler = jasmine.createSpy('statusHandler') + atom.project.getRepositories()[0].onDidChangeStatus(statusHandler) + + waitsForPromise(() => editor.save()) + + runs(() => { + expect(statusHandler.callCount).toBe(1) + expect(statusHandler).toHaveBeenCalledWith({path: editor.getPath(), pathStatus: 256}) + }) + }) + + it('emits a status-changed event when a buffer is reloaded', () => { + fs.writeFileSync(editor.getPath(), 'changed') + + const statusHandler = jasmine.createSpy('statusHandler') + atom.project.getRepositories()[0].onDidChangeStatus(statusHandler) + + waitsForPromise(() => editor.getBuffer().reload()) + + runs(() => { + expect(statusHandler.callCount).toBe(1) + expect(statusHandler).toHaveBeenCalledWith({path: editor.getPath(), pathStatus: 256}) + }) + + waitsForPromise(() => editor.getBuffer().reload()) + + runs(() => { + expect(statusHandler.callCount).toBe(1) + }) + }) + + it("emits a status-changed event when a buffer's path changes", () => { + fs.writeFileSync(editor.getPath(), 'changed') + + const statusHandler = jasmine.createSpy('statusHandler') + atom.project.getRepositories()[0].onDidChangeStatus(statusHandler) + editor.getBuffer().emitter.emit('did-change-path') + expect(statusHandler.callCount).toBe(1) + expect(statusHandler).toHaveBeenCalledWith({path: editor.getPath(), pathStatus: 256}) + editor.getBuffer().emitter.emit('did-change-path') + expect(statusHandler.callCount).toBe(1) + }) + + it('stops listening to the buffer when the repository is destroyed (regression)', () => { + atom.project.getRepositories()[0].destroy() + expect(() => editor.save()).not.toThrow() + }) + }) + + describe('when a project is deserialized', () => { + let buffer, project2, statusHandler + + afterEach(() => { + if (project2) project2.destroy() + }) + + it('subscribes to all the serialized buffers in the project', () => { + atom.project.setPaths([copyRepository()]) + + waitsForPromise(() => atom.workspace.open('file.txt')) + + waitsForPromise(() => { + project2 = new Project({notificationManager: atom.notifications, packageManager: atom.packages, confirm: atom.confirm, applicationDelegate: atom.applicationDelegate}) + return project2.deserialize(atom.project.serialize({isUnloading: false})) + }) + + waitsFor(() => buffer = project2.getBuffers()[0]) + + waitsForPromise(() => { + const originalContent = buffer.getText() + buffer.append('changes') + + statusHandler = jasmine.createSpy('statusHandler') + project2.getRepositories()[0].onDidChangeStatus(statusHandler) + return buffer.save() + }) + + runs(() => { + expect(statusHandler.callCount).toBe(1) + expect(statusHandler).toHaveBeenCalledWith({path: buffer.getPath(), pathStatus: 256}) + }) + }) + }) +}) + +function copyRepository () { + const workingDirPath = temp.mkdirSync('atom-spec-git') + fs.copySync(path.join(__dirname, 'fixtures', 'git', 'working-dir'), workingDirPath) + fs.renameSync(path.join(workingDirPath, 'git.git'), path.join(workingDirPath, '.git')) + return workingDirPath +} From 6e0b629389610120ae817cd79e6bd4f511889a1a Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 6 Nov 2017 10:57:46 -0800 Subject: [PATCH 2/2] Use async and await in git-repository-spec --- spec/git-repository-spec.js | 160 ++++++++++++++---------------------- 1 file changed, 60 insertions(+), 100 deletions(-) diff --git a/spec/git-repository-spec.js b/spec/git-repository-spec.js index 1dfad182d..e03a9788a 100644 --- a/spec/git-repository-spec.js +++ b/spec/git-repository-spec.js @@ -1,3 +1,4 @@ +const {it, fit, ffit, fffit, beforeEach, afterEach} = require('./async-spec-helpers') const path = require('path') const fs = require('fs-plus') const temp = require('temp').track() @@ -150,7 +151,7 @@ describe('GitRepository', () => { describe('.checkoutHeadForEditor(editor)', () => { let filePath, editor - beforeEach(() => { + beforeEach(async () => { spyOn(atom, 'confirm') const workingDirPath = copyRepository() @@ -158,9 +159,7 @@ describe('GitRepository', () => { filePath = path.join(workingDirPath, 'a.txt') fs.writeFileSync(filePath, 'ch ch changes') - waitsForPromise(() => atom.workspace.open(filePath)) - - runs(() => editor = atom.workspace.getActiveTextEditor()) + editor = await atom.workspace.open(filePath) }) it('displays a confirmation dialog by default', () => { @@ -248,127 +247,89 @@ describe('GitRepository', () => { fs.writeFileSync(cleanPath, 'Full of text') fs.writeFileSync(newPath, '') newPath = fs.absolute(newPath) - }) // specs could be running under symbol path. - - it('returns status information for all new and modified files', () => { - fs.writeFileSync(modifiedPath, 'making this path modified') - const statusHandler = jasmine.createSpy('statusHandler') - repo.onDidChangeStatuses(statusHandler) - repo.refreshStatus() - - waitsFor(() => statusHandler.callCount > 0) - - runs(() => { - expect(repo.getCachedPathStatus(cleanPath)).toBeUndefined() - expect(repo.isStatusNew(repo.getCachedPathStatus(newPath))).toBeTruthy() - expect(repo.isStatusModified(repo.getCachedPathStatus(modifiedPath))).toBeTruthy() - }) }) - it('caches the proper statuses when a subdir is open', () => { + it('returns status information for all new and modified files', async () => { + const statusHandler = jasmine.createSpy('statusHandler') + repo.onDidChangeStatuses(statusHandler) + fs.writeFileSync(modifiedPath, 'making this path modified') + + await repo.refreshStatus() + expect(statusHandler.callCount).toBe(1) + expect(repo.getCachedPathStatus(cleanPath)).toBeUndefined() + expect(repo.isStatusNew(repo.getCachedPathStatus(newPath) )).toBeTruthy() + expect(repo.isStatusModified(repo.getCachedPathStatus(modifiedPath))).toBeTruthy() + }) + + it('caches the proper statuses when a subdir is open', async () => { const subDir = path.join(workingDirectory, 'dir') fs.mkdirSync(subDir) - const filePath = path.join(subDir, 'b.txt') fs.writeFileSync(filePath, '') - atom.project.setPaths([subDir]) + await atom.workspace.open('b.txt') + repo = atom.project.getRepositories()[0] - waitsForPromise(() => atom.workspace.open('b.txt')) - - let statusHandler = null - runs(() => { - repo = atom.project.getRepositories()[0] - - statusHandler = jasmine.createSpy('statusHandler') - repo.onDidChangeStatuses(statusHandler) - repo.refreshStatus() - }) - - waitsFor(() => statusHandler.callCount > 0) - - runs(() => { - const status = repo.getCachedPathStatus(filePath) - expect(repo.isStatusModified(status)).toBe(false) - expect(repo.isStatusNew(status)).toBe(false) - }) + await repo.refreshStatus() + const status = repo.getCachedPathStatus(filePath) + expect(repo.isStatusModified(status)).toBe(false) + expect(repo.isStatusNew(status)).toBe(false) }) - it('works correctly when the project has multiple folders (regression)', () => { + it('works correctly when the project has multiple folders (regression)', async () => { atom.project.addPath(workingDirectory) atom.project.addPath(path.join(__dirname, 'fixtures', 'dir')) - const statusHandler = jasmine.createSpy('statusHandler') - repo.onDidChangeStatuses(statusHandler) - repo.refreshStatus() - - waitsFor(() => statusHandler.callCount > 0) - - runs(() => { - expect(repo.getCachedPathStatus(cleanPath)).toBeUndefined() - expect(repo.isStatusNew(repo.getCachedPathStatus(newPath))).toBeTruthy() - expect(repo.isStatusModified(repo.getCachedPathStatus(modifiedPath))).toBeTruthy() - }) + await repo.refreshStatus() + expect(repo.getCachedPathStatus(cleanPath)).toBeUndefined() + expect(repo.isStatusNew(repo.getCachedPathStatus(newPath))).toBeTruthy() + expect(repo.isStatusModified(repo.getCachedPathStatus(modifiedPath))).toBeTruthy() }) - it('caches statuses that were looked up synchronously', () => { + it('caches statuses that were looked up synchronously', async () => { const originalContent = 'undefined' fs.writeFileSync(modifiedPath, 'making this path modified') repo.getPathStatus('file.txt') fs.writeFileSync(modifiedPath, originalContent) - waitsForPromise(() => repo.refreshStatus()) - runs(() => { - expect(repo.isStatusModified(repo.getCachedPathStatus(modifiedPath))).toBeFalsy() - }) + await repo.refreshStatus() + expect(repo.isStatusModified(repo.getCachedPathStatus(modifiedPath))).toBeFalsy() }) }) describe('buffer events', () => { let editor - beforeEach(() => { - let statusRefreshed = false + beforeEach(async () => { atom.project.setPaths([copyRepository()]) - atom.project.getRepositories()[0].onDidChangeStatuses(() => statusRefreshed = true) - - waitsForPromise(() => atom.workspace.open('other.txt').then(o => editor = o)) - - waitsFor('repo to refresh', () => statusRefreshed) + const refreshPromise = new Promise(resolve => atom.project.getRepositories()[0].onDidChangeStatuses(resolve)) + editor = await atom.workspace.open('other.txt') + await refreshPromise }) - it('emits a status-changed event when a buffer is saved', () => { + it('emits a status-changed event when a buffer is saved', async () => { editor.insertNewline() const statusHandler = jasmine.createSpy('statusHandler') atom.project.getRepositories()[0].onDidChangeStatus(statusHandler) - waitsForPromise(() => editor.save()) - - runs(() => { - expect(statusHandler.callCount).toBe(1) - expect(statusHandler).toHaveBeenCalledWith({path: editor.getPath(), pathStatus: 256}) - }) + await editor.save() + expect(statusHandler.callCount).toBe(1) + expect(statusHandler).toHaveBeenCalledWith({path: editor.getPath(), pathStatus: 256}) }) - it('emits a status-changed event when a buffer is reloaded', () => { + it('emits a status-changed event when a buffer is reloaded', async () => { fs.writeFileSync(editor.getPath(), 'changed') const statusHandler = jasmine.createSpy('statusHandler') atom.project.getRepositories()[0].onDidChangeStatus(statusHandler) - waitsForPromise(() => editor.getBuffer().reload()) + await editor.getBuffer().reload() + expect(statusHandler.callCount).toBe(1) + expect(statusHandler).toHaveBeenCalledWith({path: editor.getPath(), pathStatus: 256}) - runs(() => { - expect(statusHandler.callCount).toBe(1) - expect(statusHandler).toHaveBeenCalledWith({path: editor.getPath(), pathStatus: 256}) - }) - - waitsForPromise(() => editor.getBuffer().reload()) - - runs(() => { - expect(statusHandler.callCount).toBe(1) - }) + await editor.getBuffer().reload() + expect(statusHandler.callCount).toBe(1) }) it("emits a status-changed event when a buffer's path changes", () => { @@ -396,31 +357,30 @@ describe('GitRepository', () => { if (project2) project2.destroy() }) - it('subscribes to all the serialized buffers in the project', () => { + it('subscribes to all the serialized buffers in the project', async () => { atom.project.setPaths([copyRepository()]) - waitsForPromise(() => atom.workspace.open('file.txt')) + await atom.workspace.open('file.txt') - waitsForPromise(() => { - project2 = new Project({notificationManager: atom.notifications, packageManager: atom.packages, confirm: atom.confirm, applicationDelegate: atom.applicationDelegate}) - return project2.deserialize(atom.project.serialize({isUnloading: false})) + project2 = new Project({ + notificationManager: atom.notifications, + packageManager: atom.packages, + confirm: atom.confirm, + applicationDelegate: atom.applicationDelegate }) + await project2.deserialize(atom.project.serialize({isUnloading: false})) - waitsFor(() => buffer = project2.getBuffers()[0]) + buffer = project2.getBuffers()[0] - waitsForPromise(() => { - const originalContent = buffer.getText() - buffer.append('changes') + const originalContent = buffer.getText() + buffer.append('changes') - statusHandler = jasmine.createSpy('statusHandler') - project2.getRepositories()[0].onDidChangeStatus(statusHandler) - return buffer.save() - }) + statusHandler = jasmine.createSpy('statusHandler') + project2.getRepositories()[0].onDidChangeStatus(statusHandler) + await buffer.save() - runs(() => { - expect(statusHandler.callCount).toBe(1) - expect(statusHandler).toHaveBeenCalledWith({path: buffer.getPath(), pathStatus: 256}) - }) + expect(statusHandler.callCount).toBe(1) + expect(statusHandler).toHaveBeenCalledWith({path: buffer.getPath(), pathStatus: 256}) }) }) })