diff --git a/_infrastructure/tests/runner.js b/_infrastructure/tests/runner.js index 2721d83ab..37aefb7e5 100644 --- a/_infrastructure/tests/runner.js +++ b/_infrastructure/tests/runner.js @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. // + var ExecResult = (function () { function ExecResult() { this.stdout = ""; @@ -69,14 +70,14 @@ var NodeExec = (function () { return NodeExec; })(); -var Exec = (function () { +var Exec = function () { var global = Function("return this;").call(null); if (typeof global.ActiveXObject !== "undefined") { return new WindowsScriptHostExec(); } else { return new NodeExec(); } -})(); +}(); // // Copyright (c) Microsoft Corporation. All rights reserved. // @@ -91,6 +92,7 @@ var Exec = (function () { // 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 @@ -125,6 +127,8 @@ var IOUtils; IOUtils.throwIOError = throwIOError; })(IOUtils || (IOUtils = {})); + + var IO = (function () { // Create an IO object for use inside WindowsScriptHost hosts // Depends on WSCript and FileSystemObject @@ -154,11 +158,11 @@ var IO = (function () { try { var streamObj = getStreamObject(); streamObj.Open(); - streamObj.Type = 2; - streamObj.Charset = 'x-ansi'; + streamObj.Type = 2; // Text data + streamObj.Charset = 'x-ansi'; // Assume we are reading ansi text streamObj.LoadFromFile(path); var bomChar = streamObj.ReadText(2); - streamObj.Position = 0; + streamObj.Position = 0; // Position has to be at 0 before changing the encoding 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) { @@ -213,7 +217,7 @@ var IO = (function () { deleteFile: function (path) { try { if (fso.FileExists(path)) { - fso.DeleteFile(path, true); + fso.DeleteFile(path, true); // true: delete read-only files } } catch (e) { IOUtils.throwIOError("Couldn't delete file '" + path + "'.", e); @@ -386,7 +390,7 @@ var IO = (function () { return; } else { mkdirRecursiveSync(_path.dirname(path)); - _fs.mkdirSync(path, 0775); + _fs.mkdirSync(path, parseInt('0775', 8)); } } @@ -465,6 +469,7 @@ var IO = (function () { } else { var parentPath = _path.resolve(rootPath, ".."); + // Node will just continue to repeat the root path, rather than return null if (rootPath === parentPath) { return null; } else { @@ -547,622 +552,681 @@ var IO = (function () { if (typeof ActiveXObject === "function") return getWindowsScriptHostIO(); -else if (typeof require === "function") + else if (typeof require === "function") return getNodeIO(); -else + else return null; })(); +var DT; +(function (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 + ///////////////////////////////// + var File = (function () { + function File(baseDir, filePathWithName) { + this.baseDir = baseDir; + this.filePathWithName = filePathWithName; + 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); + } + Object.defineProperty(File.prototype, "formatName", { + // From '/complete/path/to/file' to 'specfolder/specfile.d.ts' + get: function () { + var dirName = path.dirname(this.filePathWithName.substr(this.baseDir.length + 1)).replace('\\', '/'); + return this.dir + ((dirName.split('/').length > 1) ? '/-/' : '/') + this.file + this.ext; + }, + enumerable: true, + configurable: true + }); + return File; + })(); + DT.File = File; +})(DT || (DT = {})); +/// +/// +/// +var DT; +(function (DT) { + var Tsc = (function () { + function Tsc() { + } + Tsc.run = function (tsfile, options, callback) { + options = options || {}; + options.tscVersion = options.tscVersion || DT.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], function (execResult) { + callback(execResult); + }); + }; + return Tsc; + })(); + DT.Tsc = Tsc; +})(DT || (DT = {})); +/// +/// +var DT; +(function (DT) { + ///////////////////////////////// + // Timer.start starts a timer + // Timer.end stops the timer and sets asString to the pretty print value + ///////////////////////////////// + var Timer = (function () { + function Timer() { + this.time = 0; + } + Timer.prototype.start = function () { + this.time = 0; + this.startTime = this.now(); + }; + + Timer.prototype.now = function () { + return Date.now(); + }; + + Timer.prototype.end = function () { + this.time = (this.now() - this.startTime) / 1000; + this.asString = Timer.prettyDate(this.startTime, this.now()); + }; + + Timer.prettyDate = function (date1, date2) { + var diff = ((date2 - date1) / 1000), day_diff = Math.floor(diff / 86400); + + if (isNaN(day_diff) || day_diff < 0 || day_diff >= 31) + return; + + return (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"); + }; + return Timer; + })(); + DT.Timer = Timer; +})(DT || (DT = {})); +var DT; +(function (DT) { + function endsWith(str, suffix) { + return str.indexOf(suffix, str.length - suffix.length) !== -1; + } + DT.endsWith = endsWith; +})(DT || (DT = {})); +/// +/// +var DT; +(function (DT) { + ///////////////////////////////// + // All the common things that we pring are functions of this class + ///////////////////////////////// + var Print = (function () { + function Print(version, typings, tests, tsFiles) { + this.version = version; + this.typings = typings; + this.tests = tests; + this.tsFiles = tsFiles; + this.WIDTH = 77; + } + Print.prototype.out = function (s) { + process.stdout.write(s); + return this; + }; + + Print.prototype.repeat = function (s, times) { + return new Array(times + 1).join(s); + }; + + Print.prototype.printHeader = function () { + 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'); + }; + + Print.prototype.printSuiteHeader = function (title) { + 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(); + }; + + Print.prototype.printDiv = function () { + this.out('-----------------------------------------------------------------------------\n'); + }; + + Print.prototype.printBoldDiv = function () { + this.out('=============================================================================\n'); + }; + + Print.prototype.printErrorsHeader = function () { + this.out('=============================================================================\n'); + this.out(' \33[34m\33[1mErrors in files\33[0m \n'); + this.out('=============================================================================\n'); + }; + + Print.prototype.printErrorsForFile = function (testResult) { + this.out('----------------- For file:' + testResult.targetFile.formatName); + this.printBreak().out(testResult.stderr).printBreak(); + }; + + Print.prototype.printBreak = function () { + this.out('\n'); + return this; + }; + + Print.prototype.clearCurrentLine = function () { + this.out("\r\33[K"); + return this; + }; + + Print.prototype.printSuccessCount = function (current, total) { + this.out(' \33[36m\33[1mSuccessful :\33[0m \33[32m\33[1m' + ((current / total) * 100).toFixed(2) + '% (' + current + '/' + total + ')\33[0m\n'); + }; + + Print.prototype.printFailedCount = function (current, total) { + this.out(' \33[36m\33[1mFailure :\33[0m \33[31m\33[1m' + ((current / total) * 100).toFixed(2) + '% (' + current + '/' + total + ')\33[0m\n'); + }; + + Print.prototype.printTypingsWithoutTestsMessage = function () { + this.out(' \33[36m\33[1mTyping without tests\33[0m\n'); + }; + + Print.prototype.printTotalMessage = function () { + this.out(' \33[36m\33[1mTotal\33[0m\n'); + }; + + Print.prototype.printElapsedTime = function (time, s) { + this.out(' \33[36m\33[1mElapsed time :\33[0m ~' + time + ' (' + s + 's)\n'); + }; + + Print.prototype.printSuiteErrorCount = function (errorHeadline, current, total, valuesColor) { + if (typeof valuesColor === "undefined") { 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'); + }; + + Print.prototype.printTypingsWithoutTestName = function (file) { + this.out(' - \33[33m\33[1m' + file + '\33[0m\n'); + }; + + Print.prototype.printTypingsWithoutTest = function (withoutTestTypings) { + var _this = this; + if (withoutTestTypings.length > 0) { + this.printTypingsWithoutTestsMessage(); + + this.printDiv(); + withoutTestTypings.forEach(function (t) { + _this.printTypingsWithoutTestName(t); + }); + } + }; + return Print; + })(); + DT.Print = Print; +})(DT || (DT = {})); +var DT; +(function (DT) { + + + ///////////////////////////////// + // Default test reporter + ///////////////////////////////// + var DefaultTestReporter = (function () { + function DefaultTestReporter(print) { + this.print = print; + } + DefaultTestReporter.prototype.printPositiveCharacter = function (index, testResult) { + this.print.out('\33[36m\33[1m' + '.' + '\33[0m'); + + this.printBreakIfNeeded(index); + }; + + DefaultTestReporter.prototype.printNegativeCharacter = function (index, testResult) { + this.print.out("x"); + + this.printBreakIfNeeded(index); + }; + + DefaultTestReporter.prototype.printBreakIfNeeded = function (index) { + if (index % this.print.WIDTH === 0) { + this.print.printBreak(); + } + }; + return DefaultTestReporter; + })(); + DT.DefaultTestReporter = DefaultTestReporter; +})(DT || (DT = {})); +/// +var DT; +(function (DT) { + + + ///////////////////////////////// + // Base class for test suite + ///////////////////////////////// + var TestSuiteBase = (function () { + function TestSuiteBase(options, testSuiteName, errorHeadline) { + this.options = options; + this.testSuiteName = testSuiteName; + this.errorHeadline = errorHeadline; + this.timer = new DT.Timer(); + this.testResults = []; + this.printErrorCount = true; + } + TestSuiteBase.prototype.filterTargetFiles = function (files) { + throw new Error("please implement this method"); + }; + + TestSuiteBase.prototype.start = function (targetFiles, testCallback, suiteCallback) { + var _this = this; + targetFiles = this.filterTargetFiles(targetFiles); + this.timer.start(); + var count = 0; + + // exec test is async process. serialize. + var executor = function () { + var targetFile = targetFiles[count]; + if (targetFile) { + _this.runTest(targetFile, function (result) { + testCallback(result, count + 1); + count++; + executor(); + }); + } else { + _this.timer.end(); + _this.finish(suiteCallback); + } + }; + executor(); + }; + + TestSuiteBase.prototype.runTest = function (targetFile, callback) { + var _this = this; + new DT.Test(this, targetFile, { tscVersion: this.options.tscVersion }).run(function (result) { + _this.testResults.push(result); + callback(result); + }); + }; + + TestSuiteBase.prototype.finish = function (suiteCallback) { + suiteCallback(this); + }; + + Object.defineProperty(TestSuiteBase.prototype, "okTests", { + get: function () { + return this.testResults.filter(function (r) { + return r.success; + }); + }, + enumerable: true, + configurable: true + }); + + Object.defineProperty(TestSuiteBase.prototype, "ngTests", { + get: function () { + return this.testResults.filter(function (r) { + return !r.success; + }); + }, + enumerable: true, + configurable: true + }); + return TestSuiteBase; + })(); + DT.TestSuiteBase = TestSuiteBase; +})(DT || (DT = {})); +/// +/// var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } __.prototype = b.prototype; d.prototype = new __(); }; -var DefinitelyTyped; -(function (DefinitelyTyped) { - /// - /// - /// - (function (TestManager) { - var path = require('path'); - - TestManager.DEFAULT_TSC_VERSION = "0.9.1.1"; - - function endsWith(str, suffix) { - return str.indexOf(suffix, str.length - suffix.length) !== -1; +var DT; +(function (DT) { + ///////////////////////////////// + // .d.ts syntax inspection + ///////////////////////////////// + var SyntaxChecking = (function (_super) { + __extends(SyntaxChecking, _super); + function SyntaxChecking(options) { + _super.call(this, options, "Syntax checking", "Syntax error"); } - - var Tsc = (function () { - function Tsc() { - } - Tsc.run = function (tsfile, options, callback) { - options = options || {}; - options.tscVersion = options.tscVersion || TestManager.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], function (execResult) { - callback(execResult); - }); - }; - return Tsc; - })(); - - var Test = (function () { - function Test(suite, tsfile, options) { - this.suite = suite; - this.tsfile = tsfile; - this.options = options; - } - Test.prototype.run = function (callback) { - var _this = this; - Tsc.run(this.tsfile.filePathWithName, this.options, function (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; - - callback(testResult); - }); - }; - return Test; - })(); - - ///////////////////////////////// - // Timer.start starts a timer - // Timer.end stops the timer and sets asString to the pretty print value - ///////////////////////////////// - var Timer = (function () { - function Timer() { - this.time = 0; - } - Timer.prototype.start = function () { - this.time = 0; - this.startTime = this.now(); - }; - - Timer.prototype.now = function () { - return Date.now(); - }; - - Timer.prototype.end = function () { - this.time = (this.now() - this.startTime) / 1000; - this.asString = Timer.prettyDate(this.startTime, this.now()); - }; - - Timer.prettyDate = function (date1, date2) { - var diff = ((date2 - date1) / 1000), day_diff = Math.floor(diff / 86400); - - if (isNaN(day_diff) || day_diff < 0 || day_diff >= 31) - return; - - return (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"); - }; - return Timer; - })(); - TestManager.Timer = Timer; - - ///////////////////////////////// - // Given a document root + ts file pattern this class returns: - // all the TS files OR just tests OR just definition files - ///////////////////////////////// - var File = (function () { - function File(baseDir, filePathWithName) { - this.baseDir = baseDir; - this.filePathWithName = filePathWithName; - 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); - } - Object.defineProperty(File.prototype, "formatName", { - get: // From '/complete/path/to/file' to 'specfolder/specfile.d.ts' - function () { - var dirName = path.dirname(this.filePathWithName.substr(this.baseDir.length + 1)).replace('\\', '/'); - return this.dir + ((dirName.split('/').length > 1) ? '/-/' : '/') + this.file + this.ext; - }, - enumerable: true, - configurable: true + SyntaxChecking.prototype.filterTargetFiles = function (files) { + return files.filter(function (file) { + return DT.endsWith(file.formatName.toUpperCase(), '.D.TS'); }); - return File; - })(); - TestManager.File = File; - - ///////////////////////////////// - // Test results - ///////////////////////////////// - var TestResult = (function () { - function TestResult() { - } - Object.defineProperty(TestResult.prototype, "success", { - get: function () { - return this.exitCode === 0; - }, - enumerable: true, - configurable: true + }; + return SyntaxChecking; + })(DT.TestSuiteBase); + DT.SyntaxChecking = SyntaxChecking; +})(DT || (DT = {})); +/// +/// +var DT; +(function (DT) { + ///////////////////////////////// + // Compile with *-tests.ts + ///////////////////////////////// + var TestEval = (function (_super) { + __extends(TestEval, _super); + function TestEval(options) { + _super.call(this, options, "Typing tests", "Failed tests"); + } + TestEval.prototype.filterTargetFiles = function (files) { + return files.filter(function (file) { + return DT.endsWith(file.formatName.toUpperCase(), '-TESTS.TS'); }); - return TestResult; - })(); - TestManager.TestResult = TestResult; + }; + return TestEval; + })(DT.TestSuiteBase); + DT.TestEval = TestEval; +})(DT || (DT = {})); +/// +/// +var DT; +(function (DT) { + ///////////////////////////////// + // Try compile without .tscparams + // It may indicate that it is compatible with --noImplicitAny maybe... + ///////////////////////////////// + var FindNotRequiredTscparams = (function (_super) { + __extends(FindNotRequiredTscparams, _super); + function FindNotRequiredTscparams(options, print) { + var _this = this; + _super.call(this, options, "Find not required .tscparams files", "New arrival!"); + this.print = print; + this.printErrorCount = false; - ///////////////////////////////// - // Default test reporter - ///////////////////////////////// - var DefaultTestReporter = (function () { - function DefaultTestReporter(print) { - this.print = print; - } - DefaultTestReporter.prototype.printPositiveCharacter = function (index, testResult) { - this.print.out('\33[36m\33[1m' + '.' + '\33[0m'); - - this.printBreakIfNeeded(index); - }; - - DefaultTestReporter.prototype.printNegativeCharacter = function (index, testResult) { - this.print.out("x"); - - this.printBreakIfNeeded(index); - }; - - DefaultTestReporter.prototype.printBreakIfNeeded = function (index) { - if (index % this.print.WIDTH === 0) { - this.print.printBreak(); + this.testReporter = { + printPositiveCharacter: function (index, testResult) { + _this.print.clearCurrentLine().printTypingsWithoutTestName(testResult.targetFile.formatName); + }, + printNegativeCharacter: function (index, testResult) { } }; - return DefaultTestReporter; - })(); + } + FindNotRequiredTscparams.prototype.filterTargetFiles = function (files) { + return files.filter(function (file) { + return IO.fileExists(file.filePathWithName + '.tscparams'); + }); + }; - ///////////////////////////////// - // All the common things that we pring are functions of this class - ///////////////////////////////// - var Print = (function () { - function Print(version, typings, tests, tsFiles) { - this.version = version; - this.typings = typings; - this.tests = tests; - this.tsFiles = tsFiles; - this.WIDTH = 77; + FindNotRequiredTscparams.prototype.runTest = function (targetFile, callback) { + var _this = this; + this.print.clearCurrentLine().out(targetFile.formatName); + new DT.Test(this, targetFile, { tscVersion: this.options.tscVersion, useTscParams: false, checkNoImplicitAny: true }).run(function (result) { + _this.testResults.push(result); + callback(result); + }); + }; + + FindNotRequiredTscparams.prototype.finish = function (suiteCallback) { + this.print.clearCurrentLine(); + suiteCallback(this); + }; + + Object.defineProperty(FindNotRequiredTscparams.prototype, "ngTests", { + get: function () { + // Do not show ng test results + return []; + }, + enumerable: true, + configurable: true + }); + return FindNotRequiredTscparams; + })(DT.TestSuiteBase); + DT.FindNotRequiredTscparams = FindNotRequiredTscparams; +})(DT || (DT = {})); +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +var DT; +(function (DT) { + var fs = require('fs'); + var path = require('path'); + + DT.DEFAULT_TSC_VERSION = "0.9.1.1"; + + var Test = (function () { + function Test(suite, tsfile, options) { + this.suite = suite; + this.tsfile = tsfile; + this.options = options; + } + Test.prototype.run = function (callback) { + var _this = this; + DT.Tsc.run(this.tsfile.filePathWithName, this.options, function (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; + + callback(testResult); + }); + }; + return Test; + })(); + DT.Test = Test; + + ///////////////////////////////// + // Test results + ///////////////////////////////// + var TestResult = (function () { + function TestResult() { + } + Object.defineProperty(TestResult.prototype, "success", { + get: function () { + return this.exitCode === 0; + }, + enumerable: true, + configurable: true + }); + return TestResult; + })(); + DT.TestResult = TestResult; + + ///////////////////////////////// + // The main class to kick things off + ///////////////////////////////// + var TestRunner = (function () { + function TestRunner(dtPath, options) { + if (typeof options === "undefined") { options = { tscVersion: DT.DEFAULT_TSC_VERSION }; } + this.options = options; + this.suites = []; + 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 + this.files = filesName.filter(function (fileName) { + return fileName.indexOf('../_infrastructure') < 0; + }).filter(function (fileName) { + return fileName.indexOf('../node_modules') < 0; + }).filter(function (fileName) { + return !DT.endsWith(fileName, ".tscparams"); + }).map(function (fileName) { + return new DT.File(dtPath, fileName); + }); + } + TestRunner.prototype.addSuite = function (suite) { + this.suites.push(suite); + }; + + TestRunner.prototype.run = function () { + var _this = this; + this.timer = new DT.Timer(); + this.timer.start(); + + var syntaxChecking = new DT.SyntaxChecking(this.options); + var testEval = new DT.TestEval(this.options); + if (!this.options.findNotRequiredTscparams) { + this.addSuite(syntaxChecking); + this.addSuite(testEval); } - Print.prototype.out = function (s) { - process.stdout.write(s); - return this; - }; - Print.prototype.repeat = function (s, times) { - return new Array(times + 1).join(s); - }; + 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); + this.print.printHeader(); - Print.prototype.printHeader = function () { - 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'); - }; + if (this.options.findNotRequiredTscparams) { + this.addSuite(new DT.FindNotRequiredTscparams(this.options, this.print)); + } - Print.prototype.printSuiteHeader = function (title) { - 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(); - }; + var count = 0; + var executor = function () { + var suite = _this.suites[count]; + if (suite) { + suite.testReporter = suite.testReporter || new DT.DefaultTestReporter(_this.print); - Print.prototype.printDiv = function () { - this.out('-----------------------------------------------------------------------------\n'); - }; - - Print.prototype.printBoldDiv = function () { - this.out('=============================================================================\n'); - }; - - Print.prototype.printErrorsHeader = function () { - this.out('=============================================================================\n'); - this.out(' \33[34m\33[1mErrors in files\33[0m \n'); - this.out('=============================================================================\n'); - }; - - Print.prototype.printErrorsForFile = function (testResult) { - this.out('----------------- For file:' + testResult.targetFile.formatName); - this.printBreak().out(testResult.stderr).printBreak(); - }; - - Print.prototype.printBreak = function () { - this.out('\n'); - return this; - }; - - Print.prototype.clearCurrentLine = function () { - this.out("\r\33[K"); - return this; - }; - - Print.prototype.printSuccessCount = function (current, total) { - this.out(' \33[36m\33[1mSuccessful :\33[0m \33[32m\33[1m' + ((current / total) * 100).toFixed(2) + '% (' + current + '/' + total + ')\33[0m\n'); - }; - - Print.prototype.printFailedCount = function (current, total) { - this.out(' \33[36m\33[1mFailure :\33[0m \33[31m\33[1m' + ((current / total) * 100).toFixed(2) + '% (' + current + '/' + total + ')\33[0m\n'); - }; - - Print.prototype.printTypingsWithoutTestsMessage = function () { - this.out(' \33[36m\33[1mTyping without tests\33[0m\n'); - }; - - Print.prototype.printTotalMessage = function () { - this.out(' \33[36m\33[1mTotal\33[0m\n'); - }; - - Print.prototype.printElapsedTime = function (time, s) { - this.out(' \33[36m\33[1mElapsed time :\33[0m ~' + time + ' (' + s + 's)\n'); - }; - - Print.prototype.printSuiteErrorCount = function (errorHeadline, current, total, valuesColor) { - if (typeof valuesColor === "undefined") { 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'); - }; - - Print.prototype.printTypingsWithoutTestName = function (file) { - this.out(' - \33[33m\33[1m' + file + '\33[0m\n'); - }; - - Print.prototype.printTypingsWithoutTest = function (withoutTestTypings) { - var _this = this; - if (withoutTestTypings.length > 0) { - this.printTypingsWithoutTestsMessage(); - - this.printDiv(); - withoutTestTypings.forEach(function (t) { - _this.printTypingsWithoutTestName(t); + _this.print.printSuiteHeader(suite.testSuiteName); + var targetFiles = suite.filterTargetFiles(_this.files); + suite.start(targetFiles, function (testResult, index) { + _this.testCompleteCallback(testResult, index); + }, function (suite) { + _this.suiteCompleteCallback(suite); + count++; + executor(); }); - } - }; - return Print; - })(); - - ///////////////////////////////// - // Base class for test suite - ///////////////////////////////// - var TestSuiteBase = (function () { - function TestSuiteBase(options, testSuiteName, errorHeadline) { - this.options = options; - this.testSuiteName = testSuiteName; - this.errorHeadline = errorHeadline; - this.timer = new Timer(); - this.testResults = []; - this.printErrorCount = true; - } - TestSuiteBase.prototype.filterTargetFiles = function (files) { - throw new Error("please implement this method"); - }; - - TestSuiteBase.prototype.start = function (targetFiles, testCallback, suiteCallback) { - var _this = this; - targetFiles = this.filterTargetFiles(targetFiles); - this.timer.start(); - var count = 0; - - // exec test is async process. serialize. - var executor = function () { - var targetFile = targetFiles[count]; - if (targetFile) { - _this.runTest(targetFile, function (result) { - testCallback(result, count + 1); - count++; - executor(); - }); - } else { - _this.timer.end(); - _this.finish(suiteCallback); - } - }; - executor(); - }; - - TestSuiteBase.prototype.runTest = function (targetFile, callback) { - var _this = this; - new Test(this, targetFile, { tscVersion: this.options.tscVersion }).run(function (result) { - _this.testResults.push(result); - callback(result); - }); - }; - - TestSuiteBase.prototype.finish = function (suiteCallback) { - suiteCallback(this); - }; - - Object.defineProperty(TestSuiteBase.prototype, "okTests", { - get: function () { - return this.testResults.filter(function (r) { - return r.success; - }); - }, - enumerable: true, - configurable: true - }); - - Object.defineProperty(TestSuiteBase.prototype, "ngTests", { - get: function () { - return this.testResults.filter(function (r) { - return !r.success; - }); - }, - enumerable: true, - configurable: true - }); - return TestSuiteBase; - })(); - - ///////////////////////////////// - // .d.ts syntax inspection - ///////////////////////////////// - var SyntaxChecking = (function (_super) { - __extends(SyntaxChecking, _super); - function SyntaxChecking(options) { - _super.call(this, options, "Syntax checking", "Syntax error"); - } - SyntaxChecking.prototype.filterTargetFiles = function (files) { - return files.filter(function (file) { - return endsWith(file.formatName.toUpperCase(), '.D.TS'); - }); - }; - return SyntaxChecking; - })(TestSuiteBase); - - ///////////////////////////////// - // Compile with *-tests.ts - ///////////////////////////////// - var TestEval = (function (_super) { - __extends(TestEval, _super); - function TestEval(options) { - _super.call(this, options, "Typing tests", "Failed tests"); - } - TestEval.prototype.filterTargetFiles = function (files) { - return files.filter(function (file) { - return endsWith(file.formatName.toUpperCase(), '-TESTS.TS'); - }); - }; - return TestEval; - })(TestSuiteBase); - - ///////////////////////////////// - // Try compile without .tscparams - // It may indicate that it is compatible with --noImplicitAny maybe... - ///////////////////////////////// - var FindNotRequiredTscparams = (function (_super) { - __extends(FindNotRequiredTscparams, _super); - function FindNotRequiredTscparams(options, print) { - var _this = this; - _super.call(this, options, "Find not required .tscparams files", "New arrival!"); - this.print = print; - this.printErrorCount = false; - - this.testReporter = { - printPositiveCharacter: function (index, testResult) { - _this.print.clearCurrentLine().printTypingsWithoutTestName(testResult.targetFile.formatName); - }, - printNegativeCharacter: function (index, testResult) { - } - }; - } - FindNotRequiredTscparams.prototype.filterTargetFiles = function (files) { - return files.filter(function (file) { - return IO.fileExists(file.filePathWithName + '.tscparams'); - }); - }; - - FindNotRequiredTscparams.prototype.runTest = function (targetFile, callback) { - var _this = this; - this.print.clearCurrentLine().out(targetFile.formatName); - new Test(this, targetFile, { tscVersion: this.options.tscVersion, useTscParams: false, checkNoImplicitAny: true }).run(function (result) { - _this.testResults.push(result); - callback(result); - }); - }; - - FindNotRequiredTscparams.prototype.finish = function (suiteCallback) { - this.print.clearCurrentLine(); - suiteCallback(this); - }; - - Object.defineProperty(FindNotRequiredTscparams.prototype, "ngTests", { - get: function () { - // Do not show ng test results - return []; - }, - enumerable: true, - configurable: true - }); - return FindNotRequiredTscparams; - })(TestSuiteBase); - - ///////////////////////////////// - // The main class to kick things off - ///////////////////////////////// - var TestRunner = (function () { - function TestRunner(dtPath, options) { - if (typeof options === "undefined") { options = { tscVersion: TestManager.DEFAULT_TSC_VERSION }; } - this.options = options; - this.suites = []; - 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(function (fileName) { - return fileName.indexOf('../_infrastructure') < 0; - }).filter(function (fileName) { - return !endsWith(fileName, ".tscparams"); - }); - this.files = filesName.map(function (fileName) { - return new File(dtPath, fileName); - }); - } - TestRunner.prototype.addSuite = function (suite) { - this.suites.push(suite); - }; - - TestRunner.prototype.run = function () { - var _this = this; - this.timer = new Timer(); - this.timer.start(); - - var syntaxChecking = new SyntaxChecking(this.options); - var testEval = new TestEval(this.options); - if (!this.options.findNotRequiredTscparams) { - this.addSuite(syntaxChecking); - this.addSuite(testEval); - } - - 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(); - - if (this.options.findNotRequiredTscparams) { - this.addSuite(new FindNotRequiredTscparams(this.options, this.print)); - } - - var count = 0; - var executor = function () { - var suite = _this.suites[count]; - if (suite) { - suite.testReporter = suite.testReporter || new DefaultTestReporter(_this.print); - - _this.print.printSuiteHeader(suite.testSuiteName); - var targetFiles = suite.filterTargetFiles(_this.files); - suite.start(targetFiles, function (testResult, index) { - _this.testCompleteCallback(testResult, index); - }, function (suite) { - _this.suiteCompleteCallback(suite); - count++; - executor(); - }); - } else { - _this.timer.end(); - _this.allTestCompleteCallback(); - } - }; - executor(); - }; - - TestRunner.prototype.testCompleteCallback = function (testResult, index) { - var reporter = testResult.hostedBy.testReporter; - if (testResult.success) { - reporter.printPositiveCharacter(index, testResult); } else { - reporter.printNegativeCharacter(index, testResult); + _this.timer.end(); + _this.allTestCompleteCallback(); } }; + executor(); + }; - TestRunner.prototype.suiteCompleteCallback = function (suite) { - this.print.printBreak(); + TestRunner.prototype.testCompleteCallback = function (testResult, index) { + var reporter = testResult.hostedBy.testReporter; + if (testResult.success) { + reporter.printPositiveCharacter(index, testResult); + } else { + reporter.printNegativeCharacter(index, testResult); + } + }; - 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); - }; + TestRunner.prototype.suiteCompleteCallback = function (suite) { + this.print.printBreak(); - TestRunner.prototype.allTestCompleteCallback = function () { - var _this = this; - var testEval = this.suites.filter(function (suite) { - return suite instanceof TestEval; - })[0]; - if (testEval) { - var existsTestTypings = testEval.testResults.map(function (testResult) { - return testResult.targetFile.dir; - }).reduce(function (a, b) { - return a.indexOf(b) < 0 ? a.concat([b]) : a; - }, []); - var typings = this.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; - }); - this.print.printDiv(); - this.print.printTypingsWithoutTest(withoutTestTypings); - } + 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); + }; - this.print.printDiv(); - this.print.printTotalMessage(); - - this.print.printDiv(); - this.print.printElapsedTime(this.timer.asString, this.timer.time); - this.suites.filter(function (suite) { - return suite.printErrorCount; - }).forEach(function (suite) { - _this.print.printSuiteErrorCount(suite.errorHeadline, suite.ngTests.length, suite.testResults.length); + TestRunner.prototype.allTestCompleteCallback = function () { + var _this = this; + var testEval = this.suites.filter(function (suite) { + return suite instanceof DT.TestEval; + })[0]; + if (testEval) { + var existsTestTypings = testEval.testResults.map(function (testResult) { + return testResult.targetFile.dir; + }).reduce(function (a, b) { + return a.indexOf(b) < 0 ? a.concat([b]) : a; + }, []); + var typings = this.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; }); - if (testEval) { - this.print.printSuiteErrorCount("Without tests", withoutTestTypings.length, typings.length, '\33[33m\33[1m'); - } - this.print.printDiv(); - if (this.suites.some(function (suite) { + 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(function (suite) { + return suite.printErrorCount; + }).forEach(function (suite) { + _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(function (suite) { + return suite.ngTests.length !== 0; + })) { + this.print.printErrorsHeader(); + + this.suites.filter(function (suite) { return suite.ngTests.length !== 0; - })) { - this.print.printErrorsHeader(); - - this.suites.filter(function (suite) { - return suite.ngTests.length !== 0; - }).forEach(function (suite) { - suite.ngTests.forEach(function (testResult) { - _this.print.printErrorsForFile(testResult); - }); - _this.print.printBoldDiv(); + }).forEach(function (suite) { + suite.ngTests.forEach(function (testResult) { + _this.print.printErrorsForFile(testResult); }); + _this.print.printBoldDiv(); + }); - process.exit(1); - } - }; - return TestRunner; - })(); - TestManager.TestRunner = TestRunner; - })(DefinitelyTyped.TestManager || (DefinitelyTyped.TestManager = {})); - var TestManager = DefinitelyTyped.TestManager; -})(DefinitelyTyped || (DefinitelyTyped = {})); + process.exit(1); + } + }; + return TestRunner; + })(); + DT.TestRunner = TestRunner; -var dtPath = __dirname + '/../..'; -var findNotRequiredTscparams = process.argv.some(function (arg) { - return 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(function (arg) { + return arg == "--try-without-tscparams"; + }); + var tscVersionIndex = process.argv.indexOf("--tsc-version"); + var tscVersion = DT.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(); +})(DT || (DT = {})); +//# sourceMappingURL=runner.js.map diff --git a/_infrastructure/tests/runner.ts b/_infrastructure/tests/runner.ts index f8746ab51..86a4c2caa 100644 --- a/_infrastructure/tests/runner.ts +++ b/_infrastructure/tests/runner.ts @@ -1,60 +1,33 @@ /// -/// -/// +/// +/// -module DefinitelyTyped.TestManager { +/// +/// +/// +/// + +/// +/// + +/// +/// +/// +/// + +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 (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(); +} diff --git a/_infrastructure/tests/src/exec.js b/_infrastructure/tests/src/exec.js deleted file mode 100644 index 2b8ea5c59..000000000 --- a/_infrastructure/tests/src/exec.js +++ /dev/null @@ -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(); - } -})(); diff --git a/_infrastructure/tests/src/file.ts b/_infrastructure/tests/src/file.ts new file mode 100644 index 000000000..f349a09da --- /dev/null +++ b/_infrastructure/tests/src/file.ts @@ -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; + } + } +} diff --git a/_infrastructure/tests/src/exec.ts b/_infrastructure/tests/src/host/exec.ts similarity index 83% rename from _infrastructure/tests/src/exec.ts rename to _infrastructure/tests/src/host/exec.ts index 5123d4cfc..2bddb0043 100644 --- a/_infrastructure/tests/src/exec.ts +++ b/_infrastructure/tests/src/host/exec.ts @@ -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 = Function("return this;").call(null); - if(typeof global.ActiveXObject !== "undefined") { + if (typeof global.ActiveXObject !== "undefined") { return new WindowsScriptHostExec(); } else { return new NodeExec(); } -}(); \ No newline at end of file +}(); diff --git a/_infrastructure/tests/src/io.ts b/_infrastructure/tests/src/host/io.ts similarity index 81% rename from _infrastructure/tests/src/io.ts rename to _infrastructure/tests/src/host/io.ts index 2c7a81f4f..b308ef13f 100644 --- a/_infrastructure/tests/src/io.ts +++ b/_infrastructure/tests/src/host/io.ts @@ -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 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; }, diff --git a/_infrastructure/tests/src/indexer.ts b/_infrastructure/tests/src/indexer.ts new file mode 100644 index 000000000..e69de29bb diff --git a/_infrastructure/tests/src/io.js b/_infrastructure/tests/src/io.js deleted file mode 100644 index 0f8b9516c..000000000 --- a/_infrastructure/tests/src/io.js +++ /dev/null @@ -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; -})(); diff --git a/_infrastructure/tests/src/printer.ts b/_infrastructure/tests/src/printer.ts new file mode 100644 index 000000000..d1f0f952e --- /dev/null +++ b/_infrastructure/tests/src/printer.ts @@ -0,0 +1,111 @@ +/// +/// + +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); + }); + } + } + } +} diff --git a/_infrastructure/tests/src/reporter/reporter.ts b/_infrastructure/tests/src/reporter/reporter.ts new file mode 100644 index 000000000..d4556e0cc --- /dev/null +++ b/_infrastructure/tests/src/reporter/reporter.ts @@ -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(); + } + } + } +} diff --git a/_infrastructure/tests/src/suite/suite.ts b/_infrastructure/tests/src/suite/suite.ts new file mode 100644 index 000000000..32013cce2 --- /dev/null +++ b/_infrastructure/tests/src/suite/suite.ts @@ -0,0 +1,83 @@ +/// + +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 + }); + } + } +} diff --git a/_infrastructure/tests/src/suite/syntax.ts b/_infrastructure/tests/src/suite/syntax.ts new file mode 100644 index 000000000..f36c26d99 --- /dev/null +++ b/_infrastructure/tests/src/suite/syntax.ts @@ -0,0 +1,20 @@ +/// +/// + +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'); + }); + } + } +} diff --git a/_infrastructure/tests/src/suite/testEval.ts b/_infrastructure/tests/src/suite/testEval.ts new file mode 100644 index 000000000..860e17943 --- /dev/null +++ b/_infrastructure/tests/src/suite/testEval.ts @@ -0,0 +1,21 @@ +/// +/// + +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') + }); + } + } + +} diff --git a/_infrastructure/tests/src/suite/tscParams.ts b/_infrastructure/tests/src/suite/tscParams.ts new file mode 100644 index 000000000..65491d30d --- /dev/null +++ b/_infrastructure/tests/src/suite/tscParams.ts @@ -0,0 +1,49 @@ +/// +/// + +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 []; + } + } +} diff --git a/_infrastructure/tests/src/timer.ts b/_infrastructure/tests/src/timer.ts new file mode 100644 index 000000000..a92d08faf --- /dev/null +++ b/_infrastructure/tests/src/timer.ts @@ -0,0 +1,46 @@ +/// +/// + +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 (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"); + } + } +} diff --git a/_infrastructure/tests/src/tsc.ts b/_infrastructure/tests/src/tsc.ts new file mode 100644 index 000000000..708f42a91 --- /dev/null +++ b/_infrastructure/tests/src/tsc.ts @@ -0,0 +1,43 @@ +/// +/// + +/// + +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); + }); + } + } +} diff --git a/_infrastructure/tests/src/util.ts b/_infrastructure/tests/src/util.ts new file mode 100644 index 000000000..d907fe49d --- /dev/null +++ b/_infrastructure/tests/src/util.ts @@ -0,0 +1,5 @@ +module DT { + export function endsWith(str: string, suffix: string) { + return str.indexOf(suffix, str.length - suffix.length) !== -1; + } +}