Skip to content

Commit 32fc574

Browse files
committed
test: 两个键会在同一个包里相遇,而没有任何判据覆盖这件事
## e2e 304:提供层的包同时带私有目录 `openkal-musl` 就是这个形状 —— `provides = ["mcpp:c-abi=musl"]` **加上**内部头 覆盖层。层的目录到达**每一个**单元,所以在这里误发布覆盖层比在别处都宽:musl 的 `hidden`/`weak` 宏不只落到它的消费者,而是落到整个构建的每一个翻译单元。 两者按构造是相容的(目标侧取的是提供者的 `publicUsage`,而那已经是过滤后的集合) —— 「按构造」正是需要一条断言的地方。反向对照实测:把 fixture 里的 `private_include_dirs` 拿掉,判据当场检出 /tmp/.../dep/src/sibling.cppm ← 兄弟依赖包 /tmp/.../src/main.cpp ← 根 也就是把那句「爆炸半径」从注释变成了读数。⭐ 另加控制:提供者自己的单元必须仍然 带着它,否则「没泄漏」和「整个丢掉了」同读数。 ## e2e 305:glob 在展开之后比对 文档承诺「条目支持 `*` glob 并在展开之后比对」,而没有判据。加 `gen/*` 两条边: 提供者两个目录都要有,消费者一个都不能有。⭐ 判据落到 `gen/one`/`gen/two` **按名** 而不是 `gen`—— 只查 `gen` 的话,一个拿未展开拼写去比的实现照样通过。 反向对照实测:把 glob 从 private 列表里拿掉,两条都变红并各自点名。
1 parent ff24a88 commit 32fc574

2 files changed

Lines changed: 73 additions & 8 deletions

File tree

tests/e2e/304_the_target_side_reaches_every_unit.sh

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,20 +35,35 @@ work="$(mktemp -d)"
3535
trap 'rm -rf "$work"' EXIT
3636
cd "$work"
3737

38-
mkdir -p src abi/src abi/abi-include dep/src dep/dep-include
38+
mkdir -p src abi/src abi/abi-include abi/abi-internal dep/src dep/dep-include
3939

40-
# The provider: supplies a target-side layer and publishes one directory.
40+
# The provider: supplies a target-side layer, publishes one directory, and
41+
# keeps one to itself.
42+
#
43+
# ⭐⭐ THE TWO KEYS OF THIS RELEASE MEET IN THIS ONE PACKAGE, AND THAT IS THE
44+
# REAL-WORLD SHAPE. `openkal-musl` declares `provides = ["mcpp:c-abi=musl"]`
45+
# AND carries an internal header overlay. A layer's directories reach EVERY
46+
# unit, so publishing the overlay by mistake would put musl's `hidden`/`weak`
47+
# macros not merely on its consumers but on every translation unit of the
48+
# build — a strictly wider blast radius than the leak `private_include_dirs`
49+
# was written for.
50+
#
51+
# The two compose correctly by construction (the target side is assembled from
52+
# the provider's `publicUsage`, which is the filtered set), and "by
53+
# construction" is what an assertion is for.
4154
cat > abi/mcpp.toml <<'EOF'
4255
[package]
4356
name = "abiprov"
4457
version = "0.1.0"
4558
provides = ["mcpp:c++-abi=libc++"]
4659
4760
[build]
48-
include_dirs = ["abi-include"]
61+
include_dirs = ["abi-internal", "abi-include"]
62+
private_include_dirs = ["abi-internal"]
4963
EOF
5064
printf 'export module abiprov;\nexport int abiprov_v() { return 1; }\n' > abi/src/abiprov.cppm
5165
printf '#pragma once\n' > abi/abi-include/marker.h
66+
printf '#pragma once\n' > abi/abi-internal/private.h
5267

5368
# The sibling: a dependency package that does NOT depend on the provider.
5469
cat > dep/mcpp.toml <<'EOF'
@@ -125,4 +140,36 @@ if [ -n "$leaked" ]; then
125140
exit 1
126141
fi
127142

128-
echo "OK: the graph-supplied target side reaches every unit ($siblings sibling units), and nothing else does"
143+
# ⭐⭐ AND THE LAYER'S *PRIVATE* DIRECTORY REACHES NOBODY BUT ITSELF.
144+
#
145+
# A layer reaches every unit, so publishing an internal overlay by mistake is
146+
# wider here than anywhere else: it would land on every translation unit of the
147+
# build rather than on the provider's consumers.
148+
private_leak="$(jq -r '
149+
[ .[]
150+
| select((.file | test("/abi/src/")) | not)
151+
| { f: .file, has: ((.arguments // (.command | split(" "))) | map(test("abi-internal")) | any) }
152+
| select(.has)
153+
| .f
154+
] | .[]' compile_commands.json)"
155+
156+
if [ -n "$private_leak" ]; then
157+
echo "FAIL: the layer's PRIVATE directory reached units outside the package:"
158+
printf '%s\n' "$private_leak" | sed 's/^/ /'
159+
exit 1
160+
fi
161+
162+
# The control: private is not the same as dropped. The provider's own units
163+
# must still be built with it, or the assertion above passes for a build that
164+
# simply lost the directory.
165+
own_private="$(jq -r '
166+
[ .[]
167+
| select(.file | test("/abi/src/"))
168+
| select((.arguments // (.command | split(" "))) | map(test("abi-internal")) | any)
169+
] | length' compile_commands.json)"
170+
if [ "$own_private" -lt 1 ]; then
171+
echo "FAIL: the provider lost its own private directory — the check above proves nothing"
172+
exit 1
173+
fi
174+
175+
echo "OK: the graph-supplied target side reaches every unit ($siblings sibling units), its private directory reaches only its own $own_private unit(s), and nothing else spreads"

tests/e2e/305_built_from_is_not_published.sh

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ work="$(mktemp -d)"
3131
trap 'rm -rf "$work"' EXIT
3232
cd "$work"
3333

34-
mkdir -p src lib/src lib/pub lib/internal
34+
mkdir -p src lib/src lib/pub lib/internal lib/gen/one lib/gen/two
3535

3636
cat > lib/mcpp.toml <<'EOF'
3737
[package]
@@ -43,14 +43,21 @@ version = "0.1.0"
4343
# this list rather than a second list: the internal overlay must precede the
4444
# public headers for the package's OWN build, and two TOML arrays cannot
4545
# express one order.
46-
include_dirs = ["internal", "pub"]
47-
private_include_dirs = ["internal"]
46+
#
47+
# ⭐ `gen/*` IS A GLOB ON BOTH LINES. The filter is applied AFTER expansion, so
48+
# the glob withholds exactly the directories it expands to. Comparing the
49+
# unexpanded spellings would be the obvious implementation and would publish
50+
# every one of them, because `gen/*` is not literally equal to `gen/one`.
51+
include_dirs = ["internal", "gen/*", "pub"]
52+
private_include_dirs = ["internal", "gen/*"]
4853
EOF
4954
printf 'export module vendored;\nexport int vendored_v() { return 7; }\n' > lib/src/vendored.cppm
5055
printf '#pragma once\n#define VENDORED_PUBLIC 1\n' > lib/pub/pub.h
5156
# The internal overlay: a macro that is meaningful to the package and a
5257
# perfectly ordinary identifier to everyone else.
5358
printf '#pragma once\n#define hidden __attribute__((visibility("hidden")))\n' > lib/internal/overlay.h
59+
printf '#pragma once\n' > lib/gen/one/one.h
60+
printf '#pragma once\n' > lib/gen/two/two.h
5461

5562
cat > mcpp.toml <<'EOF'
5663
[package]
@@ -107,5 +114,16 @@ fail=0
107114
[ "$(has_dir '/src/main' '/lib/internal')" = false ] || {
108115
echo "FAIL: the private directory leaked to the consumer"; fail=1; }
109116

117+
# ⭐ AND THE GLOB WITHHOLDS WHAT IT EXPANDS TO — both directories, by name.
118+
# Checking `gen` alone would pass for an implementation that matched the
119+
# unexpanded spelling and published `gen/one` and `gen/two` anyway.
120+
for g in one two; do
121+
[ "$(has_dir '/lib/src/' "/lib/gen/$g")" = true ] || {
122+
echo "FAIL: the provider lost 'gen/$g', which its own glob names"; fail=1; }
123+
[ "$(has_dir '/src/main' "/lib/gen/$g")" = false ] || {
124+
echo "FAIL: 'gen/$g' leaked to the consumer — the glob was compared unexpanded"
125+
fail=1; }
126+
done
127+
110128
[ "$fail" = 0 ] || exit 1
111-
echo "OK: built-from and published are separable (provider=$prov consumer=$cons rows)"
129+
echo "OK: built-from and published are separable, globs included (provider=$prov consumer=$cons rows)"

0 commit comments

Comments
 (0)