diff options
| author | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-09-14 21:24:22 +0200 |
|---|---|---|
| committer | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-09-14 21:24:22 +0200 |
| commit | 8c6afca96a9f0af41c5a9d05beb7f1dedb994740 (patch) | |
| tree | 8ad65b02ced85ac1cecf6fdaf53269a602cb1666 /internal/plan/hostile_test.go | |
| parent | a92ce86c0dff7ce8f1de4113f20edd76c249371e (diff) | |
| download | krino-8c6afca96a9f0af41c5a9d05beb7f1dedb994740.tar.gz krino-8c6afca96a9f0af41c5a9d05beb7f1dedb994740.zip | |
plan 9: placeholders stay inside the directory the rule names
Diffstat (limited to 'internal/plan/hostile_test.go')
| -rw-r--r-- | internal/plan/hostile_test.go | 38 |
1 files changed, 37 insertions, 1 deletions
diff --git a/internal/plan/hostile_test.go b/internal/plan/hostile_test.go index c22fb24..a2f2bfe 100644 --- a/internal/plan/hostile_test.go +++ b/internal/plan/hostile_test.go @@ -39,7 +39,7 @@ func TestBuildRefusesDotDotFromPlaceholder(t *testing.T) { }} return Build("/r", in, time.Now(), NoDisk{}, NewClaims())[0].Steps[0] } - if s := step("/w/{1}/in"); s.Skip != `destination "/w/../in" leaves its directory through a placeholder` { + if s := step("/w/{1}/in"); s.Skip != `destination "/w/../in" leaves /w through a placeholder` { t.Errorf("placeholder ..: Skip = %q, Dst = %q", s.Skip, s.Dst) } if s := step("/w/../in"); s.Skip != "" || s.Dst != "/in/x.pdf" { @@ -49,3 +49,39 @@ func TestBuildRefusesDotDotFromPlaceholder(t *testing.T) { t.Errorf("..x: Skip = %q, Dst = %q", s.Skip, s.Dst) } } + +// TestBuildKeepsPlaceholdersInsideTheirDirectory: a capture of "~", an +// empty capture, or an extension-less {ext} at the start of a destination +// used to make it $HOME or absolute (review M1). The resolved destination +// must stay under the directory the rule's text names before its first +// placeholder; a destination with no placeholder is the rule's own +// business. +func TestBuildKeepsPlaceholdersInsideTheirDirectory(t *testing.T) { + t.Setenv("HOME", "/home/x") + step := func(name, dest string, caps ...string) Step { + in := []Input{{File: file("/r", name), Rules: []RuleMatch{{Name: "a", Captures: caps, Actions: []config.Action{act(config.Move, dest)}}}}} + return Build("/r", in, time.Now(), NoDisk{}, NewClaims())[0].Steps[0] + } + for _, tc := range []struct { + name, dest string + caps []string + skip bool + dst string + }{ + {"~_i.pdf", "{1}/Filed", []string{"~_", "~"}, true, ""}, + {"_i.pdf", "{1}/Filed", []string{"_", ""}, true, ""}, + {"README", "{ext}/tmp", nil, true, ""}, + {"a.pdf", "Out/{1}", []string{"a", "~"}, false, "/r/Out/~/a.pdf"}, + {"a.pdf", "~/docs/{1}", []string{"a", "x"}, false, "/home/x/docs/x/a.pdf"}, + {"a.pdf", "~/docs/{1}", []string{"a", ".."}, true, ""}, + {"a.pdf", "Work/Ac{1}", []string{"a", "me"}, false, "/r/Work/Acme/a.pdf"}, + {"a.pdf", "/w/{1}/in", []string{"a", ".."}, true, ""}, + {"a.pdf", "/w/../in", nil, false, "/in/a.pdf"}, + {"a.pdf", "{mtime:%Y}", nil, false, "/r/2026/a.pdf"}, + } { + s := step(tc.name, tc.dest, tc.caps...) + if tc.skip != (s.Skip != "") || (!tc.skip && s.Dst != tc.dst) { + t.Errorf("%s -> %s %q: Skip %q Dst %q; want skip=%v dst=%q", tc.name, tc.dest, tc.caps, s.Skip, s.Dst, tc.skip, tc.dst) + } + } +} |
