Testing WIP

This commit is contained in:
Ryan Cavanaugh 2018-05-21 21:24:29 -07:00
parent 6d04378e90
commit 76d2ba64df
9 changed files with 101 additions and 30 deletions

View File

@ -317,16 +317,12 @@ namespace ts {
return date2 > date1 ? date2 : date1;
}
function older(date1: Date, date2: Date): Date {
return date2 < date1 ? date2 : date1;
}
function isDeclarationFile(fileName: string) {
return fileExtensionIs(fileName, ".d.ts");
}
export function createBuildContext(options: BuildOptions): BuildContext {
const verboseDiag = options.verbose && createDiagnosticReporter(sys, /*pretty*/ false);
export function createBuildContext(options: BuildOptions, reportDiagnostic: DiagnosticReporter): BuildContext {
const verboseDiag = options.verbose && reportDiagnostic;
return {
options,
projectStatus: createFileMap(),
@ -371,8 +367,7 @@ namespace ts {
addProject(".");
}
const context = createBuildContext({ verbose, dry, force });
const builder = createSolutionBuilder(host, reportDiagnostic, context);
const builder = createSolutionBuilder(host, reportDiagnostic, { verbose, dry, force });
if (clean) {
builder.cleanProjects(projects);
}
@ -391,8 +386,9 @@ namespace ts {
}
}
export function createSolutionBuilder(host: CompilerHost, reportDiagnostic: DiagnosticReporter, context: BuildContext) {
export function createSolutionBuilder(host: CompilerHost, reportDiagnostic: DiagnosticReporter, options: BuildOptions) {
const configFileCache = createConfigFileCache(host);
let context: BuildContext = undefined!;
return {
getUpToDateStatus,
@ -473,7 +469,7 @@ namespace ts {
oldestOutputFileTime = outputTime;
oldestOutputFileName = output;
}
newestOutputFileTime = older(newestOutputFileTime, outputTime);
newestOutputFileTime = newer(newestOutputFileTime, outputTime);
// Keep track of when the most recent time a .d.ts file was changed.
// In addition to file timestamps, we also keep track of when a .d.ts file
@ -709,6 +705,8 @@ namespace ts {
}
function cleanProjects(configFileNames: string[]) {
context = createBuildContext(options, reportDiagnostic);
// Get the same graph for cleaning we'd use for building
const graph = createDependencyGraph(configFileNames);
@ -736,6 +734,8 @@ namespace ts {
}
function buildProjects(configFileNames: string[]) {
context = createBuildContext(options, reportDiagnostic);
const resolvedNames: string[] = [];
for (const name of configFileNames) {
let fullPath = resolvePath(host.getCurrentDirectory(), name);
@ -823,7 +823,7 @@ namespace ts {
context.verbose(Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist, configFileName, status.missingOutputFileName);
return;
case UpToDateStatusType.UpToDate:
context.verbose(Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2, configFileName, status.newestDeclarationFileContentChangedTime as any, status.newestOutputFileTime);
context.verbose(Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2, configFileName, status.newestInputFileTime, status.newestOutputFileTime);
return;
case UpToDateStatusType.UpToDateWithUpstreamTypes:
context.verbose(Diagnostics.Project_0_is_up_to_date_with_its_upstream_types, configFileName);

View File

@ -3,7 +3,7 @@
namespace ts {
let currentTime = 100;
const bfs = new vfs.FileSystem(/*ignoreCase*/ false, { time });
const lastDiagnostics: Diagnostic[] = [];
let lastDiagnostics: Diagnostic[] = [];
const reportDiagnostic: DiagnosticReporter = diagnostic => lastDiagnostics.push(diagnostic);
const sampleRoot = resolvePath(__dirname, "../../tests/projects/sample1");
@ -12,47 +12,109 @@ namespace ts {
bfs.writeFileSync("/lib/lib.d.ts", Harness.IO.readFile(combinePaths(Harness.libFolder, "lib.d.ts")));
bfs.meta.set("defaultLibLocation", "/lib");
bfs.makeReadonly();
tick();
describe("tsbuild tests", () => {
it("builds the referenced project", () => {
it("can build the sample project 'tests' without error", () => {
const fs = bfs.shadow();
const host = new fakes.CompilerHost(fs);
const builder = createSolutionBuilder(host, reportDiagnostic, createBuildContext({ dry: false, force: false, verbose: false }));
const builder = createSolutionBuilder(host, reportDiagnostic, { dry: false, force: false, verbose: false });
fs.chdir("/src/tests");
fs.debugPrint();
builder.buildProjects(["."]);
printDiagnostics();
fs.debugPrint();
assertDiagnosticMessages(Diagnostics.File_0_does_not_exist);
assertDiagnosticMessages(/*empty*/);
});
it("can detect when and what to rebuild", () => {
const fs = bfs.shadow();
const host = new fakes.CompilerHost(fs);
const builder = createSolutionBuilder(host, reportDiagnostic, { dry: false, force: false, verbose: true });
fs.chdir("/src/tests");
builder.buildProjects(["."]);
assertDiagnosticMessages(Diagnostics.Sorted_list_of_input_projects_Colon_0,
Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist,
Diagnostics.Building_project_0,
Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist,
Diagnostics.Building_project_0,
Diagnostics.Project_0_is_out_of_date_because_output_file_1_does_not_exist,
Diagnostics.Building_project_0);
tick();
// All three projects are up to date
clearDiagnostics();
builder.buildProjects(["."]);
assertDiagnosticMessages(Diagnostics.Sorted_list_of_input_projects_Colon_0,
Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2,
Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2,
Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2);
tick();
// Update a file in the leaf node (tests), only it should rebuild the last one
clearDiagnostics();
fs.writeFileSync("/src/tests/index.ts", "const m = 10;");
builder.buildProjects(["."]);
assertDiagnosticMessages(Diagnostics.Sorted_list_of_input_projects_Colon_0,
Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2,
Diagnostics.Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2,
Diagnostics.Project_0_is_out_of_date_because_oldest_output_1_is_older_than_newest_input_2,
Diagnostics.Building_project_0);
tick();
// Update a file in the parent (without affecting types), should get fast downstream builds
clearDiagnostics();
replaceText(fs, "/src/core/index.ts", "HELLO WORLD", "WELCOME PLANET");
builder.buildProjects(["."]);
assertDiagnosticMessages(Diagnostics.Sorted_list_of_input_projects_Colon_0,
Diagnostics.Project_0_is_out_of_date_because_oldest_output_1_is_older_than_newest_input_2,
Diagnostics.Building_project_0,
Diagnostics.Project_0_is_up_to_date_with_its_upstream_types,
Diagnostics.Updating_output_timestamps_of_project_0,
Diagnostics.Project_0_is_up_to_date_with_its_upstream_types,
Diagnostics.Updating_output_timestamps_of_project_0);
});
});
function replaceText(fs: vfs.FileSystem, path: string, oldText: string, newText: string) {
if (!fs.statSync(path).isFile()) {
throw new Error(`File ${path} does not exist`);
}
const old = fs.readFileSync(path, 'utf-8');
if (old.indexOf(oldText) < 0) {
throw new Error(`Text "${oldText}" does not exist in file ${path}`);
}
const newContent = old.replace(oldText, newText);
fs.writeFileSync(path, newContent, 'utf-8');
}
function assertDiagnosticMessages(...expected: DiagnosticMessage[]) {
const actual = lastDiagnostics.slice();
actual.sort((a, b) => b.code - a.code);
expected.sort((a, b) => b.code - a.code);
if (actual.length !== expected.length) {
assert.fail<any>(actual, expected, `Diagnostic arrays did not match - expected ${actual.join(",")}, got ${expected.join(",")}`);
assert.fail<any>(actual, expected, `Diagnostic arrays did not match - expected\r\n${actual.map(a => " " + a.messageText).join("\r\n")}\r\ngot\r\n${expected.map(e => " " + e.message).join("\r\n")}`);
}
for (let i = 0; i < actual.length; i++) {
if (actual[i].code !== expected[i].code) {
assert.fail(actual[i].messageText, expected[i].message, "Mismatched error code");
assert.fail(actual[i].messageText, expected[i].message, `Mismatched error code - expected diagnostic ${i} "${actual[i].messageText}" to match ${expected[i].message}`);
}
}
}
export function printDiagnostics() {
function clearDiagnostics() {
lastDiagnostics = [];
}
export function printDiagnostics(header = "== Diagnostics ==") {
const out = createDiagnosticReporter(sys);
sys.write(header + "\r\n");
for (const d of lastDiagnostics) {
out(d);
}
}
function tick() {
currentTime += 10;
currentTime += 100000;
}
function time() {
return currentTime;

View File

@ -1,2 +1,3 @@
export const someString: string = "HELLO WORLD";
export function leftPad(s: string, n: number) { return s + n; }
export function multiply(a: number, b: number) { return a * b; }

View File

@ -1,3 +1,6 @@
{
"compilerOptions": {
"composite": true,
"declaration": true
}
}

View File

@ -1,4 +1,4 @@
import * as c from '../core';
import * as c from '../core/index';
export function getSecondsInDay() {
return c.multiply(10, 15);
}

View File

@ -1,4 +1,8 @@
{
"compilerOptions": {
"composite": true,
"declaration": true
},
"references": [
{ "path": "../core" }
]

View File

@ -1,5 +1,5 @@
import * as c from '../core';
import * as logic from '../logic';
import * as c from '../core/index';
import * as logic from '../logic/index';
c.leftPad("", 10);
logic.getSecondsInDay();

View File

@ -2,5 +2,6 @@
"references": [
{ "path": "../core" },
{ "path": "../logic" }
]
],
"files": ["index.ts"]
}

View File

@ -1,5 +1,5 @@
{
"references": [
{ "path": "../logic" }
{ "path": "../logic/index" }
]
}