split runner code over files

main file got cumbersome
- extracted parts to own files
- still one --out file
- existing code into DT module
cleaned some syntax and lint
expanded arrow-functions to full form
builds using 0.9.7
This commit is contained in:
Bart van der Schoor
2014-02-28 20:27:32 +01:00
parent bac5b43114
commit 513db1d6ad
17 changed files with 1288 additions and 1668 deletions
File diff suppressed because it is too large Load Diff
+93 -454
View File
@@ -1,60 +1,33 @@
/// <reference path='../../node/node.d.ts' />
/// <reference path='src/exec.ts' />
/// <reference path='src/io.ts' />
/// <reference path='src/host/exec.ts' />
/// <reference path='src/host/io.ts' />
module DefinitelyTyped.TestManager {
/// <reference path='src/file.ts' />
/// <reference path='src/tsc.ts' />
/// <reference path='src/timer.ts' />
/// <reference path="src/util.ts" />
/// <reference path='src/printer.ts' />
/// <reference path='src/reporter/reporter.ts' />
/// <reference path='src/suite/suite.ts' />
/// <reference path='src/suite/syntax.ts' />
/// <reference path='src/suite/testEval.ts' />
/// <reference path='src/suite/tscParams.ts' />
module DT {
var fs = require('fs');
var path = require('path');
export var DEFAULT_TSC_VERSION = "0.9.1.1";
function endsWith(str:string, suffix:string) {
return str.indexOf(suffix, str.length - suffix.length) !== -1;
}
export interface TscExecOptions {
tscVersion?:string;
useTscParams?:boolean;
checkNoImplicitAny?:boolean;
}
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 (!IO.fileExists(tsfile)) {
throw new Error(tsfile + " not exists");
}
var tscPath = './_infrastructure/tests/typescript/' + options.tscVersion + '/tsc.js';
if (!IO.fileExists(tscPath)) {
throw new Error(tscPath + ' is not exists');
}
var command = 'node ' + tscPath + ' --module commonjs ';
if (options.useTscParams && IO.fileExists(tsfile + '.tscparams')) {
command += '@' + tsfile + '.tscparams';
} else if (options.checkNoImplicitAny) {
command += '--noImplicitAny';
}
Exec.exec(command, [tsfile], (execResult) => {
callback(execResult);
});
}
}
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)=> {
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;
@@ -68,380 +41,22 @@ module DefinitelyTyped.TestManager {
});
}
}
/////////////////////////////////
// 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 start() {
this.time = 0;
this.startTime = this.now();
}
public now():number {
return Date.now();
}
public end() {
this.time = (this.now() - this.startTime) / 1000;
this.asString = Timer.prettyDate(this.startTime, this.now());
}
public static prettyDate(date1:number, date2:number):string {
var diff = ((date2 - date1) / 1000),
day_diff = Math.floor(diff / 86400);
if (isNaN(day_diff) || day_diff < 0 || day_diff >= 31)
return;
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");
}
}
/////////////////////////////////
// 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;
constructor(public baseDir:string, public filePathWithName:string) {
var dirName = path.dirname(this.filePathWithName.substr(this.baseDir.length + 1)).replace('\\', '/');
this.dir = dirName.split('/')[0];
this.file = path.basename(this.filePathWithName, '.ts');
this.ext = path.extname(this.filePathWithName);
}
// From '/complete/path/to/file' to 'specfolder/specfile.d.ts'
public get formatName():string {
var dirName = path.dirname(this.filePathWithName.substr(this.baseDir.length + 1)).replace('\\', '/');
return this.dir + ((dirName.split('/').length > 1) ? '/-/' : '/') + this.file + this.ext;
}
}
/////////////////////////////////
// Test results
/////////////////////////////////
export class TestResult {
hostedBy:ITestSuite;
targetFile:File;
options:TscExecOptions;
hostedBy: ITestSuite;
targetFile: File;
options: TscExecOptions;
stdout:string;
stderr:string;
exitCode:number;
stdout: string;
stderr: string;
exitCode: number;
public get success():boolean {
public get success(): boolean {
return this.exitCode === 0;
}
}
/////////////////////////////////
// The interface for test suite
/////////////////////////////////
export interface ITestSuite {
testSuiteName:string;
errorHeadline:string;
filterTargetFiles(files:File[]):File[];
start(targetFiles:File[], testCallback:(result:TestResult, index:number)=>void, suiteCallback:(suite:ITestSuite)=>void):void;
testResults:TestResult[];
okTests:TestResult[];
ngTests:TestResult[];
timer:Timer;
testReporter:ITestReporter;
printErrorCount:boolean;
}
/////////////////////////////////
// Test reporter interface
// for example, . and x
/////////////////////////////////
export interface ITestReporter {
printPositiveCharacter(index:number, testResult:TestResult):void;
printNegativeCharacter(index:number, testResult:TestResult):void;
}
/////////////////////////////////
// Default test reporter
/////////////////////////////////
class DefaultTestReporter implements ITestReporter {
constructor(public print:Print) {
}
public printPositiveCharacter(index:number, testResult:TestResult) {
this.print.out('\33[36m\33[1m' + '.' + '\33[0m');
this.printBreakIfNeeded(index);
}
public printNegativeCharacter(index:number, testResult:TestResult) {
this.print.out("x");
this.printBreakIfNeeded(index);
}
private printBreakIfNeeded(index:number) {
if (index % this.print.WIDTH === 0) {
this.print.printBreak();
}
}
}
/////////////////////////////////
// All the common things that we pring are functions of this class
/////////////////////////////////
class Print {
WIDTH = 77;
constructor(public version:string, public typings:number, public tests:number, public tsFiles:number) {
}
public out(s:any):Print {
process.stdout.write(s);
return this;
}
public repeat(s:string, times:number):string {
return new Array(times + 1).join(s);
}
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 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 printDiv() {
this.out('-----------------------------------------------------------------------------\n');
}
public printBoldDiv() {
this.out('=============================================================================\n');
}
public printErrorsHeader() {
this.out('=============================================================================\n');
this.out(' \33[34m\33[1mErrors in files\33[0m \n');
this.out('=============================================================================\n');
}
public printErrorsForFile(testResult:TestResult) {
this.out('----------------- For file:' + testResult.targetFile.formatName);
this.printBreak().out(testResult.stderr).printBreak();
}
public printBreak():Print {
this.out('\n');
return this;
}
public clearCurrentLine():Print {
this.out("\r\33[K");
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 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 printTypingsWithoutTestsMessage() {
this.out(' \33[36m\33[1mTyping without tests\33[0m\n');
}
public printTotalMessage() {
this.out(' \33[36m\33[1mTotal\33[0m\n');
}
public printElapsedTime(time:string, s:number) {
this.out(' \33[36m\33[1mElapsed time :\33[0m ~' + time + ' (' + s + 's)\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 printTypingsWithoutTestName(file:string) {
this.out(' - \33[33m\33[1m' + file + '\33[0m\n');
}
public printTypingsWithoutTest(withoutTestTypings:string[]) {
if (withoutTestTypings.length > 0) {
this.printTypingsWithoutTestsMessage();
this.printDiv();
withoutTestTypings.forEach(t=> {
this.printTypingsWithoutTestName(t);
});
}
}
}
/////////////////////////////////
// Base class for test suite
/////////////////////////////////
class TestSuiteBase implements ITestSuite {
timer:Timer = new Timer();
testResults:TestResult[] = [];
testReporter:ITestReporter;
printErrorCount = true;
constructor(public options:ITestRunnerOptions, public testSuiteName:string, public errorHeadline:string) {
}
public filterTargetFiles(files:File[]):File[] {
throw new Error("please implement this method");
}
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 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 finish(suiteCallback:(suite:ITestSuite)=>void) {
suiteCallback(this);
}
public get okTests():TestResult[] {
return this.testResults.filter(r=>r.success);
}
public get ngTests():TestResult[] {
return this.testResults.filter(r=>!r.success);
}
}
/////////////////////////////////
// .d.ts syntax inspection
/////////////////////////////////
class SyntaxChecking extends TestSuiteBase {
constructor(options:ITestRunnerOptions) {
super(options, "Syntax checking", "Syntax error");
}
public filterTargetFiles(files:File[]):File[] {
return files.filter(file => endsWith(file.formatName.toUpperCase(), '.D.TS'));
}
}
/////////////////////////////////
// Compile with *-tests.ts
/////////////////////////////////
class TestEval extends TestSuiteBase {
constructor(options) {
super(options, "Typing tests", "Failed tests");
}
public filterTargetFiles(files:File[]):File[] {
return files.filter(file => endsWith(file.formatName.toUpperCase(), '-TESTS.TS'));
}
}
/////////////////////////////////
// Try compile without .tscparams
// It may indicate that it is compatible with --noImplicitAny maybe...
/////////////////////////////////
class FindNotRequiredTscparams extends TestSuiteBase {
testReporter:ITestReporter;
printErrorCount = false;
constructor(options:ITestRunnerOptions, private print:Print) {
super(options, "Find not required .tscparams files", "New arrival!");
this.testReporter = {
printPositiveCharacter: (index:number, testResult:TestResult)=> {
this.print
.clearCurrentLine()
.printTypingsWithoutTestName(testResult.targetFile.formatName);
},
printNegativeCharacter: (index:number, testResult:TestResult)=> {
}
}
}
public filterTargetFiles(files:File[]):File[] {
return files.filter(file=> IO.fileExists(file.filePathWithName + '.tscparams'));
}
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 finish(suiteCallback:(suite:ITestSuite)=>void) {
this.print.clearCurrentLine();
suiteCallback(this);
}
public get ngTests():TestResult[] {
// Do not show ng test results
return [];
}
}
export interface ITestRunnerOptions {
tscVersion:string;
findNotRequiredTscparams?:boolean;
@@ -451,23 +66,31 @@ module DefinitelyTyped.TestManager {
// The main class to kick things off
/////////////////////////////////
export class TestRunner {
files:File[];
timer:Timer;
suites:ITestSuite[] = [];
private print:Print;
files: File[];
timer: Timer;
suites: ITestSuite[] = [];
private print: Print;
constructor(dtPath:string, public options:ITestRunnerOptions = {tscVersion: DEFAULT_TSC_VERSION}) {
constructor(dtPath: string, public options: ITestRunnerOptions = {tscVersion: DT.DEFAULT_TSC_VERSION}) {
this.options.findNotRequiredTscparams = !!this.options.findNotRequiredTscparams;
var filesName = IO.dir(dtPath, /.\.ts/g, { recursive: true }).sort();
// only includes .d.ts or -tests.ts or -test.ts or .ts
filesName = filesName
.filter(fileName => fileName.indexOf('../_infrastructure') < 0)
.filter(fileName => !endsWith(fileName, ".tscparams"));
this.files = filesName.map(fileName => new File(dtPath, fileName));
this.files = filesName
.filter((fileName) => {
return fileName.indexOf('../_infrastructure') < 0;
})
.filter((fileName) => {
return fileName.indexOf('../node_modules') < 0;
})
.filter((fileName) => {
return !DT.endsWith(fileName, ".tscparams");
}).map((fileName) => {
return new File(dtPath, fileName);
});
}
public addSuite(suite:ITestSuite) {
public addSuite(suite: ITestSuite) {
this.suites.push(suite);
}
@@ -504,7 +127,7 @@ module DefinitelyTyped.TestManager {
(testResult, index) => {
this.testCompleteCallback(testResult, index);
},
suite=> {
(suite) => {
this.suiteCompleteCallback(suite);
count++;
executor();
@@ -517,7 +140,7 @@ module DefinitelyTyped.TestManager {
executor();
}
private testCompleteCallback(testResult:TestResult, index:number) {
private testCompleteCallback(testResult: TestResult, index: number) {
var reporter = testResult.hostedBy.testReporter;
if (testResult.success) {
reporter.printPositiveCharacter(index, testResult);
@@ -526,7 +149,7 @@ module DefinitelyTyped.TestManager {
}
}
private suiteCompleteCallback(suite:ITestSuite) {
private suiteCompleteCallback(suite: ITestSuite) {
this.print.printBreak();
this.print.printDiv();
@@ -536,16 +159,26 @@ module DefinitelyTyped.TestManager {
}
private allTestCompleteCallback() {
var testEval = this.suites.filter(suite=>suite instanceof TestEval)[0];
var testEval = this.suites.filter(suite => suite instanceof TestEval)[0];
if (testEval) {
var existsTestTypings:string[] = testEval.testResults
.map(testResult=>testResult.targetFile.dir)
.reduce((a, b)=> a.indexOf(b) < 0 ? a.concat([b]) : a, []);
var typings:string[] = this.files
.map(file=>file.dir)
.reduce((a, b)=> a.indexOf(b) < 0 ? a.concat([b]) : a, []);
var withoutTestTypings:string[] = typings
.filter(typing=>existsTestTypings.indexOf(typing) < 0);
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);
}
@@ -556,8 +189,10 @@ module DefinitelyTyped.TestManager {
this.print.printDiv();
this.print.printElapsedTime(this.timer.asString, this.timer.time);
this.suites
.filter(suite=>suite.printErrorCount)
.forEach(suite=> {
.filter((suite: ITestSuite) => {
return suite.printErrorCount;
})
.forEach((suite: ITestSuite) => {
this.print.printSuiteErrorCount(suite.errorHeadline, suite.ngTests.length, suite.testResults.length);
});
if (testEval) {
@@ -565,13 +200,17 @@ module DefinitelyTyped.TestManager {
}
this.print.printDiv();
if (this.suites.some(suite=>suite.ngTests.length !== 0)) {
if (this.suites.some((suite) => {
return suite.ngTests.length !== 0
})) {
this.print.printErrorsHeader();
this.suites
.filter(suite=>suite.ngTests.length !== 0)
.forEach(suite=> {
suite.ngTests.forEach(testResult => {
.filter((suite) => {
return suite.ngTests.length !== 0;
})
.forEach((suite) => {
suite.ngTests.forEach((testResult) => {
this.print.printErrorsForFile(testResult);
});
this.print.printBoldDiv();
@@ -581,18 +220,18 @@ module DefinitelyTyped.TestManager {
}
}
}
}
var dtPath = __dirname + '/../..';
var findNotRequiredTscparams = process.argv.some(arg=>arg == "--try-without-tscparams");
var tscVersionIndex = process.argv.indexOf("--tsc-version");
var tscVersion = DefinitelyTyped.TestManager.DEFAULT_TSC_VERSION;
if (-1 < tscVersionIndex) {
tscVersion = process.argv[tscVersionIndex + 1];
}
var dtPath = __dirname + '/../..';
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];
}
var runner = new DefinitelyTyped.TestManager.TestRunner(dtPath, {
tscVersion: tscVersion,
findNotRequiredTscparams: findNotRequiredTscparams
});
runner.run();
var runner = new TestRunner(dtPath, {
tscVersion: tscVersion,
findNotRequiredTscparams: findNotRequiredTscparams
});
runner.run();
}
-79
View File
@@ -1,79 +0,0 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
var ExecResult = (function () {
function ExecResult() {
this.stdout = "";
this.stderr = "";
}
return ExecResult;
})();
var WindowsScriptHostExec = (function () {
function WindowsScriptHostExec() {
}
WindowsScriptHostExec.prototype.exec = function (filename, cmdLineArgs, handleResult) {
var result = new ExecResult();
var shell = new ActiveXObject('WScript.Shell');
try {
var process = shell.Exec(filename + ' ' + cmdLineArgs.join(' '));
} catch (e) {
result.stderr = e.message;
result.exitCode = 1;
handleResult(result);
return;
}
while (process.Status != 0) {
}
result.exitCode = process.ExitCode;
if (!process.StdOut.AtEndOfStream)
result.stdout = process.StdOut.ReadAll();
if (!process.StdErr.AtEndOfStream)
result.stderr = process.StdErr.ReadAll();
handleResult(result);
};
return WindowsScriptHostExec;
})();
var NodeExec = (function () {
function NodeExec() {
}
NodeExec.prototype.exec = function (filename, cmdLineArgs, handleResult) {
var nodeExec = require('child_process').exec;
var result = new ExecResult();
result.exitCode = null;
var cmdLine = filename + ' ' + cmdLineArgs.join(' ');
var process = nodeExec(cmdLine, function (error, stdout, stderr) {
result.stdout = stdout;
result.stderr = stderr;
result.exitCode = error ? error.code : 0;
handleResult(result);
});
};
return NodeExec;
})();
var Exec = (function () {
var global = Function("return this;").call(null);
if (typeof global.ActiveXObject !== "undefined") {
return new WindowsScriptHostExec();
} else {
return new NodeExec();
}
})();
+26
View File
@@ -0,0 +1,26 @@
module DT {
var path = require('path');
/////////////////////////////////
// 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;
constructor(public baseDir: string, public filePathWithName: string) {
var dirName = path.dirname(this.filePathWithName.substr(this.baseDir.length + 1)).replace('\\', '/');
this.dir = dirName.split('/')[0];
this.file = path.basename(this.filePathWithName, '.ts');
this.ext = path.extname(this.filePathWithName);
}
// From '/complete/path/to/file' to 'specfolder/specfile.d.ts'
public get formatName(): string {
var dirName = path.dirname(this.filePathWithName.substr(this.baseDir.length + 1)).replace('\\', '/');
return this.dir + ((dirName.split('/').length > 1) ? '/-/' : '/') + this.file + this.ext;
}
}
}
@@ -18,8 +18,6 @@ interface IExec {
exec: (filename: string, cmdLineArgs: string[], handleResult: (ExecResult) => void) => void;
}
declare var require;
class ExecResult {
public stdout = "";
public stderr = "";
@@ -27,31 +25,31 @@ class ExecResult {
}
class WindowsScriptHostExec implements IExec {
public exec(filename: string, cmdLineArgs: string[], handleResult: (ExecResult) => void) : void {
public exec(filename: string, cmdLineArgs: string[], handleResult: (ExecResult) => void): void {
var result = new ExecResult();
var shell = new ActiveXObject('WScript.Shell');
try {
var process = shell.Exec(filename + ' ' + cmdLineArgs.join(' '));
} catch(e) {
} catch (e) {
result.stderr = e.message;
result.exitCode = 1
handleResult(result);
return;
}
// Wait for it to finish running
while (process.Status != 0) { /* todo: sleep? */ }
while (process.Status != 0) { /* todo: sleep? */
}
result.exitCode = process.ExitCode;
if(!process.StdOut.AtEndOfStream) result.stdout = process.StdOut.ReadAll();
if(!process.StdErr.AtEndOfStream) result.stderr = process.StdErr.ReadAll();
if (!process.StdOut.AtEndOfStream) result.stdout = process.StdOut.ReadAll();
if (!process.StdErr.AtEndOfStream) result.stderr = process.StdErr.ReadAll();
handleResult(result);
}
}
class NodeExec implements IExec {
public exec(filename: string, cmdLineArgs: string[], handleResult: (ExecResult) => void) : void {
public exec(filename: string, cmdLineArgs: string[], handleResult: (ExecResult) => void): void {
var nodeExec = require('child_process').exec;
var result = new ExecResult();
@@ -67,11 +65,11 @@ class NodeExec implements IExec {
}
}
var Exec: IExec = function() : IExec {
var Exec: IExec = function (): IExec {
var global = <any>Function("return this;").call(null);
if(typeof global.ActiveXObject !== "undefined") {
if (typeof global.ActiveXObject !== "undefined") {
return new WindowsScriptHostExec();
} else {
return new NodeExec();
}
}();
}();
@@ -27,7 +27,8 @@ interface IIO {
writeFile(path: string, contents: string): void;
createFile(path: string, useUTF8?: boolean): ITextWriter;
deleteFile(path: string): void;
dir(path: string, re?: RegExp, options?: { recursive?: boolean; deep?: number; }): string[];
dir(path: string, re?: RegExp, options?: { recursive?: boolean; deep?: number;
}): string[];
fileExists(path: string): boolean;
directoryExists(path: string): boolean;
createDirectory(path: string): void;
@@ -39,7 +40,7 @@ interface IIO {
arguments: string[];
stderr: ITextWriter;
stdout: ITextWriter;
watchFile(filename: string, callback: (string) => void ): IFileWatcher;
watchFile(filename: string, callback: (string) => void): IFileWatcher;
run(source: string, filename: string): void;
getExecutingFilePath(): string;
quit(exitCode?: number);
@@ -79,9 +80,12 @@ module IOUtils {
// Declare dependencies needed for all supported hosts
declare class Enumerator {
public atEnd(): boolean;
public moveNext();
public item(): any;
constructor (o: any);
constructor(o: any);
}
// Missing in node definitions, but called in code below.
@@ -91,7 +95,7 @@ interface NodeProcess {
}
}
var IO = (function() {
var IO = (function () {
// Create an IO object for use inside WindowsScriptHost hosts
// Depends on WSCript and FileSystemObject
@@ -99,15 +103,15 @@ var IO = (function() {
var fso = new ActiveXObject("Scripting.FileSystemObject");
var streamObjectPool = [];
function getStreamObject(): any {
function getStreamObject(): any {
if (streamObjectPool.length > 0) {
return streamObjectPool.pop();
} else {
} else {
return new ActiveXObject("ADODB.Stream");
}
}
function releaseStreamObject(obj: any) {
function releaseStreamObject(obj: any) {
streamObjectPool.push(obj);
}
@@ -117,7 +121,7 @@ var IO = (function() {
}
return {
readFile: function(path) {
readFile: function (path) {
try {
var streamObj = getStreamObject();
streamObj.Open();
@@ -130,7 +134,7 @@ var IO = (function() {
|| (bomChar.charCodeAt(0) == 0xFF && bomChar.charCodeAt(1) == 0xFE)) {
streamObj.Charset = 'unicode';
} else if (bomChar.charCodeAt(0) == 0xEF && bomChar.charCodeAt(1) == 0xBB) {
streamObj.Charset = 'utf-8';
streamObj.Charset = 'utf-8';
}
// Read the whole file
@@ -144,25 +148,25 @@ var IO = (function() {
}
},
writeFile: function(path, contents) {
writeFile: function (path, contents) {
var file = this.createFile(path);
file.Write(contents);
file.Close();
},
fileExists: function(path: string): boolean {
fileExists: function (path: string): boolean {
return fso.FileExists(path);
},
resolvePath: function(path: string): string {
resolvePath: function (path: string): string {
return fso.GetAbsolutePathName(path);
},
dirName: function(path: string): string {
dirName: function (path: string): string {
return fso.GetParentFolderName(path);
},
findFile: function(rootPath: string, partialFilePath: string): IResolvedFile {
findFile: function (rootPath: string, partialFilePath: string): IResolvedFile {
var path = fso.GetAbsolutePathName(rootPath) + "/" + partialFilePath;
while (true) {
@@ -188,7 +192,7 @@ var IO = (function() {
}
},
deleteFile: function(path: string): void {
deleteFile: function (path: string): void {
try {
if (fso.FileExists(path)) {
fso.DeleteFile(path, true); // true: delete read-only files
@@ -204,9 +208,13 @@ var IO = (function() {
streamObj.Charset = useUTF8 ? 'utf-8' : 'x-ansi';
streamObj.Open();
return {
Write: function (str) { streamObj.WriteText(str, 0); },
WriteLine: function (str) { streamObj.WriteText(str, 1); },
Close: function() {
Write: function (str) {
streamObj.WriteText(str, 0);
},
WriteLine: function (str) {
streamObj.WriteText(str, 1);
},
Close: function () {
try {
streamObj.SaveToFile(path, 2);
} catch (saveError) {
@@ -225,11 +233,11 @@ var IO = (function() {
}
},
directoryExists: function(path) {
directoryExists: function (path) {
return <boolean>fso.FolderExists(path);
},
createDirectory: function(path) {
createDirectory: function (path) {
try {
if (!this.directoryExists(path)) {
fso.CreateFolder(path);
@@ -239,23 +247,24 @@ var IO = (function() {
}
},
dir: function(path, spec?, options?) {
options = options || <{ recursive?: boolean; deep?: number; }>{};
function filesInFolder(folder, root): string[]{
dir: function (path, spec?, options?) {
options = options || <{ recursive?: boolean; deep?: number;
}>{};
function filesInFolder(folder, root): string[] {
var paths = [];
var fc: Enumerator;
if (options.recursive) {
fc = new Enumerator(folder.subfolders);
for (; !fc.atEnd() ; fc.moveNext()) {
for (; !fc.atEnd(); fc.moveNext()) {
paths = paths.concat(filesInFolder(fc.item(), root + "/" + fc.item().Name));
}
}
fc = new Enumerator(folder.files);
for (; !fc.atEnd() ; fc.moveNext()) {
for (; !fc.atEnd(); fc.moveNext()) {
if (!spec || fc.item().Name.match(spec)) {
paths.push(root + "/" + fc.item().Name);
}
@@ -270,11 +279,11 @@ var IO = (function() {
return filesInFolder(folder, path);
},
print: function(str) {
print: function (str) {
WScript.StdOut.Write(str);
},
printLine: function(str) {
printLine: function (str) {
WScript.Echo(str);
},
@@ -282,7 +291,7 @@ var IO = (function() {
stderr: WScript.StdErr,
stdout: WScript.StdOut,
watchFile: null,
run: function(source, filename) {
run: function (source, filename) {
try {
eval(source);
} catch (e) {
@@ -292,7 +301,7 @@ var IO = (function() {
getExecutingFilePath: function () {
return WScript.ScriptFullName;
},
quit: function (exitCode : number = 0) {
quit: function (exitCode: number = 0) {
try {
WScript.Quit(exitCode);
} catch (e) {
@@ -311,7 +320,7 @@ var IO = (function() {
var _module = require('module');
return {
readFile: function(file) {
readFile: function (file) {
try {
var buffer = _fs.readFileSync(file);
switch (buffer[0]) {
@@ -348,17 +357,17 @@ var IO = (function() {
}
},
writeFile: <(path: string, contents: string) => void >_fs.writeFileSync,
deleteFile: function(path) {
deleteFile: function (path) {
try {
_fs.unlinkSync(path);
} catch (e) {
IOUtils.throwIOError("Couldn't delete file '" + path + "'.", e);
}
},
fileExists: function(path): boolean {
fileExists: function (path): boolean {
return _fs.existsSync(path);
},
createFile: function(path, useUTF8?) {
createFile: function (path, useUTF8?) {
function mkdirRecursiveSync(path) {
var stats = _fs.statSync(path);
if (stats.isFile()) {
@@ -367,7 +376,7 @@ var IO = (function() {
return;
} else {
mkdirRecursiveSync(_path.dirname(path));
_fs.mkdirSync(path, 0775);
_fs.mkdirSync(path, parseInt('0775', 8));
}
}
@@ -379,15 +388,23 @@ var IO = (function() {
IOUtils.throwIOError("Couldn't write to file '" + path + "'.", e);
}
return {
Write: function(str) { _fs.writeSync(fd, str); },
WriteLine: function(str) { _fs.writeSync(fd, str + '\r\n'); },
Close: function() { _fs.closeSync(fd); fd = null; }
Write: function (str) {
_fs.writeSync(fd, str);
},
WriteLine: function (str) {
_fs.writeSync(fd, str + '\r\n');
},
Close: function () {
_fs.closeSync(fd);
fd = null;
}
};
},
dir: function dir(path, spec?, options?) {
options = options || <{ recursive?: boolean; deep?: number; }>{};
options = options || <{ recursive?: boolean; deep?: number;
}>{};
function filesInFolder(folder: string, deep?: number): string[]{
function filesInFolder(folder: string, deep?: number): string[] {
var paths = [];
var files = _fs.readdirSync(folder);
@@ -407,7 +424,7 @@ var IO = (function() {
return filesInFolder(path, 0);
},
createDirectory: function(path: string): void {
createDirectory: function (path: string): void {
try {
if (!this.directoryExists(path)) {
_fs.mkdirSync(path);
@@ -417,16 +434,16 @@ var IO = (function() {
}
},
directoryExists: function(path: string): boolean {
directoryExists: function (path: string): boolean {
return _fs.existsSync(path) && _fs.lstatSync(path).isDirectory();
},
resolvePath: function(path: string): string {
resolvePath: function (path: string): string {
return _path.resolve(path);
},
dirName: function(path: string): string {
dirName: function (path: string): string {
return _path.dirname(path);
},
findFile: function(rootPath: string, partialFilePath): IResolvedFile {
findFile: function (rootPath: string, partialFilePath): IResolvedFile {
var path = rootPath + "/" + partialFilePath;
while (true) {
@@ -452,24 +469,38 @@ var IO = (function() {
}
}
},
print: function(str) { process.stdout.write(str) },
printLine: function(str) { process.stdout.write(str + '\n') },
print: function (str) {
process.stdout.write(str)
},
printLine: function (str) {
process.stdout.write(str + '\n')
},
arguments: process.argv.slice(2),
stderr: {
Write: function(str) { process.stderr.write(str); },
WriteLine: function(str) { process.stderr.write(str + '\n'); },
Close: function() { }
Write: function (str) {
process.stderr.write(str);
},
WriteLine: function (str) {
process.stderr.write(str + '\n');
},
Close: function () {
}
},
stdout: {
Write: function(str) { process.stdout.write(str); },
WriteLine: function(str) { process.stdout.write(str + '\n'); },
Close: function() { }
Write: function (str) {
process.stdout.write(str);
},
WriteLine: function (str) {
process.stdout.write(str + '\n');
},
Close: function () {
}
},
watchFile: function(filename: string, callback: (string) => void ): IFileWatcher {
watchFile: function (filename: string, callback: (string) => void): IFileWatcher {
var firstRun = true;
var processingChange = false;
var fileChanged: any = function(curr, prev) {
var fileChanged: any = function (curr, prev) {
if (!firstRun) {
if (curr.mtime < prev.mtime) {
return;
@@ -479,7 +510,9 @@ var IO = (function() {
if (!processingChange) {
processingChange = true;
callback(filename);
setTimeout(function() { processingChange = false; }, 100);
setTimeout(function () {
processingChange = false;
}, 100);
}
}
firstRun = false;
@@ -489,16 +522,16 @@ var IO = (function() {
fileChanged();
return {
filename: filename,
close: function() {
close: function () {
_fs.unwatchFile(filename, fileChanged);
}
};
},
run: function(source, filename) {
run: function (source, filename) {
require.main.filename = filename;
require.main.paths = _module._nodeModulePaths(_path.dirname(_fs.realpathSync(filename)));
require.main._compile(source, filename);
},
},
getExecutingFilePath: function () {
return process.mainModule.filename;
},
-475
View File
@@ -1,475 +0,0 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
var IOUtils;
(function (IOUtils) {
// Creates the directory including its parent if not already present
function createDirectoryStructure(ioHost, dirName) {
if (ioHost.directoryExists(dirName)) {
return;
}
var parentDirectory = ioHost.dirName(dirName);
if (parentDirectory != "") {
createDirectoryStructure(ioHost, parentDirectory);
}
ioHost.createDirectory(dirName);
}
// Creates a file including its directory structure if not already present
function createFileAndFolderStructure(ioHost, fileName, useUTF8) {
var path = ioHost.resolvePath(fileName);
var dirName = ioHost.dirName(path);
createDirectoryStructure(ioHost, dirName);
return ioHost.createFile(path, useUTF8);
}
IOUtils.createFileAndFolderStructure = createFileAndFolderStructure;
function throwIOError(message, error) {
var errorMessage = message;
if (error && error.message) {
errorMessage += (" " + error.message);
}
throw new Error(errorMessage);
}
IOUtils.throwIOError = throwIOError;
})(IOUtils || (IOUtils = {}));
var IO = (function () {
// Create an IO object for use inside WindowsScriptHost hosts
// Depends on WSCript and FileSystemObject
function getWindowsScriptHostIO() {
var fso = new ActiveXObject("Scripting.FileSystemObject");
var streamObjectPool = [];
function getStreamObject() {
if (streamObjectPool.length > 0) {
return streamObjectPool.pop();
} else {
return new ActiveXObject("ADODB.Stream");
}
}
function releaseStreamObject(obj) {
streamObjectPool.push(obj);
}
var args = [];
for (var i = 0; i < WScript.Arguments.length; i++) {
args[i] = WScript.Arguments.Item(i);
}
return {
readFile: function (path) {
try {
var streamObj = getStreamObject();
streamObj.Open();
streamObj.Type = 2;
streamObj.Charset = 'x-ansi';
streamObj.LoadFromFile(path);
var bomChar = streamObj.ReadText(2);
streamObj.Position = 0;
if ((bomChar.charCodeAt(0) == 0xFE && bomChar.charCodeAt(1) == 0xFF) || (bomChar.charCodeAt(0) == 0xFF && bomChar.charCodeAt(1) == 0xFE)) {
streamObj.Charset = 'unicode';
} else if (bomChar.charCodeAt(0) == 0xEF && bomChar.charCodeAt(1) == 0xBB) {
streamObj.Charset = 'utf-8';
}
// Read the whole file
var str = streamObj.ReadText(-1);
streamObj.Close();
releaseStreamObject(streamObj);
return str;
} catch (err) {
IOUtils.throwIOError("Error reading file \"" + path + "\".", err);
}
},
writeFile: function (path, contents) {
var file = this.createFile(path);
file.Write(contents);
file.Close();
},
fileExists: function (path) {
return fso.FileExists(path);
},
resolvePath: function (path) {
return fso.GetAbsolutePathName(path);
},
dirName: function (path) {
return fso.GetParentFolderName(path);
},
findFile: function (rootPath, partialFilePath) {
var path = fso.GetAbsolutePathName(rootPath) + "/" + partialFilePath;
while (true) {
if (fso.FileExists(path)) {
try {
var content = this.readFile(path);
return { content: content, path: path };
} catch (err) {
//Tools.CompilerDiagnostics.debugPrint("Could not find " + path + ", trying parent");
}
} else {
rootPath = fso.GetParentFolderName(fso.GetAbsolutePathName(rootPath));
if (rootPath == "") {
return null;
} else {
path = fso.BuildPath(rootPath, partialFilePath);
}
}
}
},
deleteFile: function (path) {
try {
if (fso.FileExists(path)) {
fso.DeleteFile(path, true);
}
} catch (e) {
IOUtils.throwIOError("Couldn't delete file '" + path + "'.", e);
}
},
createFile: function (path, useUTF8) {
try {
var streamObj = getStreamObject();
streamObj.Charset = useUTF8 ? 'utf-8' : 'x-ansi';
streamObj.Open();
return {
Write: function (str) {
streamObj.WriteText(str, 0);
},
WriteLine: function (str) {
streamObj.WriteText(str, 1);
},
Close: function () {
try {
streamObj.SaveToFile(path, 2);
} catch (saveError) {
IOUtils.throwIOError("Couldn't write to file '" + path + "'.", saveError);
} finally {
if (streamObj.State != 0) {
streamObj.Close();
}
releaseStreamObject(streamObj);
}
}
};
} catch (creationError) {
IOUtils.throwIOError("Couldn't write to file '" + path + "'.", creationError);
}
},
directoryExists: function (path) {
return fso.FolderExists(path);
},
createDirectory: function (path) {
try {
if (!this.directoryExists(path)) {
fso.CreateFolder(path);
}
} catch (e) {
IOUtils.throwIOError("Couldn't create directory '" + path + "'.", e);
}
},
dir: function (path, spec, options) {
options = options || {};
function filesInFolder(folder, root) {
var paths = [];
var fc;
if (options.recursive) {
fc = new Enumerator(folder.subfolders);
for (; !fc.atEnd(); fc.moveNext()) {
paths = paths.concat(filesInFolder(fc.item(), root + "/" + fc.item().Name));
}
}
fc = new Enumerator(folder.files);
for (; !fc.atEnd(); fc.moveNext()) {
if (!spec || fc.item().Name.match(spec)) {
paths.push(root + "/" + fc.item().Name);
}
}
return paths;
}
var folder = fso.GetFolder(path);
var paths = [];
return filesInFolder(folder, path);
},
print: function (str) {
WScript.StdOut.Write(str);
},
printLine: function (str) {
WScript.Echo(str);
},
arguments: args,
stderr: WScript.StdErr,
stdout: WScript.StdOut,
watchFile: null,
run: function (source, filename) {
try {
eval(source);
} catch (e) {
IOUtils.throwIOError("Error while executing file '" + filename + "'.", e);
}
},
getExecutingFilePath: function () {
return WScript.ScriptFullName;
},
quit: function (exitCode) {
if (typeof exitCode === "undefined") { exitCode = 0; }
try {
WScript.Quit(exitCode);
} catch (e) {
}
}
};
}
;
// Create an IO object for use inside Node.js hosts
// Depends on 'fs' and 'path' modules
function getNodeIO() {
var _fs = require('fs');
var _path = require('path');
var _module = require('module');
return {
readFile: function (file) {
try {
var buffer = _fs.readFileSync(file);
switch (buffer[0]) {
case 0xFE:
if (buffer[1] == 0xFF) {
// utf16-be. Reading the buffer as big endian is not supported, so convert it to
// Little Endian first
var i = 0;
while ((i + 1) < buffer.length) {
var temp = buffer[i];
buffer[i] = buffer[i + 1];
buffer[i + 1] = temp;
i += 2;
}
return buffer.toString("ucs2", 2);
}
break;
case 0xFF:
if (buffer[1] == 0xFE) {
// utf16-le
return buffer.toString("ucs2", 2);
}
break;
case 0xEF:
if (buffer[1] == 0xBB) {
// utf-8
return buffer.toString("utf8", 3);
}
}
// Default behaviour
return buffer.toString();
} catch (e) {
IOUtils.throwIOError("Error reading file \"" + file + "\".", e);
}
},
writeFile: _fs.writeFileSync,
deleteFile: function (path) {
try {
_fs.unlinkSync(path);
} catch (e) {
IOUtils.throwIOError("Couldn't delete file '" + path + "'.", e);
}
},
fileExists: function (path) {
return _fs.existsSync(path);
},
createFile: function (path, useUTF8) {
function mkdirRecursiveSync(path) {
var stats = _fs.statSync(path);
if (stats.isFile()) {
IOUtils.throwIOError("\"" + path + "\" exists but isn't a directory.", null);
} else if (stats.isDirectory()) {
return;
} else {
mkdirRecursiveSync(_path.dirname(path));
_fs.mkdirSync(path, 0775);
}
}
mkdirRecursiveSync(_path.dirname(path));
try {
var fd = _fs.openSync(path, 'w');
} catch (e) {
IOUtils.throwIOError("Couldn't write to file '" + path + "'.", e);
}
return {
Write: function (str) {
_fs.writeSync(fd, str);
},
WriteLine: function (str) {
_fs.writeSync(fd, str + '\r\n');
},
Close: function () {
_fs.closeSync(fd);
fd = null;
}
};
},
dir: function dir(path, spec, options) {
options = options || {};
function filesInFolder(folder, deep) {
var paths = [];
var files = _fs.readdirSync(folder);
for (var i = 0; i < files.length; i++) {
var stat = _fs.statSync(folder + "/" + files[i]);
if (options.recursive && stat.isDirectory()) {
if (deep < (options.deep || 100)) {
paths = paths.concat(filesInFolder(folder + "/" + files[i], 1));
}
} else if (stat.isFile() && (!spec || files[i].match(spec))) {
paths.push(folder + "/" + files[i]);
}
}
return paths;
}
return filesInFolder(path, 0);
},
createDirectory: function (path) {
try {
if (!this.directoryExists(path)) {
_fs.mkdirSync(path);
}
} catch (e) {
IOUtils.throwIOError("Couldn't create directory '" + path + "'.", e);
}
},
directoryExists: function (path) {
return _fs.existsSync(path) && _fs.lstatSync(path).isDirectory();
},
resolvePath: function (path) {
return _path.resolve(path);
},
dirName: function (path) {
return _path.dirname(path);
},
findFile: function (rootPath, partialFilePath) {
var path = rootPath + "/" + partialFilePath;
while (true) {
if (_fs.existsSync(path)) {
try {
var content = this.readFile(path);
return { content: content, path: path };
} catch (err) {
//Tools.CompilerDiagnostics.debugPrint(("Could not find " + path) + ", trying parent");
}
} else {
var parentPath = _path.resolve(rootPath, "..");
if (rootPath === parentPath) {
return null;
} else {
rootPath = parentPath;
path = _path.resolve(rootPath, partialFilePath);
}
}
}
},
print: function (str) {
process.stdout.write(str);
},
printLine: function (str) {
process.stdout.write(str + '\n');
},
arguments: process.argv.slice(2),
stderr: {
Write: function (str) {
process.stderr.write(str);
},
WriteLine: function (str) {
process.stderr.write(str + '\n');
},
Close: function () {
}
},
stdout: {
Write: function (str) {
process.stdout.write(str);
},
WriteLine: function (str) {
process.stdout.write(str + '\n');
},
Close: function () {
}
},
watchFile: function (filename, callback) {
var firstRun = true;
var processingChange = false;
var fileChanged = function (curr, prev) {
if (!firstRun) {
if (curr.mtime < prev.mtime) {
return;
}
_fs.unwatchFile(filename, fileChanged);
if (!processingChange) {
processingChange = true;
callback(filename);
setTimeout(function () {
processingChange = false;
}, 100);
}
}
firstRun = false;
_fs.watchFile(filename, { persistent: true, interval: 500 }, fileChanged);
};
fileChanged();
return {
filename: filename,
close: function () {
_fs.unwatchFile(filename, fileChanged);
}
};
},
run: function (source, filename) {
require.main.filename = filename;
require.main.paths = _module._nodeModulePaths(_path.dirname(_fs.realpathSync(filename)));
require.main._compile(source, filename);
},
getExecutingFilePath: function () {
return process.mainModule.filename;
},
quit: process.exit
};
}
;
if (typeof ActiveXObject === "function")
return getWindowsScriptHostIO();
else if (typeof require === "function")
return getNodeIO();
else
return null;
})();
+111
View File
@@ -0,0 +1,111 @@
/// <reference path='../../../node/node.d.ts' />
/// <reference path='../runner.ts' />
module DT {
/////////////////////////////////
// All the common things that we pring are functions of this class
/////////////////////////////////
export class Print {
WIDTH = 77;
constructor(public version: string, public typings: number, public tests: number, public tsFiles: number) {
}
public out(s: any): Print {
process.stdout.write(s);
return this;
}
public repeat(s: string, times: number): string {
return new Array(times + 1).join(s);
}
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 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 printDiv() {
this.out('-----------------------------------------------------------------------------\n');
}
public printBoldDiv() {
this.out('=============================================================================\n');
}
public printErrorsHeader() {
this.out('=============================================================================\n');
this.out(' \33[34m\33[1mErrors in files\33[0m \n');
this.out('=============================================================================\n');
}
public printErrorsForFile(testResult: TestResult) {
this.out('----------------- For file:' + testResult.targetFile.formatName);
this.printBreak().out(testResult.stderr).printBreak();
}
public printBreak(): Print {
this.out('\n');
return this;
}
public clearCurrentLine(): Print {
this.out("\r\33[K");
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 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 printTypingsWithoutTestsMessage() {
this.out(' \33[36m\33[1mTyping without tests\33[0m\n');
}
public printTotalMessage() {
this.out(' \33[36m\33[1mTotal\33[0m\n');
}
public printElapsedTime(time: string, s: number) {
this.out(' \33[36m\33[1mElapsed time :\33[0m ~' + time + ' (' + s + 's)\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 printTypingsWithoutTestName(file: string) {
this.out(' - \33[33m\33[1m' + file + '\33[0m\n');
}
public printTypingsWithoutTest(withoutTestTypings: string[]) {
if (withoutTestTypings.length > 0) {
this.printTypingsWithoutTestsMessage();
this.printDiv();
withoutTestTypings.forEach((t) => {
this.printTypingsWithoutTestName(t);
});
}
}
}
}
@@ -0,0 +1,36 @@
module DT {
/////////////////////////////////
// Test reporter interface
// for example, . and x
/////////////////////////////////
export interface ITestReporter {
printPositiveCharacter(index: number, testResult: TestResult):void;
printNegativeCharacter(index: number, testResult: TestResult):void;
}
/////////////////////////////////
// Default test reporter
/////////////////////////////////
export class DefaultTestReporter implements ITestReporter {
constructor(public print: Print) {
}
public printPositiveCharacter(index: number, testResult: TestResult) {
this.print.out('\33[36m\33[1m' + '.' + '\33[0m');
this.printBreakIfNeeded(index);
}
public printNegativeCharacter(index: number, testResult: TestResult) {
this.print.out("x");
this.printBreakIfNeeded(index);
}
private printBreakIfNeeded(index: number) {
if (index % this.print.WIDTH === 0) {
this.print.printBreak();
}
}
}
}
+83
View File
@@ -0,0 +1,83 @@
/// <reference path="../../runner.ts" />
module DT {
/////////////////////////////////
// The interface for test suite
/////////////////////////////////
export interface ITestSuite {
testSuiteName:string;
errorHeadline:string;
filterTargetFiles(files: File[]):File[];
start(targetFiles: File[], testCallback: (result: TestResult, index: number) => void, suiteCallback: (suite: ITestSuite) => void):void;
testResults:TestResult[];
okTests:TestResult[];
ngTests:TestResult[];
timer:Timer;
testReporter:ITestReporter;
printErrorCount:boolean;
}
/////////////////////////////////
// Base class for test suite
/////////////////////////////////
export class TestSuiteBase implements ITestSuite {
timer: Timer = new Timer();
testResults: TestResult[] = [];
testReporter: ITestReporter;
printErrorCount = true;
constructor(public options: ITestRunnerOptions, public testSuiteName: string, public errorHeadline: string) {
}
public filterTargetFiles(files: File[]): File[] {
throw new Error("please implement this method");
}
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 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 finish(suiteCallback: (suite: ITestSuite) => void) {
suiteCallback(this);
}
public get okTests(): TestResult[] {
return this.testResults.filter((r) => {
return r.success;
});
}
public get ngTests(): TestResult[] {
return this.testResults.filter((r) => {
return !r.success
});
}
}
}
+20
View File
@@ -0,0 +1,20 @@
/// <reference path="../../runner.ts" />
/// <reference path="../util.ts" />
module DT {
/////////////////////////////////
// .d.ts syntax inspection
/////////////////////////////////
export class SyntaxChecking extends TestSuiteBase {
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');
});
}
}
}
@@ -0,0 +1,21 @@
/// <reference path="../../runner.ts" />
/// <reference path="../util.ts" />
module DT {
/////////////////////////////////
// Compile with *-tests.ts
/////////////////////////////////
export class TestEval extends TestSuiteBase {
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')
});
}
}
}
@@ -0,0 +1,49 @@
/// <reference path="../../runner.ts" />
/// <reference path="../file.ts" />
module DT {
/////////////////////////////////
// Try compile without .tscparams
// It may indicate that it is compatible with --noImplicitAny maybe...
/////////////////////////////////
export class FindNotRequiredTscparams extends TestSuiteBase {
testReporter: ITestReporter;
printErrorCount = false;
constructor(options: ITestRunnerOptions, private print: Print) {
super(options, "Find not required .tscparams files", "New arrival!");
this.testReporter = {
printPositiveCharacter: (index: number, testResult: TestResult) => {
this.print
.clearCurrentLine()
.printTypingsWithoutTestName(testResult.targetFile.formatName);
},
printNegativeCharacter: (index: number, testResult: TestResult) => {
}
}
}
public filterTargetFiles(files: File[]): File[] {
return files.filter(file=> IO.fileExists(file.filePathWithName + '.tscparams'));
}
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 finish(suiteCallback: (suite: ITestSuite)=>void) {
this.print.clearCurrentLine();
suiteCallback(this);
}
public get ngTests(): TestResult[] {
// Do not show ng test results
return [];
}
}
}
+46
View File
@@ -0,0 +1,46 @@
/// <reference path='../../../node/node.d.ts' />
/// <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;
public start() {
this.time = 0;
this.startTime = this.now();
}
public now(): number {
return Date.now();
}
public end() {
this.time = (this.now() - this.startTime) / 1000;
this.asString = Timer.prettyDate(this.startTime, this.now());
}
public static prettyDate(date1: number, date2: number): string {
var diff = ((date2 - date1) / 1000),
day_diff = Math.floor(diff / 86400);
if (isNaN(day_diff) || day_diff < 0 || day_diff >= 31)
return;
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");
}
}
}
+43
View File
@@ -0,0 +1,43 @@
/// <reference path='../../../node/node.d.ts' />
/// <reference path='../runner.ts' />
/// <reference path='host/exec.ts' />
module DT {
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;
}
if (!IO.fileExists(tsfile)) {
throw new Error(tsfile + " not exists");
}
var tscPath = './_infrastructure/tests/typescript/' + options.tscVersion + '/tsc.js';
if (!IO.fileExists(tscPath)) {
throw new Error(tscPath + ' is not exists');
}
var command = 'node ' + tscPath + ' --module commonjs ';
if (options.useTscParams && IO.fileExists(tsfile + '.tscparams')) {
command += '@' + tsfile + '.tscparams';
} else if (options.checkNoImplicitAny) {
command += '--noImplicitAny';
}
Exec.exec(command, [tsfile], (execResult) => {
callback(execResult);
});
}
}
}
+5
View File
@@ -0,0 +1,5 @@
module DT {
export function endsWith(str: string, suffix: string) {
return str.indexOf(suffix, str.length - suffix.length) !== -1;
}
}