// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package scripttest adapts the script engine for use in tests.
package scripttest

import (
	"bytes"
	"cmd/internal/script"
	"context"
	"fmt"
	"internal/testenv"
	"internal/txtar"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"testing"
	"time"
)

// ToolReplacement records the name of a tool to replace
// within a given GOROOT for script testing purposes.
type ToolReplacement struct {
	ToolName        string // e.g. compile, link, addr2line, etc
	ReplacementPath string // path to replacement tool exe
	EnvVar          string // env var setting (e.g. "FOO=BAR")
}

// RunToolScriptTest kicks off a set of script tests runs for
// a tool of some sort (compiler, linker, etc). The expectation
// is that we'll be called from the top level cmd/X dir for tool X,
// and that instead of executing the install tool X we'll use the
// test binary instead.
func RunToolScriptTest(t *testing.T, repls []ToolReplacement, scriptsdir string, fixReadme bool) {
	// Nearly all script tests involve doing builds, so don't
	// bother here if we don't have "go build".
	testenv.MustHaveGoBuild(t)

	// Skip this path on plan9, which doesn't support symbolic
	// links (we would have to copy too much).
	if runtime.GOOS == "plan9" {
		t.Skipf("no symlinks on plan9")
	}

	// Locate our Go tool.
	gotool, err := testenv.GoTool()
	if err != nil {
		t.Fatalf("locating go tool: %v", err)
	}

	goEnv := func(name string) string {
		out, err := exec.Command(gotool, "env", name).CombinedOutput()
		if err != nil {
			t.Fatalf("go env %s: %v\n%s", name, err, out)
		}
		return strings.TrimSpace(string(out))
	}

	// Construct an initial set of commands + conditions to make available
	// to the script tests.
	cmds := DefaultCmds()
	conds := DefaultConds()

	addcmd := func(name string, cmd script.Cmd) {
		if _, ok := cmds[name]; ok {
			panic(fmt.Sprintf("command %q is already registered", name))
		}
		cmds[name] = cmd
	}

	prependToPath := func(env []string, dir string) {
		found := false
		for k := range env {
			ev := env[k]
			if !strings.HasPrefix(ev, "PATH=") {
				continue
			}
			oldpath := ev[5:]
			env[k] = "PATH=" + dir + string(filepath.ListSeparator) + oldpath
			found = true
			break
		}
		if !found {
			t.Fatalf("could not update PATH")
		}
	}

	setenv := func(env []string, varname, val string) []string {
		pref := varname + "="
		found := false
		for k := range env {
			if !strings.HasPrefix(env[k], pref) {
				continue
			}
			env[k] = pref + val
			found = true
			break
		}
		if !found {
			env = append(env, varname+"="+val)
		}
		return env
	}

	interrupt := func(cmd *exec.Cmd) error {
		return cmd.Process.Signal(os.Interrupt)
	}
	gracePeriod := 60 * time.Second // arbitrary

	// Set up an alternate go root for running script tests, since it
	// is possible that we might want to replace one of the installed
	// tools with a unit test executable.
	goroot := goEnv("GOROOT")
	tmpdir := t.TempDir()
	tgr := SetupTestGoRoot(t, tmpdir, goroot)

	// Replace tools if appropriate
	for _, repl := range repls {
		ReplaceGoToolInTestGoRoot(t, tgr, repl.ToolName, repl.ReplacementPath)
	}

	// Add in commands for "go" and "cc".
	testgo := filepath.Join(tgr, "bin", "go")
	gocmd := script.Program(testgo, interrupt, gracePeriod)
	addcmd("go", gocmd)
	cmdExec := cmds["exec"]
	addcmd("cc", scriptCC(cmdExec, goEnv("CC")))

	// Add various helpful conditions related to builds and toolchain use.
	goHostOS, goHostArch := goEnv("GOHOSTOS"), goEnv("GOHOSTARCH")
	AddToolChainScriptConditions(t, conds, goHostOS, goHostArch)

	// Environment setup.
	env := os.Environ()
	prependToPath(env, filepath.Join(tgr, "bin"))
	env = setenv(env, "GOROOT", tgr)
	// GOOS and GOARCH are expected to be set by the toolchain script conditions.
	env = setenv(env, "GOOS", runtime.GOOS)
	env = setenv(env, "GOARCH", runtime.GOARCH)
	for _, repl := range repls {
		// consistency check
		chunks := strings.Split(repl.EnvVar, "=")
		if len(chunks) != 2 {
			t.Fatalf("malformed env var setting: %s", repl.EnvVar)
		}
		env = append(env, repl.EnvVar)
	}

	// Manufacture engine...
	engine := &script.Engine{
		Conds: conds,
		Cmds:  cmds,
		Quiet: !testing.Verbose(),
	}

	t.Run("README", func(t *testing.T) {
		checkScriptReadme(t, engine, env, scriptsdir, gotool, fixReadme)
	})

	// ... and kick off tests.
	ctx := context.Background()
	pattern := filepath.Join(scriptsdir, "*.txt")
	RunTests(t, ctx, engine, env, pattern)
}

// RunTests kicks off one or more script-based tests using the
// specified engine, running all test files that match pattern.
// This function adapted from Russ's rsc.io/script/scripttest#Run
// function, which was in turn forked off cmd/go's runner.
func RunTests(t *testing.T, ctx context.Context, engine *script.Engine, env []string, pattern string) {
	gracePeriod := 100 * time.Millisecond
	if deadline, ok := t.Deadline(); ok {
		timeout := time.Until(deadline)

		// If time allows, increase the termination grace period to 5% of the
		// remaining time.
		if gp := timeout / 20; gp > gracePeriod {
			gracePeriod = gp
		}

		// When we run commands that execute subprocesses, we want to
		// reserve two grace periods to clean up. We will send the
		// first termination signal when the context expires, then
		// wait one grace period for the process to produce whatever
		// useful output it can (such as a stack trace). After the
		// first grace period expires, we'll escalate to os.Kill,
		// leaving the second grace period for the test function to
		// record its output before the test process itself
		// terminates.
		timeout -= 2 * gracePeriod

		var cancel context.CancelFunc
		ctx, cancel = context.WithTimeout(ctx, timeout)
		t.Cleanup(cancel)
	}

	files, _ := filepath.Glob(pattern)
	if len(files) == 0 {
		t.Fatal("no testdata")
	}
	for _, file := range files {
		file := file
		name := strings.TrimSuffix(filepath.Base(file), ".txt")
		t.Run(name, func(t *testing.T) {
			t.Parallel()

			workdir := t.TempDir()
			s, err := script.NewState(ctx, workdir, env)
			if err != nil {
				t.Fatal(err)
			}

			// Unpack archive.
			a, err := txtar.ParseFile(file)
			if err != nil {
				t.Fatal(err)
			}
			initScriptDirs(t, s)
			if err := s.ExtractFiles(a); err != nil {
				t.Fatal(err)
			}

			t.Log(time.Now().UTC().Format(time.RFC3339))
			work, _ := s.LookupEnv("WORK")
			t.Logf("$WORK=%s", work)

			// Note: Do not use filepath.Base(file) here:
			// editors that can jump to file:line references in the output
			// will work better seeing the full path relative to the
			// directory containing the command being tested
			// (e.g. where "go test" command is usually run).
			Run(t, engine, s, file, bytes.NewReader(a.Comment))
		})
	}
}

func initScriptDirs(t testing.TB, s *script.State) {
	must := func(err error) {
		if err != nil {
			t.Helper()
			t.Fatal(err)
		}
	}

	work := s.Getwd()
	must(s.Setenv("WORK", work))
	must(os.MkdirAll(filepath.Join(work, "tmp"), 0777))
	must(s.Setenv(tempEnvName(), filepath.Join(work, "tmp")))
}

func tempEnvName() string {
	switch runtime.GOOS {
	case "windows":
		return "TMP"
	case "plan9":
		return "TMPDIR" // actually plan 9 doesn't have one at all but this is fine
	default:
		return "TMPDIR"
	}
}

// scriptCC runs the platform C compiler.
func scriptCC(cmdExec script.Cmd, ccexe string) script.Cmd {
	return script.Command(
		script.CmdUsage{
			Summary: "run the platform C compiler",
			Args:    "args...",
		},
		func(s *script.State, args ...string) (script.WaitFunc, error) {
			return cmdExec.Run(s, append([]string{ccexe}, args...)...)
		})
}
