angular-docs-cn/tools/broccoli/tree-differ.spec.ts
Caitlin Potter aad5795408 fix(tree-differ): treat symlinks to deleted paths as removals
Previously, tree-differ would not correctly handle symlinks to deleted files, resulting in
an ENOENT errno being tossed by libuv.

This change fixes this to ensure that symlinks are safely handled, performantly.

Closes #1961
2015-05-18 20:36:29 -04:00

355 lines
12 KiB
TypeScript

/// <reference path="../typings/node/node.d.ts" />
/// <reference path="../typings/jasmine/jasmine.d.ts" />
let mockfs = require('mock-fs');
import fs = require('fs');
import {TreeDiffer} from './tree-differ';
describe('TreeDiffer', () => {
afterEach(() => mockfs.restore());
describe('diff of changed files', () => {
it('should list all files but no directories during the first diff', () => {
let testDir = {
'dir1': {
'file-1.txt': mockfs.file({content: 'file-1.txt content', mtime: new Date(1000)}),
'file-2.txt': mockfs.file({content: 'file-2.txt content', mtime: new Date(1000)}),
'subdir-1': {
'file-1.1.txt': mockfs.file({content: 'file-1.1.txt content', mtime: new Date(1000)})
},
'empty-dir': {}
}
};
mockfs(testDir);
let differ = new TreeDiffer('dir1');
let diffResult = differ.diffTree();
expect(diffResult.changedPaths)
.toEqual(['file-1.txt', 'file-2.txt', 'subdir-1/file-1.1.txt']);
expect(diffResult.removedPaths).toEqual([]);
});
it('should return empty diff if nothing has changed', () => {
let testDir = {
'dir1': {
'file-1.txt': mockfs.file({content: 'file-1.txt content', mtime: new Date(1000)}),
'file-2.txt': mockfs.file({content: 'file-2.txt content', mtime: new Date(1000)}),
'subdir-1': {
'file-1.1.txt': mockfs.file({content: 'file-1.1.txt content', mtime: new Date(1000)})
},
}
};
mockfs(testDir);
let differ = new TreeDiffer('dir1');
let diffResult = differ.diffTree();
expect(diffResult.changedPaths).not.toEqual([]);
expect(diffResult.removedPaths).toEqual([]);
diffResult = differ.diffTree();
expect(diffResult.changedPaths).toEqual([]);
expect(diffResult.removedPaths).toEqual([]);
});
it('should list only changed files during the subsequent diffs', () => {
let testDir = {
'dir1': {
'file-1.txt': mockfs.file({content: 'file-1.txt content', mtime: new Date(1000)}),
'file-2.txt': mockfs.file({content: 'file-2.txt content', mtime: new Date(1000)}),
'subdir-1': {
'file-1.1.txt':
mockfs.file({content: 'file-1.1.txt content', mtime: new Date(1000)})
}
}
};
mockfs(testDir);
let differ = new TreeDiffer('dir1');
let diffResult = differ.diffTree();
expect(diffResult.changedPaths)
.toEqual(['file-1.txt', 'file-2.txt', 'subdir-1/file-1.1.txt']);
// change two files
testDir['dir1']['file-1.txt'] = mockfs.file({content: 'new content', mtime: new Date(1000)});
testDir['dir1']['subdir-1']['file-1.1.txt'] =
mockfs.file({content: 'file-1.1.txt content', mtime: new Date(9999)});
mockfs(testDir);
diffResult = differ.diffTree();
expect(diffResult.changedPaths).toEqual(['file-1.txt', 'subdir-1/file-1.1.txt']);
expect(diffResult.removedPaths).toEqual([]);
// change one file
testDir['dir1']['file-1.txt'] = mockfs.file({content: 'super new', mtime: new Date(1000)});
mockfs(testDir);
diffResult = differ.diffTree();
expect(diffResult.changedPaths).toEqual(['file-1.txt']);
});
it('should handle changes via symbolic links', () => {
let testDir = {
'orig_path': {
'file-1.txt': mockfs.file({content: 'file-1.txt content', mtime: new Date(1000)}),
'file-2.txt': mockfs.file({content: 'file-2.txt content', mtime: new Date(1000)}),
'subdir-1': {
'file-1.1.txt':
mockfs.file({content: 'file-1.1.txt content', mtime: new Date(1000)})
}
},
'symlinks': {
'file-1.txt': mockfs.symlink({path: '../orig_path/file-1.txt'}),
'file-2.txt': mockfs.symlink({path: '../orig_path/file-2.txt'}),
'subdir-1':
{'file-1.1.txt': mockfs.symlink({path: '../../orig_path/subdir-1/file-1.1.txt'})}
}
};
mockfs(testDir);
let differ = new TreeDiffer('symlinks');
let diffResult = differ.diffTree();
expect(diffResult.changedPaths)
.toEqual(['file-1.txt', 'file-2.txt', 'subdir-1/file-1.1.txt']);
// change two files
testDir['orig_path']['file-1.txt'] =
mockfs.file({content: 'new content', mtime: new Date(1000)});
testDir['orig_path']['subdir-1']['file-1.1.txt'] =
mockfs.file({content: 'file-1.1.txt content', mtime: new Date(9999)});
mockfs(testDir);
diffResult = differ.diffTree();
expect(diffResult.changedPaths).toEqual(['file-1.txt', 'subdir-1/file-1.1.txt']);
expect(diffResult.removedPaths).toEqual([]);
// change one file
testDir['orig_path']['file-1.txt'] =
mockfs.file({content: 'super new', mtime: new Date(1000)});
mockfs(testDir);
diffResult = differ.diffTree();
expect(diffResult.changedPaths).toEqual(['file-1.txt']);
// remove a link
delete testDir['orig_path']['file-1.txt'];
mockfs(testDir);
diffResult = differ.diffTree();
expect(diffResult.changedPaths).toEqual([]);
expect(diffResult.removedPaths).toEqual(['file-1.txt']);
// don't report it as a removal twice
mockfs(testDir);
diffResult = differ.diffTree();
expect(diffResult.changedPaths).toEqual([]);
expect(diffResult.removedPaths).toEqual([]);
// re-add it.
testDir['orig_path']['file-1.txt'] =
mockfs.file({content: 'super new', mtime: new Date(1000)});
mockfs(testDir);
diffResult = differ.diffTree();
expect(diffResult.changedPaths).toEqual(['file-1.txt']);
expect(diffResult.removedPaths).toEqual([]);
});
it('should ignore files with extensions not listed in includeExtensions', () => {
let testDir = {
'dir1': {
'file-1.js': mockfs.file({content: 'file-1.js content', mtime: new Date(1000)}),
'file-2.md': mockfs.file({content: 'file-2.md content', mtime: new Date(1000)}),
'file-3.coffee': mockfs.file({content: 'file-3.coffee content', mtime: new Date(1000)}),
'subdir-1': {
'file-1.1.cc': mockfs.file({content: 'file-1.1.cc content', mtime: new Date(1000)})
}
}
};
mockfs(testDir);
let differ = new TreeDiffer('dir1', ['.js', '.coffee']);
let diffResult = differ.diffTree();
expect(diffResult.changedPaths).toEqual(['file-1.js', 'file-3.coffee']);
// change two files
testDir['dir1']['file-1.js'] = mockfs.file({content: 'new content', mtime: new Date(1000)});
testDir['dir1']['file-3.coffee'] =
mockfs.file({content: 'new content', mtime: new Date(1000)});
testDir['dir1']['subdir-1']['file-1.1.cc'] =
mockfs.file({content: 'file-1.1.cc content', mtime: new Date(9999)});
mockfs(testDir);
diffResult = differ.diffTree();
expect(diffResult.changedPaths).toEqual(['file-1.js', 'file-3.coffee']);
expect(diffResult.removedPaths).toEqual([]);
// change one file
testDir['dir1']['file-1.js'] = mockfs.file({content: 'super new', mtime: new Date(1000)});
mockfs(testDir);
diffResult = differ.diffTree();
expect(diffResult.changedPaths).toEqual(['file-1.js']);
});
it('should ignore files with extensions listed in excludeExtensions', () => {
let testDir = {
'dir1': {
'file-1.ts': mockfs.file({content: 'file-1.ts content', mtime: new Date(1000)}),
'file-1.cs': mockfs.file({content: 'file-1.cs content', mtime: new Date(1000)}),
'file-1d.cs': mockfs.file({content: 'file-1d.cs content', mtime: new Date(1000)}),
'file-1.d.cs': mockfs.file({content: 'file-1.d.cs content', mtime: new Date(1000)}),
'file-2.md': mockfs.file({content: 'file-2.md content', mtime: new Date(1000)}),
'file-3.ts': mockfs.file({content: 'file-3.ts content', mtime: new Date(1000)}),
'file-4.d.ts': mockfs.file({content: 'file-4.d.ts content', mtime: new Date(1000)}),
'subdir-1': {
'file-1.1.cc': mockfs.file({content: 'file-1.1.cc content', mtime: new Date(1000)})
}
}
};
mockfs(testDir);
let differ = new TreeDiffer('dir1', ['.ts', '.cs'], ['.d.ts', '.d.cs']);
let diffResult = differ.diffTree();
expect(diffResult.changedPaths)
.toEqual(['file-1.cs', 'file-1.ts', 'file-1d.cs', 'file-3.ts']);
// change two files
testDir['dir1']['file-1.ts'] = mockfs.file({content: 'new content', mtime: new Date(1000)});
testDir['dir1']['file-1.cs'] = mockfs.file({content: 'new content', mtime: new Date(1000)});
testDir['dir1']['file-1.d.cs'] = mockfs.file({content: 'new content', mtime: new Date(1000)});
testDir['dir1']['file-3.ts'] = mockfs.file({content: 'new content', mtime: new Date(1000)});
testDir['dir1']['file-4.d.ts'] = mockfs.file({content: 'new content', mtime: new Date(1000)});
testDir['dir1']['subdir-1']['file-1.1.cc'] =
mockfs.file({content: 'file-1.1.cc content', mtime: new Date(9999)});
mockfs(testDir);
diffResult = differ.diffTree();
expect(diffResult.changedPaths).toEqual(['file-1.cs', 'file-1.ts', 'file-3.ts']);
expect(diffResult.removedPaths).toEqual([]);
// change one file
testDir['dir1']['file-4.d.ts'] = mockfs.file({content: 'super new', mtime: new Date(1000)});
mockfs(testDir);
diffResult = differ.diffTree();
expect(diffResult.changedPaths).toEqual([]);
});
});
describe('diff of new files', () => {
it('should detect file additions and report them as changed files', () => {
let testDir = {
'dir1':
{'file-1.txt': mockfs.file({content: 'file-1.txt content', mtime: new Date(1000)})}
};
mockfs(testDir);
let differ = new TreeDiffer('dir1');
differ.diffTree();
testDir['dir1']['file-2.txt'] = 'new file';
mockfs(testDir);
let diffResult = differ.diffTree();
expect(diffResult.changedPaths).toEqual(['file-2.txt']);
});
});
it('should detect file additions mixed with file changes', () => {
let testDir = {
'dir1': {'file-1.txt': mockfs.file({content: 'file-1.txt content', mtime: new Date(1000)})}
};
mockfs(testDir);
let differ = new TreeDiffer('dir1');
differ.diffTree();
testDir['dir1']['file-1.txt'] = 'new content';
testDir['dir1']['file-2.txt'] = 'new file';
mockfs(testDir);
let diffResult = differ.diffTree();
expect(diffResult.changedPaths).toEqual(['file-1.txt', 'file-2.txt']);
});
describe('diff of removed files', () => {
it('should detect file removals and report them as removed files', () => {
let testDir = {
'dir1':
{'file-1.txt': mockfs.file({content: 'file-1.txt content', mtime: new Date(1000)})}
};
mockfs(testDir);
let differ = new TreeDiffer('dir1');
differ.diffTree();
delete testDir['dir1']['file-1.txt'];
mockfs(testDir);
let diffResult = differ.diffTree();
expect(diffResult.changedPaths).toEqual([]);
expect(diffResult.removedPaths).toEqual(['file-1.txt']);
});
});
it('should detect file removals mixed with file changes and additions', () => {
let testDir = {
'dir1': {
'file-1.txt': mockfs.file({content: 'file-1.txt content', mtime: new Date(1000)}),
'file-2.txt': mockfs.file({content: 'file-1.txt content', mtime: new Date(1000)})
}
};
mockfs(testDir);
let differ = new TreeDiffer('dir1');
differ.diffTree();
testDir['dir1']['file-1.txt'] = 'changed content';
delete testDir['dir1']['file-2.txt'];
testDir['dir1']['file-3.txt'] = 'new content';
mockfs(testDir);
let diffResult = differ.diffTree();
expect(diffResult.changedPaths).toEqual(['file-1.txt', 'file-3.txt']);
expect(diffResult.removedPaths).toEqual(['file-2.txt']);
});
});