A go template renderer based on Perl's Template Toolkit
at main 206 lines 4.6 kB view raw
1package gott 2 3import ( 4 "fmt" 5 "strings" 6 "testing" 7) 8 9func TestFunctionCalls(t *testing.T) { 10 tests := []struct { 11 name string 12 template string 13 vars map[string]any 14 want string 15 wantErr bool 16 }{ 17 // Option 1: Functions with no arguments 18 { 19 name: "no-arg function returns string", 20 template: "[% myfunc() %]", 21 vars: map[string]any{ 22 "myfunc": func() string { 23 return "hello" 24 }, 25 }, 26 want: "hello", 27 }, 28 { 29 name: "no-arg function returns int", 30 template: "[% counter() %]", 31 vars: map[string]any{ 32 "counter": func() int { 33 return 42 34 }, 35 }, 36 want: "42", 37 }, 38 { 39 name: "no-arg function returns any (struct)", 40 template: "[% user() %]", 41 vars: map[string]any{ 42 "user": func() any { 43 return TestUser{Handle: "testuser", DisplayName: "Test User"} 44 }, 45 }, 46 want: "{testuser Test User }", 47 }, 48 // Option 2: Functions with string arguments 49 { 50 name: "function with string args", 51 template: "[% greet('world') %]", 52 vars: map[string]any{ 53 "greet": func(name string) string { 54 return "Hello, " + name + "!" 55 }, 56 }, 57 want: "Hello, world!", 58 }, 59 { 60 name: "function with multiple string args", 61 template: "[% concat('hello', ' ', 'world') %]", 62 vars: map[string]any{ 63 "concat": func(a, b, c string) string { 64 return a + b + c 65 }, 66 }, 67 want: "hello world", 68 }, 69 { 70 name: "function with variadic string args", 71 template: "[% join('a', 'b', 'c') %]", 72 vars: map[string]any{ 73 "join": func(parts ...string) string { 74 result := "" 75 for i, p := range parts { 76 if i > 0 { 77 result += "-" 78 } 79 result += p 80 } 81 return result 82 }, 83 }, 84 want: "a-b-c", 85 }, 86 { 87 name: "function with variadic string args (all args converted to strings)", 88 template: "[% greet('hello', 'world') %]", 89 vars: map[string]any{ 90 "greet": func(args ...string) any { 91 return args[0] + " " + args[1] 92 }, 93 }, 94 want: "hello world", 95 }, 96 { 97 name: "variadic function with numbers (converted to strings)", 98 template: "[% concat(1, 2, 3) %]", 99 vars: map[string]any{ 100 "concat": func(args ...string) any { 101 return args[0] + "-" + args[1] + "-" + args[2] 102 }, 103 }, 104 want: "1-2-3", 105 }, 106 { 107 name: "function returns any and needs string conversion", 108 template: "[% getNumber() %]", 109 vars: map[string]any{ 110 "getNumber": func() any { 111 return 123.45 112 }, 113 }, 114 want: "123.45", 115 }, 116 // Edge cases and more complex scenarios 117 { 118 name: "function with no args in condition", 119 template: "[% IF enabled() %]enabled[% ELSE %]disabled[% END %]", 120 vars: map[string]any{ 121 "enabled": func() bool { 122 return true 123 }, 124 }, 125 want: "enabled", 126 }, 127 { 128 name: "function in foreach loop", 129 template: "[% FOREACH i IN items %][% item() %][% END %]", 130 vars: map[string]any{ 131 "items": []int{1, 2, 3}, 132 "item": func() string { return "x" }, 133 }, 134 want: "xxx", 135 }, 136 { 137 name: "function with expression as argument", 138 template: "[% sum(2 + 3, 4) %]", 139 vars: map[string]any{ 140 "sum": func(args ...string) any { 141 total := 0 142 for _, s := range args { 143 var n int 144 fmt.Sscanf(s, "%d", &n) 145 total += n 146 } 147 return fmt.Sprintf("%d", total) 148 }, 149 }, 150 want: "9", 151 }, 152 { 153 name: "function with variable as argument", 154 template: "[% greet(name) %]", 155 vars: map[string]any{ 156 "name": "Alice", 157 "greet": func(args ...string) any { 158 return "Hello, " + args[0] + "!" 159 }, 160 }, 161 want: "Hello, Alice!", 162 }, 163 { 164 name: "function with filter chain", 165 template: "[% upper('hello') | upper %]", 166 vars: map[string]any{ 167 "upper": func(args ...string) any { 168 return strings.ToUpper(args[0]) 169 }, 170 }, 171 want: "HELLO", 172 }, 173 { 174 name: "undefined function", 175 template: "[% unknown() %]", 176 vars: map[string]any{}, 177 wantErr: true, 178 }, 179 { 180 name: "variable with same name as function", 181 template: "[% myvar %]", 182 vars: map[string]any{ 183 "myvar": "I am a variable", 184 }, 185 want: "I am a variable", 186 }, 187 } 188 189 for _, tt := range tests { 190 t.Run(tt.name, func(t *testing.T) { 191 r, err := New(nil) 192 if err != nil { 193 t.Fatalf("New() error = %v", err) 194 } 195 196 got, err := r.Process(tt.template, tt.vars) 197 if (err != nil) != tt.wantErr { 198 t.Errorf("Process() error = %v, wantErr %v", err, tt.wantErr) 199 return 200 } 201 if !tt.wantErr && got != tt.want { 202 t.Errorf("Process() = %q, want %q", got, tt.want) 203 } 204 }) 205 } 206}