golang.org/x/playground@v0.0.0-20230418134305-14ebe15bcd59/txtar_test.go (about) 1 // Copyright 2019 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "fmt" 9 "reflect" 10 "strings" 11 "testing" 12 ) 13 14 func newFileSet(kv ...string) *fileSet { 15 fs := new(fileSet) 16 if kv[0] == "prog.go!implicit" { 17 fs.noHeader = true 18 kv[0] = "prog.go" 19 } 20 for len(kv) > 0 { 21 fs.AddFile(kv[0], []byte(kv[1])) 22 kv = kv[2:] 23 } 24 return fs 25 } 26 27 func TestSplitFiles(t *testing.T) { 28 for _, tt := range []struct { 29 name string 30 in string 31 want *fileSet 32 wantErr string 33 }{ 34 { 35 name: "classic", 36 in: "package main", 37 want: newFileSet("prog.go!implicit", "package main\n"), 38 }, 39 { 40 name: "implicit prog.go", 41 in: "package main\n-- two.go --\nsecond", 42 want: newFileSet( 43 "prog.go!implicit", "package main\n", 44 "two.go", "second\n", 45 ), 46 }, 47 { 48 name: "basic txtar", 49 in: "-- main.go --\npackage main\n-- foo.go --\npackage main\n", 50 want: newFileSet( 51 "main.go", "package main\n", 52 "foo.go", "package main\n", 53 ), 54 }, 55 { 56 name: "reject dotdot 1", 57 in: "-- ../foo --\n", 58 wantErr: `invalid file name "../foo"`, 59 }, 60 { 61 name: "reject dotdot 2", 62 in: "-- .. --\n", 63 wantErr: `invalid file name ".."`, 64 }, 65 { 66 name: "reject dotdot 3", 67 in: "-- bar/../foo --\n", 68 wantErr: `invalid file name "bar/../foo"`, 69 }, 70 { 71 name: "reject long", 72 in: "-- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx --\n", 73 wantErr: `file name too long`, 74 }, 75 { 76 name: "reject deep", 77 in: "-- x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x --\n", 78 wantErr: `file name "x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x/x" too deep`, 79 }, 80 { 81 name: "reject abs", 82 in: "-- /etc/passwd --\n", 83 wantErr: `invalid file name "/etc/passwd"`, 84 }, 85 { 86 name: "reject backslash", 87 in: "-- foo\\bar --\n", 88 wantErr: `invalid file name "foo\\bar"`, 89 }, 90 { 91 name: "reject binary null", 92 in: "-- foo\x00bar --\n", 93 wantErr: `invalid file name "foo\x00bar"`, 94 }, 95 { 96 name: "reject binary low", 97 in: "-- foo\x1fbar --\n", 98 wantErr: `invalid file name "foo\x1fbar"`, 99 }, 100 { 101 name: "reject dup", 102 in: "-- foo.go --\n-- foo.go --\n", 103 wantErr: `duplicate file name "foo.go"`, 104 }, 105 { 106 name: "reject implicit dup", 107 in: "package main\n-- prog.go --\n", 108 wantErr: `duplicate file name "prog.go"`, 109 }, 110 { 111 name: "skip leading whitespace comment", 112 in: "\n \n\n \n\n-- f.go --\ncontents", 113 want: newFileSet("f.go", "contents\n"), 114 }, 115 { 116 name: "reject many files", 117 in: strings.Repeat("-- x.go --\n", 50), 118 wantErr: `too many files in txtar archive (50 exceeds limit of 20)`, 119 }, 120 } { 121 got, err := splitFiles([]byte(tt.in)) 122 var gotErr string 123 if err != nil { 124 gotErr = err.Error() 125 } 126 if gotErr != tt.wantErr { 127 if tt.wantErr == "" { 128 t.Errorf("%s: unexpected error: %v", tt.name, err) 129 continue 130 } 131 t.Errorf("%s: error = %#q; want error %#q", tt.name, err, tt.wantErr) 132 continue 133 } 134 if err != nil { 135 continue 136 } 137 if !reflect.DeepEqual(got, tt.want) { 138 t.Errorf("%s: wrong files\n got:\n%s\nwant:\n%s", tt.name, filesAsString(got), filesAsString(tt.want)) 139 } 140 } 141 } 142 143 func filesAsString(fs *fileSet) string { 144 var sb strings.Builder 145 for i, f := range fs.files { 146 var implicit string 147 if i == 0 && f == progName && fs.noHeader { 148 implicit = " (implicit)" 149 } 150 fmt.Fprintf(&sb, "[file %q%s]: %q\n", f, implicit, fs.Data(f)) 151 } 152 return sb.String() 153 }