first setup for incremental testing

combines reference parser and git changes

still very dev mode
This commit is contained in:
Bart van der Schoor
2014-02-28 20:27:33 +01:00
parent 35765e6305
commit 76ffe56a44
15 changed files with 981 additions and 790 deletions
+162 -69
View File
@@ -47,6 +47,8 @@ var Exec = function () {
/// <reference path="../_ref.d.ts" />
var DT;
(function (DT) {
'use-strict';
var path = require('path');
/////////////////////////////////
@@ -55,30 +57,17 @@ var DT;
/////////////////////////////////
var File = (function () {
function File(baseDir, filePathWithName) {
this.references = [];
this.baseDir = baseDir;
this.filePathWithName = filePathWithName;
this.references = [];
this.ext = path.extname(this.filePathWithName);
this.file = path.basename(this.filePathWithName, this.ext);
this.dir = path.dirname(this.filePathWithName);
this.formatName = path.join(this.dir, this.file + this.ext);
this.fullPath = path.join(this.baseDir, this.dir, this.file + this.ext);
// lock it (shallow)
// Object.freeze(this);
}
Object.defineProperty(File.prototype, "formatName", {
// From '/complete/path/to/file' to 'specfolder/specfile.d.ts'
get: function () {
return path.join(this.dir, this.file + this.ext);
},
enumerable: true,
configurable: true
});
Object.defineProperty(File.prototype, "fullPath", {
get: function () {
return path.join(this.baseDir, this.dir, this.file + this.ext);
},
enumerable: true,
configurable: true
});
File.prototype.toString = function () {
return '[File ' + this.filePathWithName + ']';
};
@@ -91,6 +80,7 @@ var DT;
/// <reference path="host/exec.ts" />
var DT;
(function (DT) {
'use-strict';
var fs = require('fs');
var Tsc = (function () {
@@ -132,6 +122,8 @@ var DT;
/// <reference path="../runner.ts" />
var DT;
(function (DT) {
'use-strict';
/////////////////////////////////
// Timer.start starts a timer
// Timer.end stops the timer and sets asString to the pretty print value
@@ -171,6 +163,8 @@ var DT;
/// <reference path="../_ref.d.ts" />
var DT;
(function (DT) {
'use-strict';
var referenceTagExp = /<reference[ \t]*path=["']?([\w\.\/_-]*)["']?[ \t]*\/>/g;
function endsWith(str, suffix) {
@@ -201,6 +195,8 @@ var DT;
/// <reference path="util.ts" />
var DT;
(function (DT) {
'use-strict';
var fs = require('fs');
var path = require('path');
@@ -219,6 +215,17 @@ var DT;
});
};
FileIndex.prototype.hasFile = function (target) {
return target in this.fileMap;
};
FileIndex.prototype.getFile = function (target) {
if (target in this.fileMap) {
return this.fileMap[target];
}
return null;
};
FileIndex.prototype.loadReferences = function (files, callback) {
var _this = this;
var queue = files.slice(0);
@@ -276,6 +283,8 @@ var DT;
/// <reference path="../_ref.d.ts" />
var DT;
(function (DT) {
'use-strict';
var fs = require('fs');
var path = require('path');
var Git = require('git-wrapper');
@@ -283,7 +292,8 @@ var DT;
var GitChanges = (function () {
function GitChanges(baseDir) {
this.baseDir = baseDir;
this.options = [];
this.options = {};
this.paths = [];
var dir = path.join(baseDir, '.git');
if (!fs.existsSync(dir)) {
throw new Error('cannot locate git-dir: ' + dir);
@@ -291,19 +301,20 @@ var DT;
this.options['git-dir'] = dir;
}
GitChanges.prototype.getChanges = function (callback) {
var _this = this;
//git diff --name-only HEAD~1
var git = new Git(this.options);
var opts = {};
var args = ['--name-only HEAD~1'];
git.exec('diff', opts, args, function (err, msg) {
if (err) {
callback(err, null);
callback(err);
return;
}
var paths = msg.replace(/^\s+/, '').replace(/\s+$/, '').split(/\r?\n/g);
_this.paths = msg.replace(/^\s+/, '').replace(/\s+$/, '').split(/\r?\n/g);
// console.log(paths);
callback(null, paths);
callback(null);
});
};
return GitChanges;
@@ -314,6 +325,8 @@ var DT;
/// <reference path="../runner.ts" />
var DT;
(function (DT) {
'use-strict';
/////////////////////////////////
// All the common things that we pring are functions of this class
/////////////////////////////////
@@ -430,6 +443,8 @@ var DT;
/// <reference path="../printer.ts" />
var DT;
(function (DT) {
'use-strict';
/////////////////////////////////
@@ -463,6 +478,8 @@ var DT;
/// <reference path="../../runner.ts" />
var DT;
(function (DT) {
'use-strict';
/////////////////////////////////
@@ -549,6 +566,8 @@ var __extends = this.__extends || function (d, b) {
};
var DT;
(function (DT) {
'use-strict';
/////////////////////////////////
// .d.ts syntax inspection
/////////////////////////////////
@@ -570,6 +589,8 @@ var DT;
/// <reference path="../util.ts" />
var DT;
(function (DT) {
'use-strict';
/////////////////////////////////
// Compile with *-tests.ts
/////////////////////////////////
@@ -591,6 +612,8 @@ var DT;
/// <reference path="../file.ts" />
var DT;
(function (DT) {
'use-strict';
var fs = require('fs');
/////////////////////////////////
@@ -665,6 +688,8 @@ var DT;
/// <reference path="src/suite/tscParams.ts" />
var DT;
(function (DT) {
'use-strict';
require('source-map-support').install();
var fs = require('fs');
@@ -673,17 +698,6 @@ var DT;
var tsExp = /\.ts$/;
// TOD0 remove this after dev!
var testNames = [
'async/',
'jquery/jquery.d',
'angularjs/angular.d',
'pixi/'
];
/* if (process.env.TRAVIS) {
testNames = null;
} */
DT.DEFAULT_TSC_VERSION = "0.9.1.1";
var Test = (function () {
@@ -731,6 +745,8 @@ var DT;
/////////////////////////////////
// The main class to kick things off
/////////////////////////////////
// TODO move to bluebird (Promises)
// TODO move to lazy.js (functional)
var TestRunner = (function () {
function TestRunner(dtPath, options) {
if (typeof options === "undefined") { options = { tscVersion: DT.DEFAULT_TSC_VERSION }; }
@@ -741,8 +757,9 @@ var DT;
this.options.findNotRequiredTscparams = !!this.options.findNotRequiredTscparams;
this.index = new DT.FileIndex(this.options);
this.changes = new DT.GitChanges(this.dtPath);
// should be async
// should be async (way faster)
// only includes .d.ts or -tests.ts or -test.ts or .ts
var filesName = glob.sync('**/*.ts', { cwd: dtPath });
this.files = filesName.filter(function (fileName) {
@@ -751,29 +768,50 @@ var DT;
return new DT.File(dtPath, fileName);
});
}
TestRunner.prototype.checkAcceptFile = function (fileName) {
var ok = tsExp.test(fileName);
ok = ok && fileName.indexOf('_infrastructure') < 0;
ok = ok && fileName.indexOf('node_modules/') < 0;
ok = ok && /^[a-z]/i.test(fileName);
//TODO remove this dev code
ok = ok && (!testNames || testNames.some(function (pattern) {
return fileName.indexOf(pattern) > -1;
}));
return ok;
};
TestRunner.prototype.addSuite = function (suite) {
this.suites.push(suite);
};
TestRunner.prototype.run = function () {
var _this = this;
this.timer = new DT.Timer();
this.timer.start();
// we need promises
this.doGetChanges();
};
TestRunner.prototype.checkAcceptFile = function (fileName) {
var ok = tsExp.test(fileName);
ok = ok && fileName.indexOf('_infrastructure') < 0;
ok = ok && fileName.indexOf('node_modules/') < 0;
ok = ok && /^[a-z]/i.test(fileName);
return ok;
};
TestRunner.prototype.doGetChanges = function () {
var _this = this;
this.changes.getChanges(function (err) {
if (err) {
throw err;
}
console.log('');
console.log('changes:');
console.log('---');
_this.changes.paths.forEach(function (file) {
console.log(file);
});
console.log('---');
// chain
_this.doGetReferences();
});
};
TestRunner.prototype.doGetReferences = function () {
var _this = this;
this.index.parseFiles(this.files, function () {
console.log('');
console.log('files:');
console.log('---');
_this.files.forEach(function (file) {
@@ -783,29 +821,80 @@ var DT;
});
});
console.log('---');
_this.getChanges();
// chain
_this.doCollectTargets();
});
};
TestRunner.prototype.getChanges = function () {
TestRunner.prototype.doCollectTargets = function () {
// TODO clean this up when functional (do we need changeMap?)
var _this = this;
var changes = new DT.GitChanges(this.dtPath);
changes.getChanges(function (err, changes) {
if (err) {
throw err;
// bake map for lookup
var changeMap = this.changes.paths.filter(function (full) {
return _this.checkAcceptFile(full);
}).map(function (local) {
return path.resolve(_this.dtPath, local);
}).reduce(function (memo, full) {
var file = _this.index.getFile(full);
if (!file) {
// what does it mean? deleted?
console.log('not in index: ' + full);
return memo;
}
console.log('changes:');
console.log('---');
changes.forEach(function (file) {
console.log(file);
});
console.log('---');
memo[full] = file;
return memo;
}, Object.create(null));
_this.runTests();
// collect referring files (and also log)
var touched = Object.create(null);
console.log('');
console.log('relevant changes:');
console.log('---');
Object.keys(changeMap).sort().forEach(function (src) {
touched[src] = changeMap[src];
console.log(changeMap[src].formatName);
});
console.log('---');
// terrible loop (whatever)
// just add stuff until there is nothing new added
// TODO improve it
var added;
do {
added = 0;
this.files.forEach(function (file) {
// lol getter
if (file.fullPath in touched) {
return;
}
// check if one of our references is touched
file.references.some(function (ref) {
if (ref.fullPath in touched) {
// add us
touched[file.fullPath] = file;
added++;
return true;
}
return false;
});
});
} while(added > 0);
console.log('');
console.log('touched:');
console.log('---');
var files = Object.keys(touched).sort().map(function (src) {
console.log(touched[src].formatName);
return touched[src];
});
console.log('---');
this.runTests(files);
};
TestRunner.prototype.runTests = function () {
TestRunner.prototype.runTests = function (files) {
var _this = this;
var syntaxChecking = new DT.SyntaxChecking(this.options);
var testEval = new DT.TestEval(this.options);
@@ -814,9 +903,10 @@ var DT;
this.addSuite(testEval);
}
var typings = syntaxChecking.filterTargetFiles(this.files).length;
var testFiles = testEval.filterTargetFiles(this.files).length;
this.print = new DT.Print(this.options.tscVersion, typings, testFiles, this.files.length);
var typings = syntaxChecking.filterTargetFiles(files).length;
var testFiles = testEval.filterTargetFiles(files).length;
this.print = new DT.Print(this.options.tscVersion, typings, testFiles, files.length);
this.print.printHeader();
if (this.options.findNotRequiredTscparams) {
@@ -830,7 +920,7 @@ var DT;
suite.testReporter = suite.testReporter || new DT.DefaultTestReporter(_this.print);
_this.print.printSuiteHeader(suite.testSuiteName);
var targetFiles = suite.filterTargetFiles(_this.files);
var targetFiles = suite.filterTargetFiles(files);
suite.start(targetFiles, function (testResult, index) {
_this.testCompleteCallback(testResult, index);
}, function (suite) {
@@ -840,7 +930,7 @@ var DT;
});
} else {
_this.timer.end();
_this.allTestCompleteCallback();
_this.allTestCompleteCallback(files);
}
};
executor();
@@ -864,7 +954,7 @@ var DT;
this.print.printFailedCount(suite.ngTests.length, suite.testResults.length);
};
TestRunner.prototype.allTestCompleteCallback = function () {
TestRunner.prototype.allTestCompleteCallback = function (files) {
var _this = this;
var testEval = this.suites.filter(function (suite) {
return suite instanceof DT.TestEval;
@@ -875,11 +965,13 @@ var DT;
}).reduce(function (a, b) {
return a.indexOf(b) < 0 ? a.concat([b]) : a;
}, []);
var typings = this.files.map(function (file) {
var typings = files.map(function (file) {
return file.dir;
}).reduce(function (a, b) {
return a.indexOf(b) < 0 ? a.concat([b]) : a;
}, []);
var withoutTestTypings = typings.filter(function (typing) {
return existsTestTypings.indexOf(typing) < 0;
});
@@ -892,6 +984,7 @@ var DT;
this.print.printDiv();
this.print.printElapsedTime(this.timer.asString, this.timer.time);
this.suites.filter(function (suite) {
return suite.printErrorCount;
}).forEach(function (suite) {
+308 -247
View File
@@ -19,291 +19,352 @@
/// <reference path="src/suite/tscParams.ts" />
module DT {
require('source-map-support').install();
'use-strict';
var fs = require('fs');
var path = require('path');
var glob = require('glob');
require('source-map-support').install();
var tsExp = /\.ts$/;
var fs = require('fs');
var path = require('path');
var glob = require('glob');
// TOD0 remove this after dev!
var testNames = [
'async/',
'jquery/jquery.d',
'angularjs/angular.d',
'pixi/'
];
/* if (process.env.TRAVIS) {
testNames = null;
} */
var tsExp = /\.ts$/;
export var DEFAULT_TSC_VERSION = "0.9.1.1";
export var DEFAULT_TSC_VERSION = "0.9.1.1";
export class Test {
constructor(public suite: ITestSuite, public tsfile: File, public options?: TscExecOptions) {
}
export class Test {
constructor(public suite: ITestSuite, public tsfile: File, public options?: TscExecOptions) {
}
public run(callback: (result: TestResult) => void) {
Tsc.run(this.tsfile.filePathWithName, this.options, (execResult) => {
var testResult = new TestResult();
testResult.hostedBy = this.suite;
testResult.targetFile = this.tsfile;
testResult.options = this.options;
public run(callback: (result: TestResult) => void) {
Tsc.run(this.tsfile.filePathWithName, this.options, (execResult) => {
var testResult = new TestResult();
testResult.hostedBy = this.suite;
testResult.targetFile = this.tsfile;
testResult.options = this.options;
testResult.stdout = execResult.stdout;
testResult.stderr = execResult.stderr;
testResult.exitCode = execResult.exitCode;
testResult.stdout = execResult.stdout;
testResult.stderr = execResult.stderr;
testResult.exitCode = execResult.exitCode;
callback(testResult);
});
}
}
/////////////////////////////////
// Test results
/////////////////////////////////
export class TestResult {
hostedBy: ITestSuite;
targetFile: File;
options: TscExecOptions;
callback(testResult);
});
}
}
stdout: string;
stderr: string;
exitCode: number;
/////////////////////////////////
// Test results
/////////////////////////////////
export class TestResult {
hostedBy: ITestSuite;
targetFile: File;
options: TscExecOptions;
public get success(): boolean {
return this.exitCode === 0;
}
}
export interface ITestRunnerOptions {
tscVersion:string;
findNotRequiredTscparams?:boolean;
}
stdout: string;
stderr: string;
exitCode: number;
/////////////////////////////////
// The main class to kick things off
/////////////////////////////////
export class TestRunner {
files: File[];
timer: Timer;
suites: ITestSuite[] = [];
private index: FileIndex;
private print: Print;
public get success(): boolean {
return this.exitCode === 0;
}
}
constructor(public dtPath: string, public options: ITestRunnerOptions = {tscVersion: DT.DEFAULT_TSC_VERSION}) {
this.options.findNotRequiredTscparams = !!this.options.findNotRequiredTscparams;
export interface ITestRunnerOptions {
tscVersion:string;
findNotRequiredTscparams?:boolean;
}
/////////////////////////////////
// The main class to kick things off
/////////////////////////////////
// TODO move to bluebird (Promises)
// TODO move to lazy.js (functional)
export class TestRunner {
files: File[];
timer: Timer;
suites: ITestSuite[] = [];
this.index = new FileIndex(this.options);
private index: FileIndex;
private changes: GitChanges;
private print: Print;
// should be async
// only includes .d.ts or -tests.ts or -test.ts or .ts
var filesName = glob.sync('**/*.ts', { cwd: dtPath });
this.files = filesName
.filter((fileName) => {
return this.checkAcceptFile(fileName);
})
.sort()
.map((fileName) => {
return new File(dtPath, fileName);
});
}
constructor(public dtPath: string, public options: ITestRunnerOptions = {tscVersion: DT.DEFAULT_TSC_VERSION}) {
this.options.findNotRequiredTscparams = !!this.options.findNotRequiredTscparams;
public checkAcceptFile(fileName: string): boolean {
var ok = tsExp.test(fileName);
ok = ok && fileName.indexOf('_infrastructure') < 0;
ok = ok && fileName.indexOf('node_modules/') < 0;
ok = ok && /^[a-z]/i.test(fileName);
this.index = new FileIndex(this.options);
this.changes = new GitChanges(this.dtPath);
//TODO remove this dev code
ok = ok && (!testNames || testNames.some((pattern) => {
return fileName.indexOf(pattern) > -1;
}));
return ok;
}
// should be async (way faster)
// only includes .d.ts or -tests.ts or -test.ts or .ts
var filesName = glob.sync('**/*.ts', { cwd: dtPath });
this.files = filesName.filter((fileName) => {
return this.checkAcceptFile(fileName);
}).sort().map((fileName) => {
return new File(dtPath, fileName);
});
}
public addSuite(suite: ITestSuite):void {
this.suites.push(suite);
}
public addSuite(suite: ITestSuite): void {
this.suites.push(suite);
}
public run():void {
this.timer = new Timer();
this.timer.start();
public run(): void {
this.timer = new Timer();
this.timer.start();
this.index.parseFiles(this.files, () => {
console.log('files:');
console.log('---');
this.files.forEach((file) => {
console.log(file.filePathWithName);
file.references.forEach((file) => {
console.log(' - %s', file.filePathWithName);
});
});
console.log('---');
this.getChanges();
});
}
// we need promises
this.doGetChanges();
}
public getChanges():void {
var changes = new GitChanges(this.dtPath);
changes.getChanges((err, changes: string[]) => {
if (err) {
throw err;
}
console.log('changes:');
console.log('---');
changes.forEach((file) => {
console.log(file);
});
console.log('---');
private checkAcceptFile(fileName: string): boolean {
var ok = tsExp.test(fileName);
ok = ok && fileName.indexOf('_infrastructure') < 0;
ok = ok && fileName.indexOf('node_modules/') < 0;
ok = ok && /^[a-z]/i.test(fileName);
return ok;
}
this.runTests();
});
}
private doGetChanges(): void {
this.changes.getChanges((err) => {
if (err) {
throw err;
}
console.log('');
console.log('changes:');
console.log('---');
public runTests():void {
this.changes.paths.forEach((file) => {
console.log(file);
});
console.log('---');
var syntaxChecking = new SyntaxChecking(this.options);
var testEval = new TestEval(this.options);
if (!this.options.findNotRequiredTscparams) {
this.addSuite(syntaxChecking);
this.addSuite(testEval);
}
// chain
this.doGetReferences();
});
}
var typings = syntaxChecking.filterTargetFiles(this.files).length;
var testFiles = testEval.filterTargetFiles(this.files).length;
this.print = new Print(this.options.tscVersion, typings, testFiles, this.files.length);
this.print.printHeader();
private doGetReferences(): void {
this.index.parseFiles(this.files, () => {
console.log('');
console.log('files:');
console.log('---');
this.files.forEach((file) => {
console.log(file.filePathWithName);
file.references.forEach((file) => {
console.log(' - %s', file.filePathWithName);
});
});
console.log('---');
if (this.options.findNotRequiredTscparams) {
this.addSuite(new FindNotRequiredTscparams(this.options, this.print));
}
// chain
this.doCollectTargets();
});
}
var count = 0;
var executor = () => {
var suite = this.suites[count];
if (suite) {
suite.testReporter = suite.testReporter || new DefaultTestReporter(this.print);
private doCollectTargets(): void {
this.print.printSuiteHeader(suite.testSuiteName);
var targetFiles = suite.filterTargetFiles(this.files);
suite.start(
targetFiles,
(testResult, index) => {
this.testCompleteCallback(testResult, index);
},
(suite) => {
this.suiteCompleteCallback(suite);
count++;
executor();
});
} else {
this.timer.end();
this.allTestCompleteCallback();
}
};
executor();
}
// TODO clean this up when functional (do we need changeMap?)
private testCompleteCallback(testResult: TestResult, index: number) {
var reporter = testResult.hostedBy.testReporter;
if (testResult.success) {
reporter.printPositiveCharacter(index, testResult);
} else {
reporter.printNegativeCharacter(index, testResult);
}
}
// bake map for lookup
var changeMap = this.changes.paths.filter((full) => {
return this.checkAcceptFile(full);
}).map((local) => {
return path.resolve(this.dtPath, local);
}).reduce((memo, full) => {
var file = this.index.getFile(full);
if (!file) {
// what does it mean? deleted?
console.log('not in index: ' + full);
return memo;
}
memo[full] = file;
return memo;
}, Object.create(null));
private suiteCompleteCallback(suite: ITestSuite) {
this.print.printBreak();
// collect referring files (and also log)
var touched = Object.create(null);
console.log('');
console.log('relevant changes:');
console.log('---');
Object.keys(changeMap).sort().forEach((src) => {
touched[src] = changeMap[src];
console.log(changeMap[src].formatName);
});
console.log('---');
this.print.printDiv();
this.print.printElapsedTime(suite.timer.asString, suite.timer.time);
this.print.printSuccessCount(suite.okTests.length, suite.testResults.length);
this.print.printFailedCount(suite.ngTests.length, suite.testResults.length);
}
// terrible loop (whatever)
// just add stuff until there is nothing new added
// TODO improve it
var added:number;
do {
added = 0;
this.files.forEach((file) => {
// lol getter
if (file.fullPath in touched) {
return;
}
// check if one of our references is touched
file.references.some((ref) => {
if (ref.fullPath in touched) {
// add us
touched[file.fullPath] = file;
added++;
return true;
}
return false;
});
});
}
while(added > 0);
private allTestCompleteCallback() {
var testEval = this.suites.filter(suite => suite instanceof TestEval)[0];
if (testEval) {
var existsTestTypings: string[] = testEval.testResults
.map((testResult) => {
return testResult.targetFile.dir;
})
.reduce((a: string[], b: string) => {
return a.indexOf(b) < 0 ? a.concat([b]) : a;
}, []);
var typings: string[] = this.files
.map((file) => {
return file.dir;
})
.reduce((a: string[], b: string) => {
return a.indexOf(b) < 0 ? a.concat([b]) : a;
}, []);
var withoutTestTypings: string[] = typings
.filter((typing) => {
return existsTestTypings.indexOf(typing) < 0;
});
this.print.printDiv();
this.print.printTypingsWithoutTest(withoutTestTypings);
}
console.log('');
console.log('touched:');
console.log('---');
var files: File[] = Object.keys(touched).sort().map((src) => {
console.log(touched[src].formatName);
return touched[src];
});
console.log('---');
this.print.printDiv();
this.print.printTotalMessage();
this.runTests(files);
}
this.print.printDiv();
this.print.printElapsedTime(this.timer.asString, this.timer.time);
this.suites
.filter((suite: ITestSuite) => {
return suite.printErrorCount;
})
.forEach((suite: ITestSuite) => {
this.print.printSuiteErrorCount(suite.errorHeadline, suite.ngTests.length, suite.testResults.length);
});
if (testEval) {
this.print.printSuiteErrorCount("Without tests", withoutTestTypings.length, typings.length, '\33[33m\33[1m');
}
private runTests(files: File[]): void {
this.print.printDiv();
if (this.suites.some((suite) => {
return suite.ngTests.length !== 0
})) {
this.print.printErrorsHeader();
var syntaxChecking = new SyntaxChecking(this.options);
var testEval = new TestEval(this.options);
if (!this.options.findNotRequiredTscparams) {
this.addSuite(syntaxChecking);
this.addSuite(testEval);
}
this.suites
.filter((suite) => {
return suite.ngTests.length !== 0;
})
.forEach((suite) => {
suite.ngTests.forEach((testResult) => {
this.print.printErrorsForFile(testResult);
});
this.print.printBoldDiv();
});
var typings = syntaxChecking.filterTargetFiles(files).length;
var testFiles = testEval.filterTargetFiles(files).length;
process.exit(1);
}
}
}
this.print = new Print(this.options.tscVersion, typings, testFiles, files.length);
this.print.printHeader();
var dtPath = path.resolve(path.dirname((module).filename), '..', '..');
var findNotRequiredTscparams = process.argv.some(arg => arg == "--try-without-tscparams");
var tscVersionIndex = process.argv.indexOf("--tsc-version");
var tscVersion = DEFAULT_TSC_VERSION;
if (-1 < tscVersionIndex) {
tscVersion = process.argv[tscVersionIndex + 1];
}
if (this.options.findNotRequiredTscparams) {
this.addSuite(new FindNotRequiredTscparams(this.options, this.print));
}
console.log('--');
console.log(' dtPath %s', dtPath);
console.log(' tscVersion %s', tscVersion);
console.log(' findNotRequiredTscparams %s', findNotRequiredTscparams);
console.log('--');
console.log('');
var count = 0;
var executor = () => {
var suite = this.suites[count];
if (suite) {
suite.testReporter = suite.testReporter || new DefaultTestReporter(this.print);
var runner = new TestRunner(dtPath, {
tscVersion: tscVersion,
findNotRequiredTscparams: findNotRequiredTscparams
});
runner.run();
this.print.printSuiteHeader(suite.testSuiteName);
var targetFiles = suite.filterTargetFiles(files);
suite.start(targetFiles, (testResult, index) => {
this.testCompleteCallback(testResult, index);
}, (suite) => {
this.suiteCompleteCallback(suite);
count++;
executor();
});
}
else {
this.timer.end();
this.allTestCompleteCallback(files);
}
};
executor();
}
private testCompleteCallback(testResult: TestResult, index: number) {
var reporter = testResult.hostedBy.testReporter;
if (testResult.success) {
reporter.printPositiveCharacter(index, testResult);
}
else {
reporter.printNegativeCharacter(index, testResult);
}
}
private suiteCompleteCallback(suite: ITestSuite) {
this.print.printBreak();
this.print.printDiv();
this.print.printElapsedTime(suite.timer.asString, suite.timer.time);
this.print.printSuccessCount(suite.okTests.length, suite.testResults.length);
this.print.printFailedCount(suite.ngTests.length, suite.testResults.length);
}
private allTestCompleteCallback(files: File[]) {
var testEval = this.suites.filter(suite => suite instanceof TestEval)[0];
if (testEval) {
var existsTestTypings: string[] = testEval.testResults.map((testResult) => {
return testResult.targetFile.dir;
}).reduce((a: string[], b: string) => {
return a.indexOf(b) < 0 ? a.concat([b]) : a;
}, []);
var typings: string[] = files.map((file) => {
return file.dir;
}).reduce((a: string[], b: string) => {
return a.indexOf(b) < 0 ? a.concat([b]) : a;
}, []);
var withoutTestTypings: string[] = typings.filter((typing) => {
return existsTestTypings.indexOf(typing) < 0;
});
this.print.printDiv();
this.print.printTypingsWithoutTest(withoutTestTypings);
}
this.print.printDiv();
this.print.printTotalMessage();
this.print.printDiv();
this.print.printElapsedTime(this.timer.asString, this.timer.time);
this.suites.filter((suite: ITestSuite) => {
return suite.printErrorCount;
}).forEach((suite: ITestSuite) => {
this.print.printSuiteErrorCount(suite.errorHeadline, suite.ngTests.length, suite.testResults.length);
});
if (testEval) {
this.print.printSuiteErrorCount("Without tests", withoutTestTypings.length, typings.length, '\33[33m\33[1m');
}
this.print.printDiv();
if (this.suites.some((suite) => {
return suite.ngTests.length !== 0
})) {
this.print.printErrorsHeader();
this.suites.filter((suite) => {
return suite.ngTests.length !== 0;
}).forEach((suite) => {
suite.ngTests.forEach((testResult) => {
this.print.printErrorsForFile(testResult);
});
this.print.printBoldDiv();
});
process.exit(1);
}
}
}
var dtPath = path.resolve(path.dirname((module).filename), '..', '..');
var findNotRequiredTscparams = process.argv.some(arg => arg == "--try-without-tscparams");
var tscVersionIndex = process.argv.indexOf("--tsc-version");
var tscVersion = DEFAULT_TSC_VERSION;
if (-1 < tscVersionIndex) {
tscVersion = process.argv[tscVersionIndex + 1];
}
console.log('--');
console.log(' dtPath %s', dtPath);
console.log(' tscVersion %s', tscVersion);
console.log(' findNotRequiredTscparams %s', findNotRequiredTscparams);
console.log('--');
console.log('');
var runner = new TestRunner(dtPath, {
tscVersion: tscVersion,
findNotRequiredTscparams: findNotRequiredTscparams
});
runner.run();
}
+30 -28
View File
@@ -1,37 +1,39 @@
/// <reference path="../_ref.d.ts" />
module DT {
'use-strict';
var fs = require('fs');
var path = require('path');
var Git = require('git-wrapper');
var fs = require('fs');
var path = require('path');
var Git = require('git-wrapper');
export class GitChanges {
export class GitChanges {
options = [];
options = {};
paths: string[] = [];
constructor(public baseDir: string) {
var dir = path.join(baseDir, '.git');
if (!fs.existsSync(dir)) {
throw new Error('cannot locate git-dir: ' + dir);
}
this.options['git-dir'] = dir;
}
constructor(public baseDir: string) {
var dir = path.join(baseDir, '.git');
if (!fs.existsSync(dir)) {
throw new Error('cannot locate git-dir: ' + dir);
}
this.options['git-dir'] = dir;
}
getChanges(callback: (err, paths: string[]) => void): void {
//git diff --name-only HEAD~1
var git = new Git(this.options);
var opts = {};
var args = ['--name-only HEAD~1'];
git.exec('diff', opts, args, (err, msg: string) => {
if (err) {
callback(err, null);
return;
}
var paths = msg.replace(/^\s+/, '').replace(/\s+$/, '').split(/\r?\n/g);
// console.log(paths);
callback(null, paths);
});
}
}
getChanges(callback: (err) => void): void {
//git diff --name-only HEAD~1
var git = new Git(this.options);
var opts = {};
var args = ['--name-only HEAD~1'];
git.exec('diff', opts, args, (err, msg: string) => {
if (err) {
callback(err);
return;
}
this.paths = msg.replace(/^\s+/, '').replace(/\s+$/, '').split(/\r?\n/g);
// console.log(paths);
callback(null);
});
}
}
}
+30 -26
View File
@@ -1,35 +1,39 @@
/// <reference path="../_ref.d.ts" />
module DT {
var path = require('path');
'use-strict';
/////////////////////////////////
// Given a document root + ts file pattern this class returns:
// all the TS files OR just tests OR just definition files
/////////////////////////////////
export class File {
dir: string;
file: string;
ext: string;
references: File[] = [];
var path = require('path');
constructor(public baseDir: string, public filePathWithName: string) {
this.ext = path.extname(this.filePathWithName);
this.file = path.basename(this.filePathWithName, this.ext);
this.dir = path.dirname(this.filePathWithName);
}
/////////////////////////////////
// Given a document root + ts file pattern this class returns:
// all the TS files OR just tests OR just definition files
/////////////////////////////////
export class File {
baseDir: string;
filePathWithName: string;
dir: string;
file: string;
ext: string;
formatName: string;
fullPath: string;
references: File[] = [];
// From '/complete/path/to/file' to 'specfolder/specfile.d.ts'
public get formatName(): string {
return path.join(this.dir, this.file + this.ext);
}
constructor(baseDir: string, filePathWithName: string) {
this.baseDir = baseDir;
this.filePathWithName = filePathWithName;
this.ext = path.extname(this.filePathWithName);
this.file = path.basename(this.filePathWithName, this.ext);
this.dir = path.dirname(this.filePathWithName);
this.formatName = path.join(this.dir, this.file + this.ext);
this.fullPath = path.join(this.baseDir, this.dir, this.file + this.ext);
public get fullPath(): string {
return path.join(this.baseDir, this.dir, this.file + this.ext);
}
// lock it (shallow)
// Object.freeze(this);
}
toString() {
return '[File ' + this.filePathWithName + ']';
}
}
toString() {
return '[File ' + this.filePathWithName + ']';
}
}
}
+17 -17
View File
@@ -15,32 +15,32 @@
// Allows for executing a program with command-line arguments and reading the result
interface IExec {
exec: (filename: string, cmdLineArgs: string[], handleResult: (ExecResult) => void) => void;
exec: (filename: string, cmdLineArgs: string[], handleResult: (ExecResult) => void) => void;
}
class ExecResult {
public stdout = "";
public stderr = "";
public exitCode: number;
public stdout = "";
public stderr = "";
public exitCode: number;
}
class NodeExec implements IExec {
public exec(filename: string, cmdLineArgs: string[], handleResult: (ExecResult) => void): void {
var nodeExec = require('child_process').exec;
public exec(filename: string, cmdLineArgs: string[], handleResult: (ExecResult) => void): void {
var nodeExec = require('child_process').exec;
var result = new ExecResult();
result.exitCode = null;
var cmdLine = filename + ' ' + cmdLineArgs.join(' ');
var result = new ExecResult();
result.exitCode = null;
var cmdLine = filename + ' ' + cmdLineArgs.join(' ');
var process = nodeExec(cmdLine, {maxBuffer: 1 * 1024 * 1024}, function (error, stdout, stderr) {
result.stdout = stdout;
result.stderr = stderr;
result.exitCode = error ? error.code : 0;
handleResult(result);
});
}
var process = nodeExec(cmdLine, {maxBuffer: 1 * 1024 * 1024}, function (error, stdout, stderr) {
result.stdout = stdout;
result.stderr = stderr;
result.exitCode = error ? error.code : 0;
handleResult(result);
});
}
}
var Exec: IExec = function (): IExec {
return new NodeExec();
return new NodeExec();
}();
+77 -63
View File
@@ -3,77 +3,91 @@
/// <reference path="util.ts" />
module DT {
var fs = require('fs');
var path = require('path');
'use-strict';
export class FileIndex {
var fs = require('fs');
var path = require('path');
fileMap: {[path:string]:File};
export class FileIndex {
constructor(public options: ITestRunnerOptions) {
fileMap: {[path:string]:File
};
}
constructor(public options: ITestRunnerOptions) {
parseFiles(files: File[], callback: () => void): void {
this.fileMap = Object.create(null);
files.forEach((file) => {
this.fileMap[file.fullPath] = file;
});
this.loadReferences(files, () => {
callback();
});
}
}
private loadReferences(files: File[], callback: () => void): void {
var queue = files.slice(0);
var active = [];
var max = 50;
var next = () => {
if (queue.length === 0 && active.length === 0) {
callback();
return;
}
// queue paralel
while (queue.length > 0 && active.length < max) {
var file = queue.pop();
active.push(file);
this.parseFile(file, (file) => {
active.splice(active.indexOf(file), 1);
next();
});
}
};
process.nextTick(next);
}
parseFiles(files: File[], callback: () => void): void {
this.fileMap = Object.create(null);
files.forEach((file) => {
this.fileMap[file.fullPath] = file;
});
this.loadReferences(files, () => {
callback();
});
}
private parseFile(file: File, callback: (file: File) => void): void {
fs.readFile(file.filePathWithName, {
encoding: 'utf8',
flag: 'r'
}, (err, content) => {
if (err) {
// just blow up?
throw err;
}
// console.log('----');
// console.log(file.filePathWithName);
hasFile(target: string): boolean {
return target in this.fileMap;
}
file.references = extractReferenceTags(content).map((ref: string) => {
return path.resolve(path.dirname(file.fullPath), ref);
}).reduce((memo: File[], ref: string) => {
if (ref in this.fileMap) {
memo.push(this.fileMap[ref]);
}
else {
console.log('not mapped? -> ' + ref);
}
return memo;
}, []);
getFile(target: string): File {
if (target in this.fileMap) {
return this.fileMap[target];
}
return null;
}
// console.log(file.references);
private loadReferences(files: File[], callback: () => void): void {
var queue = files.slice(0);
var active = [];
var max = 50;
var next = () => {
if (queue.length === 0 && active.length === 0) {
callback();
return;
}
// queue paralel
while (queue.length > 0 && active.length < max) {
var file = queue.pop();
active.push(file);
this.parseFile(file, (file) => {
active.splice(active.indexOf(file), 1);
next();
});
}
};
process.nextTick(next);
}
callback(file);
});
}
}
private parseFile(file: File, callback: (file: File) => void): void {
fs.readFile(file.filePathWithName, {
encoding: 'utf8',
flag: 'r'
}, (err, content) => {
if (err) {
// just blow up?
throw err;
}
// console.log('----');
// console.log(file.filePathWithName);
file.references = extractReferenceTags(content).map((ref: string) => {
return path.resolve(path.dirname(file.fullPath), ref);
}).reduce((memo: File[], ref: string) => {
if (ref in this.fileMap) {
memo.push(this.fileMap[ref]);
}
else {
console.log('not mapped? -> ' + ref);
}
return memo;
}, []);
// console.log(file.references);
callback(file);
});
}
}
}
+87 -85
View File
@@ -2,110 +2,112 @@
/// <reference path="../runner.ts" />
module DT {
/////////////////////////////////
// All the common things that we pring are functions of this class
/////////////////////////////////
export class Print {
'use-strict';
WIDTH = 77;
/////////////////////////////////
// All the common things that we pring are functions of this class
/////////////////////////////////
export class Print {
constructor(public version: string, public typings: number, public tests: number, public tsFiles: number) {
}
WIDTH = 77;
public out(s: any): Print {
process.stdout.write(s);
return this;
}
constructor(public version: string, public typings: number, public tests: number, public tsFiles: number) {
}
public repeat(s: string, times: number): string {
return new Array(times + 1).join(s);
}
public out(s: any): Print {
process.stdout.write(s);
return this;
}
public printHeader() {
this.out('=============================================================================\n');
this.out(' \33[36m\33[1mDefinitelyTyped test runner 0.4.0\33[0m\n');
this.out('=============================================================================\n');
this.out(' \33[36m\33[1mTypescript version:\33[0m ' + this.version + '\n');
this.out(' \33[36m\33[1mTypings :\33[0m ' + this.typings + '\n');
this.out(' \33[36m\33[1mTests :\33[0m ' + this.tests + '\n');
this.out(' \33[36m\33[1mTypeScript files :\33[0m ' + this.tsFiles + '\n');
}
public repeat(s: string, times: number): string {
return new Array(times + 1).join(s);
}
public printSuiteHeader(title: string) {
var left = Math.floor((this.WIDTH - title.length ) / 2) - 1;
var right = Math.ceil((this.WIDTH - title.length ) / 2) - 1;
this.out(this.repeat("=", left)).out(" \33[34m\33[1m");
this.out(title);
this.out("\33[0m ").out(this.repeat("=", right)).printBreak();
}
public printHeader() {
this.out('=============================================================================\n');
this.out(' \33[36m\33[1mDefinitelyTyped test runner 0.4.0\33[0m\n');
this.out('=============================================================================\n');
this.out(' \33[36m\33[1mTypescript version:\33[0m ' + this.version + '\n');
this.out(' \33[36m\33[1mTypings :\33[0m ' + this.typings + '\n');
this.out(' \33[36m\33[1mTests :\33[0m ' + this.tests + '\n');
this.out(' \33[36m\33[1mTypeScript files :\33[0m ' + this.tsFiles + '\n');
}
public printDiv() {
this.out('-----------------------------------------------------------------------------\n');
}
public printSuiteHeader(title: string) {
var left = Math.floor((this.WIDTH - title.length ) / 2) - 1;
var right = Math.ceil((this.WIDTH - title.length ) / 2) - 1;
this.out(this.repeat("=", left)).out(" \33[34m\33[1m");
this.out(title);
this.out("\33[0m ").out(this.repeat("=", right)).printBreak();
}
public printBoldDiv() {
this.out('=============================================================================\n');
}
public printDiv() {
this.out('-----------------------------------------------------------------------------\n');
}
public printErrorsHeader() {
this.out('=============================================================================\n');
this.out(' \33[34m\33[1mErrors in files\33[0m \n');
this.out('=============================================================================\n');
}
public printBoldDiv() {
this.out('=============================================================================\n');
}
public printErrorsForFile(testResult: TestResult) {
this.out('----------------- For file:' + testResult.targetFile.formatName);
this.printBreak().out(testResult.stderr).printBreak();
}
public printErrorsHeader() {
this.out('=============================================================================\n');
this.out(' \33[34m\33[1mErrors in files\33[0m \n');
this.out('=============================================================================\n');
}
public printBreak(): Print {
this.out('\n');
return this;
}
public printErrorsForFile(testResult: TestResult) {
this.out('----------------- For file:' + testResult.targetFile.formatName);
this.printBreak().out(testResult.stderr).printBreak();
}
public clearCurrentLine(): Print {
this.out("\r\33[K");
return this;
}
public printBreak(): Print {
this.out('\n');
return this;
}
public printSuccessCount(current: number, total: number) {
this.out(' \33[36m\33[1mSuccessful :\33[0m \33[32m\33[1m' + ((current / total) * 100).toFixed(2) + '% (' + current + '/' + total + ')\33[0m\n');
}
public clearCurrentLine(): Print {
this.out("\r\33[K");
return this;
}
public printFailedCount(current: number, total: number) {
this.out(' \33[36m\33[1mFailure :\33[0m \33[31m\33[1m' + ((current / total) * 100).toFixed(2) + '% (' + current + '/' + total + ')\33[0m\n');
}
public printSuccessCount(current: number, total: number) {
this.out(' \33[36m\33[1mSuccessful :\33[0m \33[32m\33[1m' + ((current / total) * 100).toFixed(2) + '% (' + current + '/' + total + ')\33[0m\n');
}
public printTypingsWithoutTestsMessage() {
this.out(' \33[36m\33[1mTyping without tests\33[0m\n');
}
public printFailedCount(current: number, total: number) {
this.out(' \33[36m\33[1mFailure :\33[0m \33[31m\33[1m' + ((current / total) * 100).toFixed(2) + '% (' + current + '/' + total + ')\33[0m\n');
}
public printTotalMessage() {
this.out(' \33[36m\33[1mTotal\33[0m\n');
}
public printTypingsWithoutTestsMessage() {
this.out(' \33[36m\33[1mTyping without tests\33[0m\n');
}
public printElapsedTime(time: string, s: number) {
this.out(' \33[36m\33[1mElapsed time :\33[0m ~' + time + ' (' + s + 's)\n');
}
public printTotalMessage() {
this.out(' \33[36m\33[1mTotal\33[0m\n');
}
public printSuiteErrorCount(errorHeadline: string, current: number, total: number, valuesColor = '\33[31m\33[1m') {
this.out(' \33[36m\33[1m').out(errorHeadline).out(this.repeat(' ', 16 - errorHeadline.length));
this.out(':\33[0m ' + valuesColor + ((current / total) * 100).toFixed(2) + '% (' + current + '/' + total + ')\33[0m\n');
}
public printElapsedTime(time: string, s: number) {
this.out(' \33[36m\33[1mElapsed time :\33[0m ~' + time + ' (' + s + 's)\n');
}
public printTypingsWithoutTestName(file: string) {
this.out(' - \33[33m\33[1m' + file + '\33[0m\n');
}
public printSuiteErrorCount(errorHeadline: string, current: number, total: number, valuesColor = '\33[31m\33[1m') {
this.out(' \33[36m\33[1m').out(errorHeadline).out(this.repeat(' ', 16 - errorHeadline.length));
this.out(':\33[0m ' + valuesColor + ((current / total) * 100).toFixed(2) + '% (' + current + '/' + total + ')\33[0m\n');
}
public printTypingsWithoutTest(withoutTestTypings: string[]) {
if (withoutTestTypings.length > 0) {
this.printTypingsWithoutTestsMessage();
public printTypingsWithoutTestName(file: string) {
this.out(' - \33[33m\33[1m' + file + '\33[0m\n');
}
this.printDiv();
withoutTestTypings.forEach((t) => {
this.printTypingsWithoutTestName(t);
});
}
}
}
public printTypingsWithoutTest(withoutTestTypings: string[]) {
if (withoutTestTypings.length > 0) {
this.printTypingsWithoutTestsMessage();
this.printDiv();
withoutTestTypings.forEach((t) => {
this.printTypingsWithoutTestName(t);
});
}
}
}
}
+30 -28
View File
@@ -2,38 +2,40 @@
/// <reference path="../printer.ts" />
module DT {
/////////////////////////////////
// Test reporter interface
// for example, . and x
/////////////////////////////////
export interface ITestReporter {
printPositiveCharacter(index: number, testResult: TestResult):void;
printNegativeCharacter(index: number, testResult: TestResult):void;
}
'use-strict';
/////////////////////////////////
// Default test reporter
/////////////////////////////////
export class DefaultTestReporter implements ITestReporter {
constructor(public print: Print) {
}
/////////////////////////////////
// Test reporter interface
// for example, . and x
/////////////////////////////////
export interface ITestReporter {
printPositiveCharacter(index: number, testResult: TestResult):void;
printNegativeCharacter(index: number, testResult: TestResult):void;
}
public printPositiveCharacter(index: number, testResult: TestResult) {
this.print.out('\33[36m\33[1m' + '.' + '\33[0m');
/////////////////////////////////
// Default test reporter
/////////////////////////////////
export class DefaultTestReporter implements ITestReporter {
constructor(public print: Print) {
}
this.printBreakIfNeeded(index);
}
public printPositiveCharacter(index: number, testResult: TestResult) {
this.print.out('\33[36m\33[1m' + '.' + '\33[0m');
public printNegativeCharacter(index: number, testResult: TestResult) {
this.print.out("x");
this.printBreakIfNeeded(index);
}
this.printBreakIfNeeded(index);
}
public printNegativeCharacter(index: number, testResult: TestResult) {
this.print.out("x");
private printBreakIfNeeded(index: number) {
if (index % this.print.WIDTH === 0) {
this.print.printBreak();
}
}
}
this.printBreakIfNeeded(index);
}
private printBreakIfNeeded(index: number) {
if (index % this.print.WIDTH === 0) {
this.print.printBreak();
}
}
}
}
+71 -68
View File
@@ -1,83 +1,86 @@
/// <reference path="../../runner.ts" />
module DT {
/////////////////////////////////
// The interface for test suite
/////////////////////////////////
export interface ITestSuite {
testSuiteName:string;
errorHeadline:string;
filterTargetFiles(files: File[]):File[];
'use-strict';
start(targetFiles: File[], testCallback: (result: TestResult, index: number) => void, suiteCallback: (suite: ITestSuite) => void):void;
/////////////////////////////////
// The interface for test suite
/////////////////////////////////
export interface ITestSuite {
testSuiteName:string;
errorHeadline:string;
filterTargetFiles(files: File[]):File[];
testResults:TestResult[];
okTests:TestResult[];
ngTests:TestResult[];
timer:Timer;
start(targetFiles: File[], testCallback: (result: TestResult, index: number) => void, suiteCallback: (suite: ITestSuite) => void):void;
testReporter:ITestReporter;
printErrorCount:boolean;
}
testResults:TestResult[];
okTests:TestResult[];
ngTests:TestResult[];
timer:Timer;
/////////////////////////////////
// Base class for test suite
/////////////////////////////////
export class TestSuiteBase implements ITestSuite {
timer: Timer = new Timer();
testResults: TestResult[] = [];
testReporter: ITestReporter;
printErrorCount = true;
testReporter:ITestReporter;
printErrorCount:boolean;
}
constructor(public options: ITestRunnerOptions, public testSuiteName: string, public errorHeadline: string) {
}
/////////////////////////////////
// Base class for test suite
/////////////////////////////////
export class TestSuiteBase implements ITestSuite {
timer: Timer = new Timer();
testResults: TestResult[] = [];
testReporter: ITestReporter;
printErrorCount = true;
public filterTargetFiles(files: File[]): File[] {
throw new Error("please implement this method");
}
constructor(public options: ITestRunnerOptions, public testSuiteName: string, public errorHeadline: string) {
}
public start(targetFiles: File[], testCallback: (result: TestResult, index: number) => void, suiteCallback: (suite: ITestSuite) => void): void {
targetFiles = this.filterTargetFiles(targetFiles);
this.timer.start();
var count = 0;
// exec test is async process. serialize.
var executor = () => {
var targetFile = targetFiles[count];
if (targetFile) {
this.runTest(targetFile, (result) => {
testCallback(result, count + 1);
count++;
executor();
});
} else {
this.timer.end();
this.finish(suiteCallback);
}
};
executor();
}
public filterTargetFiles(files: File[]): File[] {
throw new Error("please implement this method");
}
public runTest(targetFile: File, callback: (result: TestResult) => void): void {
new Test(this, targetFile, {tscVersion: this.options.tscVersion}).run((result) => {
this.testResults.push(result);
callback(result);
});
}
public start(targetFiles: File[], testCallback: (result: TestResult, index: number) => void, suiteCallback: (suite: ITestSuite) => void): void {
targetFiles = this.filterTargetFiles(targetFiles);
this.timer.start();
var count = 0;
// exec test is async process. serialize.
var executor = () => {
var targetFile = targetFiles[count];
if (targetFile) {
this.runTest(targetFile, (result) => {
testCallback(result, count + 1);
count++;
executor();
});
}
else {
this.timer.end();
this.finish(suiteCallback);
}
};
executor();
}
public finish(suiteCallback: (suite: ITestSuite) => void) {
suiteCallback(this);
}
public runTest(targetFile: File, callback: (result: TestResult) => void): void {
new Test(this, targetFile, {tscVersion: this.options.tscVersion}).run((result) => {
this.testResults.push(result);
callback(result);
});
}
public get okTests(): TestResult[] {
return this.testResults.filter((r) => {
return r.success;
});
}
public finish(suiteCallback: (suite: ITestSuite) => void) {
suiteCallback(this);
}
public get ngTests(): TestResult[] {
return this.testResults.filter((r) => {
return !r.success
});
}
}
public get okTests(): TestResult[] {
return this.testResults.filter((r) => {
return r.success;
});
}
public get ngTests(): TestResult[] {
return this.testResults.filter((r) => {
return !r.success
});
}
}
}
+15 -13
View File
@@ -2,19 +2,21 @@
/// <reference path="../util.ts" />
module DT {
/////////////////////////////////
// .d.ts syntax inspection
/////////////////////////////////
export class SyntaxChecking extends TestSuiteBase {
'use-strict';
constructor(options: ITestRunnerOptions) {
super(options, "Syntax checking", "Syntax error");
}
/////////////////////////////////
// .d.ts syntax inspection
/////////////////////////////////
export class SyntaxChecking extends TestSuiteBase {
public filterTargetFiles(files: File[]): File[] {
return files.filter((file) => {
return DT.endsWith(file.formatName.toUpperCase(), '.D.TS');
});
}
}
constructor(options: ITestRunnerOptions) {
super(options, "Syntax checking", "Syntax error");
}
public filterTargetFiles(files: File[]): File[] {
return files.filter((file) => {
return DT.endsWith(file.formatName.toUpperCase(), '.D.TS');
});
}
}
}
+14 -13
View File
@@ -2,20 +2,21 @@
/// <reference path="../util.ts" />
module DT {
/////////////////////////////////
// Compile with *-tests.ts
/////////////////////////////////
export class TestEval extends TestSuiteBase {
'use-strict';
/////////////////////////////////
// Compile with *-tests.ts
/////////////////////////////////
export class TestEval extends TestSuiteBase {
constructor(options) {
super(options, "Typing tests", "Failed tests");
}
constructor(options) {
super(options, "Typing tests", "Failed tests");
}
public filterTargetFiles(files: File[]): File[] {
return files.filter((file) => {
return DT.endsWith(file.formatName.toUpperCase(), '-TESTS.TS')
});
}
}
public filterTargetFiles(files: File[]): File[] {
return files.filter((file) => {
return DT.endsWith(file.formatName.toUpperCase(), '-TESTS.TS')
});
}
}
}
+47 -45
View File
@@ -2,56 +2,58 @@
/// <reference path="../file.ts" />
module DT {
var fs = require('fs');
'use-strict';
/////////////////////////////////
// Try compile without .tscparams
// It may indicate that it is compatible with --noImplicitAny maybe...
/////////////////////////////////
export class FindNotRequiredTscparams extends TestSuiteBase {
testReporter: ITestReporter;
printErrorCount = false;
var fs = require('fs');
constructor(options: ITestRunnerOptions, private print: Print) {
super(options, "Find not required .tscparams files", "New arrival!");
/////////////////////////////////
// Try compile without .tscparams
// It may indicate that it is compatible with --noImplicitAny maybe...
/////////////////////////////////
export class FindNotRequiredTscparams extends TestSuiteBase {
testReporter: ITestReporter;
printErrorCount = false;
this.testReporter = {
printPositiveCharacter: (index: number, testResult: TestResult) => {
this.print
.clearCurrentLine()
.printTypingsWithoutTestName(testResult.targetFile.formatName);
},
printNegativeCharacter: (index: number, testResult: TestResult) => {
}
}
}
constructor(options: ITestRunnerOptions, private print: Print) {
super(options, "Find not required .tscparams files", "New arrival!");
public filterTargetFiles(files: File[]): File[] {
return files.filter((file) => {
return fs.existsSync(file.filePathWithName + '.tscparams');
});
}
this.testReporter = {
printPositiveCharacter: (index: number, testResult: TestResult) => {
this.print
.clearCurrentLine()
.printTypingsWithoutTestName(testResult.targetFile.formatName);
},
printNegativeCharacter: (index: number, testResult: TestResult) => {
}
}
}
public runTest(targetFile: File, callback: (result: TestResult) => void): void {
this.print.clearCurrentLine().out(targetFile.formatName);
new Test(this, targetFile, {
tscVersion: this.options.tscVersion,
useTscParams: false,
checkNoImplicitAny: true
}).run(result=> {
this.testResults.push(result);
callback(result);
});
}
public filterTargetFiles(files: File[]): File[] {
return files.filter((file) => {
return fs.existsSync(file.filePathWithName + '.tscparams');
});
}
public finish(suiteCallback: (suite: ITestSuite)=>void) {
this.print.clearCurrentLine();
suiteCallback(this);
}
public runTest(targetFile: File, callback: (result: TestResult) => void): void {
this.print.clearCurrentLine().out(targetFile.formatName);
new Test(this, targetFile, {
tscVersion: this.options.tscVersion,
useTscParams: false,
checkNoImplicitAny: true
}).run(result=> {
this.testResults.push(result);
callback(result);
});
}
public get ngTests(): TestResult[] {
// Do not show ng test results
return [];
}
}
public finish(suiteCallback: (suite: ITestSuite)=>void) {
this.print.clearCurrentLine();
suiteCallback(this);
}
public get ngTests(): TestResult[] {
// Do not show ng test results
return [];
}
}
}
+38 -36
View File
@@ -2,46 +2,48 @@
/// <reference path="../runner.ts" />
module DT {
/////////////////////////////////
// Timer.start starts a timer
// Timer.end stops the timer and sets asString to the pretty print value
/////////////////////////////////
export class Timer {
startTime: number;
time = 0;
asString: string;
'use-strict';
public start() {
this.time = 0;
this.startTime = this.now();
}
/////////////////////////////////
// Timer.start starts a timer
// Timer.end stops the timer and sets asString to the pretty print value
/////////////////////////////////
export class Timer {
startTime: number;
time = 0;
asString: string;
public now(): number {
return Date.now();
}
public start() {
this.time = 0;
this.startTime = this.now();
}
public end() {
this.time = (this.now() - this.startTime) / 1000;
this.asString = Timer.prettyDate(this.startTime, this.now());
}
public now(): number {
return Date.now();
}
public static prettyDate(date1: number, date2: number): string {
var diff = ((date2 - date1) / 1000);
var day_diff = Math.floor(diff / 86400);
public end() {
this.time = (this.now() - this.startTime) / 1000;
this.asString = Timer.prettyDate(this.startTime, this.now());
}
if (isNaN(day_diff) || day_diff < 0 || day_diff >= 31) {
return null;
}
public static prettyDate(date1: number, date2: number): string {
var diff = ((date2 - date1) / 1000);
var day_diff = Math.floor(diff / 86400);
return (<string><any> (day_diff == 0 && (
diff < 60 && (diff + " seconds") ||
diff < 120 && "1 minute" ||
diff < 3600 && Math.floor(diff / 60) + " minutes" ||
diff < 7200 && "1 hour" ||
diff < 86400 && Math.floor(diff / 3600) + " hours") ||
day_diff == 1 && "Yesterday" ||
day_diff < 7 && day_diff + " days" ||
day_diff < 31 && Math.ceil(day_diff / 7) + " weeks"));
}
}
if (isNaN(day_diff) || day_diff < 0 || day_diff >= 31) {
return null;
}
return (<string><any> (day_diff == 0 && (
diff < 60 && (diff + " seconds") ||
diff < 120 && "1 minute" ||
diff < 3600 && Math.floor(diff / 60) + " minutes" ||
diff < 7200 && "1 hour" ||
diff < 86400 && Math.floor(diff / 3600) + " hours") ||
day_diff == 1 && "Yesterday" ||
day_diff < 7 && day_diff + " days" ||
day_diff < 31 && Math.ceil(day_diff / 7) + " weeks"));
}
}
}
+36 -34
View File
@@ -3,42 +3,44 @@
/// <reference path="host/exec.ts" />
module DT {
var fs = require('fs');
'use-strict';
var fs = require('fs');
export interface TscExecOptions {
tscVersion?:string;
useTscParams?:boolean;
checkNoImplicitAny?:boolean;
}
export interface TscExecOptions {
tscVersion?:string;
useTscParams?:boolean;
checkNoImplicitAny?:boolean;
}
export class Tsc {
public static run(tsfile: string, options: TscExecOptions, callback: (result: ExecResult) => void) {
options = options || {};
options.tscVersion = options.tscVersion || DEFAULT_TSC_VERSION;
if (typeof options.checkNoImplicitAny === "undefined") {
options.checkNoImplicitAny = true;
}
if (typeof options.useTscParams === "undefined") {
options.useTscParams = true;
}
export class Tsc {
public static run(tsfile: string, options: TscExecOptions, callback: (result: ExecResult) => void) {
options = options || {};
options.tscVersion = options.tscVersion || DEFAULT_TSC_VERSION;
if (typeof options.checkNoImplicitAny === "undefined") {
options.checkNoImplicitAny = true;
}
if (typeof options.useTscParams === "undefined") {
options.useTscParams = true;
}
if (!fs.existsSync(tsfile)) {
throw new Error(tsfile + " not exists");
}
if (!fs.existsSync(tsfile)) {
throw new Error(tsfile + " not exists");
}
var tscPath = './_infrastructure/tests/typescript/' + options.tscVersion + '/tsc.js';
if (!fs.existsSync(tscPath)) {
throw new Error(tscPath + ' is not exists');
}
var command = 'node ' + tscPath + ' --module commonjs ';
if (options.useTscParams && fs.existsSync(tsfile + '.tscparams')) {
command += '@' + tsfile + '.tscparams';
} else if (options.checkNoImplicitAny) {
command += '--noImplicitAny';
}
Exec.exec(command, [tsfile], (execResult) => {
callback(execResult);
});
}
}
var tscPath = './_infrastructure/tests/typescript/' + options.tscVersion + '/tsc.js';
if (!fs.existsSync(tscPath)) {
throw new Error(tscPath + ' is not exists');
}
var command = 'node ' + tscPath + ' --module commonjs ';
if (options.useTscParams && fs.existsSync(tsfile + '.tscparams')) {
command += '@' + tsfile + '.tscparams';
}
else if (options.checkNoImplicitAny) {
command += '--noImplicitAny';
}
Exec.exec(command, [tsfile], (execResult) => {
callback(execResult);
});
}
}
}
+19 -18
View File
@@ -1,27 +1,28 @@
/// <reference path="../_ref.d.ts" />
module DT {
'use-strict';
var referenceTagExp = /<reference[ \t]*path=["']?([\w\.\/_-]*)["']?[ \t]*\/>/g;
var referenceTagExp = /<reference[ \t]*path=["']?([\w\.\/_-]*)["']?[ \t]*\/>/g;
export function endsWith(str: string, suffix: string) {
return str.indexOf(suffix, str.length - suffix.length) !== -1;
}
export function endsWith(str: string, suffix: string) {
return str.indexOf(suffix, str.length - suffix.length) !== -1;
}
export function extractReferenceTags(source: string): string[] {
var ret: string[] = [];
var match: RegExpExecArray;
export function extractReferenceTags(source: string): string[] {
var ret: string[] = [];
var match: RegExpExecArray;
if (!referenceTagExp.global) {
throw new Error('referenceTagExp RegExp must have global flag');
}
referenceTagExp.lastIndex = 0;
if (!referenceTagExp.global) {
throw new Error('referenceTagExp RegExp must have global flag');
}
referenceTagExp.lastIndex = 0;
while ((match = referenceTagExp.exec(source))) {
if (match.length > 0 && match[1].length > 0) {
ret.push(match[1]);
}
}
return ret;
}
while ((match = referenceTagExp.exec(source))) {
if (match.length > 0 && match[1].length > 0) {
ret.push(match[1]);
}
}
return ret;
}
}