2025-10-15 10:12:44 +03:00

193 lines
6.9 KiB
Go

package tsctests
import (
"fmt"
"path/filepath"
"slices"
"strings"
"testing"
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/core"
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/execute"
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/execute/tsc"
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/testutil/baseline"
"efprojects.com/kitten-ipc/kitcom/internal/tsgo/tspath"
)
type tscEdit struct {
caption string
commandLineArgs []string
edit func(*testSys)
expectedDiff string
}
var noChange = &tscEdit{
caption: "no change",
}
var noChangeOnlyEdit = []*tscEdit{
noChange,
}
type tscInput struct {
subScenario string
commandLineArgs []string
files FileMap
cwd string
edits []*tscEdit
env map[string]string
ignoreCase bool
windowsStyleRoot string
}
func (test *tscInput) executeCommand(sys *testSys, baselineBuilder *strings.Builder, commandLineArgs []string) tsc.CommandLineResult {
fmt.Fprint(baselineBuilder, "tsgo ", strings.Join(commandLineArgs, " "), "\n")
result := execute.CommandLine(sys, commandLineArgs, sys)
switch result.Status {
case tsc.ExitStatusSuccess:
baselineBuilder.WriteString("ExitStatus:: Success")
case tsc.ExitStatusDiagnosticsPresent_OutputsSkipped:
baselineBuilder.WriteString("ExitStatus:: DiagnosticsPresent_OutputsSkipped")
case tsc.ExitStatusDiagnosticsPresent_OutputsGenerated:
baselineBuilder.WriteString("ExitStatus:: DiagnosticsPresent_OutputsGenerated")
case tsc.ExitStatusInvalidProject_OutputsSkipped:
baselineBuilder.WriteString("ExitStatus:: InvalidProject_OutputsSkipped")
case tsc.ExitStatusProjectReferenceCycle_OutputsSkipped:
baselineBuilder.WriteString("ExitStatus:: ProjectReferenceCycle_OutputsSkipped")
case tsc.ExitStatusNotImplemented:
baselineBuilder.WriteString("ExitStatus:: NotImplemented")
default:
panic(fmt.Sprintf("UnknownExitStatus %d", result.Status))
}
return result
}
func (test *tscInput) run(t *testing.T, scenario string) {
t.Helper()
t.Run(test.getBaselineSubFolder()+"/"+test.subScenario, func(t *testing.T) {
t.Parallel()
// initial test tsc compile
baselineBuilder := &strings.Builder{}
sys := newTestSys(test, false)
fmt.Fprint(
baselineBuilder,
"currentDirectory::",
sys.GetCurrentDirectory(),
"\nuseCaseSensitiveFileNames::",
sys.FS().UseCaseSensitiveFileNames(),
"\nInput::\n",
)
sys.baselineFSwithDiff(baselineBuilder)
result := test.executeCommand(sys, baselineBuilder, test.commandLineArgs)
sys.serializeState(baselineBuilder)
unexpectedDiff := sys.baselinePrograms(baselineBuilder, "Initial build")
for index, do := range test.edits {
sys.clearOutput()
wg := core.NewWorkGroup(false)
var nonIncrementalSys *testSys
commandLineArgs := core.IfElse(do.commandLineArgs == nil, test.commandLineArgs, do.commandLineArgs)
wg.Queue(func() {
baselineBuilder.WriteString(fmt.Sprintf("\n\nEdit [%d]:: %s\n", index, do.caption))
if do.edit != nil {
do.edit(sys)
}
sys.baselineFSwithDiff(baselineBuilder)
if result.Watcher == nil {
test.executeCommand(sys, baselineBuilder, commandLineArgs)
} else {
result.Watcher.DoCycle()
}
sys.serializeState(baselineBuilder)
unexpectedDiff += sys.baselinePrograms(baselineBuilder, fmt.Sprintf("Edit [%d]:: %s\n", index, do.caption))
})
wg.Queue(func() {
// Compute build with all the edits
nonIncrementalSys = newTestSys(test, true)
for i := range index + 1 {
if test.edits[i].edit != nil {
test.edits[i].edit(nonIncrementalSys)
}
}
execute.CommandLine(nonIncrementalSys, commandLineArgs, nonIncrementalSys)
})
wg.RunAndWait()
diff := getDiffForIncremental(sys, nonIncrementalSys)
if diff != "" {
baselineBuilder.WriteString(fmt.Sprintf("\n\nDiff:: %s\n", core.IfElse(do.expectedDiff == "", "!!! Unexpected diff, please review and either fix or write explanation as expectedDiff !!!", do.expectedDiff)))
baselineBuilder.WriteString(diff)
if do.expectedDiff == "" {
unexpectedDiff += fmt.Sprintf("Edit [%d]:: %s\n!!! Unexpected diff, please review and either fix or write explanation as expectedDiff !!!\n%s\n", index, do.caption, diff)
}
} else if do.expectedDiff != "" {
baselineBuilder.WriteString(fmt.Sprintf("\n\nDiff:: %s !!! Diff not found but explanation present, please review and remove the explanation !!!\n", do.expectedDiff))
unexpectedDiff += fmt.Sprintf("Edit [%d]:: %s\n!!! Diff not found but explanation present, please review and remove the explanation !!!\n", index, do.caption)
}
}
baseline.Run(t, strings.ReplaceAll(test.subScenario, " ", "-")+".js", baselineBuilder.String(), baseline.Options{Subfolder: filepath.Join(test.getBaselineSubFolder(), scenario)})
if unexpectedDiff != "" {
t.Errorf("Test %s has unexpected diff %s with incremental build, please review the baseline file", test.subScenario, unexpectedDiff)
}
})
}
func getDiffForIncremental(incrementalSys *testSys, nonIncrementalSys *testSys) string {
var diffBuilder strings.Builder
nonIncrementalOutputs := nonIncrementalSys.fs.writtenFiles.ToSlice()
slices.Sort(nonIncrementalOutputs)
for _, nonIncrementalOutput := range nonIncrementalOutputs {
if tspath.FileExtensionIs(nonIncrementalOutput, tspath.ExtensionTsBuildInfo) ||
strings.HasSuffix(nonIncrementalOutput, ".readable.baseline.txt") {
// Just check existence
if !incrementalSys.fsFromFileMap().FileExists(nonIncrementalOutput) {
diffBuilder.WriteString(baseline.DiffText("nonIncremental "+nonIncrementalOutput, "incremental "+nonIncrementalOutput, "Exists", ""))
diffBuilder.WriteString("\n")
}
} else {
nonIncrementalText, ok := nonIncrementalSys.fsFromFileMap().ReadFile(nonIncrementalOutput)
if !ok {
panic("Written file not found " + nonIncrementalOutput)
}
incrementalText, ok := incrementalSys.fsFromFileMap().ReadFile(nonIncrementalOutput)
if !ok || incrementalText != nonIncrementalText {
diffBuilder.WriteString(baseline.DiffText("nonIncremental "+nonIncrementalOutput, "incremental "+nonIncrementalOutput, nonIncrementalText, incrementalText))
diffBuilder.WriteString("\n")
}
}
}
incrementalOutput := incrementalSys.getOutput(true)
nonIncrementalOutput := nonIncrementalSys.getOutput(true)
if incrementalOutput != nonIncrementalOutput {
diffBuilder.WriteString(baseline.DiffText("nonIncremental.output.txt", "incremental.output.txt", nonIncrementalOutput, incrementalOutput))
}
return diffBuilder.String()
}
func (test *tscInput) getBaselineSubFolder() string {
commandName := "tsc"
if slices.ContainsFunc(test.commandLineArgs, func(arg string) bool {
switch arg {
case "-b", "--b", "-build", "--build":
return true
}
return false
}) {
commandName = "tsbuild"
}
w := ""
if slices.ContainsFunc(test.commandLineArgs, func(arg string) bool {
switch arg {
case "-w", "--w", "-watch", "--watch":
return true
}
return false
}) {
w = "Watch"
}
return commandName + w
}