test.go

105 lines
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
package commands

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
)

const testUsage = `Run project tests

Usage:
  congo test [flags] [packages]

Flags:
  --verbose    Show verbose test output (-v)
  --count <n>  Run tests n times (useful with --count=1 to skip cache)

Without arguments, runs all tests in the project. Pass package paths
to test specific packages.

Examples:
  congo test                          # run all tests
  congo test ./web/models/...         # test models only
  congo test --verbose                # verbose output
  congo test --count 1                # skip test cache
  congo test ./web/models/... -run TestInsert  # single test
`

func Test() {
	fs := flag.NewFlagSet("test", flag.ExitOnError)
	fs.Usage = func() { fmt.Print(testUsage) }

	verbose := fs.Bool("verbose", false, "Verbose test output")
	count := fs.String("count", "", "Run tests n times")

	// Partition args: flags for us vs passthrough to go test.
	var flagArgs, passthrough []string
	seenDash := false
	rawArgs := os.Args[2:]
	for i := 0; i < len(rawArgs); i++ {
		arg := rawArgs[i]
		if arg == "--" {
			seenDash = true
			continue
		}
		if seenDash {
			passthrough = append(passthrough, arg)
			continue
		}
		// Our flags
		if arg == "--verbose" || arg == "-verbose" {
			flagArgs = append(flagArgs, arg)
		} else if len(arg) > 7 && arg[:8] == "--count=" {
			flagArgs = append(flagArgs, arg)
		} else if (arg == "--count" || arg == "-count") && i+1 < len(rawArgs) {
			flagArgs = append(flagArgs, arg, rawArgs[i+1])
			i++ // consume the value
		} else {
			passthrough = append(passthrough, arg)
		}
	}
	fs.Parse(flagArgs)

	// Verify we're in a Go project.
	if _, err := os.Stat("go.mod"); err != nil {
		log.Fatal("go.mod not found. Run this from a Congo project root.")
	}

	// Build go test args.
	args := []string{"test"}
	if *verbose {
		args = append(args, "-v")
	}
	if *count != "" {
		args = append(args, "-count="+*count)
	}

	// Default to ./... if no packages specified.
	hasPackage := false
	for _, arg := range passthrough {
		if len(arg) > 0 && arg[0] != '-' {
			hasPackage = true
			break
		}
	}
	if !hasPackage {
		args = append(args, "./...")
	}

	args = append(args, passthrough...)

	cmd := exec.Command("go", args...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	cmd.Env = os.Environ()

	if err := cmd.Run(); err != nil {
		if exitErr, ok := err.(*exec.ExitError); ok {
			os.Exit(exitErr.ExitCode())
		}
		os.Exit(1)
	}
}