1// Copyright 2019 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5package main
6
7import (
8	"bytes"
9	"errors"
10	"fmt"
11	"io"
12	"strings"
13	"syscall"
14	"testing"
15)
16
17func TestAddCommonFlags(t *testing.T) {
18	withTestContext(t, func(ctx *testContext) {
19		ctx.cfg.commonFlags = []string{"-someflag"}
20		cmd := ctx.must(callCompiler(ctx, ctx.cfg,
21			ctx.newCommand(gccX86_64, mainCc)))
22		if err := verifyArgOrder(cmd, "-someflag", mainCc); err != nil {
23			t.Error(err)
24		}
25	})
26}
27
28func TestAddGccConfigFlags(t *testing.T) {
29	withTestContext(t, func(ctx *testContext) {
30		ctx.cfg.gccFlags = []string{"-someflag"}
31		cmd := ctx.must(callCompiler(ctx, ctx.cfg,
32			ctx.newCommand(gccX86_64, mainCc)))
33		if err := verifyArgOrder(cmd, "-someflag", mainCc); err != nil {
34			t.Error(err)
35		}
36	})
37}
38
39func TestAddClangConfigFlags(t *testing.T) {
40	withTestContext(t, func(ctx *testContext) {
41		ctx.cfg.clangFlags = []string{"-someflag"}
42		cmd := ctx.must(callCompiler(ctx, ctx.cfg,
43			ctx.newCommand(clangX86_64, mainCc)))
44		if err := verifyArgOrder(cmd, "-someflag", mainCc); err != nil {
45			t.Error(err)
46		}
47	})
48}
49
50func TestLogGeneralExecError(t *testing.T) {
51	withTestContext(t, func(ctx *testContext) {
52		ctx.cmdMock = func(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error {
53			return errors.New("someerror")
54		}
55		stderr := ctx.mustFail(callCompiler(ctx, ctx.cfg, ctx.newCommand(gccX86_64, mainCc)))
56		if err := verifyInternalError(stderr); err != nil {
57			t.Fatal(err)
58		}
59		if !strings.Contains(stderr, gccX86_64) {
60			t.Errorf("could not find compiler path on stderr. Got: %s", stderr)
61		}
62		if !strings.Contains(stderr, "someerror") {
63			t.Errorf("could not find original error on stderr. Got: %s", stderr)
64		}
65	})
66}
67
68func TestForwardStdin(t *testing.T) {
69	withTestContext(t, func(ctx *testContext) {
70		io.WriteString(&ctx.stdinBuffer, "someinput")
71		ctx.cmdMock = func(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error {
72			stdinStr := ctx.readAllString(stdin)
73			if stdinStr != "someinput" {
74				return fmt.Errorf("unexpected stdin. Got: %s", stdinStr)
75			}
76			return nil
77		}
78		ctx.must(callCompiler(ctx, ctx.cfg, ctx.newCommand(gccX86_64, "-", mainCc)))
79	})
80}
81
82func TestLogMissingCCacheExecError(t *testing.T) {
83	withTestContext(t, func(ctx *testContext) {
84		ctx.cfg.useCCache = true
85
86		ctx.cmdMock = func(cmd *command, stdin io.Reader, stdout io.Writer, stderr io.Writer) error {
87			return syscall.ENOENT
88		}
89		ctx.stderrBuffer.Reset()
90		stderr := ctx.mustFail(callCompiler(ctx, ctx.cfg, ctx.newCommand(gccX86_64, mainCc)))
91		if err := verifyNonInternalError(stderr, "ccache not found under .*. Please install it"); err != nil {
92			t.Fatal(err)
93		}
94	})
95}
96
97func TestErrorOnLogRusageAndForceDisableWError(t *testing.T) {
98	withTestContext(t, func(ctx *testContext) {
99		ctx.env = []string{
100			"FORCE_DISABLE_WERROR=1",
101			"GETRUSAGE=rusage.log",
102		}
103		stderr := ctx.mustFail(callCompiler(ctx, ctx.cfg, ctx.newCommand(gccX86_64, mainCc)))
104		if err := verifyNonInternalError(stderr, "GETRUSAGE is meaningless with FORCE_DISABLE_WERROR"); err != nil {
105			t.Error(err)
106		}
107	})
108}
109
110func TestErrorOnLogRusageAndBisect(t *testing.T) {
111	withTestContext(t, func(ctx *testContext) {
112		ctx.env = []string{
113			"BISECT_STAGE=xyz",
114			"GETRUSAGE=rusage.log",
115		}
116		stderr := ctx.mustFail(callCompiler(ctx, ctx.cfg, ctx.newCommand(gccX86_64, mainCc)))
117		if err := verifyNonInternalError(stderr, "BISECT_STAGE is meaningless with GETRUSAGE"); err != nil {
118			t.Error(err)
119		}
120	})
121}
122
123func TestErrorOnBisectAndForceDisableWError(t *testing.T) {
124	withTestContext(t, func(ctx *testContext) {
125		ctx.env = []string{
126			"BISECT_STAGE=xyz",
127			"FORCE_DISABLE_WERROR=1",
128		}
129		stderr := ctx.mustFail(callCompiler(ctx, ctx.cfg, ctx.newCommand(gccX86_64, mainCc)))
130		if err := verifyNonInternalError(stderr, "BISECT_STAGE is meaningless with FORCE_DISABLE_WERROR"); err != nil {
131			t.Error(err)
132		}
133	})
134}
135
136func TestPrintUserCompilerError(t *testing.T) {
137	buffer := bytes.Buffer{}
138	printCompilerError(&buffer, newUserErrorf("abcd"))
139	if buffer.String() != "abcd\n" {
140		t.Errorf("Unexpected string. Got: %s", buffer.String())
141	}
142}
143
144func TestPrintOtherCompilerError(t *testing.T) {
145	buffer := bytes.Buffer{}
146	printCompilerError(&buffer, errors.New("abcd"))
147	if buffer.String() != "Internal error. Please report to chromeos-toolchain@google.com.\nabcd\n" {
148		t.Errorf("Unexpected string. Got: %s", buffer.String())
149	}
150}
151
152func TestPrintOtherCompilerErrorForAndroidLLVM(t *testing.T) {
153	buffer := bytes.Buffer{}
154
155	oldConfigName := ConfigName
156	defer func() { ConfigName = oldConfigName }()
157
158	ConfigName = "android"
159	printCompilerError(&buffer, errors.New("abcd"))
160	if buffer.String() != "Internal error. Please report to android-llvm@google.com.\nabcd\n" {
161		t.Errorf("Unexpected string. Got: %s", buffer.String())
162	}
163}
164
165func TestCalculateAndroidWrapperPath(t *testing.T) {
166	t.Parallel()
167
168	testCases := []struct {
169		mainBuilderPath string
170		absWrapperPath  string
171		want            string
172	}{
173		{
174			mainBuilderPath: "/foo/bar",
175			absWrapperPath:  "/bar/baz",
176			want:            "/foo/baz.real",
177		},
178		{
179			mainBuilderPath: "/my_wrapper",
180			absWrapperPath:  "/bar/baz",
181			want:            "/baz.real",
182		},
183		{
184			mainBuilderPath: "no_seps",
185			absWrapperPath:  "/bar/baz",
186			want:            "baz.real",
187		},
188		{
189			mainBuilderPath: "./a_sep",
190			absWrapperPath:  "/bar/baz",
191			want:            "./baz.real",
192		},
193	}
194
195	for _, tc := range testCases {
196		if result := calculateAndroidWrapperPath(tc.mainBuilderPath, tc.absWrapperPath); result != tc.want {
197			t.Errorf("Failed calculating the wrapper path with (%q, %q); got %q, want %q", tc.mainBuilderPath, tc.absWrapperPath, result, tc.want)
198		}
199	}
200}
201