<commit_before>// Copyright 2017 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 ssa_test

import (
	"bytes"
	"flag"
	"fmt"
	"internal/testenv"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"strconv"
	"strings"
	"testing"
	"time"
)

var update = flag.Bool("u", false, "update debug_test reference files")
var verbose = flag.Bool("v", false, "print more information about what's happening")
var dryrun = flag.Bool("n", false, "just print the command line and first bits")
var delve = flag.Bool("d", false, "use delve instead of gdb")
var force = flag.Bool("f", false, "force run under not linux-amd64; also do not use tempdir")

var hexRe = regexp.MustCompile("0x[a-zA-Z0-9]+")
var numRe = regexp.MustCompile("-?[0-9]+")
var stringRe = regexp.MustCompile("\"([^\\\"]|(\\.))*\"")

var gdb = "gdb" // Might be "ggdb" on Darwin, because gdb no longer part of XCode

// TestNexting go-builds a file, then uses a debugger (default gdb, optionally delve)
// to next through the generated executable, recording each line landed at, and
// then compares those lines with reference file(s).
// Flag -u updates the reference file(s).
// Flag -d changes the debugger to delve (and uses delve-specific reference files)
// Flag -v is ever-so-slightly verbose.
// Flag -n is for dry-run, and prints the shell and first debug commands.
//
// The file being tested may contain comments of the form
// //DBG-TAG=(v1,v2,v3)
// where DBG = {gdb,dlv} and TAG={dbg,opt}
// each variable may optionally be followed by a / and one or more of S,A,N
// to indicate normalization of Strings, (hex) addresses, and numbers.
// For example:
/*
	if len(os.Args) > 1 { //gdb-dbg=(hist/A,cannedInput/A) //dlv-dbg=(hist/A,cannedInput/A)
*/
// TODO: not implemented for Delve yet, but this is the plan
//
// After a compiler change that causes a difference in the debug behavior, check
// to see if it is sensible or not, and if it is, update the reference files with
// go test debug_test.go -args -u
// (for Delve)
// go test debug_test.go -args -u -d

func TestNexting(t *testing.T) {
	// Skip this test in an ordinary run.bash.  Too many things
	// can cause it to break.
	if testing.Short() {
		t.Skip("skipping in short mode; see issue #22206")
	}

	testenv.MustHaveGoBuild(t)

	if !*delve && !*force && !(runtime.GOOS == "linux" && runtime.GOARCH == "amd64") {
		// Running gdb on OSX/darwin is very flaky.
		// Sometimes it is called ggdb, depending on how it is installed.
		// It also probably requires an admin password typed into a dialog box.
		// Various architectures tend to differ slightly sometimes, and keeping them
		// all in sync is a pain for people who don't have them all at hand,
		// so limit testing to amd64 (for now)

		t.Skip("Skipped unless -d (delve), -f (force), or linux-amd64")
	}

	if *delve {
		_, err := exec.LookPath("dlv")
		if err != nil {
			t.Fatal("dlv specified on command line with -d but no dlv on path")
		}
	} else {
		_, err := exec.LookPath(gdb)
		if err != nil {
			if runtime.GOOS != "darwin" {
				t.Skip("Skipped because gdb not available")
			}
			_, err = exec.LookPath("ggdb")
			if err != nil {
				t.Skip("Skipped because gdb (and also ggdb) not available")
			}
			gdb = "ggdb"
		}
	}

	testNexting(t, "hist", "dbg", "-N -l")
	// If this is test is run with a runtime compiled with -N -l, it is very likely to fail.
	// This occurs in the noopt builders (for example).
	if gogcflags := os.Getenv("GO_GCFLAGS"); *force || !strings.Contains(gogcflags, "-N") && !strings.Contains(gogcflags, "-l") {
		testNexting(t, "hist", "opt", "")
	}
}

func testNexting(t *testing.T, base, tag, gcflags string) {
	// (1) In testdata, build sample.go into sample<commit_msg>cmd/compile: split TestNexting into subtests<commit_after>// Copyright 2017 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 ssa_test

import (
	"bytes"
	"flag"
	"fmt"
	"internal/testenv"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"strconv"
	"strings"
	"testing"
	"time"
)

var update = flag.Bool("u", false, "update debug_test reference files")
var verbose = flag.Bool("v", false, "print more information about what's happening")
var dryrun = flag.Bool("n", false, "just print the command line and first bits")
var delve = flag.Bool("d", false, "use delve instead of gdb")
var force = flag.Bool("f", false, "force run under not linux-amd64; also do not use tempdir")

var hexRe = regexp.MustCompile("0x[a-zA-Z0-9]+")
var numRe = regexp.MustCompile("-?[0-9]+")
var stringRe = regexp.MustCompile("\"([^\\\"]|(\\.))*\"")

var gdb = "gdb" // Might be "ggdb" on Darwin, because gdb no longer part of XCode

// TestNexting go-builds a file, then uses a debugger (default gdb, optionally delve)
// to next through the generated executable, recording each line landed at, and
// then compares those lines with reference file(s).
// Flag -u updates the reference file(s).
// Flag -d changes the debugger to delve (and uses delve-specific reference files)
// Flag -v is ever-so-slightly verbose.
// Flag -n is for dry-run, and prints the shell and first debug commands.
//
// The file being tested may contain comments of the form
// //DBG-TAG=(v1,v2,v3)
// where DBG = {gdb,dlv} and TAG={dbg,opt}
// each variable may optionally be followed by a / and one or more of S,A,N
// to indicate normalization of Strings, (hex) addresses, and numbers.
// For example:
/*
	if len(os.Args) > 1 { //gdb-dbg=(hist/A,cannedInput/A) //dlv-dbg=(hist/A,cannedInput/A)
*/
// TODO: not implemented for Delve yet, but this is the plan
//
// After a compiler change that causes a difference in the debug behavior, check
// to see if it is sensible or not, and if it is, update the reference files with
// go test debug_test.go -args -u
// (for Delve)
// go test debug_test.go -args -u -d

func TestNexting(t *testing.T) {
	// Skip this test in an ordinary run.bash.  Too many things
	// can cause it to break.
	if testing.Short() {
		t.Skip("skipping in short mode; see issue #22206")
	}

	testenv.MustHaveGoBuild(t)

	if !*delve && !*force && !(runtime.GOOS == "linux" && runtime.GOARCH == "amd64") {
		// Running gdb on OSX/darwin is very flaky.
		// Sometimes it is called ggdb, depending on how it is installed.
		// It also probably requires an admin password typed into a dialog box.
		// Various architectures tend to differ slightly sometimes, and keeping them
		// all in sync is a pain for people who don't have them all at hand,
		// so limit testing to amd64 (for now)

		t.Skip("Skipped unless -d (delve), -f (force), or linux-amd64")
	}

	if *delve {
		_, err := exec.LookPath("dlv")
		if err != nil {
			t.Fatal("dlv specified on command line with -d but no dlv on path")
		}
	} else {
		_, err := exec.LookPath(gdb)
		if err != nil {
			if runtime.GOOS != "darwin" {
				t.Skip("Skipped because gdb not available")
			}
			_, err = exec.LookPath("ggdb")
			if err != nil {
				t.Skip("Skipped because gdb (and also ggdb) not available")
			}
			gdb = "ggdb"
		}
	}

	t.Run("dbg", func(t *testing.T) {
		testNexting(t, "hist", "dbg", "-N -l")
	})
	t.Run("opt", func(t *testing.T) {
		// If this is test is run with a runtime compiled with -N -l, it is very likely to fail.
		// This occurs in the noopt builders (for example).
		if gogcflags := os.Getenv("GO_GCFLAGS"); *force || (!strings.Contains(gogcflags, "-N") && !strings.Contains(gogcflags, "-l")) {
			testNexting(t, "hist", "opt", "")
		} else {
			t.Skip("skipping for unoptimized runtime")
		}
	})
}

func testNexting(t *testing.T, base, tag, gcflags string) {
	// (1) In testdata, build sample.go into sample
{'fraction_non_alphanumeric': 0.14002049705354855, 'fraction_numerical': 0.006917755572636433, 'mean_word_length': 3.3541550474065813, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2390253', 'n_tokens_mistral': 2803, 'n_tokens_neox': 2649, 'n_words': 1014}