whatcanGOwrong
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
// Copyright 2023 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.
|
||||
|
||||
//go:build !go1.20
|
||||
|
||||
package main
|
||||
|
||||
import "os/exec"
|
||||
|
||||
func cmdInterrupt(cmd *exec.Cmd) {
|
||||
// cmd.Cancel and cmd.WaitDelay not available before Go 1.20.
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright 2023 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.
|
||||
|
||||
//go:build go1.20
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"time"
|
||||
)
|
||||
|
||||
func cmdInterrupt(cmd *exec.Cmd) {
|
||||
cmd.Cancel = func() error {
|
||||
// On timeout, send interrupt,
|
||||
// in hopes of shutting down process tree.
|
||||
// Ignore errors sending signal; it's all best effort
|
||||
// and not even implemented on Windows.
|
||||
// TODO(rsc): Maybe use a new process group and kill the whole group?
|
||||
cmd.Process.Signal(os.Interrupt)
|
||||
return nil
|
||||
}
|
||||
cmd.WaitDelay = 2 * time.Second
|
||||
}
|
||||
@@ -0,0 +1,733 @@
|
||||
// Copyright 2023 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.
|
||||
|
||||
// Bisect finds changes responsible for causing a failure.
|
||||
// A typical use is to identify the source locations in a program
|
||||
// that are miscompiled by a given compiler optimization.
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// bisect [flags] [var=value...] command [arguments...]
|
||||
//
|
||||
// Bisect operates on a target command line – the target – that can be
|
||||
// run with various changes individually enabled or disabled. With none
|
||||
// of the changes enabled, the target is known to succeed (exit with exit
|
||||
// code zero). With all the changes enabled, the target is known to fail
|
||||
// (exit any other way). Bisect repeats the target with different sets of
|
||||
// changes enabled, using binary search to find (non-overlapping) minimal
|
||||
// change sets that provoke the failure.
|
||||
//
|
||||
// The target must cooperate with bisect by accepting a change pattern
|
||||
// and then enabling and reporting the changes that match that pattern.
|
||||
// The change pattern is passed to the target by substituting it anywhere
|
||||
// the string PATTERN appears in the environment values or the command
|
||||
// arguments. For each change that matches the pattern, the target must
|
||||
// enable that change and also print one or more “match lines”
|
||||
// (to standard output or standard error) describing the change.
|
||||
// The [golang.org/x/tools/internal/bisect] package provides functions to help
|
||||
// targets implement this protocol. We plan to publish that package
|
||||
// in a non-internal location after finalizing its API.
|
||||
//
|
||||
// Bisect starts by running the target with no changes enabled and then
|
||||
// with all changes enabled. It expects the former to succeed and the latter to fail,
|
||||
// and then it will search for the minimal set of changes that must be enabled
|
||||
// to provoke the failure. If the situation is reversed – the target fails with no
|
||||
// changes enabled and succeeds with all changes enabled – then bisect
|
||||
// automatically runs in reverse as well, searching for the minimal set of changes
|
||||
// that must be disabled to provoke the failure.
|
||||
//
|
||||
// Bisect prints tracing logs to standard error and the minimal change sets
|
||||
// to standard output.
|
||||
//
|
||||
// # Command Line Flags
|
||||
//
|
||||
// Bisect supports the following command-line flags:
|
||||
//
|
||||
// -max=M
|
||||
//
|
||||
// Stop after finding M minimal change sets. The default is no maximum, meaning to run until
|
||||
// all changes that provoke a failure have been identified.
|
||||
//
|
||||
// -maxset=S
|
||||
//
|
||||
// Disallow change sets larger than S elements. The default is no maximum.
|
||||
//
|
||||
// -timeout=D
|
||||
//
|
||||
// If the target runs for longer than duration D, stop the target and interpret that as a failure.
|
||||
// The default is no timeout.
|
||||
//
|
||||
// -count=N
|
||||
//
|
||||
// Run each trial N times (default 2), checking for consistency.
|
||||
//
|
||||
// -v
|
||||
//
|
||||
// Print verbose output, showing each run and its match lines.
|
||||
//
|
||||
// In addition to these general flags,
|
||||
// bisect supports a few “shortcut” flags that make it more convenient
|
||||
// to use with specific targets.
|
||||
//
|
||||
// -compile=<rewrite>
|
||||
//
|
||||
// This flag is equivalent to adding an environment variable
|
||||
// “GOCOMPILEDEBUG=<rewrite>hash=PATTERN”,
|
||||
// which, as discussed in more detail in the example below,
|
||||
// allows bisect to identify the specific source locations where the
|
||||
// compiler rewrite causes the target to fail.
|
||||
//
|
||||
// -godebug=<name>=<value>
|
||||
//
|
||||
// This flag is equivalent to adding an environment variable
|
||||
// “GODEBUG=<name>=<value>#PATTERN”,
|
||||
// which allows bisect to identify the specific call stacks where
|
||||
// the changed [GODEBUG setting] value causes the target to fail.
|
||||
//
|
||||
// # Example
|
||||
//
|
||||
// The Go compiler provides support for enabling or disabling certain rewrites
|
||||
// and optimizations to allow bisect to identify specific source locations where
|
||||
// the rewrite causes the program to fail. For example, to bisect a failure caused
|
||||
// by the new loop variable semantics:
|
||||
//
|
||||
// bisect go test -gcflags=all=-d=loopvarhash=PATTERN
|
||||
//
|
||||
// The -gcflags=all= instructs the go command to pass the -d=... to the Go compiler
|
||||
// when compiling all packages. Bisect varies PATTERN to determine the minimal set of changes
|
||||
// needed to reproduce the failure.
|
||||
//
|
||||
// The go command also checks the GOCOMPILEDEBUG environment variable for flags
|
||||
// to pass to the compiler, so the above command is equivalent to:
|
||||
//
|
||||
// bisect GOCOMPILEDEBUG=loopvarhash=PATTERN go test
|
||||
//
|
||||
// Finally, as mentioned earlier, the -compile flag allows shortening this command further:
|
||||
//
|
||||
// bisect -compile=loopvar go test
|
||||
//
|
||||
// # Defeating Build Caches
|
||||
//
|
||||
// Build systems cache build results, to avoid repeating the same compilations
|
||||
// over and over. When using a cached build result, the go command (correctly)
|
||||
// reprints the cached standard output and standard error associated with that
|
||||
// command invocation. (This makes commands like 'go build -gcflags=-S' for
|
||||
// printing an assembly listing work reliably.)
|
||||
//
|
||||
// Unfortunately, most build systems, including Bazel, are not as careful
|
||||
// as the go command about reprinting compiler output. If the compiler is
|
||||
// what prints match lines, a build system that suppresses compiler
|
||||
// output when using cached compiler results will confuse bisect.
|
||||
// To defeat such build caches, bisect replaces the literal text “RANDOM”
|
||||
// in environment values and command arguments with a random 64-bit value
|
||||
// during each invocation. The Go compiler conveniently accepts a
|
||||
// -d=ignore=... debug flag that ignores its argument, so to run the
|
||||
// previous example using Bazel, the invocation is:
|
||||
//
|
||||
// bazel test --define=gc_goopts=-d=loopvarhash=PATTERN,unused=RANDOM //path/to:test
|
||||
//
|
||||
// [GODEBUG setting]: https://tip.golang.org/doc/godebug
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"math/bits"
|
||||
"math/rand"
|
||||
"os"
|
||||
"os/exec"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/tools/internal/bisect"
|
||||
)
|
||||
|
||||
// Preserve import of bisect, to allow [bisect.Match] in the doc comment.
|
||||
var _ bisect.Matcher
|
||||
|
||||
func usage() {
|
||||
fmt.Fprintf(os.Stderr, "usage: bisect [flags] [var=value...] command [arguments...]\n")
|
||||
flag.PrintDefaults()
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
func main() {
|
||||
log.SetFlags(0)
|
||||
log.SetPrefix("bisect: ")
|
||||
|
||||
var b Bisect
|
||||
b.Stdout = os.Stdout
|
||||
b.Stderr = os.Stderr
|
||||
flag.IntVar(&b.Max, "max", 0, "stop after finding `m` failing change sets")
|
||||
flag.IntVar(&b.MaxSet, "maxset", 0, "do not search for change sets larger than `s` elements")
|
||||
flag.DurationVar(&b.Timeout, "timeout", 0, "stop target and consider failed after duration `d`")
|
||||
flag.IntVar(&b.Count, "count", 2, "run target `n` times for each trial")
|
||||
flag.BoolVar(&b.Verbose, "v", false, "enable verbose output")
|
||||
|
||||
env := ""
|
||||
envFlag := ""
|
||||
flag.Func("compile", "bisect source locations affected by Go compiler `rewrite` (fma, loopvar, ...)", func(value string) error {
|
||||
if envFlag != "" {
|
||||
return fmt.Errorf("cannot use -%s and -compile", envFlag)
|
||||
}
|
||||
envFlag = "compile"
|
||||
env = "GOCOMPILEDEBUG=" + value + "hash=PATTERN"
|
||||
return nil
|
||||
})
|
||||
flag.Func("godebug", "bisect call stacks affected by GODEBUG setting `name=value`", func(value string) error {
|
||||
if envFlag != "" {
|
||||
return fmt.Errorf("cannot use -%s and -godebug", envFlag)
|
||||
}
|
||||
envFlag = "godebug"
|
||||
env = "GODEBUG=" + value + "#PATTERN"
|
||||
return nil
|
||||
})
|
||||
|
||||
flag.Usage = usage
|
||||
flag.Parse()
|
||||
args := flag.Args()
|
||||
|
||||
// Split command line into env settings, command name, args.
|
||||
i := 0
|
||||
for i < len(args) && strings.Contains(args[i], "=") {
|
||||
i++
|
||||
}
|
||||
if i == len(args) {
|
||||
usage()
|
||||
}
|
||||
b.Env, b.Cmd, b.Args = args[:i], args[i], args[i+1:]
|
||||
if env != "" {
|
||||
b.Env = append([]string{env}, b.Env...)
|
||||
}
|
||||
|
||||
// Check that PATTERN is available for us to vary.
|
||||
found := false
|
||||
for _, e := range b.Env {
|
||||
if _, v, _ := strings.Cut(e, "="); strings.Contains(v, "PATTERN") {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
for _, a := range b.Args {
|
||||
if strings.Contains(a, "PATTERN") {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
log.Fatalf("no PATTERN in target environment or args")
|
||||
}
|
||||
|
||||
if !b.Search() {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// A Bisect holds the state for a bisect invocation.
|
||||
type Bisect struct {
|
||||
// Env is the additional environment variables for the command.
|
||||
// PATTERN and RANDOM are substituted in the values, but not the names.
|
||||
Env []string
|
||||
|
||||
// Cmd is the command (program name) to run.
|
||||
// PATTERN and RANDOM are not substituted.
|
||||
Cmd string
|
||||
|
||||
// Args is the command arguments.
|
||||
// PATTERN and RANDOM are substituted anywhere they appear.
|
||||
Args []string
|
||||
|
||||
// Command-line flags controlling bisect behavior.
|
||||
Max int // maximum number of sets to report (0 = unlimited)
|
||||
MaxSet int // maximum number of elements in a set (0 = unlimited)
|
||||
Timeout time.Duration // kill target and assume failed after this duration (0 = unlimited)
|
||||
Count int // run target this many times for each trial and give up if flaky (min 1 assumed; default 2 on command line set in main)
|
||||
Verbose bool // print long output about each trial (only useful for debugging bisect itself)
|
||||
|
||||
// State for running bisect, replaced during testing.
|
||||
// Failing change sets are printed to Stdout; all other output goes to Stderr.
|
||||
Stdout io.Writer // where to write standard output (usually os.Stdout)
|
||||
Stderr io.Writer // where to write standard error (usually os.Stderr)
|
||||
TestRun func(env []string, cmd string, args []string) (out []byte, err error) // if non-nil, used instead of exec.Command
|
||||
|
||||
// State maintained by Search.
|
||||
|
||||
// By default, Search looks for a minimal set of changes that cause a failure when enabled.
|
||||
// If Disable is true, the search is inverted and seeks a minimal set of changes that
|
||||
// cause a failure when disabled. In this case, the search proceeds as normal except that
|
||||
// each pattern starts with a !.
|
||||
Disable bool
|
||||
|
||||
// SkipDigits is the number of hex digits to use in skip messages.
|
||||
// If the set of available changes is the same in each run, as it should be,
|
||||
// then this doesn't matter: we'll only exclude suffixes that uniquely identify
|
||||
// a given change. But for some programs, especially bisecting runtime
|
||||
// behaviors, sometimes enabling one change unlocks questions about other
|
||||
// changes. Strictly speaking this is a misuse of bisect, but just to make
|
||||
// bisect more robust, we use the y and n runs to create an estimate of the
|
||||
// number of bits needed for a unique suffix, and then we round it up to
|
||||
// a number of hex digits, with one extra digit for good measure, and then
|
||||
// we always use that many hex digits for skips.
|
||||
SkipHexDigits int
|
||||
|
||||
// Add is a list of suffixes to add to every trial, because they
|
||||
// contain changes that are necessary for a group we are assembling.
|
||||
Add []string
|
||||
|
||||
// Skip is a list of suffixes that uniquely identify changes to exclude from every trial,
|
||||
// because they have already been used in failing change sets.
|
||||
// Suffixes later in the list may only be unique after removing
|
||||
// the ones earlier in the list.
|
||||
// Skip applies after Add.
|
||||
Skip []string
|
||||
}
|
||||
|
||||
// A Result holds the result of a single target trial.
|
||||
type Result struct {
|
||||
Success bool // whether the target succeeded (exited with zero status)
|
||||
Cmd string // full target command line
|
||||
Out string // full target output (stdout and stderr combined)
|
||||
|
||||
Suffix string // the suffix used for collecting MatchIDs, MatchText, and MatchFull
|
||||
MatchIDs []uint64 // match IDs enabled during this trial
|
||||
MatchText []string // match reports for the IDs, with match markers removed
|
||||
MatchFull []string // full match lines for the IDs, with match markers kept
|
||||
}
|
||||
|
||||
// &searchFatal is a special panic value to signal that Search failed.
|
||||
// This lets us unwind the search recursion on a fatal error
|
||||
// but have Search return normally.
|
||||
var searchFatal int
|
||||
|
||||
// Search runs a bisect search according to the configuration in b.
|
||||
// It reports whether any failing change sets were found.
|
||||
func (b *Bisect) Search() bool {
|
||||
defer func() {
|
||||
// Recover from panic(&searchFatal), implicitly returning false from Search.
|
||||
// Re-panic on any other panic.
|
||||
if e := recover(); e != nil && e != &searchFatal {
|
||||
panic(e)
|
||||
}
|
||||
}()
|
||||
|
||||
// Run with no changes and all changes, to figure out which direction we're searching.
|
||||
// The goal is to find the minimal set of changes to toggle
|
||||
// starting with the state where everything works.
|
||||
// If "no changes" succeeds and "all changes" fails,
|
||||
// we're looking for a minimal set of changes to enable to provoke the failure
|
||||
// (broken = runY, b.Negate = false)
|
||||
// If "no changes" fails and "all changes" succeeds,
|
||||
// we're looking for a minimal set of changes to disable to provoke the failure
|
||||
// (broken = runN, b.Negate = true).
|
||||
|
||||
b.Logf("checking target with all changes disabled")
|
||||
runN := b.Run("n")
|
||||
|
||||
b.Logf("checking target with all changes enabled")
|
||||
runY := b.Run("y")
|
||||
|
||||
var broken *Result
|
||||
switch {
|
||||
case runN.Success && !runY.Success:
|
||||
b.Logf("target succeeds with no changes, fails with all changes")
|
||||
b.Logf("searching for minimal set of enabled changes causing failure")
|
||||
broken = runY
|
||||
b.Disable = false
|
||||
|
||||
case !runN.Success && runY.Success:
|
||||
b.Logf("target fails with no changes, succeeds with all changes")
|
||||
b.Logf("searching for minimal set of disabled changes causing failure")
|
||||
broken = runN
|
||||
b.Disable = true
|
||||
|
||||
case runN.Success && runY.Success:
|
||||
b.Fatalf("target succeeds with no changes and all changes")
|
||||
|
||||
case !runN.Success && !runY.Success:
|
||||
b.Fatalf("target fails with no changes and all changes")
|
||||
}
|
||||
|
||||
// Compute minimum number of bits needed to distinguish
|
||||
// all the changes we saw during N and all the changes we saw during Y.
|
||||
b.SkipHexDigits = skipHexDigits(runN.MatchIDs, runY.MatchIDs)
|
||||
|
||||
// Loop finding and printing change sets, until none remain.
|
||||
found := 0
|
||||
for {
|
||||
// Find set.
|
||||
bad := b.search(broken)
|
||||
if bad == nil {
|
||||
if found == 0 {
|
||||
b.Fatalf("cannot find any failing change sets of size ≤ %d", b.MaxSet)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
// Confirm that set really does fail, to avoid false accusations.
|
||||
// Also asking for user-visible output; earlier runs did not.
|
||||
b.Logf("confirming failing change set")
|
||||
b.Add = append(b.Add[:0], bad...)
|
||||
broken = b.Run("v")
|
||||
if broken.Success {
|
||||
b.Logf("confirmation run succeeded unexpectedly")
|
||||
}
|
||||
b.Add = b.Add[:0]
|
||||
|
||||
// Print confirmed change set.
|
||||
found++
|
||||
b.Logf("FOUND failing change set")
|
||||
desc := "(enabling changes causes failure)"
|
||||
if b.Disable {
|
||||
desc = "(disabling changes causes failure)"
|
||||
}
|
||||
fmt.Fprintf(b.Stdout, "--- change set #%d %s\n%s\n---\n", found, desc, strings.Join(broken.MatchText, "\n"))
|
||||
|
||||
// Stop if we've found enough change sets.
|
||||
if b.Max > 0 && found >= b.Max {
|
||||
break
|
||||
}
|
||||
|
||||
// If running bisect target | tee bad.txt, prints to stdout and stderr
|
||||
// both appear on the terminal, but the ones to stdout go through tee
|
||||
// and can take a little bit of extra time. Sleep 1 millisecond to give
|
||||
// tee time to catch up, so that its stdout print does not get interlaced
|
||||
// with the stderr print from the next b.Log message.
|
||||
time.Sleep(1 * time.Millisecond)
|
||||
|
||||
// Disable the now-known-bad changes and see if any failures remain.
|
||||
b.Logf("checking for more failures")
|
||||
b.Skip = append(bad, b.Skip...)
|
||||
broken = b.Run("")
|
||||
if broken.Success {
|
||||
what := "enabled"
|
||||
if b.Disable {
|
||||
what = "disabled"
|
||||
}
|
||||
b.Logf("target succeeds with all remaining changes %s", what)
|
||||
break
|
||||
}
|
||||
b.Logf("target still fails; searching for more bad changes")
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Fatalf prints a message to standard error and then panics,
|
||||
// causing Search to return false.
|
||||
func (b *Bisect) Fatalf(format string, args ...any) {
|
||||
s := fmt.Sprintf("bisect: fatal error: "+format, args...)
|
||||
if !strings.HasSuffix(s, "\n") {
|
||||
s += "\n"
|
||||
}
|
||||
b.Stderr.Write([]byte(s))
|
||||
panic(&searchFatal)
|
||||
}
|
||||
|
||||
// Logf prints a message to standard error.
|
||||
func (b *Bisect) Logf(format string, args ...any) {
|
||||
s := fmt.Sprintf("bisect: "+format, args...)
|
||||
if !strings.HasSuffix(s, "\n") {
|
||||
s += "\n"
|
||||
}
|
||||
b.Stderr.Write([]byte(s))
|
||||
}
|
||||
|
||||
func skipHexDigits(idY, idN []uint64) int {
|
||||
var all []uint64
|
||||
seen := make(map[uint64]bool)
|
||||
for _, x := range idY {
|
||||
seen[x] = true
|
||||
all = append(all, x)
|
||||
}
|
||||
for _, x := range idN {
|
||||
if !seen[x] {
|
||||
seen[x] = true
|
||||
all = append(all, x)
|
||||
}
|
||||
}
|
||||
sort.Slice(all, func(i, j int) bool { return bits.Reverse64(all[i]) < bits.Reverse64(all[j]) })
|
||||
digits := sort.Search(64/4, func(digits int) bool {
|
||||
mask := uint64(1)<<(4*digits) - 1
|
||||
for i := 0; i+1 < len(all); i++ {
|
||||
if all[i]&mask == all[i+1]&mask {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
if digits < 64/4 {
|
||||
digits++
|
||||
}
|
||||
return digits
|
||||
}
|
||||
|
||||
// search searches for a single locally minimal change set.
|
||||
//
|
||||
// Invariant: r describes the result of r.Suffix + b.Add, which failed.
|
||||
// (There's an implicit -b.Skip everywhere here. b.Skip does not change.)
|
||||
// We want to extend r.Suffix to preserve the failure, working toward
|
||||
// a suffix that identifies a single change.
|
||||
func (b *Bisect) search(r *Result) []string {
|
||||
// The caller should be passing in a failure result that we diagnose.
|
||||
if r.Success {
|
||||
b.Fatalf("internal error: unexpected success") // mistake by caller
|
||||
}
|
||||
|
||||
// If the failure reported no changes, the target is misbehaving.
|
||||
if len(r.MatchIDs) == 0 {
|
||||
b.Fatalf("failure with no reported changes:\n\n$ %s\n%s\n", r.Cmd, r.Out)
|
||||
}
|
||||
|
||||
// If there's one matching change, that's the one we're looking for.
|
||||
if len(r.MatchIDs) == 1 {
|
||||
return []string{fmt.Sprintf("x%0*x", b.SkipHexDigits, r.MatchIDs[0]&(1<<(4*b.SkipHexDigits)-1))}
|
||||
}
|
||||
|
||||
// If the suffix we were tracking in the trial is already 64 bits,
|
||||
// either the target is bad or bisect itself is buggy.
|
||||
if len(r.Suffix) >= 64 {
|
||||
b.Fatalf("failed to isolate a single change with very long suffix")
|
||||
}
|
||||
|
||||
// We want to split the current matchIDs by left-extending the suffix with 0 and 1.
|
||||
// If all the matches have the same next bit, that won't cause a split, which doesn't
|
||||
// break the algorithm but does waste time. Avoid wasting time by left-extending
|
||||
// the suffix to the longest suffix shared by all the current match IDs
|
||||
// before adding 0 or 1.
|
||||
suffix := commonSuffix(r.MatchIDs)
|
||||
if !strings.HasSuffix(suffix, r.Suffix) {
|
||||
b.Fatalf("internal error: invalid common suffix") // bug in commonSuffix
|
||||
}
|
||||
|
||||
// Run 0suffix and 1suffix. If one fails, chase down the failure in that half.
|
||||
r0 := b.Run("0" + suffix)
|
||||
if !r0.Success {
|
||||
return b.search(r0)
|
||||
}
|
||||
r1 := b.Run("1" + suffix)
|
||||
if !r1.Success {
|
||||
return b.search(r1)
|
||||
}
|
||||
|
||||
// suffix failed, but 0suffix and 1suffix succeeded.
|
||||
// Assuming the target isn't flaky, this means we need
|
||||
// at least one change from 0suffix AND at least one from 1suffix.
|
||||
// We are already tracking N = len(b.Add) other changes and are
|
||||
// allowed to build sets of size at least 1+N (or we shouldn't be here at all).
|
||||
// If we aren't allowed to build sets of size 2+N, give up this branch.
|
||||
if b.MaxSet > 0 && 2+len(b.Add) > b.MaxSet {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Adding all matches for 1suffix, recurse to narrow down 0suffix.
|
||||
old := len(b.Add)
|
||||
b.Add = append(b.Add, "1"+suffix)
|
||||
r0 = b.Run("0" + suffix)
|
||||
if r0.Success {
|
||||
// 0suffix + b.Add + 1suffix = suffix + b.Add is what r describes, and it failed.
|
||||
b.Fatalf("target fails inconsistently")
|
||||
}
|
||||
bad0 := b.search(r0)
|
||||
if bad0 == nil {
|
||||
// Search failed due to MaxSet limit.
|
||||
return nil
|
||||
}
|
||||
b.Add = b.Add[:old]
|
||||
|
||||
// Adding the specific match we found in 0suffix, recurse to narrow down 1suffix.
|
||||
b.Add = append(b.Add[:old], bad0...)
|
||||
r1 = b.Run("1" + suffix)
|
||||
if r1.Success {
|
||||
// 1suffix + b.Add + bad0 = bad0 + b.Add + 1suffix is what b.search(r0) reported as a failure.
|
||||
b.Fatalf("target fails inconsistently")
|
||||
}
|
||||
bad1 := b.search(r1)
|
||||
if bad1 == nil {
|
||||
// Search failed due to MaxSet limit.
|
||||
return nil
|
||||
}
|
||||
b.Add = b.Add[:old]
|
||||
|
||||
// bad0 and bad1 together provoke the failure.
|
||||
return append(bad0, bad1...)
|
||||
}
|
||||
|
||||
// Run runs a set of trials selecting changes with the given suffix,
|
||||
// plus the ones in b.Add and not the ones in b.Skip.
|
||||
// The returned result's MatchIDs, MatchText, and MatchFull
|
||||
// only list the changes that match suffix.
|
||||
// When b.Count > 1, Run runs b.Count trials and requires
|
||||
// that they all succeed or they all fail. If not, it calls b.Fatalf.
|
||||
func (b *Bisect) Run(suffix string) *Result {
|
||||
out := b.run(suffix)
|
||||
for i := 1; i < b.Count; i++ {
|
||||
r := b.run(suffix)
|
||||
if r.Success != out.Success {
|
||||
b.Fatalf("target fails inconsistently")
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// run runs a single trial for Run.
|
||||
func (b *Bisect) run(suffix string) *Result {
|
||||
random := fmt.Sprint(rand.Uint64())
|
||||
|
||||
// Accept suffix == "v" to mean we need user-visible output.
|
||||
visible := ""
|
||||
if suffix == "v" {
|
||||
visible = "v"
|
||||
suffix = ""
|
||||
}
|
||||
|
||||
// Construct change ID pattern.
|
||||
var pattern string
|
||||
if suffix == "y" || suffix == "n" {
|
||||
pattern = suffix
|
||||
suffix = ""
|
||||
} else {
|
||||
var elem []string
|
||||
if suffix != "" {
|
||||
elem = append(elem, "+", suffix)
|
||||
}
|
||||
for _, x := range b.Add {
|
||||
elem = append(elem, "+", x)
|
||||
}
|
||||
for _, x := range b.Skip {
|
||||
elem = append(elem, "-", x)
|
||||
}
|
||||
pattern = strings.Join(elem, "")
|
||||
if pattern == "" {
|
||||
pattern = "y"
|
||||
}
|
||||
}
|
||||
if b.Disable {
|
||||
pattern = "!" + pattern
|
||||
}
|
||||
pattern = visible + pattern
|
||||
|
||||
// Construct substituted env and args.
|
||||
env := make([]string, len(b.Env))
|
||||
for i, x := range b.Env {
|
||||
k, v, _ := strings.Cut(x, "=")
|
||||
env[i] = k + "=" + replace(v, pattern, random)
|
||||
}
|
||||
args := make([]string, len(b.Args))
|
||||
for i, x := range b.Args {
|
||||
args[i] = replace(x, pattern, random)
|
||||
}
|
||||
|
||||
// Construct and log command line.
|
||||
// There is no newline in the log print.
|
||||
// The line will be completed when the command finishes.
|
||||
cmdText := strings.Join(append(append(env, b.Cmd), args...), " ")
|
||||
fmt.Fprintf(b.Stderr, "bisect: run: %s...", cmdText)
|
||||
|
||||
// Run command with args and env.
|
||||
var out []byte
|
||||
var err error
|
||||
if b.TestRun != nil {
|
||||
out, err = b.TestRun(env, b.Cmd, args)
|
||||
} else {
|
||||
ctx := context.Background()
|
||||
if b.Timeout != 0 {
|
||||
var cancel context.CancelFunc
|
||||
ctx, cancel = context.WithTimeout(ctx, b.Timeout)
|
||||
defer cancel()
|
||||
}
|
||||
cmd := exec.CommandContext(ctx, b.Cmd, args...)
|
||||
cmd.Env = append(os.Environ(), env...)
|
||||
// Set up cmd.Cancel, cmd.WaitDelay on Go 1.20 and later
|
||||
// TODO(rsc): Inline go120.go's cmdInterrupt once we stop supporting Go 1.19.
|
||||
cmdInterrupt(cmd)
|
||||
out, err = cmd.CombinedOutput()
|
||||
}
|
||||
|
||||
// Parse output to construct result.
|
||||
r := &Result{
|
||||
Suffix: suffix,
|
||||
Success: err == nil,
|
||||
Cmd: cmdText,
|
||||
Out: string(out),
|
||||
}
|
||||
|
||||
// Calculate bits, mask to identify suffix matches.
|
||||
var bits, mask uint64
|
||||
if suffix != "" && suffix != "y" && suffix != "n" && suffix != "v" {
|
||||
var err error
|
||||
bits, err = strconv.ParseUint(suffix, 2, 64)
|
||||
if err != nil {
|
||||
b.Fatalf("internal error: bad suffix")
|
||||
}
|
||||
mask = uint64(1<<len(suffix)) - 1
|
||||
}
|
||||
|
||||
// Process output, collecting match reports for suffix.
|
||||
have := make(map[uint64]bool)
|
||||
all := r.Out
|
||||
for all != "" {
|
||||
var line string
|
||||
line, all, _ = strings.Cut(all, "\n")
|
||||
short, id, ok := bisect.CutMarker(line)
|
||||
if !ok || (id&mask) != bits {
|
||||
continue
|
||||
}
|
||||
|
||||
if !have[id] {
|
||||
have[id] = true
|
||||
r.MatchIDs = append(r.MatchIDs, id)
|
||||
}
|
||||
r.MatchText = append(r.MatchText, short)
|
||||
r.MatchFull = append(r.MatchFull, line)
|
||||
}
|
||||
|
||||
// Finish log print from above, describing the command's completion.
|
||||
if err == nil {
|
||||
fmt.Fprintf(b.Stderr, " ok (%d matches)\n", len(r.MatchIDs))
|
||||
} else {
|
||||
fmt.Fprintf(b.Stderr, " FAIL (%d matches)\n", len(r.MatchIDs))
|
||||
}
|
||||
|
||||
if err != nil && len(r.MatchIDs) == 0 {
|
||||
b.Fatalf("target failed without printing any matches\n%s", r.Out)
|
||||
}
|
||||
|
||||
// In verbose mode, print extra debugging: all the lines with match markers.
|
||||
if b.Verbose {
|
||||
b.Logf("matches:\n%s", strings.Join(r.MatchFull, "\n\t"))
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// replace returns x with literal text PATTERN and RANDOM replaced by pattern and random.
|
||||
func replace(x, pattern, random string) string {
|
||||
x = strings.ReplaceAll(x, "PATTERN", pattern)
|
||||
x = strings.ReplaceAll(x, "RANDOM", random)
|
||||
return x
|
||||
}
|
||||
|
||||
// commonSuffix returns the longest common binary suffix shared by all uint64s in list.
|
||||
// If list is empty, commonSuffix returns an empty string.
|
||||
func commonSuffix(list []uint64) string {
|
||||
if len(list) == 0 {
|
||||
return ""
|
||||
}
|
||||
b := list[0]
|
||||
n := 64
|
||||
for _, x := range list {
|
||||
for x&((1<<n)-1) != b {
|
||||
n--
|
||||
b &= (1 << n) - 1
|
||||
}
|
||||
}
|
||||
s := make([]byte, n)
|
||||
for i := n - 1; i >= 0; i-- {
|
||||
s[i] = '0' + byte(b&1)
|
||||
b >>= 1
|
||||
}
|
||||
return string(s[:])
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
// Copyright 2023 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 main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/build/constraint"
|
||||
"math/rand"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/tools/internal/bisect"
|
||||
"golang.org/x/tools/internal/diffp"
|
||||
"golang.org/x/tools/txtar"
|
||||
)
|
||||
|
||||
var update = flag.Bool("update", false, "update testdata with new stdout/stderr")
|
||||
|
||||
func Test(t *testing.T) {
|
||||
files, err := filepath.Glob("testdata/*.txt")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, file := range files {
|
||||
t.Run(strings.TrimSuffix(filepath.Base(file), ".txt"), func(t *testing.T) {
|
||||
data, err := os.ReadFile(file)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
a := txtar.Parse(data)
|
||||
var wantStdout, wantStderr []byte
|
||||
files := a.Files
|
||||
if len(files) > 0 && files[0].Name == "stdout" {
|
||||
wantStdout = files[0].Data
|
||||
files = files[1:]
|
||||
}
|
||||
if len(files) > 0 && files[0].Name == "stderr" {
|
||||
wantStderr = files[0].Data
|
||||
files = files[1:]
|
||||
}
|
||||
if len(files) > 0 {
|
||||
t.Fatalf("unexpected txtar entry: %s", files[0].Name)
|
||||
}
|
||||
|
||||
var tt struct {
|
||||
Fail string
|
||||
Bisect Bisect
|
||||
}
|
||||
if err := json.Unmarshal(a.Comment, &tt); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expr, err := constraint.Parse("//go:build " + tt.Fail)
|
||||
if err != nil {
|
||||
t.Fatalf("invalid Cmd: %v", err)
|
||||
}
|
||||
|
||||
rnd := rand.New(rand.NewSource(1))
|
||||
b := &tt.Bisect
|
||||
b.Cmd = "test"
|
||||
b.Args = []string{"PATTERN"}
|
||||
var stdout, stderr bytes.Buffer
|
||||
b.Stdout = &stdout
|
||||
b.Stderr = &stderr
|
||||
b.TestRun = func(env []string, cmd string, args []string) (out []byte, err error) {
|
||||
pattern := args[0]
|
||||
m, err := bisect.New(pattern)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
have := make(map[string]bool)
|
||||
for i, color := range colors {
|
||||
if m.ShouldEnable(uint64(i)) {
|
||||
have[color] = true
|
||||
}
|
||||
if m.ShouldReport(uint64(i)) {
|
||||
out = fmt.Appendf(out, "%s %s\n", color, bisect.Marker(uint64(i)))
|
||||
}
|
||||
}
|
||||
err = nil
|
||||
if eval(rnd, expr, have) {
|
||||
err = fmt.Errorf("failed")
|
||||
}
|
||||
return out, err
|
||||
}
|
||||
|
||||
if !b.Search() {
|
||||
stderr.WriteString("<bisect failed>\n")
|
||||
}
|
||||
rewrite := false
|
||||
if !bytes.Equal(stdout.Bytes(), wantStdout) {
|
||||
if *update {
|
||||
rewrite = true
|
||||
} else {
|
||||
t.Errorf("incorrect stdout: %s", diffp.Diff("have", stdout.Bytes(), "want", wantStdout))
|
||||
}
|
||||
}
|
||||
if !bytes.Equal(stderr.Bytes(), wantStderr) {
|
||||
if *update {
|
||||
rewrite = true
|
||||
} else {
|
||||
t.Errorf("incorrect stderr: %s", diffp.Diff("have", stderr.Bytes(), "want", wantStderr))
|
||||
}
|
||||
}
|
||||
if rewrite {
|
||||
a.Files = []txtar.File{{Name: "stdout", Data: stdout.Bytes()}, {Name: "stderr", Data: stderr.Bytes()}}
|
||||
err := os.WriteFile(file, txtar.Format(a), 0666)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Logf("updated %s", file)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func eval(rnd *rand.Rand, z constraint.Expr, have map[string]bool) bool {
|
||||
switch z := z.(type) {
|
||||
default:
|
||||
panic(fmt.Sprintf("unexpected type %T", z))
|
||||
case *constraint.NotExpr:
|
||||
return !eval(rnd, z.X, have)
|
||||
case *constraint.AndExpr:
|
||||
return eval(rnd, z.X, have) && eval(rnd, z.Y, have)
|
||||
case *constraint.OrExpr:
|
||||
return eval(rnd, z.X, have) || eval(rnd, z.Y, have)
|
||||
case *constraint.TagExpr:
|
||||
if z.Tag == "random" {
|
||||
return rnd.Intn(2) == 1
|
||||
}
|
||||
return have[z.Tag]
|
||||
}
|
||||
}
|
||||
|
||||
var colors = strings.Fields(`
|
||||
aliceblue
|
||||
amaranth
|
||||
amber
|
||||
amethyst
|
||||
applegreen
|
||||
applered
|
||||
apricot
|
||||
aquamarine
|
||||
azure
|
||||
babyblue
|
||||
beige
|
||||
brickred
|
||||
black
|
||||
blue
|
||||
bluegreen
|
||||
blueviolet
|
||||
blush
|
||||
bronze
|
||||
brown
|
||||
burgundy
|
||||
byzantium
|
||||
carmine
|
||||
cerise
|
||||
cerulean
|
||||
champagne
|
||||
chartreusegreen
|
||||
chocolate
|
||||
cobaltblue
|
||||
coffee
|
||||
copper
|
||||
coral
|
||||
crimson
|
||||
cyan
|
||||
desertsand
|
||||
electricblue
|
||||
emerald
|
||||
erin
|
||||
gold
|
||||
gray
|
||||
green
|
||||
harlequin
|
||||
indigo
|
||||
ivory
|
||||
jade
|
||||
junglegreen
|
||||
lavender
|
||||
lemon
|
||||
lilac
|
||||
lime
|
||||
magenta
|
||||
magentarose
|
||||
maroon
|
||||
mauve
|
||||
navyblue
|
||||
ochre
|
||||
olive
|
||||
orange
|
||||
orangered
|
||||
orchid
|
||||
peach
|
||||
pear
|
||||
periwinkle
|
||||
persianblue
|
||||
pink
|
||||
plum
|
||||
prussianblue
|
||||
puce
|
||||
purple
|
||||
raspberry
|
||||
red
|
||||
redviolet
|
||||
rose
|
||||
ruby
|
||||
salmon
|
||||
sangria
|
||||
sapphire
|
||||
scarlet
|
||||
silver
|
||||
slategray
|
||||
springbud
|
||||
springgreen
|
||||
tan
|
||||
taupe
|
||||
teal
|
||||
turquoise
|
||||
ultramarine
|
||||
violet
|
||||
viridian
|
||||
white
|
||||
yellow
|
||||
`)
|
||||
@@ -0,0 +1,20 @@
|
||||
// Copyright 2023 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.
|
||||
|
||||
// Starting in Go 1.20, the global rand is auto-seeded,
|
||||
// with a better value than the current Unix nanoseconds.
|
||||
// Only seed if we're using older versions of Go.
|
||||
|
||||
//go:build !go1.20
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
func init() {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
This directory contains test inputs for the bisect command.
|
||||
|
||||
Each text file is a txtar archive (see <https://pkg.go.dev/golang.org/x/tools/txtar>
|
||||
or `go doc txtar`).
|
||||
|
||||
The comment at the top of the archive is a JSON object describing a
|
||||
target behavior. Specifically, the Fail key gives a boolean expression
|
||||
that should provoke a failure. Bisect's job is to discover this
|
||||
condition.
|
||||
|
||||
The Bisect key describes settings in the Bisect struct that we want to
|
||||
change, to simulate the use of various command-line options.
|
||||
|
||||
The txtar archive files should be "stdout" and "stderr", giving the
|
||||
expected standard output and standard error. If the bisect command
|
||||
should exit with a non-zero status, the stderr in the archive will end
|
||||
with the line "<bisect failed>".
|
||||
|
||||
Running `go test -update` will rewrite the stdout and stderr files in
|
||||
each testdata archive to match the current state of the tool. This is
|
||||
a useful command when the logging prints from bisect change or when
|
||||
writing a new test.
|
||||
|
||||
To use `go test -update` to write a new test:
|
||||
|
||||
- Create a new .txt file with just a JSON object at the top,
|
||||
specifying what you want to test.
|
||||
- Run `go test -update`.
|
||||
- Reload the .txt file and read the stdout and stderr to see if you agree.
|
||||
@@ -0,0 +1,44 @@
|
||||
{"Fail": "amber || apricot"}
|
||||
-- stdout --
|
||||
--- change set #1 (enabling changes causes failure)
|
||||
amber
|
||||
---
|
||||
--- change set #2 (enabling changes causes failure)
|
||||
apricot
|
||||
---
|
||||
-- stderr --
|
||||
bisect: checking target with all changes disabled
|
||||
bisect: run: test n... ok (90 matches)
|
||||
bisect: checking target with all changes enabled
|
||||
bisect: run: test y... FAIL (90 matches)
|
||||
bisect: target succeeds with no changes, fails with all changes
|
||||
bisect: searching for minimal set of enabled changes causing failure
|
||||
bisect: run: test +0... FAIL (45 matches)
|
||||
bisect: run: test +00... ok (23 matches)
|
||||
bisect: run: test +10... FAIL (22 matches)
|
||||
bisect: run: test +010... FAIL (11 matches)
|
||||
bisect: run: test +0010... FAIL (6 matches)
|
||||
bisect: run: test +00010... FAIL (3 matches)
|
||||
bisect: run: test +000010... FAIL (2 matches)
|
||||
bisect: run: test +0000010... FAIL (1 matches)
|
||||
bisect: confirming failing change set
|
||||
bisect: run: test v+x002... FAIL (1 matches)
|
||||
bisect: FOUND failing change set
|
||||
bisect: checking for more failures
|
||||
bisect: run: test -x002... FAIL (89 matches)
|
||||
bisect: target still fails; searching for more bad changes
|
||||
bisect: run: test +0-x002... FAIL (44 matches)
|
||||
bisect: run: test +00-x002... ok (23 matches)
|
||||
bisect: run: test +10-x002... FAIL (21 matches)
|
||||
bisect: run: test +010-x002... ok (10 matches)
|
||||
bisect: run: test +110-x002... FAIL (11 matches)
|
||||
bisect: run: test +0110-x002... FAIL (6 matches)
|
||||
bisect: run: test +00110-x002... FAIL (3 matches)
|
||||
bisect: run: test +000110-x002... FAIL (2 matches)
|
||||
bisect: run: test +0000110-x002... FAIL (1 matches)
|
||||
bisect: confirming failing change set
|
||||
bisect: run: test v+x006-x002... FAIL (1 matches)
|
||||
bisect: FOUND failing change set
|
||||
bisect: checking for more failures
|
||||
bisect: run: test -x006-x002... ok (88 matches)
|
||||
bisect: target succeeds with all remaining changes enabled
|
||||
@@ -0,0 +1,67 @@
|
||||
{"Fail": "amber || apricot", "Bisect": {"Count": 2}}
|
||||
-- stdout --
|
||||
--- change set #1 (enabling changes causes failure)
|
||||
amber
|
||||
---
|
||||
--- change set #2 (enabling changes causes failure)
|
||||
apricot
|
||||
---
|
||||
-- stderr --
|
||||
bisect: checking target with all changes disabled
|
||||
bisect: run: test n... ok (90 matches)
|
||||
bisect: run: test n... ok (90 matches)
|
||||
bisect: checking target with all changes enabled
|
||||
bisect: run: test y... FAIL (90 matches)
|
||||
bisect: run: test y... FAIL (90 matches)
|
||||
bisect: target succeeds with no changes, fails with all changes
|
||||
bisect: searching for minimal set of enabled changes causing failure
|
||||
bisect: run: test +0... FAIL (45 matches)
|
||||
bisect: run: test +0... FAIL (45 matches)
|
||||
bisect: run: test +00... ok (23 matches)
|
||||
bisect: run: test +00... ok (23 matches)
|
||||
bisect: run: test +10... FAIL (22 matches)
|
||||
bisect: run: test +10... FAIL (22 matches)
|
||||
bisect: run: test +010... FAIL (11 matches)
|
||||
bisect: run: test +010... FAIL (11 matches)
|
||||
bisect: run: test +0010... FAIL (6 matches)
|
||||
bisect: run: test +0010... FAIL (6 matches)
|
||||
bisect: run: test +00010... FAIL (3 matches)
|
||||
bisect: run: test +00010... FAIL (3 matches)
|
||||
bisect: run: test +000010... FAIL (2 matches)
|
||||
bisect: run: test +000010... FAIL (2 matches)
|
||||
bisect: run: test +0000010... FAIL (1 matches)
|
||||
bisect: run: test +0000010... FAIL (1 matches)
|
||||
bisect: confirming failing change set
|
||||
bisect: run: test v+x002... FAIL (1 matches)
|
||||
bisect: run: test v+x002... FAIL (1 matches)
|
||||
bisect: FOUND failing change set
|
||||
bisect: checking for more failures
|
||||
bisect: run: test -x002... FAIL (89 matches)
|
||||
bisect: run: test -x002... FAIL (89 matches)
|
||||
bisect: target still fails; searching for more bad changes
|
||||
bisect: run: test +0-x002... FAIL (44 matches)
|
||||
bisect: run: test +0-x002... FAIL (44 matches)
|
||||
bisect: run: test +00-x002... ok (23 matches)
|
||||
bisect: run: test +00-x002... ok (23 matches)
|
||||
bisect: run: test +10-x002... FAIL (21 matches)
|
||||
bisect: run: test +10-x002... FAIL (21 matches)
|
||||
bisect: run: test +010-x002... ok (10 matches)
|
||||
bisect: run: test +010-x002... ok (10 matches)
|
||||
bisect: run: test +110-x002... FAIL (11 matches)
|
||||
bisect: run: test +110-x002... FAIL (11 matches)
|
||||
bisect: run: test +0110-x002... FAIL (6 matches)
|
||||
bisect: run: test +0110-x002... FAIL (6 matches)
|
||||
bisect: run: test +00110-x002... FAIL (3 matches)
|
||||
bisect: run: test +00110-x002... FAIL (3 matches)
|
||||
bisect: run: test +000110-x002... FAIL (2 matches)
|
||||
bisect: run: test +000110-x002... FAIL (2 matches)
|
||||
bisect: run: test +0000110-x002... FAIL (1 matches)
|
||||
bisect: run: test +0000110-x002... FAIL (1 matches)
|
||||
bisect: confirming failing change set
|
||||
bisect: run: test v+x006-x002... FAIL (1 matches)
|
||||
bisect: run: test v+x006-x002... FAIL (1 matches)
|
||||
bisect: FOUND failing change set
|
||||
bisect: checking for more failures
|
||||
bisect: run: test -x006-x002... ok (88 matches)
|
||||
bisect: run: test -x006-x002... ok (88 matches)
|
||||
bisect: target succeeds with all remaining changes enabled
|
||||
@@ -0,0 +1,57 @@
|
||||
{"Fail": "amber || apricot && peach"}
|
||||
-- stdout --
|
||||
--- change set #1 (enabling changes causes failure)
|
||||
amber
|
||||
---
|
||||
--- change set #2 (enabling changes causes failure)
|
||||
apricot
|
||||
peach
|
||||
---
|
||||
-- stderr --
|
||||
bisect: checking target with all changes disabled
|
||||
bisect: run: test n... ok (90 matches)
|
||||
bisect: checking target with all changes enabled
|
||||
bisect: run: test y... FAIL (90 matches)
|
||||
bisect: target succeeds with no changes, fails with all changes
|
||||
bisect: searching for minimal set of enabled changes causing failure
|
||||
bisect: run: test +0... FAIL (45 matches)
|
||||
bisect: run: test +00... ok (23 matches)
|
||||
bisect: run: test +10... FAIL (22 matches)
|
||||
bisect: run: test +010... FAIL (11 matches)
|
||||
bisect: run: test +0010... FAIL (6 matches)
|
||||
bisect: run: test +00010... FAIL (3 matches)
|
||||
bisect: run: test +000010... FAIL (2 matches)
|
||||
bisect: run: test +0000010... FAIL (1 matches)
|
||||
bisect: confirming failing change set
|
||||
bisect: run: test v+x002... FAIL (1 matches)
|
||||
bisect: FOUND failing change set
|
||||
bisect: checking for more failures
|
||||
bisect: run: test -x002... FAIL (89 matches)
|
||||
bisect: target still fails; searching for more bad changes
|
||||
bisect: run: test +0-x002... ok (44 matches)
|
||||
bisect: run: test +1-x002... ok (45 matches)
|
||||
bisect: run: test +0+1-x002... FAIL (44 matches)
|
||||
bisect: run: test +00+1-x002... ok (23 matches)
|
||||
bisect: run: test +10+1-x002... FAIL (21 matches)
|
||||
bisect: run: test +010+1-x002... ok (10 matches)
|
||||
bisect: run: test +110+1-x002... FAIL (11 matches)
|
||||
bisect: run: test +0110+1-x002... FAIL (6 matches)
|
||||
bisect: run: test +00110+1-x002... FAIL (3 matches)
|
||||
bisect: run: test +000110+1-x002... FAIL (2 matches)
|
||||
bisect: run: test +0000110+1-x002... FAIL (1 matches)
|
||||
bisect: run: test +1+x006-x002... FAIL (45 matches)
|
||||
bisect: run: test +01+x006-x002... ok (23 matches)
|
||||
bisect: run: test +11+x006-x002... FAIL (22 matches)
|
||||
bisect: run: test +011+x006-x002... FAIL (11 matches)
|
||||
bisect: run: test +0011+x006-x002... ok (6 matches)
|
||||
bisect: run: test +1011+x006-x002... FAIL (5 matches)
|
||||
bisect: run: test +01011+x006-x002... ok (3 matches)
|
||||
bisect: run: test +11011+x006-x002... FAIL (2 matches)
|
||||
bisect: run: test +011011+x006-x002... ok (1 matches)
|
||||
bisect: run: test +111011+x006-x002... FAIL (1 matches)
|
||||
bisect: confirming failing change set
|
||||
bisect: run: test v+x006+x03b-x002... FAIL (2 matches)
|
||||
bisect: FOUND failing change set
|
||||
bisect: checking for more failures
|
||||
bisect: run: test -x006-x03b-x002... ok (87 matches)
|
||||
bisect: target succeeds with all remaining changes enabled
|
||||
@@ -0,0 +1,23 @@
|
||||
{"Fail": "amber || apricot && peach", "Bisect": {"Max": 1}}
|
||||
-- stdout --
|
||||
--- change set #1 (enabling changes causes failure)
|
||||
amber
|
||||
---
|
||||
-- stderr --
|
||||
bisect: checking target with all changes disabled
|
||||
bisect: run: test n... ok (90 matches)
|
||||
bisect: checking target with all changes enabled
|
||||
bisect: run: test y... FAIL (90 matches)
|
||||
bisect: target succeeds with no changes, fails with all changes
|
||||
bisect: searching for minimal set of enabled changes causing failure
|
||||
bisect: run: test +0... FAIL (45 matches)
|
||||
bisect: run: test +00... ok (23 matches)
|
||||
bisect: run: test +10... FAIL (22 matches)
|
||||
bisect: run: test +010... FAIL (11 matches)
|
||||
bisect: run: test +0010... FAIL (6 matches)
|
||||
bisect: run: test +00010... FAIL (3 matches)
|
||||
bisect: run: test +000010... FAIL (2 matches)
|
||||
bisect: run: test +0000010... FAIL (1 matches)
|
||||
bisect: confirming failing change set
|
||||
bisect: run: test v+x002... FAIL (1 matches)
|
||||
bisect: FOUND failing change set
|
||||
@@ -0,0 +1,59 @@
|
||||
{"Fail": "amber || apricot && peach || red && green && blue || cyan && magenta && yellow && black", "Bisect": {"Max": 2}}
|
||||
-- stdout --
|
||||
--- change set #1 (enabling changes causes failure)
|
||||
amber
|
||||
---
|
||||
--- change set #2 (enabling changes causes failure)
|
||||
blue
|
||||
green
|
||||
red
|
||||
---
|
||||
-- stderr --
|
||||
bisect: checking target with all changes disabled
|
||||
bisect: run: test n... ok (90 matches)
|
||||
bisect: checking target with all changes enabled
|
||||
bisect: run: test y... FAIL (90 matches)
|
||||
bisect: target succeeds with no changes, fails with all changes
|
||||
bisect: searching for minimal set of enabled changes causing failure
|
||||
bisect: run: test +0... FAIL (45 matches)
|
||||
bisect: run: test +00... ok (23 matches)
|
||||
bisect: run: test +10... FAIL (22 matches)
|
||||
bisect: run: test +010... FAIL (11 matches)
|
||||
bisect: run: test +0010... FAIL (6 matches)
|
||||
bisect: run: test +00010... FAIL (3 matches)
|
||||
bisect: run: test +000010... FAIL (2 matches)
|
||||
bisect: run: test +0000010... FAIL (1 matches)
|
||||
bisect: confirming failing change set
|
||||
bisect: run: test v+x002... FAIL (1 matches)
|
||||
bisect: FOUND failing change set
|
||||
bisect: checking for more failures
|
||||
bisect: run: test -x002... FAIL (89 matches)
|
||||
bisect: target still fails; searching for more bad changes
|
||||
bisect: run: test +0-x002... ok (44 matches)
|
||||
bisect: run: test +1-x002... FAIL (45 matches)
|
||||
bisect: run: test +01-x002... ok (23 matches)
|
||||
bisect: run: test +11-x002... ok (22 matches)
|
||||
bisect: run: test +01+11-x002... FAIL (23 matches)
|
||||
bisect: run: test +001+11-x002... ok (12 matches)
|
||||
bisect: run: test +101+11-x002... FAIL (11 matches)
|
||||
bisect: run: test +0101+11-x002... ok (6 matches)
|
||||
bisect: run: test +1101+11-x002... ok (5 matches)
|
||||
bisect: run: test +0101+11+1101-x002... FAIL (6 matches)
|
||||
bisect: run: test +00101+11+1101-x002... FAIL (3 matches)
|
||||
bisect: run: test +000101+11+1101-x002... FAIL (2 matches)
|
||||
bisect: run: test +0000101+11+1101-x002... ok (1 matches)
|
||||
bisect: run: test +1000101+11+1101-x002... FAIL (1 matches)
|
||||
bisect: run: test +1101+11+x045-x002... FAIL (5 matches)
|
||||
bisect: run: test +01101+11+x045-x002... FAIL (3 matches)
|
||||
bisect: run: test +001101+11+x045-x002... FAIL (2 matches)
|
||||
bisect: run: test +0001101+11+x045-x002... FAIL (1 matches)
|
||||
bisect: run: test +11+x045+x00d-x002... FAIL (22 matches)
|
||||
bisect: run: test +011+x045+x00d-x002... ok (11 matches)
|
||||
bisect: run: test +111+x045+x00d-x002... FAIL (11 matches)
|
||||
bisect: run: test +0111+x045+x00d-x002... FAIL (6 matches)
|
||||
bisect: run: test +00111+x045+x00d-x002... FAIL (3 matches)
|
||||
bisect: run: test +000111+x045+x00d-x002... ok (2 matches)
|
||||
bisect: run: test +100111+x045+x00d-x002... FAIL (1 matches)
|
||||
bisect: confirming failing change set
|
||||
bisect: run: test v+x045+x00d+x027-x002... FAIL (3 matches)
|
||||
bisect: FOUND failing change set
|
||||
@@ -0,0 +1,84 @@
|
||||
{"Fail": "amber || apricot && peach || red && green && blue || cyan && magenta && yellow && black", "Bisect": {"MaxSet": 3}}
|
||||
-- stdout --
|
||||
--- change set #1 (enabling changes causes failure)
|
||||
amber
|
||||
---
|
||||
--- change set #2 (enabling changes causes failure)
|
||||
blue
|
||||
green
|
||||
red
|
||||
---
|
||||
-- stderr --
|
||||
bisect: checking target with all changes disabled
|
||||
bisect: run: test n... ok (90 matches)
|
||||
bisect: checking target with all changes enabled
|
||||
bisect: run: test y... FAIL (90 matches)
|
||||
bisect: target succeeds with no changes, fails with all changes
|
||||
bisect: searching for minimal set of enabled changes causing failure
|
||||
bisect: run: test +0... FAIL (45 matches)
|
||||
bisect: run: test +00... ok (23 matches)
|
||||
bisect: run: test +10... FAIL (22 matches)
|
||||
bisect: run: test +010... FAIL (11 matches)
|
||||
bisect: run: test +0010... FAIL (6 matches)
|
||||
bisect: run: test +00010... FAIL (3 matches)
|
||||
bisect: run: test +000010... FAIL (2 matches)
|
||||
bisect: run: test +0000010... FAIL (1 matches)
|
||||
bisect: confirming failing change set
|
||||
bisect: run: test v+x002... FAIL (1 matches)
|
||||
bisect: FOUND failing change set
|
||||
bisect: checking for more failures
|
||||
bisect: run: test -x002... FAIL (89 matches)
|
||||
bisect: target still fails; searching for more bad changes
|
||||
bisect: run: test +0-x002... ok (44 matches)
|
||||
bisect: run: test +1-x002... FAIL (45 matches)
|
||||
bisect: run: test +01-x002... ok (23 matches)
|
||||
bisect: run: test +11-x002... ok (22 matches)
|
||||
bisect: run: test +01+11-x002... FAIL (23 matches)
|
||||
bisect: run: test +001+11-x002... ok (12 matches)
|
||||
bisect: run: test +101+11-x002... FAIL (11 matches)
|
||||
bisect: run: test +0101+11-x002... ok (6 matches)
|
||||
bisect: run: test +1101+11-x002... ok (5 matches)
|
||||
bisect: run: test +0101+11+1101-x002... FAIL (6 matches)
|
||||
bisect: run: test +00101+11+1101-x002... FAIL (3 matches)
|
||||
bisect: run: test +000101+11+1101-x002... FAIL (2 matches)
|
||||
bisect: run: test +0000101+11+1101-x002... ok (1 matches)
|
||||
bisect: run: test +1000101+11+1101-x002... FAIL (1 matches)
|
||||
bisect: run: test +1101+11+x045-x002... FAIL (5 matches)
|
||||
bisect: run: test +01101+11+x045-x002... FAIL (3 matches)
|
||||
bisect: run: test +001101+11+x045-x002... FAIL (2 matches)
|
||||
bisect: run: test +0001101+11+x045-x002... FAIL (1 matches)
|
||||
bisect: run: test +11+x045+x00d-x002... FAIL (22 matches)
|
||||
bisect: run: test +011+x045+x00d-x002... ok (11 matches)
|
||||
bisect: run: test +111+x045+x00d-x002... FAIL (11 matches)
|
||||
bisect: run: test +0111+x045+x00d-x002... FAIL (6 matches)
|
||||
bisect: run: test +00111+x045+x00d-x002... FAIL (3 matches)
|
||||
bisect: run: test +000111+x045+x00d-x002... ok (2 matches)
|
||||
bisect: run: test +100111+x045+x00d-x002... FAIL (1 matches)
|
||||
bisect: confirming failing change set
|
||||
bisect: run: test v+x045+x00d+x027-x002... FAIL (3 matches)
|
||||
bisect: FOUND failing change set
|
||||
bisect: checking for more failures
|
||||
bisect: run: test -x045-x00d-x027-x002... FAIL (86 matches)
|
||||
bisect: target still fails; searching for more bad changes
|
||||
bisect: run: test +0-x045-x00d-x027-x002... ok (44 matches)
|
||||
bisect: run: test +1-x045-x00d-x027-x002... ok (42 matches)
|
||||
bisect: run: test +0+1-x045-x00d-x027-x002... FAIL (44 matches)
|
||||
bisect: run: test +00+1-x045-x00d-x027-x002... FAIL (23 matches)
|
||||
bisect: run: test +000+1-x045-x00d-x027-x002... ok (12 matches)
|
||||
bisect: run: test +100+1-x045-x00d-x027-x002... ok (11 matches)
|
||||
bisect: run: test +000+1+100-x045-x00d-x027-x002... FAIL (12 matches)
|
||||
bisect: run: test +0000+1+100-x045-x00d-x027-x002... FAIL (6 matches)
|
||||
bisect: run: test +00000+1+100-x045-x00d-x027-x002... FAIL (3 matches)
|
||||
bisect: run: test +000000+1+100-x045-x00d-x027-x002... ok (2 matches)
|
||||
bisect: run: test +100000+1+100-x045-x00d-x027-x002... FAIL (1 matches)
|
||||
bisect: run: test +100+1+x020-x045-x00d-x027-x002... FAIL (11 matches)
|
||||
bisect: run: test +0100+1+x020-x045-x00d-x027-x002... ok (6 matches)
|
||||
bisect: run: test +1100+1+x020-x045-x00d-x027-x002... FAIL (5 matches)
|
||||
bisect: run: test +01100+1+x020-x045-x00d-x027-x002... FAIL (3 matches)
|
||||
bisect: run: test +001100+1+x020-x045-x00d-x027-x002... FAIL (2 matches)
|
||||
bisect: run: test +0001100+1+x020-x045-x00d-x027-x002... FAIL (1 matches)
|
||||
bisect: run: test +1+x020+x00c-x045-x00d-x027-x002... FAIL (42 matches)
|
||||
bisect: run: test +01+x020+x00c-x045-x00d-x027-x002... FAIL (21 matches)
|
||||
bisect: run: test +001+x020+x00c-x045-x00d-x027-x002... FAIL (12 matches)
|
||||
bisect: run: test +0001+x020+x00c-x045-x00d-x027-x002... ok (6 matches)
|
||||
bisect: run: test +1001+x020+x00c-x045-x00d-x027-x002... ok (6 matches)
|
||||
@@ -0,0 +1,13 @@
|
||||
{"Fail": "apricot && peach", "Bisect": {"MaxSet": 1}}
|
||||
-- stdout --
|
||||
-- stderr --
|
||||
bisect: checking target with all changes disabled
|
||||
bisect: run: test n... ok (90 matches)
|
||||
bisect: checking target with all changes enabled
|
||||
bisect: run: test y... FAIL (90 matches)
|
||||
bisect: target succeeds with no changes, fails with all changes
|
||||
bisect: searching for minimal set of enabled changes causing failure
|
||||
bisect: run: test +0... ok (45 matches)
|
||||
bisect: run: test +1... ok (45 matches)
|
||||
bisect: fatal error: cannot find any failing change sets of size ≤ 1
|
||||
<bisect failed>
|
||||
@@ -0,0 +1,138 @@
|
||||
{"Fail": "amber || apricot && peach || red && green && blue || cyan && magenta && yellow && black", "Bisect": {"MaxSet": 4}}
|
||||
-- stdout --
|
||||
--- change set #1 (enabling changes causes failure)
|
||||
amber
|
||||
---
|
||||
--- change set #2 (enabling changes causes failure)
|
||||
blue
|
||||
green
|
||||
red
|
||||
---
|
||||
--- change set #3 (enabling changes causes failure)
|
||||
black
|
||||
cyan
|
||||
magenta
|
||||
yellow
|
||||
---
|
||||
--- change set #4 (enabling changes causes failure)
|
||||
apricot
|
||||
peach
|
||||
---
|
||||
-- stderr --
|
||||
bisect: checking target with all changes disabled
|
||||
bisect: run: test n... ok (90 matches)
|
||||
bisect: checking target with all changes enabled
|
||||
bisect: run: test y... FAIL (90 matches)
|
||||
bisect: target succeeds with no changes, fails with all changes
|
||||
bisect: searching for minimal set of enabled changes causing failure
|
||||
bisect: run: test +0... FAIL (45 matches)
|
||||
bisect: run: test +00... ok (23 matches)
|
||||
bisect: run: test +10... FAIL (22 matches)
|
||||
bisect: run: test +010... FAIL (11 matches)
|
||||
bisect: run: test +0010... FAIL (6 matches)
|
||||
bisect: run: test +00010... FAIL (3 matches)
|
||||
bisect: run: test +000010... FAIL (2 matches)
|
||||
bisect: run: test +0000010... FAIL (1 matches)
|
||||
bisect: confirming failing change set
|
||||
bisect: run: test v+x002... FAIL (1 matches)
|
||||
bisect: FOUND failing change set
|
||||
bisect: checking for more failures
|
||||
bisect: run: test -x002... FAIL (89 matches)
|
||||
bisect: target still fails; searching for more bad changes
|
||||
bisect: run: test +0-x002... ok (44 matches)
|
||||
bisect: run: test +1-x002... FAIL (45 matches)
|
||||
bisect: run: test +01-x002... ok (23 matches)
|
||||
bisect: run: test +11-x002... ok (22 matches)
|
||||
bisect: run: test +01+11-x002... FAIL (23 matches)
|
||||
bisect: run: test +001+11-x002... ok (12 matches)
|
||||
bisect: run: test +101+11-x002... FAIL (11 matches)
|
||||
bisect: run: test +0101+11-x002... ok (6 matches)
|
||||
bisect: run: test +1101+11-x002... ok (5 matches)
|
||||
bisect: run: test +0101+11+1101-x002... FAIL (6 matches)
|
||||
bisect: run: test +00101+11+1101-x002... FAIL (3 matches)
|
||||
bisect: run: test +000101+11+1101-x002... FAIL (2 matches)
|
||||
bisect: run: test +0000101+11+1101-x002... ok (1 matches)
|
||||
bisect: run: test +1000101+11+1101-x002... FAIL (1 matches)
|
||||
bisect: run: test +1101+11+x045-x002... FAIL (5 matches)
|
||||
bisect: run: test +01101+11+x045-x002... FAIL (3 matches)
|
||||
bisect: run: test +001101+11+x045-x002... FAIL (2 matches)
|
||||
bisect: run: test +0001101+11+x045-x002... FAIL (1 matches)
|
||||
bisect: run: test +11+x045+x00d-x002... FAIL (22 matches)
|
||||
bisect: run: test +011+x045+x00d-x002... ok (11 matches)
|
||||
bisect: run: test +111+x045+x00d-x002... FAIL (11 matches)
|
||||
bisect: run: test +0111+x045+x00d-x002... FAIL (6 matches)
|
||||
bisect: run: test +00111+x045+x00d-x002... FAIL (3 matches)
|
||||
bisect: run: test +000111+x045+x00d-x002... ok (2 matches)
|
||||
bisect: run: test +100111+x045+x00d-x002... FAIL (1 matches)
|
||||
bisect: confirming failing change set
|
||||
bisect: run: test v+x045+x00d+x027-x002... FAIL (3 matches)
|
||||
bisect: FOUND failing change set
|
||||
bisect: checking for more failures
|
||||
bisect: run: test -x045-x00d-x027-x002... FAIL (86 matches)
|
||||
bisect: target still fails; searching for more bad changes
|
||||
bisect: run: test +0-x045-x00d-x027-x002... ok (44 matches)
|
||||
bisect: run: test +1-x045-x00d-x027-x002... ok (42 matches)
|
||||
bisect: run: test +0+1-x045-x00d-x027-x002... FAIL (44 matches)
|
||||
bisect: run: test +00+1-x045-x00d-x027-x002... FAIL (23 matches)
|
||||
bisect: run: test +000+1-x045-x00d-x027-x002... ok (12 matches)
|
||||
bisect: run: test +100+1-x045-x00d-x027-x002... ok (11 matches)
|
||||
bisect: run: test +000+1+100-x045-x00d-x027-x002... FAIL (12 matches)
|
||||
bisect: run: test +0000+1+100-x045-x00d-x027-x002... FAIL (6 matches)
|
||||
bisect: run: test +00000+1+100-x045-x00d-x027-x002... FAIL (3 matches)
|
||||
bisect: run: test +000000+1+100-x045-x00d-x027-x002... ok (2 matches)
|
||||
bisect: run: test +100000+1+100-x045-x00d-x027-x002... FAIL (1 matches)
|
||||
bisect: run: test +100+1+x020-x045-x00d-x027-x002... FAIL (11 matches)
|
||||
bisect: run: test +0100+1+x020-x045-x00d-x027-x002... ok (6 matches)
|
||||
bisect: run: test +1100+1+x020-x045-x00d-x027-x002... FAIL (5 matches)
|
||||
bisect: run: test +01100+1+x020-x045-x00d-x027-x002... FAIL (3 matches)
|
||||
bisect: run: test +001100+1+x020-x045-x00d-x027-x002... FAIL (2 matches)
|
||||
bisect: run: test +0001100+1+x020-x045-x00d-x027-x002... FAIL (1 matches)
|
||||
bisect: run: test +1+x020+x00c-x045-x00d-x027-x002... FAIL (42 matches)
|
||||
bisect: run: test +01+x020+x00c-x045-x00d-x027-x002... FAIL (21 matches)
|
||||
bisect: run: test +001+x020+x00c-x045-x00d-x027-x002... FAIL (12 matches)
|
||||
bisect: run: test +0001+x020+x00c-x045-x00d-x027-x002... ok (6 matches)
|
||||
bisect: run: test +1001+x020+x00c-x045-x00d-x027-x002... ok (6 matches)
|
||||
bisect: run: test +0001+x020+x00c+1001-x045-x00d-x027-x002... FAIL (6 matches)
|
||||
bisect: run: test +00001+x020+x00c+1001-x045-x00d-x027-x002... ok (3 matches)
|
||||
bisect: run: test +10001+x020+x00c+1001-x045-x00d-x027-x002... FAIL (3 matches)
|
||||
bisect: run: test +010001+x020+x00c+1001-x045-x00d-x027-x002... ok (2 matches)
|
||||
bisect: run: test +110001+x020+x00c+1001-x045-x00d-x027-x002... FAIL (1 matches)
|
||||
bisect: run: test +1001+x020+x00c+x031-x045-x00d-x027-x002... FAIL (6 matches)
|
||||
bisect: run: test +01001+x020+x00c+x031-x045-x00d-x027-x002... ok (3 matches)
|
||||
bisect: run: test +11001+x020+x00c+x031-x045-x00d-x027-x002... FAIL (3 matches)
|
||||
bisect: run: test +011001+x020+x00c+x031-x045-x00d-x027-x002... FAIL (2 matches)
|
||||
bisect: run: test +0011001+x020+x00c+x031-x045-x00d-x027-x002... ok (1 matches)
|
||||
bisect: run: test +1011001+x020+x00c+x031-x045-x00d-x027-x002... FAIL (1 matches)
|
||||
bisect: confirming failing change set
|
||||
bisect: run: test v+x020+x00c+x031+x059-x045-x00d-x027-x002... FAIL (4 matches)
|
||||
bisect: FOUND failing change set
|
||||
bisect: checking for more failures
|
||||
bisect: run: test -x020-x00c-x031-x059-x045-x00d-x027-x002... FAIL (82 matches)
|
||||
bisect: target still fails; searching for more bad changes
|
||||
bisect: run: test +0-x020-x00c-x031-x059-x045-x00d-x027-x002... ok (42 matches)
|
||||
bisect: run: test +1-x020-x00c-x031-x059-x045-x00d-x027-x002... ok (40 matches)
|
||||
bisect: run: test +0+1-x020-x00c-x031-x059-x045-x00d-x027-x002... FAIL (42 matches)
|
||||
bisect: run: test +00+1-x020-x00c-x031-x059-x045-x00d-x027-x002... ok (21 matches)
|
||||
bisect: run: test +10+1-x020-x00c-x031-x059-x045-x00d-x027-x002... FAIL (21 matches)
|
||||
bisect: run: test +010+1-x020-x00c-x031-x059-x045-x00d-x027-x002... ok (10 matches)
|
||||
bisect: run: test +110+1-x020-x00c-x031-x059-x045-x00d-x027-x002... FAIL (11 matches)
|
||||
bisect: run: test +0110+1-x020-x00c-x031-x059-x045-x00d-x027-x002... FAIL (6 matches)
|
||||
bisect: run: test +00110+1-x020-x00c-x031-x059-x045-x00d-x027-x002... FAIL (3 matches)
|
||||
bisect: run: test +000110+1-x020-x00c-x031-x059-x045-x00d-x027-x002... FAIL (2 matches)
|
||||
bisect: run: test +0000110+1-x020-x00c-x031-x059-x045-x00d-x027-x002... FAIL (1 matches)
|
||||
bisect: run: test +1+x006-x020-x00c-x031-x059-x045-x00d-x027-x002... FAIL (40 matches)
|
||||
bisect: run: test +01+x006-x020-x00c-x031-x059-x045-x00d-x027-x002... ok (19 matches)
|
||||
bisect: run: test +11+x006-x020-x00c-x031-x059-x045-x00d-x027-x002... FAIL (21 matches)
|
||||
bisect: run: test +011+x006-x020-x00c-x031-x059-x045-x00d-x027-x002... FAIL (11 matches)
|
||||
bisect: run: test +0011+x006-x020-x00c-x031-x059-x045-x00d-x027-x002... ok (6 matches)
|
||||
bisect: run: test +1011+x006-x020-x00c-x031-x059-x045-x00d-x027-x002... FAIL (5 matches)
|
||||
bisect: run: test +01011+x006-x020-x00c-x031-x059-x045-x00d-x027-x002... ok (3 matches)
|
||||
bisect: run: test +11011+x006-x020-x00c-x031-x059-x045-x00d-x027-x002... FAIL (2 matches)
|
||||
bisect: run: test +011011+x006-x020-x00c-x031-x059-x045-x00d-x027-x002... ok (1 matches)
|
||||
bisect: run: test +111011+x006-x020-x00c-x031-x059-x045-x00d-x027-x002... FAIL (1 matches)
|
||||
bisect: confirming failing change set
|
||||
bisect: run: test v+x006+x03b-x020-x00c-x031-x059-x045-x00d-x027-x002... FAIL (2 matches)
|
||||
bisect: FOUND failing change set
|
||||
bisect: checking for more failures
|
||||
bisect: run: test -x006-x03b-x020-x00c-x031-x059-x045-x00d-x027-x002... ok (80 matches)
|
||||
bisect: target succeeds with all remaining changes enabled
|
||||
@@ -0,0 +1,57 @@
|
||||
{"Fail": "!amber || !apricot && !peach"}
|
||||
-- stdout --
|
||||
--- change set #1 (disabling changes causes failure)
|
||||
amber
|
||||
---
|
||||
--- change set #2 (disabling changes causes failure)
|
||||
apricot
|
||||
peach
|
||||
---
|
||||
-- stderr --
|
||||
bisect: checking target with all changes disabled
|
||||
bisect: run: test n... FAIL (90 matches)
|
||||
bisect: checking target with all changes enabled
|
||||
bisect: run: test y... ok (90 matches)
|
||||
bisect: target fails with no changes, succeeds with all changes
|
||||
bisect: searching for minimal set of disabled changes causing failure
|
||||
bisect: run: test !+0... FAIL (45 matches)
|
||||
bisect: run: test !+00... ok (23 matches)
|
||||
bisect: run: test !+10... FAIL (22 matches)
|
||||
bisect: run: test !+010... FAIL (11 matches)
|
||||
bisect: run: test !+0010... FAIL (6 matches)
|
||||
bisect: run: test !+00010... FAIL (3 matches)
|
||||
bisect: run: test !+000010... FAIL (2 matches)
|
||||
bisect: run: test !+0000010... FAIL (1 matches)
|
||||
bisect: confirming failing change set
|
||||
bisect: run: test v!+x002... FAIL (1 matches)
|
||||
bisect: FOUND failing change set
|
||||
bisect: checking for more failures
|
||||
bisect: run: test !-x002... FAIL (89 matches)
|
||||
bisect: target still fails; searching for more bad changes
|
||||
bisect: run: test !+0-x002... ok (44 matches)
|
||||
bisect: run: test !+1-x002... ok (45 matches)
|
||||
bisect: run: test !+0+1-x002... FAIL (44 matches)
|
||||
bisect: run: test !+00+1-x002... ok (23 matches)
|
||||
bisect: run: test !+10+1-x002... FAIL (21 matches)
|
||||
bisect: run: test !+010+1-x002... ok (10 matches)
|
||||
bisect: run: test !+110+1-x002... FAIL (11 matches)
|
||||
bisect: run: test !+0110+1-x002... FAIL (6 matches)
|
||||
bisect: run: test !+00110+1-x002... FAIL (3 matches)
|
||||
bisect: run: test !+000110+1-x002... FAIL (2 matches)
|
||||
bisect: run: test !+0000110+1-x002... FAIL (1 matches)
|
||||
bisect: run: test !+1+x006-x002... FAIL (45 matches)
|
||||
bisect: run: test !+01+x006-x002... ok (23 matches)
|
||||
bisect: run: test !+11+x006-x002... FAIL (22 matches)
|
||||
bisect: run: test !+011+x006-x002... FAIL (11 matches)
|
||||
bisect: run: test !+0011+x006-x002... ok (6 matches)
|
||||
bisect: run: test !+1011+x006-x002... FAIL (5 matches)
|
||||
bisect: run: test !+01011+x006-x002... ok (3 matches)
|
||||
bisect: run: test !+11011+x006-x002... FAIL (2 matches)
|
||||
bisect: run: test !+011011+x006-x002... ok (1 matches)
|
||||
bisect: run: test !+111011+x006-x002... FAIL (1 matches)
|
||||
bisect: confirming failing change set
|
||||
bisect: run: test v!+x006+x03b-x002... FAIL (2 matches)
|
||||
bisect: FOUND failing change set
|
||||
bisect: checking for more failures
|
||||
bisect: run: test !-x006-x03b-x002... ok (87 matches)
|
||||
bisect: target succeeds with all remaining changes disabled
|
||||
@@ -0,0 +1,59 @@
|
||||
{"Fail": "amber || apricot || blue && random"}
|
||||
-- stdout --
|
||||
--- change set #1 (enabling changes causes failure)
|
||||
amber
|
||||
---
|
||||
--- change set #2 (enabling changes causes failure)
|
||||
apricot
|
||||
---
|
||||
-- stderr --
|
||||
bisect: checking target with all changes disabled
|
||||
bisect: run: test n... ok (90 matches)
|
||||
bisect: checking target with all changes enabled
|
||||
bisect: run: test y... FAIL (90 matches)
|
||||
bisect: target succeeds with no changes, fails with all changes
|
||||
bisect: searching for minimal set of enabled changes causing failure
|
||||
bisect: run: test +0... FAIL (45 matches)
|
||||
bisect: run: test +00... ok (23 matches)
|
||||
bisect: run: test +10... FAIL (22 matches)
|
||||
bisect: run: test +010... FAIL (11 matches)
|
||||
bisect: run: test +0010... FAIL (6 matches)
|
||||
bisect: run: test +00010... FAIL (3 matches)
|
||||
bisect: run: test +000010... FAIL (2 matches)
|
||||
bisect: run: test +0000010... FAIL (1 matches)
|
||||
bisect: confirming failing change set
|
||||
bisect: run: test v+x002... FAIL (1 matches)
|
||||
bisect: FOUND failing change set
|
||||
bisect: checking for more failures
|
||||
bisect: run: test -x002... FAIL (89 matches)
|
||||
bisect: target still fails; searching for more bad changes
|
||||
bisect: run: test +0-x002... FAIL (44 matches)
|
||||
bisect: run: test +00-x002... ok (23 matches)
|
||||
bisect: run: test +10-x002... FAIL (21 matches)
|
||||
bisect: run: test +010-x002... ok (10 matches)
|
||||
bisect: run: test +110-x002... FAIL (11 matches)
|
||||
bisect: run: test +0110-x002... FAIL (6 matches)
|
||||
bisect: run: test +00110-x002... FAIL (3 matches)
|
||||
bisect: run: test +000110-x002... FAIL (2 matches)
|
||||
bisect: run: test +0000110-x002... FAIL (1 matches)
|
||||
bisect: confirming failing change set
|
||||
bisect: run: test v+x006-x002... FAIL (1 matches)
|
||||
bisect: FOUND failing change set
|
||||
bisect: checking for more failures
|
||||
bisect: run: test -x006-x002... FAIL (88 matches)
|
||||
bisect: target still fails; searching for more bad changes
|
||||
bisect: run: test +0-x006-x002... ok (43 matches)
|
||||
bisect: run: test +1-x006-x002... FAIL (45 matches)
|
||||
bisect: run: test +01-x006-x002... FAIL (23 matches)
|
||||
bisect: run: test +001-x006-x002... ok (12 matches)
|
||||
bisect: run: test +101-x006-x002... FAIL (11 matches)
|
||||
bisect: run: test +0101-x006-x002... ok (6 matches)
|
||||
bisect: run: test +1101-x006-x002... FAIL (5 matches)
|
||||
bisect: run: test +01101-x006-x002... ok (3 matches)
|
||||
bisect: run: test +11101-x006-x002... ok (2 matches)
|
||||
bisect: run: test +01101+11101-x006-x002... FAIL (3 matches)
|
||||
bisect: run: test +001101+11101-x006-x002... ok (2 matches)
|
||||
bisect: run: test +101101+11101-x006-x002... ok (1 matches)
|
||||
bisect: run: test +001101+11101+101101-x006-x002... ok (2 matches)
|
||||
bisect: fatal error: target fails inconsistently
|
||||
<bisect failed>
|
||||
@@ -0,0 +1,24 @@
|
||||
{"Fail": "blue && random"}
|
||||
-- stdout --
|
||||
-- stderr --
|
||||
bisect: checking target with all changes disabled
|
||||
bisect: run: test n... ok (90 matches)
|
||||
bisect: checking target with all changes enabled
|
||||
bisect: run: test y... FAIL (90 matches)
|
||||
bisect: target succeeds with no changes, fails with all changes
|
||||
bisect: searching for minimal set of enabled changes causing failure
|
||||
bisect: run: test +0... ok (45 matches)
|
||||
bisect: run: test +1... FAIL (45 matches)
|
||||
bisect: run: test +01... FAIL (23 matches)
|
||||
bisect: run: test +001... ok (12 matches)
|
||||
bisect: run: test +101... FAIL (11 matches)
|
||||
bisect: run: test +0101... ok (6 matches)
|
||||
bisect: run: test +1101... FAIL (5 matches)
|
||||
bisect: run: test +01101... ok (3 matches)
|
||||
bisect: run: test +11101... ok (2 matches)
|
||||
bisect: run: test +01101+11101... FAIL (3 matches)
|
||||
bisect: run: test +001101+11101... ok (2 matches)
|
||||
bisect: run: test +101101+11101... ok (1 matches)
|
||||
bisect: run: test +001101+11101+101101... ok (2 matches)
|
||||
bisect: fatal error: target fails inconsistently
|
||||
<bisect failed>
|
||||
@@ -0,0 +1,19 @@
|
||||
{"Fail": "blue && random", "Bisect": {"Count": 2}}
|
||||
-- stdout --
|
||||
-- stderr --
|
||||
bisect: checking target with all changes disabled
|
||||
bisect: run: test n... ok (90 matches)
|
||||
bisect: run: test n... ok (90 matches)
|
||||
bisect: checking target with all changes enabled
|
||||
bisect: run: test y... FAIL (90 matches)
|
||||
bisect: run: test y... FAIL (90 matches)
|
||||
bisect: target succeeds with no changes, fails with all changes
|
||||
bisect: searching for minimal set of enabled changes causing failure
|
||||
bisect: run: test +0... ok (45 matches)
|
||||
bisect: run: test +0... ok (45 matches)
|
||||
bisect: run: test +1... FAIL (45 matches)
|
||||
bisect: run: test +1... FAIL (45 matches)
|
||||
bisect: run: test +01... FAIL (23 matches)
|
||||
bisect: run: test +01... ok (23 matches)
|
||||
bisect: fatal error: target fails inconsistently
|
||||
<bisect failed>
|
||||
Reference in New Issue
Block a user