(t *testing.T)
| 7 | ) |
| 8 | |
| 9 | func TestValidTreePath(t *testing.T) { |
| 10 | t.Parallel() |
| 11 | |
| 12 | tests := []struct { |
| 13 | name string |
| 14 | path string |
| 15 | wantErr bool |
| 16 | }{ |
| 17 | // Strict positional rejection at every component. |
| 18 | {"reject submodule/.git", "submodule/.git", true}, |
| 19 | {"reject a/.git", "a/.git", true}, |
| 20 | {"reject a\\.git", "a\\.git", true}, |
| 21 | {"reject root .git", ".git", true}, |
| 22 | {"reject .git/config", ".git/config", true}, |
| 23 | {"reject a/.git/b", "a/.git/b", true}, |
| 24 | {"reject git~1", "git~1", true}, |
| 25 | {"reject sub/git~1/HEAD", "sub/git~1/HEAD", true}, |
| 26 | {"reject ..", "a/../b", true}, |
| 27 | {"reject .", ".", true}, |
| 28 | {"reject empty", "", true}, |
| 29 | {"reject control char SOH", "a\x01b", true}, |
| 30 | {"reject DEL", "foo\x7fbar", true}, |
| 31 | |
| 32 | // Always-on NTFS .git-disguise variants (no flag gate at this layer). |
| 33 | {"reject .git . trailing", "sub/.git . /x", true}, |
| 34 | {"reject .git:: ADS", ".git::$INDEX_ALLOCATION/x", true}, |
| 35 | {"reject git~1 trailing space", "sub/git~1 /x", true}, |
| 36 | {"reject git~1 trailing dot", "git~1./x", true}, |
| 37 | {"reject git~1:: ADS", "git~1::$INDEX_ALLOCATION/x", true}, |
| 38 | |
| 39 | // Always-on HFS+ variants. |
| 40 | {"reject .g\u200cit zwnj", ".g\u200cit/x", true}, |
| 41 | {"reject sub/.g\u200cit zwnj", "sub/.g\u200cit/x", true}, |
| 42 | |
| 43 | // Legitimate paths pass. |
| 44 | {"allow readme.md", "readme.md", false}, |
| 45 | {"allow src/main.go", "src/main.go", false}, |
| 46 | {"allow .gitmodules", ".gitmodules", false}, |
| 47 | {"allow .gitignore", ".gitignore", false}, |
| 48 | {"allow nested .gitignore", "vendor/.gitignore", false}, |
| 49 | {"allow a..b", "a..b", false}, |
| 50 | {"allow submodule directory entry", "submodule", false}, |
| 51 | {"allow nested submodule directory", "vendor/sub", false}, |
| 52 | {"allow Çircle/file high-codepoint", "Çircle/file", false}, |
| 53 | // Windows reserved device names are not policed at this layer: |
| 54 | // they are legitimate on non-Windows and upstream Git accepts |
| 55 | // them. The wrapper enforces them when core.protectNTFS is on. |
| 56 | {"allow CON file", "CON/file", false}, |
| 57 | {"allow CON.txt", "CON.txt", false}, |
| 58 | {"allow nested NUL", "dir/NUL", false}, |
| 59 | } |
| 60 | |
| 61 | for _, tc := range tests { |
| 62 | t.Run(tc.name, func(t *testing.T) { |
| 63 | t.Parallel() |
| 64 | err := ValidTreePath(tc.path) |
| 65 | if tc.wantErr { |
| 66 | assert.Error(t, err, "ValidTreePath(%q) should return error", tc.path) |
nothing calls this directly
no test coverage detected
searching dependent graphs…