github.com/hairyhenderson/gomplate/v4@v4.0.0-pre-2.0.20240520121557-362f058f0c93/render_test.go (about) 1 package gomplate 2 3 import ( 4 "bytes" 5 "context" 6 "fmt" 7 "net/url" 8 "os" 9 "strings" 10 "testing" 11 "testing/fstest" 12 13 "github.com/hairyhenderson/go-fsimpl" 14 "github.com/hairyhenderson/gomplate/v4/internal/datafs" 15 "github.com/stretchr/testify/assert" 16 "github.com/stretchr/testify/require" 17 ) 18 19 func TestRenderTemplate(t *testing.T) { 20 wd, _ := os.Getwd() 21 t.Cleanup(func() { 22 _ = os.Chdir(wd) 23 }) 24 _ = os.Chdir("/") 25 26 fsys := fstest.MapFS{} 27 fsp := fsimpl.NewMux() 28 fsp.Add(datafs.EnvFS) 29 fsp.Add(datafs.StdinFS) 30 fsp.Add(datafs.WrappedFSProvider(fsys, "mem", "")) 31 ctx := datafs.ContextWithFSProvider(context.Background(), fsp) 32 33 // no options - built-in function 34 tr := NewRenderer(Options{}) 35 out := &bytes.Buffer{} 36 err := tr.Render(ctx, "test", "{{ `hello world` | toUpper }}", out) 37 require.NoError(t, err) 38 assert.Equal(t, "HELLO WORLD", out.String()) 39 40 // with datasource and context 41 hu, _ := url.Parse("stdin:") 42 wu, _ := url.Parse("env:WORLD") 43 44 t.Setenv("WORLD", "world") 45 46 tr = NewRenderer(Options{ 47 Context: map[string]Datasource{ 48 "hi": {URL: hu}, 49 }, 50 Datasources: map[string]Datasource{ 51 "world": {URL: wu}, 52 }, 53 }) 54 ctx = datafs.ContextWithStdin(ctx, strings.NewReader("hello")) 55 out = &bytes.Buffer{} 56 err = tr.Render(ctx, "test", `{{ .hi | toUpper }} {{ (ds "world") | toUpper }}`, out) 57 require.NoError(t, err) 58 assert.Equal(t, "HELLO WORLD", out.String()) 59 60 // with a nested template 61 nu, _ := url.Parse("nested.tmpl") 62 fsys["nested.tmpl"] = &fstest.MapFile{Data: []byte( 63 `<< . | toUpper >>`)} 64 65 tr = NewRenderer(Options{ 66 Templates: map[string]Datasource{ 67 "nested": {URL: nu}, 68 }, 69 LDelim: "<<", 70 RDelim: ">>", 71 }) 72 out = &bytes.Buffer{} 73 err = tr.Render(ctx, "test", `<< template "nested" "hello" >>`, out) 74 require.NoError(t, err) 75 assert.Equal(t, "HELLO", out.String()) 76 77 // errors contain the template name 78 tr = NewRenderer(Options{}) 79 err = tr.Render(ctx, "foo", `{{ bogus }}`, &bytes.Buffer{}) 80 assert.ErrorContains(t, err, "template: foo:") 81 } 82 83 //// examples 84 85 func ExampleRenderer() { 86 ctx := context.Background() 87 88 // create a new template renderer 89 tr := NewRenderer(Options{}) 90 91 // render a template to stdout 92 err := tr.Render(ctx, "mytemplate", 93 `{{ "hello, world!" | toUpper }}`, 94 os.Stdout) 95 if err != nil { 96 fmt.Println("gomplate error:", err) 97 } 98 99 // Output: 100 // HELLO, WORLD! 101 } 102 103 func ExampleRenderer_manyTemplates() { 104 ctx := context.Background() 105 106 // create a new template renderer 107 tr := NewRenderer(Options{}) 108 109 templates := []Template{ 110 { 111 Name: "one.tmpl", 112 Text: `contents of {{ tmpl.Path }}`, 113 Writer: &bytes.Buffer{}, 114 }, 115 { 116 Name: "two.tmpl", 117 Text: `{{ "hello world" | toUpper }}`, 118 Writer: &bytes.Buffer{}, 119 }, 120 { 121 Name: "three.tmpl", 122 Text: `1 + 1 = {{ math.Add 1 1 }}`, 123 Writer: &bytes.Buffer{}, 124 }, 125 } 126 127 // render the templates 128 err := tr.RenderTemplates(ctx, templates) 129 if err != nil { 130 panic(err) 131 } 132 133 for _, t := range templates { 134 fmt.Printf("%s: %s\n", t.Name, t.Writer.(*bytes.Buffer).String()) 135 } 136 137 // Output: 138 // one.tmpl: contents of one.tmpl 139 // two.tmpl: HELLO WORLD 140 // three.tmpl: 1 + 1 = 2 141 } 142 143 func ExampleRenderer_datasources() { 144 ctx := context.Background() 145 146 // a datasource that retrieves JSON from a public API 147 u, _ := url.Parse("https://ipinfo.io/1.1.1.1") 148 tr := NewRenderer(Options{ 149 Context: map[string]Datasource{ 150 "info": {URL: u}, 151 }, 152 }) 153 154 err := tr.Render(ctx, "jsontest", 155 `{{"\U0001F30E"}} {{ .info.hostname }} is served by {{ .info.org }}`, 156 os.Stdout) 157 if err != nil { 158 panic(err) 159 } 160 161 // Output: 162 // 🌎 one.one.one.one is served by AS13335 Cloudflare, Inc. 163 }