Skip to content

Commit 4a8c488

Browse files
committed
Use command line testing interface to sanitize output
1 parent a29db5d commit 4a8c488

File tree

14 files changed

+204
-46
lines changed

14 files changed

+204
-46
lines changed

cmd/tsgo/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,6 @@ func runMain() int {
2020
return runAPI(args[1:])
2121
}
2222
}
23-
result := execute.CommandLine(newSystem(), args, false)
23+
result := execute.CommandLine(newSystem(), args, nil)
2424
return int(result.Status)
2525
}

internal/execute/outputs.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,13 @@ func createReportErrorSummary(sys System, options *core.CompilerOptions) func(di
134134
return func(diagnostics []*ast.Diagnostic) {}
135135
}
136136

137-
func reportStatistics(sys System, program *compiler.Program, result compileAndEmitResult, memStats *runtime.MemStats) {
137+
func reportStatistics(sys System, program *compiler.Program, result compileAndEmitResult, memStats *runtime.MemStats, testing CommandLineTesting) {
138138
var stats table
139139

140+
if testing != nil {
141+
testing.OnStatisticsStart()
142+
defer testing.OnStatisticsEnd()
143+
}
140144
stats.add("Files", len(program.SourceFiles()))
141145
stats.add("Lines", program.LineCount())
142146
stats.add("Identifiers", program.IdentifierCount())

internal/execute/testsys_test.go

Lines changed: 98 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,10 @@ type testSys struct {
111111
start time.Time
112112
}
113113

114-
var _ execute.System = (*testSys)(nil)
114+
var (
115+
_ execute.System = (*testSys)(nil)
116+
_ execute.CommandLineTesting = (*testSys)(nil)
117+
)
115118

116119
func (s *testSys) Now() time.Time {
117120
// todo: make a "test time" structure
@@ -175,17 +178,20 @@ func (s *testSys) GetEnvironmentVariable(name string) string {
175178
return s.env[name]
176179
}
177180

178-
func sanitizeSysOutput(output string, prefixLine string, replaceString string) string {
179-
for {
180-
if index := strings.Index(output, prefixLine); index != -1 {
181-
indexOfNewLine := strings.Index(output[index:], "\n")
182-
if indexOfNewLine != -1 {
183-
output = output[:index] + replaceString + output[index+indexOfNewLine+1:]
184-
continue
185-
}
186-
}
187-
return output
188-
}
181+
func (s *testSys) OnListFilesStart() {
182+
fmt.Fprintln(s.Writer(), listFileStart)
183+
}
184+
185+
func (s *testSys) OnListFilesEnd() {
186+
fmt.Fprintln(s.Writer(), listFileEnd)
187+
}
188+
189+
func (s *testSys) OnStatisticsStart() {
190+
fmt.Fprintln(s.Writer(), statisticsStart)
191+
}
192+
193+
func (s *testSys) OnStatisticsEnd() {
194+
fmt.Fprintln(s.Writer(), statisticsEnd)
189195
}
190196

191197
func (s *testSys) baselineProgram(baseline *strings.Builder, program *incremental.Program, watcher *execute.Watcher) {
@@ -241,17 +247,90 @@ func (s *testSys) serializeState(baseline *strings.Builder) {
241247
// this.service?.baseline();
242248
}
243249

250+
var (
251+
fakeTimeStamp = "HH:MM:SS AM"
252+
fakeDuration = "d.ddds"
253+
254+
buildStartingAt = "build starting at "
255+
buildFinishedIn = "build finished in "
256+
listFileStart = "!!! List files start"
257+
listFileEnd = "!!! List files end"
258+
statisticsStart = "!!! Statistics start"
259+
statisticsEnd = "!!! Statistics end"
260+
)
261+
244262
func (s *testSys) baselineOutput(baseline io.Writer) {
245263
fmt.Fprint(baseline, "\nOutput::\n")
246-
fmt.Fprint(baseline, s.getOutput())
264+
output := s.getOutput(false)
265+
fmt.Fprint(baseline, output)
266+
}
267+
268+
type outputSanitizer struct {
269+
forComparing bool
270+
lines []string
271+
index int
272+
outputLines []string
273+
}
274+
275+
func (o *outputSanitizer) addOutputLine(s string) {
276+
o.outputLines = append(o.outputLines, s)
247277
}
248278

249-
func (s *testSys) getOutput() string {
250-
output := s.currentWrite.String()
251-
output = sanitizeSysOutput(output, "Version "+core.Version(), "Version "+harnessutil.FakeTSVersion+"\n")
252-
output = sanitizeSysOutput(output, "build starting at ", "")
253-
output = sanitizeSysOutput(output, "build finished in ", "")
254-
return output
279+
func (o *outputSanitizer) transformLines() string {
280+
for ; o.index < len(o.lines); o.index++ {
281+
line := o.lines[o.index]
282+
if change := strings.Replace(line, "Version "+core.Version(), "Version "+harnessutil.FakeTSVersion, 1); change != line {
283+
o.addOutputLine(change)
284+
continue
285+
}
286+
if strings.HasPrefix(line, buildStartingAt) {
287+
if !o.forComparing {
288+
o.addOutputLine(buildStartingAt + fakeTimeStamp)
289+
}
290+
continue
291+
}
292+
if strings.HasPrefix(line, buildFinishedIn) {
293+
if !o.forComparing {
294+
o.addOutputLine(buildFinishedIn + fakeDuration)
295+
}
296+
continue
297+
}
298+
if !o.addOrSkipLinesForComparing(listFileStart, listFileEnd, false) &&
299+
!o.addOrSkipLinesForComparing(statisticsStart, statisticsEnd, true) {
300+
o.addOutputLine(line)
301+
}
302+
}
303+
return strings.Join(o.outputLines, "\n")
304+
}
305+
306+
func (o *outputSanitizer) addOrSkipLinesForComparing(
307+
lineStart string,
308+
lineEnd string,
309+
skipEvenIfNotComparing bool,
310+
) bool {
311+
if o.lines[o.index] != lineStart {
312+
return false
313+
}
314+
o.index++
315+
for ; o.index < len(o.lines); o.index++ {
316+
if o.lines[o.index] == lineEnd {
317+
return true
318+
}
319+
if !o.forComparing && !skipEvenIfNotComparing {
320+
o.addOutputLine(o.lines[o.index])
321+
}
322+
}
323+
panic("Expected lineEnd" + lineEnd + " not found after " + lineStart)
324+
}
325+
326+
func (s *testSys) getOutput(forComparing bool) string {
327+
lines := strings.Split(s.currentWrite.String(), "\n")
328+
transformer := &outputSanitizer{
329+
forComparing: forComparing,
330+
lines: lines,
331+
outputLines: make([]string, 0, len(lines)),
332+
}
333+
return transformer.transformLines()
255334
}
256335

257336
func (s *testSys) clearOutput() {

internal/execute/tsc.go

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ import (
2121
"github.com/microsoft/typescript-go/internal/tspath"
2222
)
2323

24-
type cbType = func(p any) any
25-
2624
func applyBulkEdits(text string, edits []core.TextChange) string {
2725
b := strings.Builder{}
2826
b.Grow(len(text))
@@ -47,7 +45,14 @@ type CommandLineResult struct {
4745
Watcher *Watcher
4846
}
4947

50-
func CommandLine(sys System, commandLineArgs []string, testing bool) CommandLineResult {
48+
type CommandLineTesting interface {
49+
OnListFilesStart()
50+
OnListFilesEnd()
51+
OnStatisticsStart()
52+
OnStatisticsEnd()
53+
}
54+
55+
func CommandLine(sys System, commandLineArgs []string, testing CommandLineTesting) CommandLineResult {
5156
if len(commandLineArgs) > 0 {
5257
// !!! build mode
5358
switch strings.ToLower(commandLineArgs[0]) {
@@ -88,7 +93,7 @@ func fmtMain(sys System, input, output string) ExitStatus {
8893
return ExitStatusSuccess
8994
}
9095

91-
func tscCompilation(sys System, commandLine *tsoptions.ParsedCommandLine, testing bool) CommandLineResult {
96+
func tscCompilation(sys System, commandLine *tsoptions.ParsedCommandLine, testing CommandLineTesting) CommandLineResult {
9297
configFileName := ""
9398
reportDiagnostic := createDiagnosticReporter(sys, commandLine.CompilerOptions())
9499
// if commandLine.Options().Locale != nil
@@ -205,6 +210,7 @@ func tscCompilation(sys System, commandLine *tsoptions.ParsedCommandLine, testin
205210
reportDiagnostic,
206211
&extendedConfigCache,
207212
configTime,
213+
testing,
208214
)
209215
}
210216

@@ -234,7 +240,7 @@ func performIncrementalCompilation(
234240
reportDiagnostic diagnosticReporter,
235241
extendedConfigCache *collections.SyncMap[tspath.Path, *tsoptions.ExtendedConfigCacheEntry],
236242
configTime time.Duration,
237-
testing bool,
243+
testing CommandLineTesting,
238244
) CommandLineResult {
239245
host := compiler.NewCachedFSCompilerHost(sys.GetCurrentDirectory(), sys.FS(), sys.DefaultLibraryPath(), extendedConfigCache, getTraceFromSys(sys))
240246
buildInfoReadStart := sys.Now()
@@ -249,7 +255,7 @@ func performIncrementalCompilation(
249255
})
250256
parseTime := sys.Now().Sub(parseStart)
251257
changesComputeStart := sys.Now()
252-
incrementalProgram := incremental.NewProgram(program, oldProgram, testing)
258+
incrementalProgram := incremental.NewProgram(program, oldProgram, testing != nil)
253259
changesComputeTime := sys.Now().Sub(changesComputeStart)
254260
return CommandLineResult{
255261
Status: emitAndReportStatistics(
@@ -263,6 +269,7 @@ func performIncrementalCompilation(
263269

264270
buildInfoReadTime,
265271
changesComputeTime,
272+
testing,
266273
),
267274
IncrementalProgram: incrementalProgram,
268275
}
@@ -274,6 +281,7 @@ func performCompilation(
274281
reportDiagnostic diagnosticReporter,
275282
extendedConfigCache *collections.SyncMap[tspath.Path, *tsoptions.ExtendedConfigCacheEntry],
276283
configTime time.Duration,
284+
testing CommandLineTesting,
277285
) CommandLineResult {
278286
host := compiler.NewCachedFSCompilerHost(sys.GetCurrentDirectory(), sys.FS(), sys.DefaultLibraryPath(), extendedConfigCache, getTraceFromSys(sys))
279287
// todo: cache, statistics, tracing
@@ -295,6 +303,7 @@ func performCompilation(
295303
parseTime,
296304
0,
297305
0,
306+
testing,
298307
),
299308
}
300309
}
@@ -309,8 +318,9 @@ func emitAndReportStatistics(
309318
parseTime time.Duration,
310319
buildInfoReadTime time.Duration,
311320
changesComputeTime time.Duration,
321+
testing CommandLineTesting,
312322
) ExitStatus {
313-
result := emitFilesAndReportErrors(sys, programLike, program, reportDiagnostic)
323+
result := emitFilesAndReportErrors(sys, programLike, program, reportDiagnostic, testing)
314324
if result.status != ExitStatusSuccess {
315325
// compile exited early
316326
return result.status
@@ -329,7 +339,7 @@ func emitAndReportStatistics(
329339
runtime.GC()
330340
runtime.ReadMemStats(&memStats)
331341

332-
reportStatistics(sys, program, result, &memStats)
342+
reportStatistics(sys, program, result, &memStats, testing)
333343
}
334344

335345
if result.emitResult.EmitSkipped && len(result.diagnostics) > 0 {
@@ -359,6 +369,7 @@ func emitFilesAndReportErrors(
359369
programLike compiler.ProgramLike,
360370
program *compiler.Program,
361371
reportDiagnostic diagnosticReporter,
372+
testing CommandLineTesting,
362373
) (result compileAndEmitResult) {
363374
ctx := context.Background()
364375

@@ -399,12 +410,7 @@ func emitFilesAndReportErrors(
399410
reportDiagnostic(diagnostic)
400411
}
401412

402-
if sys.Writer() != nil {
403-
for _, file := range emitResult.EmittedFiles {
404-
fmt.Fprintln(sys.Writer(), "TSFILE: ", tspath.GetNormalizedAbsolutePath(file, sys.GetCurrentDirectory()))
405-
}
406-
listFiles(sys, program)
407-
}
413+
listFiles(sys, program, emitResult, testing)
408414

409415
createReportErrorSummary(sys, programLike.Options())(allDiagnostics)
410416
result.diagnostics = allDiagnostics
@@ -422,7 +428,14 @@ func showConfig(sys System, config *core.CompilerOptions) {
422428
_ = jsonutil.MarshalIndentWrite(sys.Writer(), config, "", " ")
423429
}
424430

425-
func listFiles(sys System, program *compiler.Program) {
431+
func listFiles(sys System, program *compiler.Program, emitResult *compiler.EmitResult, testing CommandLineTesting) {
432+
if testing != nil {
433+
testing.OnListFilesStart()
434+
defer testing.OnListFilesEnd()
435+
}
436+
for _, file := range emitResult.EmittedFiles {
437+
fmt.Fprintln(sys.Writer(), "TSFILE: ", tspath.GetNormalizedAbsolutePath(file, sys.GetCurrentDirectory()))
438+
}
426439
options := program.Options()
427440
if options.ExplainFiles.IsTrue() {
428441
program.ExplainFiles(sys.Writer())

internal/execute/tsctestrunner_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ type tscInput struct {
4141

4242
func (test *tscInput) executeCommand(sys *testSys, baselineBuilder *strings.Builder, commandLineArgs []string) execute.CommandLineResult {
4343
fmt.Fprint(baselineBuilder, "tsgo ", strings.Join(commandLineArgs, " "), "\n")
44-
result := execute.CommandLine(sys, commandLineArgs, true)
44+
result := execute.CommandLine(sys, commandLineArgs, sys)
4545
switch result.Status {
4646
case execute.ExitStatusSuccess:
4747
baselineBuilder.WriteString("ExitStatus:: Success")
@@ -111,7 +111,7 @@ func (test *tscInput) run(t *testing.T, scenario string) {
111111
test.edits[i].edit(nonIncrementalSys)
112112
}
113113
}
114-
execute.CommandLine(nonIncrementalSys, commandLineArgs, true)
114+
execute.CommandLine(nonIncrementalSys, commandLineArgs, nonIncrementalSys)
115115
})
116116
wg.RunAndWait()
117117

@@ -160,8 +160,8 @@ func getDiffForIncremental(incrementalSys *testSys, nonIncrementalSys *testSys)
160160
}
161161
}
162162

163-
incrementalOutput := incrementalSys.getOutput()
164-
nonIncrementalOutput := nonIncrementalSys.getOutput()
163+
incrementalOutput := incrementalSys.getOutput(true)
164+
nonIncrementalOutput := nonIncrementalSys.getOutput(true)
165165
if incrementalOutput != nonIncrementalOutput {
166166
diffBuilder.WriteString(baseline.DiffText("nonIncremental.output.txt", "incremental.output.txt", nonIncrementalOutput, incrementalOutput))
167167
}

internal/execute/watcher.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,15 @@ type Watcher struct {
1919
configFileName string
2020
options *tsoptions.ParsedCommandLine
2121
reportDiagnostic diagnosticReporter
22-
testing bool
22+
testing CommandLineTesting
2323

2424
host compiler.CompilerHost
2525
program *incremental.Program
2626
prevModified map[string]time.Time
2727
configModified bool
2828
}
2929

30-
func createWatcher(sys System, configParseResult *tsoptions.ParsedCommandLine, reportDiagnostic diagnosticReporter, testing bool) *Watcher {
30+
func createWatcher(sys System, configParseResult *tsoptions.ParsedCommandLine, reportDiagnostic diagnosticReporter, testing CommandLineTesting) *Watcher {
3131
w := &Watcher{
3232
sys: sys,
3333
options: configParseResult,
@@ -45,7 +45,7 @@ func (w *Watcher) start() {
4545
w.host = compiler.NewCompilerHost(w.sys.GetCurrentDirectory(), w.sys.FS(), w.sys.DefaultLibraryPath(), nil, getTraceFromSys(w.sys))
4646
w.program = incremental.ReadBuildInfoProgram(w.options, incremental.NewBuildInfoReader(w.host), w.host)
4747

48-
if !w.testing {
48+
if w.testing == nil {
4949
watchInterval := 1000 * time.Millisecond
5050
if w.options.ParsedConfig.WatchOptions != nil {
5151
watchInterval = time.Duration(*w.options.ParsedConfig.WatchOptions.Interval) * time.Millisecond
@@ -72,7 +72,7 @@ func (w *Watcher) DoCycle() {
7272
Config: w.options,
7373
Host: w.host,
7474
JSDocParsingMode: ast.JSDocParsingModeParseForTypeErrors,
75-
}), w.program, w.testing)
75+
}), w.program, w.testing != nil)
7676

7777
if w.hasBeenModified(w.program.GetProgram()) {
7878
fmt.Fprintln(w.sys.Writer(), "build starting at ", w.sys.Now())
@@ -88,7 +88,7 @@ func (w *Watcher) DoCycle() {
8888
func (w *Watcher) compileAndEmit() {
8989
// !!! output/error reporting is currently the same as non-watch mode
9090
// diagnostics, emitResult, exitStatus :=
91-
emitFilesAndReportErrors(w.sys, w.program, w.program.GetProgram(), w.reportDiagnostic)
91+
emitFilesAndReportErrors(w.sys, w.program, w.program.GetProgram(), w.reportDiagnostic, w.testing)
9292
}
9393

9494
func (w *Watcher) hasErrorsInTsConfig() bool {

testdata/baselines/reference/tsc/commandLine/show-help-with-ExitStatus.DiagnosticsPresent_OutputsSkipped.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ tsgo
66
ExitStatus:: DiagnosticsPresent_OutputsSkipped
77
Output::
88
Version FakeTSVersion
9-
tsc: The TypeScript Compiler - Version FakeTSVersion
9+
tsc: The TypeScript Compiler - Version FakeTSVersion [44m [39;49m
1010
 TS 
1111
COMMON COMMANDS
1212

testdata/baselines/reference/tscWatch/commandLine/Parse-watch-interval-option.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ export const a = 1
1414
tsgo -w --watchInterval 1000
1515
ExitStatus:: Success
1616
Output::
17+
build starting at HH:MM:SS AM
18+
build finished in d.ddds
1719
//// [/home/src/tslibs/TS/Lib/lib.d.ts] *Lib*
1820
/// <reference no-default-lib="true"/>
1921
interface Boolean {}

0 commit comments

Comments
 (0)