xref: /aosp_15_r20/external/bazelbuild-rules_python/gazelle/python/python_test.go (revision 60517a1edbc8ecf509223e9af94a7adec7d736b8)
1/* Copyright 2020 The Bazel Authors. All rights reserved.
2
3Licensed under the Apache License, Version 2.0 (the "License");
4you may not use this file except in compliance with the License.
5You may obtain a copy of the License at
6
7   http://www.apache.org/licenses/LICENSE-2.0
8
9Unless required by applicable law or agreed to in writing, software
10distributed under the License is distributed on an "AS IS" BASIS,
11WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12See the License for the specific language governing permissions and
13limitations under the License.
14*/
15
16// This test file was first seen on:
17// https://github.com/bazelbuild/bazel-skylib/blob/f80bc733d4b9f83d427ce3442be2e07427b2cc8d/gazelle/bzl/BUILD.
18// It was modified for the needs of this extension.
19
20package python_test
21
22import (
23	"bytes"
24	"context"
25	"errors"
26	"os"
27	"os/exec"
28	"path/filepath"
29	"strings"
30	"testing"
31	"time"
32
33	"github.com/bazelbuild/bazel-gazelle/testtools"
34	"github.com/bazelbuild/rules_go/go/tools/bazel"
35	"github.com/ghodss/yaml"
36)
37
38const (
39	extensionDir      = "python" + string(os.PathSeparator)
40	testDataPath      = extensionDir + "testdata" + string(os.PathSeparator)
41	gazelleBinaryName = "gazelle_binary"
42)
43
44func TestGazelleBinary(t *testing.T) {
45	gazellePath := mustFindGazelle()
46	tests := map[string][]bazel.RunfileEntry{}
47
48	runfiles, err := bazel.ListRunfiles()
49	if err != nil {
50		t.Fatalf("bazel.ListRunfiles() error: %v", err)
51	}
52	for _, f := range runfiles {
53		if strings.HasPrefix(f.ShortPath, testDataPath) {
54			relativePath := strings.TrimPrefix(f.ShortPath, testDataPath)
55			parts := strings.SplitN(relativePath, string(os.PathSeparator), 2)
56			if len(parts) < 2 {
57				// This file is not a part of a testcase since it must be in a dir that
58				// is the test case and then have a path inside of that.
59				continue
60			}
61
62			tests[parts[0]] = append(tests[parts[0]], f)
63		}
64	}
65	if len(tests) == 0 {
66		t.Fatal("no tests found")
67	}
68	for testName, files := range tests {
69		testPath(t, gazellePath, testName, files)
70	}
71}
72
73func testPath(t *testing.T, gazellePath, name string, files []bazel.RunfileEntry) {
74	t.Run(name, func(t *testing.T) {
75		t.Parallel()
76		var inputs, goldens []testtools.FileSpec
77
78		var config *testYAML
79		for _, f := range files {
80			path := f.Path
81			trim := filepath.Join(testDataPath, name) + string(os.PathSeparator)
82			shortPath := strings.TrimPrefix(f.ShortPath, trim)
83			info, err := os.Stat(path)
84			if err != nil {
85				t.Fatalf("os.Stat(%q) error: %v", path, err)
86			}
87
88			if info.IsDir() {
89				continue
90			}
91
92			content, err := os.ReadFile(path)
93			if err != nil {
94				t.Errorf("os.ReadFile(%q) error: %v", path, err)
95			}
96
97			if filepath.Base(shortPath) == "test.yaml" {
98				if config != nil {
99					t.Fatal("only 1 test.yaml is supported")
100				}
101				config = new(testYAML)
102				if err := yaml.Unmarshal(content, config); err != nil {
103					t.Fatal(err)
104				}
105			}
106
107			if strings.HasSuffix(shortPath, ".in") {
108				inputs = append(inputs, testtools.FileSpec{
109					Path:    filepath.Join(name, strings.TrimSuffix(shortPath, ".in")),
110					Content: string(content),
111				})
112				continue
113			}
114
115			if strings.HasSuffix(shortPath, ".out") {
116				goldens = append(goldens, testtools.FileSpec{
117					Path:    filepath.Join(name, strings.TrimSuffix(shortPath, ".out")),
118					Content: string(content),
119				})
120				continue
121			}
122
123			inputs = append(inputs, testtools.FileSpec{
124				Path:    filepath.Join(name, shortPath),
125				Content: string(content),
126			})
127			goldens = append(goldens, testtools.FileSpec{
128				Path:    filepath.Join(name, shortPath),
129				Content: string(content),
130			})
131		}
132
133		testdataDir, cleanup := testtools.CreateFiles(t, inputs)
134		t.Cleanup(cleanup)
135		t.Cleanup(func() {
136			if !t.Failed() {
137				return
138			}
139
140			filepath.Walk(testdataDir, func(path string, info os.FileInfo, err error) error {
141				if err != nil {
142					return err
143				}
144				t.Logf("%q exists", strings.TrimPrefix(path, testdataDir))
145				return nil
146			})
147		})
148
149		workspaceRoot := filepath.Join(testdataDir, name)
150
151		args := []string{"-build_file_name=BUILD,BUILD.bazel"}
152
153		ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
154		t.Cleanup(cancel)
155		cmd := exec.CommandContext(ctx, gazellePath, args...)
156		var stdout, stderr bytes.Buffer
157		cmd.Stdout = &stdout
158		cmd.Stderr = &stderr
159		cmd.Dir = workspaceRoot
160		if err := cmd.Run(); err != nil {
161			var e *exec.ExitError
162			if !errors.As(err, &e) {
163				t.Fatal(err)
164			}
165		}
166
167		actualExitCode := cmd.ProcessState.ExitCode()
168		if config.Expect.ExitCode != actualExitCode {
169			t.Errorf("expected gazelle exit code: %d\ngot: %d",
170				config.Expect.ExitCode, actualExitCode)
171		}
172		actualStdout := stdout.String()
173		if strings.TrimSpace(config.Expect.Stdout) != strings.TrimSpace(actualStdout) {
174			t.Errorf("expected gazelle stdout: %s\ngot: %s",
175				config.Expect.Stdout, actualStdout)
176		}
177		actualStderr := stderr.String()
178		if strings.TrimSpace(config.Expect.Stderr) != strings.TrimSpace(actualStderr) {
179			t.Errorf("expected gazelle stderr: %s\ngot: %s",
180				config.Expect.Stderr, actualStderr)
181		}
182		if t.Failed() {
183			t.FailNow()
184		}
185
186		testtools.CheckFiles(t, testdataDir, goldens)
187	})
188}
189
190func mustFindGazelle() string {
191	gazellePath, ok := bazel.FindBinary(extensionDir, gazelleBinaryName)
192	if !ok {
193		panic("could not find gazelle binary")
194	}
195	return gazellePath
196}
197
198type testYAML struct {
199	Expect struct {
200		ExitCode int    `json:"exit_code"`
201		Stdout   string `json:"stdout"`
202		Stderr   string `json:"stderr"`
203	} `json:"expect"`
204}
205