package source import ( "bytes" "io" "testing" "tsne.dev/hopper/internal/log" ) func TestCleanArchivePath(t *testing.T) { tests := []struct { raw string want string wantErr bool warn bool }{ {"a/b.js", "a/b.js", false, false}, {"./a//b.js", "a/b.js", false, false}, {"/abs/x", "", true, false}, {"../escape", "", true, false}, {"a/../../escape", "", true, false}, {"a/../b.js", "b.js", false, true}, // contained .. but stays in root } for _, tt := range tests { var warn bytes.Buffer log.Init(io.Discard, &warn) got, err := cleanArchivePath(tt.raw) if tt.wantErr { if err == nil { t.Errorf("%q: expected error", tt.raw) } continue } if err != nil { t.Errorf("%q: unexpected error %v", tt.raw, err) continue } if got != tt.want { t.Errorf("%q: got %q want %q", tt.raw, got, tt.want) } if tt.warn && warn.Len() == 0 { t.Errorf("%q: expected warning", tt.raw) } if !tt.warn && warn.Len() != 0 { t.Errorf("%q: unexpected warning %q", tt.raw, warn.String()) } } } func TestSelectPath(t *testing.T) { tests := []struct { cleaned string root string want string wantOK bool }{ {"assets/x.js", "", "assets/x.js", true}, {"README.md", "", "README.md", true}, {"app/assets/x.js", "app", "assets/x.js", true}, {"README.md", "app", "", false}, {"app", "app", "", false}, {"appendix/x", "app", "", false}, {"dist/public/index.html", "dist/public", "index.html", true}, {"dist/private/x", "dist/public", "", false}, } for _, tt := range tests { s := &TarGzSource{root: tt.root} got, ok := s.selectPath(tt.cleaned) if ok != tt.wantOK { t.Errorf("selectPath(%q, %q): ok = %v, want %v", tt.cleaned, tt.root, ok, tt.wantOK) continue } if ok && got != tt.want { t.Errorf("selectPath(%q, %q) = %q, want %q", tt.cleaned, tt.root, got, tt.want) } } } func TestContainsDotDot(t *testing.T) { cases := map[string]bool{ "a/b/c": false, "..": true, "../x": true, "a/../b": true, "a/..b/c": false, "": false, "a/b/..": true, } for in, want := range cases { if got := containsDotDot(in); got != want { t.Errorf("containsDotDot(%q) = %v, want %v", in, got, want) } } }