xref: /aosp_15_r20/external/bazel-skylib/tests/directory/glob_test.bzl (revision bcb5dc7965af6ee42bf2f21341a2ec00233a8c8a)
1# Copyright 2024 The Bazel Authors. All rights reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#    http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15"""Unit tests for the directory_glob rule."""
16
17load("@bazel_skylib//rules/directory:glob.bzl", "directory_glob")
18load("@bazel_skylib//rules/directory:providers.bzl", "DirectoryInfo")
19
20# buildifier: disable=bzl-visibility
21load("@bazel_skylib//rules/directory/private:glob.bzl", "directory_glob_chunk", "transitive_entries")
22load("@rules_testing//lib:analysis_test.bzl", "analysis_test", "test_suite")
23load("@rules_testing//lib:truth.bzl", "matching")
24load(":utils.bzl", "failure_matching", "failure_test")
25
26def _expect_glob_chunk(env, directory, chunk):
27    return env.expect.that_collection(
28        directory_glob_chunk(directory, chunk),
29        expr = "directory_glob_chunk({}, {})".format(directory.human_readable, repr(chunk)),
30    )
31
32def _expect_glob(env, directory, include, allow_empty = False):
33    return env.expect.that_collection(
34        directory.glob(include, allow_empty = allow_empty),
35        expr = "directory_glob({}, {}, allow_empty={})".format(directory.human_readable, include, allow_empty),
36    )
37
38def _with_children(children):
39    return DirectoryInfo(
40        entries = {k: k for k in children},
41        human_readable = repr(children),
42    )
43
44def _glob_test(name):
45    simple_name = "_simple_%s" % name
46    exclude_name = "_exclude_%s" % name
47    directory_glob(
48        name = simple_name,
49        srcs = ["testdata/f1"],
50        data = ["testdata/subdir/f2"],
51        directory = ":root",
52    )
53
54    directory_glob(
55        name = exclude_name,
56        srcs = [
57            "testdata/f1",
58            "nonexistent",
59        ],
60        allow_empty = True,
61        data = ["**"],
62        directory = ":root",
63        exclude = ["testdata/f1"],
64    )
65
66    analysis_test(
67        name = name,
68        impl = _glob_test_impl,
69        targets = {
70            "root": ":root",
71            "f1": ":f1_filegroup",
72            "f2": ":f2_filegroup",
73            "simple_glob": simple_name,
74            "glob_with_exclude": exclude_name,
75        },
76    )
77
78def _glob_test_impl(env, targets):
79    f1 = targets.f1.files.to_list()[0]
80    f2 = targets.f2.files.to_list()[0]
81    root = targets.root[DirectoryInfo]
82    testdata = root.entries["testdata"]
83    subdir = testdata.entries["subdir"]
84
85    env.expect.that_collection(transitive_entries(root)).contains_exactly([
86        root,
87        testdata,
88        subdir,
89        f1,
90        f2,
91    ])
92
93    _expect_glob_chunk(env, testdata, "f1").contains_exactly([f1])
94    _expect_glob_chunk(env, root, "nonexistent").contains_exactly([])
95    _expect_glob_chunk(env, testdata, "f2").contains_exactly([])
96    _expect_glob_chunk(env, root, "testdata").contains_exactly([testdata])
97    _expect_glob_chunk(env, testdata, "*").contains_exactly(
98        [f1, subdir],
99    )
100    _expect_glob_chunk(
101        env,
102        _with_children(["a", "d", "abc", "abbc", "ab.bc", ".abbc", "abbc."]),
103        "ab*bc",
104    ).contains_exactly([
105        "abbc",
106        "ab.bc",
107    ])
108    _expect_glob_chunk(
109        env,
110        _with_children(["abbc", "abbbc", "ab.b.bc"]),
111        "ab*b*bc",
112    ).contains_exactly([
113        "abbbc",
114        "ab.b.bc",
115    ])
116    _expect_glob_chunk(
117        env,
118        _with_children(["a", "ab", "ba"]),
119        "a*",
120    ).contains_exactly([
121        "a",
122        "ab",
123    ])
124    _expect_glob_chunk(
125        env,
126        _with_children(["a", "ab", "a.b.", "ba."]),
127        "a*b*",
128    ).contains_exactly([
129        "ab",
130        "a.b.",
131    ])
132
133    _expect_glob(env, root, ["testdata/f1"]).contains_exactly([f1])
134    _expect_glob(env, root, ["testdata/subdir/f2"]).contains_exactly([f2])
135    _expect_glob(env, root, ["**"]).contains_exactly([f1, f2])
136    _expect_glob(env, root, ["**/f1"]).contains_exactly([f1])
137    _expect_glob(env, root, ["**/**/f1"]).contains_exactly([f1])
138    _expect_glob(env, root, ["testdata/*/f1"], allow_empty = True).contains_exactly([])
139
140    simple_glob = env.expect.that_target(targets.simple_glob)
141    with_exclude = env.expect.that_target(targets.glob_with_exclude)
142
143    env.expect.that_collection(
144        simple_glob.actual[DefaultInfo].files.to_list(),
145        expr = "simple_glob's files",
146    ).contains_exactly([f1])
147    env.expect.that_collection(
148        with_exclude.actual[DefaultInfo].files.to_list(),
149        expr = "with_exclude's files",
150    ).contains_exactly([])
151
152    # target.runfiles().contains_exactly() doesn't do what we want - it converts
153    # it to a string corresponding to the runfiles import path.
154    env.expect.that_collection(
155        simple_glob.runfiles().actual.files.to_list(),
156        expr = "simple_glob's runfiles",
157    ).contains_exactly([f1, f2])
158    env.expect.that_collection(
159        with_exclude.runfiles().actual.files.to_list(),
160        expr = "with_exclude's runfiles",
161    ).contains_exactly([f2])
162
163def _glob_with_no_match_test(name):
164    failure_test(
165        name = name,
166        impl = failure_matching(matching.contains('"nonexistent" failed to match any files in')),
167        rule = directory_glob,
168        srcs = [
169            "testdata/f1",
170            "nonexistent",
171        ],
172        data = ["testdata/f1"],
173        directory = ":root",
174    )
175
176# buildifier: disable=function-docstring
177def glob_test_suite(name):
178    test_suite(
179        name = name,
180        tests = [
181            _glob_test,
182            _glob_with_no_match_test,
183        ],
184    )
185