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