blob: 3d33d9332a90de5b7e6ea3c467ee0da85cf08fd8 [file] [log] [blame]
// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package main
import (
"bytes"
"io"
"strings"
"testing"
)
func TestBuildWithAutoCrashDoesNothingIfCrashIsNotRequested(t *testing.T) {
withTestContext(t, func(ctx *testContext) {
neverAutoCrash := buildWithAutocrashPredicates{
allowInConfigure: true,
shouldAutocrash: func(env, *config, *command, compilerExecInfo) bool {
return false
},
}
exitCode, err := buildWithAutocrashImpl(ctx, ctx.cfg, ctx.newCommand(clangX86_64, mainCc), neverAutoCrash)
if err != nil {
t.Fatalf("unexpectedly failed with %v", err)
}
ctx.must(exitCode)
if ctx.cmdCount != 1 {
t.Errorf("expected 1 call. Got: %d", ctx.cmdCount)
}
})
}
func TestBuildWithAutoCrashSkipsAutocrashLogicIfInConfigureAndConfigureChecksDisabled(t *testing.T) {
withTestContext(t, func(ctx *testContext) {
alwaysAutocrash := buildWithAutocrashPredicates{
allowInConfigure: false,
shouldAutocrash: func(env, *config, *command, compilerExecInfo) bool {
return true
},
}
ctx.env = append(ctx.env, "EBUILD_PHASE=configure")
exitCode, err := buildWithAutocrashImpl(ctx, ctx.cfg, ctx.newCommand(clangX86_64, mainCc), alwaysAutocrash)
if err != nil {
t.Fatalf("unexpectedly failed with %v", err)
}
ctx.must(exitCode)
if ctx.cmdCount != 1 {
t.Errorf("expected 1 call. Got: %d", ctx.cmdCount)
}
})
}
func TestBuildWithAutoCrashRerunsIfPredicateRequestsCrash(t *testing.T) {
withTestContext(t, func(ctx *testContext) {
autocrashPostCmd := buildWithAutocrashPredicates{
allowInConfigure: true,
shouldAutocrash: func(env, *config, *command, compilerExecInfo) bool {
return true
},
}
ctx.cmdMock = func(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error {
hasDash := false
for _, arg := range cmd.Args {
if arg == "-" {
hasDash = true
break
}
}
switch ctx.cmdCount {
case 1:
if hasDash {
t.Error("Got `-` on command 1; didn't want that.")
}
return nil
case 2:
if !hasDash {
t.Error("Didn't get `-` on command 2; wanted that.")
} else {
input := stdin.(*bytes.Buffer)
if s := input.String(); !strings.Contains(s, autocrashProgramLine) {
t.Errorf("Input was %q; expected %q to be in it", s, autocrashProgramLine)
}
}
return nil
default:
t.Fatalf("Unexpected command count: %d", ctx.cmdCount)
panic("Unreachable")
}
}
exitCode, err := buildWithAutocrashImpl(ctx, ctx.cfg, ctx.newCommand(clangX86_64, mainCc), autocrashPostCmd)
if err != nil {
t.Fatalf("unexpectedly failed with %v", err)
}
ctx.must(exitCode)
if ctx.cmdCount != 2 {
t.Errorf("expected 2 calls. Got: %d", ctx.cmdCount)
}
})
}
func TestBuildWithAutoCrashAddsDashAndWritesToStdinIfInputFileIsNotStdin(t *testing.T) {
withTestContext(t, func(ctx *testContext) {
autocrashPostCmd := buildWithAutocrashPredicates{
allowInConfigure: true,
shouldAutocrash: func(env, *config, *command, compilerExecInfo) bool {
return true
},
}
ctx.cmdMock = func(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error {
numDashes := 0
for _, arg := range cmd.Args {
if arg == "-" {
numDashes++
}
}
switch ctx.cmdCount {
case 1:
if numDashes != 0 {
t.Errorf("Got %d dashes on command 1; want 0", numDashes)
}
return nil
case 2:
if numDashes != 1 {
t.Errorf("Got %d dashes on command 2; want 1", numDashes)
}
input := stdin.(*bytes.Buffer).String()
stdinHasAutocrashLine := strings.Contains(input, autocrashProgramLine)
if !stdinHasAutocrashLine {
t.Error("Got no autocrash line on the second command; wanted that")
}
return nil
default:
t.Fatalf("Unexpected command count: %d", ctx.cmdCount)
panic("Unreachable")
}
}
exitCode, err := buildWithAutocrashImpl(ctx, ctx.cfg, ctx.newCommand(clangX86_64, mainCc), autocrashPostCmd)
if err != nil {
t.Fatalf("unexpectedly failed with %v", err)
}
ctx.must(exitCode)
if ctx.cmdCount != 2 {
t.Errorf("expected 2 calls. Got: %d", ctx.cmdCount)
}
})
}
func TestBuildWithAutoCrashAppendsToStdinIfStdinIsTheOnlyInputFile(t *testing.T) {
withTestContext(t, func(ctx *testContext) {
autocrashPostCmd := buildWithAutocrashPredicates{
allowInConfigure: true,
shouldAutocrash: func(env, *config, *command, compilerExecInfo) bool {
return true
},
}
ctx.cmdMock = func(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error {
numDashes := 0
for _, arg := range cmd.Args {
if arg == "-" {
numDashes++
}
}
if numDashes != 1 {
t.Errorf("Got %d dashes on command %d (args: %#v); want 1", numDashes, ctx.cmdCount, cmd.Args)
}
input := stdin.(*bytes.Buffer).String()
stdinHasAutocrashLine := strings.Contains(input, autocrashProgramLine)
switch ctx.cmdCount {
case 1:
if stdinHasAutocrashLine {
t.Error("Got autocrash line on the first command; did not want that")
}
return nil
case 2:
if !stdinHasAutocrashLine {
t.Error("Got no autocrash line on the second command; wanted that")
}
return nil
default:
t.Fatalf("Unexpected command count: %d", ctx.cmdCount)
panic("Unreachable")
}
}
exitCode, err := buildWithAutocrashImpl(ctx, ctx.cfg, ctx.newCommand(clangX86_64, "-x", "c", "-"), autocrashPostCmd)
if err != nil {
t.Fatalf("unexpectedly failed with %v", err)
}
ctx.must(exitCode)
if ctx.cmdCount != 2 {
t.Errorf("expected 2 calls. Got: %d", ctx.cmdCount)
}
})
}
func TestCrashBuildFiltersObjectFileOptionOnCrashes(t *testing.T) {
withTestContext(t, func(ctx *testContext) {
autocrashPostCmd := buildWithAutocrashPredicates{
allowInConfigure: true,
shouldAutocrash: func(env, *config, *command, compilerExecInfo) bool {
return true
},
}
const outputFileName = "/path/to/foo.o"
ctx.cmdMock = func(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error {
cmdOutputArg := (*string)(nil)
for i, e := range cmd.Args {
if e == "-o" {
// Assume something follows. If not, we'll crash and the
// test will fail.
cmdOutputArg = &cmd.Args[i+1]
}
}
switch ctx.cmdCount {
case 1:
if cmdOutputArg == nil || *cmdOutputArg != outputFileName {
t.Errorf("Got command args %q; want `-o %q` in them", cmd.Args, outputFileName)
}
return nil
case 2:
if cmdOutputArg != nil {
t.Errorf("Got command args %q; want no mention of `-o %q` in them", cmd.Args, outputFileName)
}
return nil
default:
t.Fatalf("Unexpected command count: %d", ctx.cmdCount)
panic("Unreachable")
}
}
exitCode, err := buildWithAutocrashImpl(ctx, ctx.cfg, ctx.newCommand(clangX86_64, "-o", outputFileName, mainCc), autocrashPostCmd)
if err != nil {
t.Fatalf("unexpectedly failed with %v", err)
}
ctx.must(exitCode)
if ctx.cmdCount != 2 {
t.Errorf("expected 2 calls. Got: %d", ctx.cmdCount)
}
})
}