// 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 testing_test

import (
	"flag"
	"internal/testenv"
	"os"
	"os/exec"
	"testing"
)

var testFlagArg = flag.String("test_flag_arg", "", "TestFlag: passing -v option")

const flagTestEnv = "GO_WANT_FLAG_HELPER_PROCESS"

func TestFlag(t *testing.T) {
	if os.Getenv(flagTestEnv) == "1" {
		testFlagHelper(t)
		return
	}

	testenv.MustHaveExec(t)

	for _, flag := range []string{"", "-test.v", "-test.v=test2json"} {
		t.Run(flag, func(t *testing.T) {
			t.Parallel()
			cmd := exec.Command(testenv.Executable(t), "-test.run=^TestFlag$", "-test_flag_arg="+flag)
			if flag != "" {
				cmd.Args = append(cmd.Args, flag)
			}
			cmd.Env = append(cmd.Environ(), flagTestEnv+"=1")
			b, err := cmd.CombinedOutput()
			if len(b) > 0 {
				// When we set -test.v=test2json, we need to escape the ^V control
				// character used for JSON framing so that the JSON parser doesn't
				// misinterpret the subprocess output as output from the parent test.
				t.Logf("%q", b)
			}
			if err != nil {
				t.Error(err)
			}
		})
	}
}

// testFlagHelper is called by the TestFlagHelper subprocess.
func testFlagHelper(t *testing.T) {
	f := flag.Lookup("test.v")
	if f == nil {
		t.Fatal(`flag.Lookup("test.v") failed`)
	}

	bf, ok := f.Value.(interface{ IsBoolFlag() bool })
	if !ok {
		t.Errorf("test.v flag (type %T) does not have IsBoolFlag method", f)
	} else if !bf.IsBoolFlag() {
		t.Error("test.v IsBoolFlag() returned false")
	}

	gf, ok := f.Value.(flag.Getter)
	if !ok {
		t.Fatalf("test.v flag (type %T) does not have Get method", f)
	}
	v := gf.Get()

	var want any
	switch *testFlagArg {
	case "":
		want = false
	case "-test.v":
		want = true
	case "-test.v=test2json":
		want = "test2json"
	default:
		t.Fatalf("unexpected test_flag_arg %q", *testFlagArg)
	}

	if v != want {
		t.Errorf("test.v is %v want %v", v, want)
	}
}
