// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. // // This Source Code Form is subject to the terms of the MIT License. // If a copy of the MIT was not distributed with this file, // You can obtain one at https://github.com/gogf/gf. package gview_test import ( "context" "github.com/gogf/gf/encoding/ghtml" "github.com/gogf/gf/os/gtime" "github.com/gogf/gf/util/gconv" "io/ioutil" "os" "strings" "testing" "time" "github.com/gogf/gf/frame/g" "github.com/gogf/gf/os/gfile" "github.com/gogf/gf/os/gview" "github.com/gogf/gf/test/gtest" "github.com/gogf/gf/text/gstr" ) func init() { os.Setenv("GF_GVIEW_ERRORPRINT", "false") } func Test_Basic(t *testing.T) { gtest.C(t, func(t *gtest.T) { str := `hello {{.name}},version:{{.version}};hello {{GetName}},version:{{GetVersion}};{{.other}}` pwd := gfile.Pwd() view := gview.New() view.SetDelimiters("{{", "}}") view.AddPath(pwd) view.SetPath(pwd) view.Assign("name", "gf") view.Assigns(g.Map{"version": "1.7.0"}) view.BindFunc("GetName", func() string { return "gf" }) view.BindFuncMap(gview.FuncMap{"GetVersion": func() string { return "1.7.0" }}) result, err := view.ParseContent(context.TODO(), str, g.Map{"other": "that's all"}) t.Assert(err != nil, false) t.Assert(result, "hello gf,version:1.7.0;hello gf,version:1.7.0;that's all") //测试api方法 str = `hello {{.name}}` result, err = gview.ParseContent(context.TODO(), str, g.Map{"name": "gf"}) t.Assert(err != nil, false) t.Assert(result, "hello gf") //测试instance方法 result, err = gview.Instance().ParseContent(context.TODO(), str, g.Map{"name": "gf"}) t.Assert(err != nil, false) t.Assert(result, "hello gf") }) } func Test_Func(t *testing.T) { gtest.C(t, func(t *gtest.T) { str := `{{eq 1 1}};{{eq 1 2}};{{eq "A" "B"}}` result, err := gview.ParseContent(context.TODO(), str, nil) t.Assert(err != nil, false) t.Assert(result, `true;false;false`) str = `{{ne 1 2}};{{ne 1 1}};{{ne "A" "B"}}` result, err = gview.ParseContent(context.TODO(), str, nil) t.Assert(err != nil, false) t.Assert(result, `true;false;true`) str = `{{lt 1 2}};{{lt 1 1}};{{lt 1 0}};{{lt "A" "B"}}` result, err = gview.ParseContent(context.TODO(), str, nil) t.Assert(err != nil, false) t.Assert(result, `true;false;false;true`) str = `{{le 1 2}};{{le 1 1}};{{le 1 0}};{{le "A" "B"}}` result, err = gview.ParseContent(context.TODO(), str, nil) t.Assert(err != nil, false) t.Assert(result, `true;true;false;true`) str = `{{gt 1 2}};{{gt 1 1}};{{gt 1 0}};{{gt "A" "B"}}` result, err = gview.ParseContent(context.TODO(), str, nil) t.Assert(err != nil, false) t.Assert(result, `false;false;true;false`) str = `{{ge 1 2}};{{ge 1 1}};{{ge 1 0}};{{ge "A" "B"}}` result, err = gview.ParseContent(context.TODO(), str, nil) t.Assert(err != nil, false) t.Assert(result, `false;true;true;false`) str = `{{"
测试
"|text}}` result, err = gview.ParseContent(context.TODO(), str, nil) t.Assert(err != nil, false) t.Assert(result, `测试`) str = `{{"
测试
"|html}}` result, err = gview.ParseContent(context.TODO(), str, nil) t.Assert(err != nil, false) t.Assert(result, `<div>测试</div>`) str = `{{"
测试
"|htmlencode}}` result, err = gview.ParseContent(context.TODO(), str, nil) t.Assert(err != nil, false) t.Assert(result, `<div>测试</div>`) str = `{{"<div>测试</div>"|htmldecode}}` result, err = gview.ParseContent(context.TODO(), str, nil) t.Assert(err != nil, false) t.Assert(result, `
测试
`) str = `{{"https://goframe.org"|url}}` result, err = gview.ParseContent(context.TODO(), str, nil) t.Assert(err != nil, false) t.Assert(result, `https%3A%2F%2Fgoframe.org`) str = `{{"https://goframe.org"|urlencode}}` result, err = gview.ParseContent(context.TODO(), str, nil) t.Assert(err != nil, false) t.Assert(result, `https%3A%2F%2Fgoframe.org`) str = `{{"https%3A%2F%2Fgoframe.org"|urldecode}}` result, err = gview.ParseContent(context.TODO(), str, nil) t.Assert(err != nil, false) t.Assert(result, `https://goframe.org`) str = `{{"https%3NA%2F%2Fgoframe.org"|urldecode}}` result, err = gview.ParseContent(context.TODO(), str, nil) t.Assert(err != nil, false) t.Assert(gstr.Contains(result, "invalid URL escape"), true) str = `{{1540822968 | date "Y-m-d"}}` result, err = gview.ParseContent(context.TODO(), str, nil) t.Assert(err != nil, false) t.Assert(result, `2018-10-29`) str = `{{date "Y-m-d"}}` result, err = gview.ParseContent(context.TODO(), str, nil) t.Assert(err != nil, false) str = `{{"我是中国人" | substr 2 -1}};{{"我是中国人" | substr 2 2}}` result, err = gview.ParseContent(context.TODO(), str, nil) t.Assert(err != nil, false) t.Assert(result, `中国人;中国`) str = `{{"我是中国人" | strlimit 2 "..."}}` result, err = gview.ParseContent(context.TODO(), str, nil) t.Assert(err != nil, false) t.Assert(result, `我是...`) str = `{{"I'm中国人" | replace "I'm" "我是"}}` result, err = gview.ParseContent(context.TODO(), str, nil) t.Assert(err != nil, false) t.Assert(result, `我是中国人`) str = `{{compare "A" "B"}};{{compare "1" "2"}};{{compare 2 1}};{{compare 1 1}}` result, err = gview.ParseContent(context.TODO(), str, nil) t.Assert(err != nil, false) t.Assert(result, `-1;-1;1;0`) str = `{{"热爱GF热爱生活" | hidestr 20 "*"}};{{"热爱GF热爱生活" | hidestr 50 "*"}}` result, err = gview.ParseContent(context.TODO(), str, nil) t.Assert(err != nil, false) t.Assert(result, `热爱GF*爱生活;热爱****生活`) str = `{{"热爱GF热爱生活" | highlight "GF" "red"}}` result, err = gview.ParseContent(context.TODO(), str, nil) t.Assert(err != nil, false) t.Assert(result, `热爱GF热爱生活`) str = `{{"gf" | toupper}};{{"GF" | tolower}}` result, err = gview.ParseContent(context.TODO(), str, nil) t.Assert(err != nil, false) t.Assert(result, `GF;gf`) str = `{{concat "I" "Love" "GoFrame"}}` result, err = gview.ParseContent(context.TODO(), str, nil) t.Assert(err, nil) t.Assert(result, `ILoveGoFrame`) }) // eq: multiple values. gtest.C(t, func(t *gtest.T) { str := `{{eq 1 2 1 3 4 5}}` result, err := gview.ParseContent(context.TODO(), str, nil) t.Assert(err != nil, false) t.Assert(result, `true`) }) gtest.C(t, func(t *gtest.T) { str := `{{eq 6 2 1 3 4 5}}` result, err := gview.ParseContent(context.TODO(), str, nil) t.Assert(err != nil, false) t.Assert(result, `false`) }) } func Test_FuncNl2Br(t *testing.T) { gtest.C(t, func(t *gtest.T) { str := `{{"Go\nFrame" | nl2br}}` result, err := gview.ParseContent(context.TODO(), str, nil) t.Assert(err, nil) t.Assert(result, `Go
Frame`) }) gtest.C(t, func(t *gtest.T) { s := "" for i := 0; i < 3000; i++ { s += "Go\nFrame\n中文" } str := `{{.content | nl2br}}` result, err := gview.ParseContent(context.TODO(), str, g.Map{ "content": s, }) t.Assert(err, nil) t.Assert(result, strings.Replace(s, "\n", "
", -1)) }) } func Test_FuncInclude(t *testing.T) { gtest.C(t, func(t *gtest.T) { header := `

HEADER

` main := `

hello gf

` footer := `

FOOTER

` layout := `{{include "header.html" .}} {{include "main.html" .}} {{include "footer.html" .}}` templatePath := gfile.Pwd() + gfile.Separator + "template" gfile.Mkdir(templatePath) defer gfile.Remove(templatePath) //headerFile, _ := gfile.Create(templatePath + gfile.Separator + "header.html") err := ioutil.WriteFile(templatePath+gfile.Separator+"header.html", []byte(header), 0644) if err != nil { t.Error(err) } ioutil.WriteFile(templatePath+gfile.Separator+"main.html", []byte(main), 0644) ioutil.WriteFile(templatePath+gfile.Separator+"footer.html", []byte(footer), 0644) ioutil.WriteFile(templatePath+gfile.Separator+"layout.html", []byte(layout), 0644) view := gview.New(templatePath) result, err := view.Parse(context.TODO(), "notfound.html") t.Assert(err != nil, true) t.Assert(result, ``) result, err = view.Parse(context.TODO(), "layout.html") t.Assert(err != nil, false) t.Assert(result, `

HEADER

hello gf

FOOTER

`) notfoundPath := templatePath + gfile.Separator + "template" + gfile.Separator + "notfound.html" gfile.Mkdir(templatePath + gfile.Separator + "template") gfile.Create(notfoundPath) ioutil.WriteFile(notfoundPath, []byte("notfound"), 0644) result, err = view.Parse(context.TODO(), "notfound.html") t.Assert(err != nil, true) t.Assert(result, ``) }) } func Test_SetPath(t *testing.T) { gtest.C(t, func(t *gtest.T) { view := gview.Instance("addpath") err := view.AddPath("tmp") t.AssertNE(err, nil) err = view.AddPath("gview.go") t.AssertNE(err, nil) os.Setenv("GF_GVIEW_PATH", "tmp") view = gview.Instance("setpath") err = view.SetPath("tmp") t.AssertNE(err, nil) err = view.SetPath("gview.go") t.AssertNE(err, nil) view = gview.New(gfile.Pwd()) err = view.SetPath("tmp") t.AssertNE(err, nil) err = view.SetPath("gview.go") t.AssertNE(err, nil) os.Setenv("GF_GVIEW_PATH", "template") gfile.Mkdir(gfile.Pwd() + gfile.Separator + "template") view = gview.New() }) } func Test_ParseContent(t *testing.T) { gtest.C(t, func(t *gtest.T) { str := `{{.name}}` view := gview.New() result, err := view.ParseContent(context.TODO(), str, g.Map{"name": func() {}}) t.Assert(err != nil, true) t.Assert(result, ``) }) } func Test_HotReload(t *testing.T) { gtest.C(t, func(t *gtest.T) { dirPath := gfile.Join( gfile.TempDir(), "testdata", "template-"+gconv.String(gtime.TimestampNano()), ) defer gfile.Remove(dirPath) filePath := gfile.Join(dirPath, "test.html") // Initialize data. err := gfile.PutContents(filePath, "test:{{.var}}") t.Assert(err, nil) view := gview.New(dirPath) time.Sleep(100 * time.Millisecond) result, err := view.Parse(context.TODO(), "test.html", g.Map{ "var": "1", }) t.Assert(err, nil) t.Assert(result, `test:1`) // Update data. err = gfile.PutContents(filePath, "test2:{{.var}}") t.Assert(err, nil) time.Sleep(100 * time.Millisecond) result, err = view.Parse(context.TODO(), "test.html", g.Map{ "var": "2", }) t.Assert(err, nil) t.Assert(result, `test2:2`) }) } func Test_XSS(t *testing.T) { gtest.C(t, func(t *gtest.T) { v := gview.New() s := "
" r, err := v.ParseContent(context.TODO(), "{{.v}}", g.Map{ "v": s, }) t.Assert(err, nil) t.Assert(r, s) }) gtest.C(t, func(t *gtest.T) { v := gview.New() v.SetAutoEncode(true) s := "
" r, err := v.ParseContent(context.TODO(), "{{.v}}", g.Map{ "v": s, }) t.Assert(err, nil) t.Assert(r, ghtml.Entities(s)) }) // Tag "if". gtest.C(t, func(t *gtest.T) { v := gview.New() v.SetAutoEncode(true) s := "
" r, err := v.ParseContent(context.TODO(), "{{if eq 1 1}}{{.v}}{{end}}", g.Map{ "v": s, }) t.Assert(err, nil) t.Assert(r, ghtml.Entities(s)) }) } type TypeForBuildInFuncMap struct { Name string Score float32 } func (t *TypeForBuildInFuncMap) Test() (*TypeForBuildInFuncMap, error) { return &TypeForBuildInFuncMap{"john", 99.9}, nil } func Test_BuildInFuncMap(t *testing.T) { gtest.C(t, func(t *gtest.T) { v := gview.New() v.Assign("v", new(TypeForBuildInFuncMap)) r, err := v.ParseContent(context.TODO(), "{{range $k, $v := map .v.Test}} {{$k}}:{{$v}} {{end}}") t.Assert(err, nil) t.Assert(gstr.Contains(r, "Name:john"), true) t.Assert(gstr.Contains(r, "Score:99.9"), true) }) } type TypeForBuildInFuncMaps struct { Name string Score float32 } func (t *TypeForBuildInFuncMaps) Test() ([]*TypeForBuildInFuncMaps, error) { return []*TypeForBuildInFuncMaps{ {"john", 99.9}, {"smith", 100}, }, nil } func Test_BuildInFuncMaps(t *testing.T) { gtest.C(t, func(t *gtest.T) { v := gview.New() v.Assign("v", new(TypeForBuildInFuncMaps)) r, err := v.ParseContent(context.TODO(), "{{range $k, $v := maps .v.Test}} {{$k}}:{{$v.Name}} {{$v.Score}} {{end}}") t.Assert(err, nil) t.Assert(r, ` 0:john 99.9 1:smith 100 `) }) } func Test_BuildInFuncDump(t *testing.T) { gtest.C(t, func(t *gtest.T) { v := gview.New() v.Assign("v", g.Map{ "name": "john", "score": 100, }) r, err := v.ParseContent(context.TODO(), "{{dump .}}") t.Assert(err, nil) t.Assert(gstr.Contains(r, `"name": "john"`), true) t.Assert(gstr.Contains(r, `"score": 100`), true) }) } func Test_BuildInFuncJson(t *testing.T) { gtest.C(t, func(t *gtest.T) { v := gview.New() v.Assign("v", g.Map{ "name": "john", }) r, err := v.ParseContent(context.TODO(), "{{json .v}}") t.Assert(err, nil) t.Assert(r, `{"name":"john"}`) }) }