test.js 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. "use strict";
  2. /**
  3. * @license
  4. * Copyright 2016 Palantir Technologies, Inc.
  5. *
  6. * Licensed under the Apache License, Version 2.0 (the "License");
  7. * you may not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. Object.defineProperty(exports, "__esModule", { value: true });
  19. var chalk_1 = require("chalk");
  20. var diff = require("diff");
  21. var fs = require("fs");
  22. var glob = require("glob");
  23. var path = require("path");
  24. var semver = require("semver");
  25. var ts = require("typescript");
  26. var rule_1 = require("./language/rule/rule");
  27. var linter_1 = require("./linter");
  28. var utils_1 = require("./utils");
  29. var parse = require("./verify/parse");
  30. var MARKUP_FILE_EXTENSION = ".lint";
  31. var FIXES_FILE_EXTENSION = ".fix";
  32. function runTests(patterns, rulesDirectory) {
  33. var files = [];
  34. for (var _i = 0, patterns_1 = patterns; _i < patterns_1.length; _i++) {
  35. var pattern = patterns_1[_i];
  36. if (path.basename(pattern) !== "tslint.json") {
  37. pattern = path.join(pattern, "tslint.json");
  38. }
  39. files.push.apply(files, glob.sync(pattern));
  40. }
  41. return files.map(function (directory) { return runTest(path.dirname(directory), rulesDirectory); });
  42. }
  43. exports.runTests = runTests;
  44. function runTest(testDirectory, rulesDirectory) {
  45. var filesToLint = glob.sync(path.join(testDirectory, "**/*" + MARKUP_FILE_EXTENSION));
  46. var tslintConfig = linter_1.Linter.findConfiguration(path.join(testDirectory, "tslint.json"), "").results;
  47. var tsConfig = path.join(testDirectory, "tsconfig.json");
  48. var compilerOptions = { allowJs: true };
  49. var hasConfig = fs.existsSync(tsConfig);
  50. if (hasConfig) {
  51. var _a = ts.readConfigFile(tsConfig, ts.sys.readFile), config = _a.config, error = _a.error;
  52. if (error !== undefined) {
  53. throw new Error(JSON.stringify(error));
  54. }
  55. var parseConfigHost = {
  56. fileExists: fs.existsSync,
  57. readDirectory: ts.sys.readDirectory,
  58. readFile: function (file) { return fs.readFileSync(file, "utf8"); },
  59. useCaseSensitiveFileNames: true,
  60. };
  61. compilerOptions = ts.parseJsonConfigFileContent(config, parseConfigHost, testDirectory).options;
  62. }
  63. var results = { directory: testDirectory, results: {} };
  64. var _loop_1 = function (fileToLint) {
  65. var isEncodingRule = path.basename(testDirectory) === "encoding";
  66. var fileCompileName = utils_1.denormalizeWinPath(path.resolve(fileToLint.replace(/\.lint$/, "")));
  67. var fileText = isEncodingRule ? utils_1.readBufferWithDetectedEncoding(fs.readFileSync(fileToLint)) : fs.readFileSync(fileToLint, "utf-8");
  68. var tsVersionRequirement = parse.getTypescriptVersionRequirement(fileText);
  69. if (tsVersionRequirement !== undefined) {
  70. // remove prerelease suffix when matching to allow testing with nightly builds
  71. if (!semver.satisfies(parse.getNormalizedTypescriptVersion(), tsVersionRequirement)) {
  72. results.results[fileToLint] = {
  73. requirement: tsVersionRequirement,
  74. skipped: true,
  75. };
  76. return "continue";
  77. }
  78. // remove the first line from the file before continuing
  79. var lineBreak = fileText.search(/\n/);
  80. fileText = lineBreak === -1 ? "" : fileText.substr(lineBreak + 1);
  81. }
  82. fileText = parse.preprocessDirectives(fileText);
  83. var fileTextWithoutMarkup = parse.removeErrorMarkup(fileText);
  84. var errorsFromMarkup = parse.parseErrorsFromMarkup(fileText);
  85. var program = void 0;
  86. if (hasConfig) {
  87. var compilerHost = {
  88. fileExists: function (file) { return file === fileCompileName || fs.existsSync(file); },
  89. getCanonicalFileName: function (filename) { return filename; },
  90. getCurrentDirectory: function () { return process.cwd(); },
  91. getDefaultLibFileName: function () { return ts.getDefaultLibFileName(compilerOptions); },
  92. getDirectories: function (dir) { return fs.readdirSync(dir); },
  93. getNewLine: function () { return "\n"; },
  94. getSourceFile: function (filenameToGet, target) {
  95. if (utils_1.denormalizeWinPath(filenameToGet) === fileCompileName) {
  96. return ts.createSourceFile(filenameToGet, fileTextWithoutMarkup, target, true);
  97. }
  98. if (path.basename(filenameToGet) === filenameToGet) {
  99. // resolve path of lib.xxx.d.ts
  100. filenameToGet = path.join(path.dirname(ts.getDefaultLibFilePath(compilerOptions)), filenameToGet);
  101. }
  102. var text = fs.readFileSync(filenameToGet, "utf8");
  103. return ts.createSourceFile(filenameToGet, text, target, true);
  104. },
  105. readFile: function (x) { return x; },
  106. useCaseSensitiveFileNames: function () { return true; },
  107. writeFile: function () { return null; },
  108. };
  109. program = ts.createProgram([fileCompileName], compilerOptions, compilerHost);
  110. }
  111. var lintOptions = {
  112. fix: false,
  113. formatter: "prose",
  114. formattersDirectory: "",
  115. rulesDirectory: rulesDirectory,
  116. };
  117. var linter = new linter_1.Linter(lintOptions, program);
  118. // Need to use the true path (ending in '.lint') for "encoding" rule so that it can read the file.
  119. linter.lint(isEncodingRule ? fileToLint : fileCompileName, fileTextWithoutMarkup, tslintConfig);
  120. var failures = linter.getResult().failures;
  121. var errorsFromLinter = failures.map(function (failure) {
  122. var startLineAndCharacter = failure.getStartPosition().getLineAndCharacter();
  123. var endLineAndCharacter = failure.getEndPosition().getLineAndCharacter();
  124. return {
  125. endPos: {
  126. col: endLineAndCharacter.character,
  127. line: endLineAndCharacter.line,
  128. },
  129. message: failure.getFailure(),
  130. startPos: {
  131. col: startLineAndCharacter.character,
  132. line: startLineAndCharacter.line,
  133. },
  134. };
  135. });
  136. // test against fixed files
  137. var fixedFileText = "";
  138. var newFileText = "";
  139. try {
  140. var fixedFile = fileToLint.replace(/\.lint$/, FIXES_FILE_EXTENSION);
  141. var stat = fs.statSync(fixedFile);
  142. if (stat.isFile()) {
  143. fixedFileText = fs.readFileSync(fixedFile, "utf8");
  144. var fixes = utils_1.mapDefined(failures, function (f) { return f.getFix(); });
  145. newFileText = rule_1.Replacement.applyFixes(fileTextWithoutMarkup, fixes);
  146. }
  147. }
  148. catch (e) {
  149. fixedFileText = "";
  150. newFileText = "";
  151. }
  152. results.results[fileToLint] = {
  153. errorsFromLinter: errorsFromLinter,
  154. errorsFromMarkup: errorsFromMarkup,
  155. fixesFromLinter: newFileText,
  156. fixesFromMarkup: fixedFileText,
  157. markupFromLinter: parse.createMarkupFromErrors(fileTextWithoutMarkup, errorsFromMarkup),
  158. markupFromMarkup: parse.createMarkupFromErrors(fileTextWithoutMarkup, errorsFromLinter),
  159. skipped: false,
  160. };
  161. };
  162. for (var _i = 0, filesToLint_1 = filesToLint; _i < filesToLint_1.length; _i++) {
  163. var fileToLint = filesToLint_1[_i];
  164. _loop_1(fileToLint);
  165. }
  166. return results;
  167. }
  168. exports.runTest = runTest;
  169. function consoleTestResultsHandler(testResults, logger) {
  170. var didAllTestsPass = true;
  171. for (var _i = 0, testResults_1 = testResults; _i < testResults_1.length; _i++) {
  172. var testResult = testResults_1[_i];
  173. if (!consoleTestResultHandler(testResult, logger)) {
  174. didAllTestsPass = false;
  175. }
  176. }
  177. return didAllTestsPass;
  178. }
  179. exports.consoleTestResultsHandler = consoleTestResultsHandler;
  180. function consoleTestResultHandler(testResult, logger) {
  181. // needed to get colors to show up when passing through Grunt
  182. chalk_1.default.enabled = true;
  183. var didAllTestsPass = true;
  184. for (var _i = 0, _a = Object.keys(testResult.results); _i < _a.length; _i++) {
  185. var fileName = _a[_i];
  186. var results = testResult.results[fileName];
  187. logger.log(fileName + ":");
  188. if (results.skipped) {
  189. logger.log(chalk_1.default.yellow(" Skipped, requires typescript " + results.requirement + "\n"));
  190. }
  191. else {
  192. var markupDiffResults = diff.diffLines(results.markupFromMarkup, results.markupFromLinter);
  193. var fixesDiffResults = diff.diffLines(results.fixesFromLinter, results.fixesFromMarkup);
  194. var didMarkupTestPass = !markupDiffResults.some(function (hunk) { return hunk.added === true || hunk.removed === true; });
  195. var didFixesTestPass = !fixesDiffResults.some(function (hunk) { return hunk.added === true || hunk.removed === true; });
  196. if (didMarkupTestPass && didFixesTestPass) {
  197. logger.log(chalk_1.default.green(" Passed\n"));
  198. }
  199. else {
  200. logger.log(chalk_1.default.red(" Failed!\n"));
  201. didAllTestsPass = false;
  202. if (!didMarkupTestPass) {
  203. displayDiffResults(markupDiffResults, MARKUP_FILE_EXTENSION, logger);
  204. }
  205. if (!didFixesTestPass) {
  206. displayDiffResults(fixesDiffResults, FIXES_FILE_EXTENSION, logger);
  207. }
  208. }
  209. }
  210. }
  211. return didAllTestsPass;
  212. }
  213. exports.consoleTestResultHandler = consoleTestResultHandler;
  214. function displayDiffResults(diffResults, extension, logger) {
  215. logger.log(chalk_1.default.green("Expected (from " + extension + " file)\n"));
  216. logger.log(chalk_1.default.red("Actual (from TSLint)\n"));
  217. for (var _i = 0, diffResults_1 = diffResults; _i < diffResults_1.length; _i++) {
  218. var diffResult = diffResults_1[_i];
  219. var color = chalk_1.default.grey;
  220. if (diffResult.added) {
  221. color = chalk_1.default.green.underline;
  222. }
  223. else if (diffResult.removed) {
  224. color = chalk_1.default.red.underline;
  225. }
  226. logger.log(color(diffResult.value));
  227. }
  228. }