| 45 | } |
| 46 | |
| 47 | func (s *ModulesSuite) TestValidateBadName(c *C) { |
| 48 | input := []string{ |
| 49 | // Plain shapes the parser must reject regardless of OS. |
| 50 | "", |
| 51 | ".", |
| 52 | "..", |
| 53 | "../x", |
| 54 | "a/../../b", |
| 55 | "/abs", |
| 56 | `C:\win`, |
| 57 | "x\x00y", |
| 58 | "x/", |
| 59 | "/x", |
| 60 | `.\..\foo`, |
| 61 | "modules/../escape", |
| 62 | |
| 63 | // HFS+ ignores certain Unicode code points during path |
| 64 | // normalisation, so these all resolve to ".." on macOS. |
| 65 | ".\u200c.", // ZWNJ between dots |
| 66 | "\u200c..", // leading ZWNJ |
| 67 | "..\u200c", // trailing ZWNJ |
| 68 | "\u200c.\u200d.\u200e", // ZWNJ + ZWJ + LRM |
| 69 | "a/.\u200c./b", // hidden ".." mid-path |
| 70 | |
| 71 | // NTFS strips trailing spaces, dots, and an alternate-data |
| 72 | // -stream suffix during canonicalisation, so these all |
| 73 | // resolve to ".." on Windows. |
| 74 | ".. ", |
| 75 | ".. ", |
| 76 | "....", |
| 77 | ".. .", |
| 78 | "..::$INDEX_ALLOCATION", |
| 79 | "..:foo", |
| 80 | "a/.. /b", |
| 81 | } |
| 82 | for _, n := range input { |
| 83 | m := &Submodule{ |
| 84 | Name: n, |
| 85 | Path: "ok", |
| 86 | URL: "https://example.com/", |
| 87 | } |
| 88 | // Validate wraps the sentinel with the offending name |
| 89 | // (canonical-Git wording: "ignoring suspicious submodule |
| 90 | // name: <name>"), so use errors.Is. |
| 91 | c.Assert(errors.Is(m.Validate(), ErrModuleBadName), Equals, true, |
| 92 | Commentf("name %q", n)) |
| 93 | } |
| 94 | } |
| 95 | |
| 96 | func (s *ModulesSuite) TestValidateGoodName(c *C) { |
| 97 | for _, n := range []string{"foo", "lib-foo", "deps/x", "x.y"} { |