github.com/vugu/vugu@v0.3.6-0.20240430171613-3f6f402e014b/gen/parser-go-pkg_test.go (about) 1 package gen 2 3 import ( 4 "bytes" 5 "os" 6 "os/exec" 7 "path/filepath" 8 "regexp" 9 "testing" 10 11 "github.com/stretchr/testify/assert" 12 ) 13 14 func TestSimpleParseGoPkgRun(t *testing.T) { 15 16 assert := assert.New(t) 17 18 tmpDir, err := os.MkdirTemp("", "TestParseGoPkgRun") 19 if err != nil { 20 t.Fatal(err) 21 } 22 defer os.RemoveAll(tmpDir) 23 24 // assert.NoError(os.WriteFile(filepath.Join(tmpDir, "go.mod"), []byte(` 25 // module main 26 // `), 0644)) 27 28 assert.NoError(os.WriteFile(filepath.Join(tmpDir, "root.vugu"), []byte(` 29 <div id="root_comp"> 30 <h1>Hello!</h1> 31 </div> 32 `), 0644)) 33 34 p := NewParserGoPkg(tmpDir, nil) 35 36 assert.NoError(p.Run()) 37 38 b, err := os.ReadFile(filepath.Join(tmpDir, "root_gen.go")) 39 assert.NoError(err) 40 // t.Logf("OUT FILE root_gen.go: %s", b) 41 // log.Printf("OUT FILE root_gen.go: %s", b) 42 43 if !bytes.Contains(b, []byte(`func (c *Root) Build`)) { 44 t.Errorf("failed to find Build method signature") 45 } 46 47 b, err = os.ReadFile(filepath.Join(tmpDir, "0_missing_gen.go")) 48 assert.NoError(err) 49 50 if !bytes.Contains(b, []byte(`type Root struct`)) { 51 t.Errorf("failed to find Root struct definition") 52 } 53 54 } 55 56 func TestRun(t *testing.T) { 57 58 debug := false 59 60 pwd, err := filepath.Abs("..") 61 if err != nil { 62 t.Fatal(err) 63 } 64 65 type tcase struct { 66 name string 67 opts ParserGoPkgOpts 68 recursive bool 69 infiles map[string]string // file structure to start with 70 out map[string][]string // regexps to match in output files 71 afterRun func(dir string, t *testing.T) // called after Run 72 bfiles map[string]string // additional files to write before building 73 build string // "wasm", "default", "none" 74 } 75 76 tcList := []tcase{ 77 { 78 name: "simple", 79 opts: ParserGoPkgOpts{}, 80 recursive: false, 81 infiles: map[string]string{ 82 "root.vugu": `<div>root here</div>`, 83 "go.mod": "module testcase\nreplace github.com/vugu/vugu => " + pwd + "\n", 84 "main.go": "package main\nfunc main(){}", 85 }, 86 out: map[string][]string{ 87 "root_gen.go": {`func \(c \*Root\) Build`}, 88 "0_missing_gen.go": {`type Root struct`}, 89 }, 90 build: "default", 91 }, 92 { 93 name: "simple-wasm", 94 opts: ParserGoPkgOpts{}, 95 recursive: false, 96 infiles: map[string]string{ 97 "root.vugu": `<div>root here</div>`, 98 "go.mod": "module testcase\nreplace github.com/vugu/vugu => " + pwd + "\n", 99 }, 100 out: map[string][]string{ 101 "root_gen.go": {`func \(c \*Root\) Build`}, 102 "0_missing_gen.go": {`type Root struct`}, 103 }, 104 build: "wasm", 105 }, 106 { 107 name: "recursive", 108 opts: ParserGoPkgOpts{}, 109 recursive: true, 110 infiles: map[string]string{ 111 "root.vugu": `<div>root here</div>`, 112 "go.mod": "module testcase\nreplace github.com/vugu/vugu => " + pwd + "\n", 113 "main.go": "package main\nfunc main(){}", 114 "subdir1/example.vugu": "<div>Example Here</div>", 115 }, 116 out: map[string][]string{ 117 "root_gen.go": {`func \(c \*Root\) Build`, `root here`}, 118 "0_missing_gen.go": {`type Root struct`}, 119 "subdir1/example_gen.go": {`Example Here`}, 120 }, 121 build: "default", 122 }, 123 { 124 name: "recursive-single", 125 opts: ParserGoPkgOpts{MergeSingle: true}, 126 recursive: true, 127 infiles: map[string]string{ 128 "root.vugu": `<div>root here</div>`, 129 "go.mod": "module testcase\nreplace github.com/vugu/vugu => " + pwd + "\n", 130 "main.go": "package main\nfunc main(){}", 131 "subdir1/example.vugu": "<div>Example Here</div>", 132 }, 133 out: map[string][]string{ 134 "0_components_gen.go": {`func \(c \*Root\) Build`, `type Root struct`}, 135 "subdir1/0_components_gen.go": {`Example Here`}, 136 "root.vugu": {`root here`}, // make sure vugu files didn't get nuked 137 "subdir1/example.vugu": {`Example Here`}, 138 }, 139 afterRun: func(dir string, t *testing.T) { 140 noFile(filepath.Join(dir, "subdir1/example_gen.go"), t) 141 }, 142 build: "default", 143 }, 144 { 145 name: "events", 146 opts: ParserGoPkgOpts{}, 147 recursive: false, 148 infiles: map[string]string{ 149 "root.vugu": `<div>root here</div>`, 150 "go.mod": "module testcase\nreplace github.com/vugu/vugu => " + pwd + "\n", 151 "main.go": "package main\nfunc main(){}\n\n//vugugen:event Sample\n", 152 }, 153 out: map[string][]string{ 154 "root_gen.go": {`func \(c \*Root\) Build`}, 155 "0_missing_gen.go": {`type Root struct`, `SampleEvent`, `SampleHandler`, `SampleFunc`}, 156 }, 157 build: "default", 158 }, 159 } 160 161 for _, tc := range tcList { 162 tc := tc 163 t.Run(tc.name, func(t *testing.T) { 164 165 tmpDir, err := os.MkdirTemp("", "TestRun") 166 if err != nil { 167 t.Fatal(err) 168 } 169 170 if debug { 171 t.Logf("Test %q using tmpDir: %s", tc.name, tmpDir) 172 } else { 173 t.Parallel() 174 } 175 176 tstWriteFiles(tmpDir, tc.infiles) 177 178 if tc.recursive { 179 err = RunRecursive(tmpDir, &tc.opts) 180 } else { 181 err = Run(tmpDir, &tc.opts) 182 } 183 if err != nil { 184 t.Fatal(err) 185 } 186 187 for fname, patterns := range tc.out { 188 b, err := os.ReadFile(filepath.Join(tmpDir, fname)) 189 if err != nil { 190 t.Errorf("failed to read file %q after Run: %v", fname, err) 191 continue 192 } 193 for _, pattern := range patterns { 194 re := regexp.MustCompile(pattern) 195 if !re.Match(b) { 196 t.Errorf("failed to match regexp on file %q: %s", fname, pattern) 197 } 198 } 199 } 200 201 if tc.afterRun != nil { 202 tc.afterRun(tmpDir, t) 203 } 204 205 tstWriteFiles(tmpDir, tc.bfiles) 206 207 cmd := exec.Command("go", "mod", "tidy") 208 cmd.Dir = tmpDir 209 b, err := cmd.CombinedOutput() 210 if err != nil { 211 t.Fatalf("go mod tidy error: %s; OUTPUT:\n%s", err, b) 212 } 213 214 switch tc.build { 215 216 case "wasm": 217 cmd := exec.Command("go", "build", "-o", "main.wasm", ".") 218 cmd.Dir = tmpDir 219 cmd.Env = os.Environ() // needed? 220 cmd.Env = append(cmd.Env, "GOOS=js", "GOARCH=wasm") 221 b, err := cmd.CombinedOutput() 222 if err != nil { 223 t.Fatalf("build error: %s; OUTPUT:\n%s", err, b) 224 } 225 226 case "default": 227 cmd := exec.Command("go", "build", "-o", "main.out", ".") 228 cmd.Dir = tmpDir 229 b, err := cmd.CombinedOutput() 230 if err != nil { 231 t.Fatalf("build error: %s; OUTPUT:\n%s", err, b) 232 } 233 234 cmd = exec.Command(filepath.Join(tmpDir, "main.out")) 235 cmd.Dir = tmpDir 236 b, err = cmd.CombinedOutput() 237 if err != nil { 238 t.Fatalf("run error: %s; OUTPUT:\n%s", err, b) 239 } 240 241 case "none": 242 243 default: 244 t.Errorf("unknown build value %q", tc.build) 245 } 246 247 // only if everthing is golden do we remove 248 if !t.Failed() { 249 os.RemoveAll(tmpDir) 250 } 251 252 }) 253 } 254 255 } 256 257 func noFile(p string, t *testing.T) { 258 _, err := os.Stat(p) 259 if err == nil { 260 t.Errorf("file %q should not exist but does", p) 261 } 262 } 263 264 func tstWriteFiles(dir string, m map[string]string) { 265 266 for name, contents := range m { 267 p := filepath.Join(dir, name) 268 err := os.MkdirAll(filepath.Dir(p), 0755) 269 if err != nil { 270 panic(err) 271 } 272 err = os.WriteFile(p, []byte(contents), 0644) 273 if err != nil { 274 panic(err) 275 } 276 } 277 278 }