aboutsummaryrefslogtreecommitdiff
path: root/internal/plan/fuzz_test.go
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-09-14 23:45:23 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-09-14 23:45:23 +0200
commit97c8164bc81e0a438dab92d7244485005dac4ff2 (patch)
tree08d657f8b92a6539259b6aa8f08b0e9ef8cc6710 /internal/plan/fuzz_test.go
parent166565025832c8a8faf7397766aeaa878980dd2d (diff)
downloadkrino-97c8164bc81e0a438dab92d7244485005dac4ff2.tar.gz
krino-97c8164bc81e0a438dab92d7244485005dac4ff2.zip
literal braces are text, not placeholders, for containment and walk exclusion
Diffstat (limited to 'internal/plan/fuzz_test.go')
-rw-r--r--internal/plan/fuzz_test.go37
1 files changed, 26 insertions, 11 deletions
diff --git a/internal/plan/fuzz_test.go b/internal/plan/fuzz_test.go
index c7261ec..91a8421 100644
--- a/internal/plan/fuzz_test.go
+++ b/internal/plan/fuzz_test.go
@@ -56,7 +56,7 @@ func FuzzExpand(f *testing.F) {
if got == "" {
continue
}
- if base := textDir(dest, "/r", xdg.Home()); !underDir(got, base) {
+ if base, templated := textDir(dest, "/r", xdg.Home()); templated && !underDir(got, base) {
t.Fatalf("destination %q planned %q for %q, outside %q, the directory its text names", dest, got, name, base)
}
}
@@ -79,28 +79,43 @@ func plannedDir(dest, name string, captures []string, facts Facts) string {
}
// textDir is the directory a destination's text names before its first
-// '{' (spec 15.1), worked out here by hand rather than by staticDir: the
-// text up to the last '/' before the brace, "~" as the home directory, a
-// relative path under root.
-func textDir(dest, root, home string) string {
- prefix := dest[:strings.IndexByte(dest, '{')]
+// placeholder (spec 15.1), worked out here by hand rather than by staticDir:
+// the text up to the last '/' before the first '{' that is not "{{", with
+// "{{" and "}}" read as braces, "~" as the home directory, a relative path
+// under root. templated is false when dest has no placeholder, only literal
+// braces: then a ".." in it is the rule's own.
+func textDir(dest, root, home string) (dir string, templated bool) {
+ open := 0
+ for {
+ j := strings.IndexByte(dest[open:], '{')
+ if j < 0 {
+ return "", false
+ }
+ if open+j+1 < len(dest) && dest[open+j+1] == '{' {
+ open += j + 2
+ continue
+ }
+ open += j
+ break
+ }
+ prefix := strings.NewReplacer("{{", "{", "}}", "}").Replace(dest[:open])
switch cut := strings.LastIndexByte(prefix, '/'); {
case cut < 0:
prefix = ""
case cut == 0:
- return "/"
+ return "/", true
default:
prefix = prefix[:cut]
}
switch {
case prefix == "~":
- return home
+ return home, true
case strings.HasPrefix(prefix, "~/"):
- return path.Join(home, prefix[2:])
+ return path.Join(home, prefix[2:]), true
case strings.HasPrefix(prefix, "/"):
- return path.Clean(prefix)
+ return path.Clean(prefix), true
}
- return path.Join(root, prefix)
+ return path.Join(root, prefix), true
}
// underDir reports whether path is dir or lies under it, by whole segments.