package smplt_test import ( "bytes" "fmt" "go/parser" "go/token" "log" "mime" "os" "os/exec" "path" "sort" "strings" "testing" "time" . "github.com/meatballhat/box-o-sand/gotime/smplt" ) const ( BASIC_RENDERED_TXT_SIMPLATE = ` import ( "time" ) type Dance struct { Who string When time.Time } ctx["D"] = &Dance{ Who: "Everybody", When: time.Now(), } {{.D.Who}} Dance {{.D.When}}! ` BASIC_STATIC_TXT_SIMPLATE = ` Everybody Dance Now! ` BASIC_JSON_SIMPLATE = ` import ( "time" ) type Dance struct { Who string When time.Time } ctx["D"] = &Dance{ Who: "Everybody", When: time.Now(), response.SetBody(ctx["D"]) } ` BASIC_NEGOTIATED_SIMPLATE = ` import ( "time" ) type Dance struct { Who string When time.Time } ctx["D"] = &Dance{ Who: "Everybody", When: time.Now(), } text/plain {{.D.Who}} Dance {{.D.When}}! application/json {"who":"{{.D.Who}}","when":"{{.D.When}}"} ` ) var ( tmpdir = path.Join(os.TempDir(), fmt.Sprintf("smplt_test-%d", time.Now().UTC().UnixNano())) smpltgenDir = path.Join(tmpdir, "src", "smpltgen") testSiteRoot = path.Join(tmpdir, "test-site") goCmd string noCleanup bool testSiteFiles = map[string]string{ "hams/bone/derp": BASIC_NEGOTIATED_SIMPLATE, "shill/cans.txt": BASIC_RENDERED_TXT_SIMPLATE, "hat/v.json": BASIC_JSON_SIMPLATE, "silmarillion.handlebar.mustache.moniker.html": "INVALID AS BUTT", "Big CMS/Owns_UR Contents/flurb.txt": BASIC_STATIC_TXT_SIMPLATE, } ) func init() { err := os.Setenv("GOPATH", strings.Join([]string{tmpdir, os.Getenv("GOPATH")}, ":")) if err != nil { if noCleanup { log.Fatal(err) } else { panic(err) } } cmd, err := exec.LookPath("go") if err != nil { if noCleanup { log.Fatal(err) } else { panic(err) } } goCmdAddr := &goCmd *goCmdAddr = cmd noCleanupAddr := &noCleanup *noCleanupAddr = len(os.Getenv("SMPLT_TEST_NOCLEANUP")) > 0 } func mkTmpDir() { err := os.MkdirAll(smpltgenDir, os.ModeDir|os.ModePerm) if err != nil { panic(err) } } func rmTmpDir() { err := os.RemoveAll(tmpdir) if err != nil { panic(err) } } func mkTestSite() string { mkTmpDir() for filePath, content := range testSiteFiles { fullPath := path.Join(testSiteRoot, filePath) err := os.MkdirAll(path.Dir(fullPath), os.ModeDir|os.ModePerm) if err != nil { panic(err) } f, err := os.Create(fullPath) if err != nil { panic(err) } _, err = f.WriteString(content) if err != nil { panic(err) } err = f.Close() if err != nil { panic(err) } } return testSiteRoot } func writeRenderedTemplate() (string, error) { s := NewSimplateFromString("basic-rendered.txt", BASIC_RENDERED_TXT_SIMPLATE) outfileName := path.Join(smpltgenDir, s.OutputName()) outf, err := os.Create(outfileName) if err != nil { return outfileName, err } s.Execute(outf) err = outf.Close() if err != nil { return outfileName, err } return outfileName, nil } func runGoCommandOnSmpltgen(command string) error { cmd := exec.Command(goCmd, command, "smpltgen") var out bytes.Buffer cmd.Stdout = &out cmd.Stderr = &out err := cmd.Run() if err != nil { return err } if noCleanup { log.Println(out.String()) } return nil } func formatRenderedTemplate() error { return runGoCommandOnSmpltgen("fmt") } func buildRenderedTemplate() error { return runGoCommandOnSmpltgen("install") } func TestSimplateKnowsItsFilename(t *testing.T) { s := NewSimplateFromString("hasty-decisions.txt", "herpherpderpherp") if s.Filename != "hasty-decisions.txt" { t.Errorf("Simplate filename incorrectly assigned as %s instead of %s", s.Filename, "hasty-decisions.txt") } } func TestSimplateKnowsItsContentType(t *testing.T) { s := NewSimplateFromString("hasty-decisions.js", "function herp() { return 'derp'; }") expected := mime.TypeByExtension(".js") if s.ContentType != expected { t.Errorf("Simplate content type incorrectly assigned as %s instead of %s", s.ContentType, expected) } } func TestStaticSimplateKnowsItsOutputName(t *testing.T) { s := NewSimplateFromString("nothing.txt", "foo\nham\n") if s.OutputName() != "nothing.txt" { t.Errorf("Static simplate output name is wrong!: %v", s.OutputName()) } } func TestRenderedSimplateKnowsItsOutputName(t *testing.T) { s := NewSimplateFromString("flip/dippy slippy/snork.d/basic-rendered.txt", BASIC_RENDERED_TXT_SIMPLATE) if s.OutputName() != "flip-SLASH-dippy-SPACE-slippy-SLASH-snork-DOT-d-SLASH-basic-rendered-DOT-txt.go" { t.Errorf("Rendered simplate output name is wrong!: %v", s.OutputName()) } } func TestDetectsRenderedSimplate(t *testing.T) { s := NewSimplateFromString("basic-rendered.txt", BASIC_RENDERED_TXT_SIMPLATE) if s.Type != SIMPLATE_TYPE_RENDERED { t.Errorf("Simplate detected as %s instead of %s", s.Type, SIMPLATE_TYPE_RENDERED) } } func TestDetectsStaticSimplate(t *testing.T) { s := NewSimplateFromString("basic-static.txt", BASIC_STATIC_TXT_SIMPLATE) if s.Type != SIMPLATE_TYPE_STATIC { t.Errorf("Simplate detected as %s instead of %s", s.Type, SIMPLATE_TYPE_STATIC) } } func TestDetectsJSONSimplates(t *testing.T) { s := NewSimplateFromString("basic.json", BASIC_JSON_SIMPLATE) if s.Type != SIMPLATE_TYPE_JSON { t.Errorf("Simplate detected as %s instead of %s", s.Type, SIMPLATE_TYPE_JSON) } } func TestDetectsNegotiatedSimplates(t *testing.T) { s := NewSimplateFromString("hork", BASIC_NEGOTIATED_SIMPLATE) if s.Type != SIMPLATE_TYPE_NEGOTIATED { t.Errorf("Simplate detected as %s instead of %s", s.Type, SIMPLATE_TYPE_NEGOTIATED) } } func TestAssignsNoGoPagesToStaticSimplates(t *testing.T) { s := NewSimplateFromString("basic-static.txt", BASIC_STATIC_TXT_SIMPLATE) if s.InitPage != nil { t.Errorf("Static simplate had init page assigned!: %v", s.InitPage) } if len(s.LogicPages) > 0 { t.Errorf("Static simplate had logic pages assigned!: %v", s.LogicPages) } } func TestAssignsAnInitPageToRenderedSimplates(t *testing.T) { s := NewSimplateFromString("basic-rendered.txt", BASIC_RENDERED_TXT_SIMPLATE) if s.InitPage == nil { t.Errorf("Rendered simplate had no init page assigned!: %v", s.InitPage) } } func TestAssignsOneLogicPageToRenderedSimplates(t *testing.T) { s := NewSimplateFromString("basic-rendered.txt", BASIC_RENDERED_TXT_SIMPLATE) if len(s.LogicPages) != 1 { t.Errorf("Rendered simplate unexpected number "+ "of logic pages assigned!: %v", len(s.LogicPages)) } } func TestAssignsOneTemplatePageToRenderedSimplates(t *testing.T) { s := NewSimplateFromString("basic-rendered.txt", BASIC_RENDERED_TXT_SIMPLATE) if s.TemplatePage == nil { t.Errorf("Rendered simplate had no template page assigned!: %v", s.TemplatePage) } } func TestAssignsAnInitPageToJSONSimplates(t *testing.T) { s := NewSimplateFromString("basic.json", BASIC_JSON_SIMPLATE) if s.InitPage == nil { t.Errorf("JSON simplate had no init page assigned!: %v", s.InitPage) } } func TestAssignsOneLogicPageToJSONSimplates(t *testing.T) { s := NewSimplateFromString("basic.json", BASIC_JSON_SIMPLATE) if len(s.LogicPages) != 1 { t.Errorf("Rendered simplate unexpected number "+ "of logic pages assigned!: %v", len(s.LogicPages)) } } func TestAssignsNoTemplatePageToJSONSimplates(t *testing.T) { s := NewSimplateFromString("basic.json", BASIC_JSON_SIMPLATE) if s.TemplatePage != nil { t.Errorf("JSON simplate had a template page assigned!: %v", s.TemplatePage) } } func TestAssignsAnInitPageToNegotiatedSimplates(t *testing.T) { s := NewSimplateFromString("basic-negotiated.txt", BASIC_NEGOTIATED_SIMPLATE) if s.InitPage == nil { t.Errorf("Negotiated simplate had no init page assigned!: %v", s.InitPage) } } func TestAssignsAtLeastOneLogicPageToNegotiatedSimplates(t *testing.T) { s := NewSimplateFromString("basic-negotiated.txt", BASIC_NEGOTIATED_SIMPLATE) if len(s.LogicPages) < 1 { t.Errorf("Negotiated simplate unexpected number "+ "of logic pages assigned!: %v", len(s.LogicPages)) } } func TestAssignsNoTemplatePageToNegotiatedSimplates(t *testing.T) { s := NewSimplateFromString("basic-negotiated.txt", BASIC_NEGOTIATED_SIMPLATE) if s.TemplatePage != nil { t.Errorf("Negotiated simplate had a template page assigned!: %v", s.TemplatePage) } } func TestRenderedSimplateCanExecuteToWriter(t *testing.T) { s := NewSimplateFromString("basic-rendered.txt", BASIC_RENDERED_TXT_SIMPLATE) var out bytes.Buffer err := s.Execute(&out) if err != nil { t.Error(err) } } func TestRenderedSimplateOutputIsValidGoSource(t *testing.T) { mkTmpDir() if noCleanup { fmt.Println("tmpdir =", tmpdir) } else { defer rmTmpDir() } outfileName, err := writeRenderedTemplate() if err != nil { t.Error(err) return } fset := token.NewFileSet() _, err = parser.ParseFile(fset, outfileName, nil, parser.DeclarationErrors) if err != nil { t.Error(err) return } } func TestRenderedSimplateCanBeCompiled(t *testing.T) { mkTmpDir() if noCleanup { fmt.Println("tmpdir =", tmpdir) } else { defer rmTmpDir() } _, err := writeRenderedTemplate() if err != nil { t.Error(err) return } err = formatRenderedTemplate() if err != nil { t.Error(err) return } err = buildRenderedTemplate() if err != nil { t.Error(err) return } } func TestTreeWalkerRequiresValidDirectoryRoot(t *testing.T) { _, err := NewTreeWalker("/dev/null") if err == nil { t.Errorf("New tree walker failed to reject invalid dir!") return } } func TestTreeWalkerYieldsSimplates(t *testing.T) { siteRoot := mkTestSite() if noCleanup { fmt.Println("tmpdir =", tmpdir) } else { defer rmTmpDir() } tw, err := NewTreeWalker(siteRoot) if err != nil { t.Error(err) return } n := 0 simplates, err := tw.Simplates() if err != nil { t.Error(err) } for simplate := range simplates { if sort.SearchStrings(SIMPLATE_TYPES, simplate.Type) < 0 { t.Errorf("Simplate yielded with invalid type: %v", simplate.Type) return } n++ } if n != 5 { t.Errorf("Tree walking yielded unexpected number of files: %v", n) } }