@@ -167,3 +167,204 @@ func TestTemplateInclusion(t *testing.T) {
167167 }
168168}
169169
170+ func TestMathOperatorsInt (t * testing.T ) {
171+ tests := []struct {
172+ name string
173+ template string
174+ expected string
175+ }{
176+ {"add" , `{{set _x=(1 + 2)}}{{_x}}{{/set}}` , "3" },
177+ {"subtract" , `{{set _x=(5 - 3)}}{{_x}}{{/set}}` , "2" },
178+ {"multiply" , `{{set _x=(3 * 4)}}{{_x}}{{/set}}` , "12" },
179+ {"divide" , `{{set _x=(10 / 2)}}{{_x}}{{/set}}` , "5" },
180+ {"modulo" , `{{set _x=(10 % 3)}}{{_x}}{{/set}}` , "1" },
181+ {"precedence" , `{{set _x=(2 + 3 * 4)}}{{_x}}{{/set}}` , "14" },
182+ {"parentheses" , `{{set _x=((2 + 3) * 4)}}{{_x}}{{/set}}` , "20" },
183+ {"negative" , `{{set _x=(0 - 5)}}{{_x}}{{/set}}` , "-5" },
184+ {"shift_left" , `{{set _x=(1 << 3)}}{{_x}}{{/set}}` , "8" },
185+ {"shift_right" , `{{set _x=(8 >> 2)}}{{_x}}{{/set}}` , "2" },
186+ {"bitwise_and" , `{{set _x=(7 & 3)}}{{_x}}{{/set}}` , "3" },
187+ {"bitwise_xor" , `{{set _x=(5 ^ 3)}}{{_x}}{{/set}}` , "6" },
188+ }
189+
190+ for _ , tt := range tests {
191+ t .Run (tt .name , func (t * testing.T ) {
192+ engine := tpl .New ()
193+ engine .Raw .TemplateData ["main" ] = tt .template
194+
195+ ctx := context .Background ()
196+
197+ if err := engine .Compile (ctx ); err != nil {
198+ t .Fatalf ("Compile failed: %v" , err )
199+ }
200+
201+ result , err := engine .ParseAndReturn (ctx , "main" )
202+ if err != nil {
203+ t .Fatalf ("ParseAndReturn failed: %v" , err )
204+ }
205+
206+ if result != tt .expected {
207+ t .Errorf ("got %q, want %q" , result , tt .expected )
208+ }
209+ })
210+ }
211+ }
212+
213+ func TestMathOperatorsFloat (t * testing.T ) {
214+ tests := []struct {
215+ name string
216+ template string
217+ expected string
218+ }{
219+ {"add" , `{{set _x=(1.5 + 2.5)}}{{_x}}{{/set}}` , "4" },
220+ {"subtract" , `{{set _x=(5.5 - 3.0)}}{{_x}}{{/set}}` , "2.5" },
221+ {"multiply" , `{{set _x=(2.5 * 4)}}{{_x}}{{/set}}` , "10" },
222+ {"divide" , `{{set _x=(10.0 / 4)}}{{_x}}{{/set}}` , "2.5" },
223+ }
224+
225+ for _ , tt := range tests {
226+ t .Run (tt .name , func (t * testing.T ) {
227+ engine := tpl .New ()
228+ engine .Raw .TemplateData ["main" ] = tt .template
229+
230+ ctx := context .Background ()
231+
232+ if err := engine .Compile (ctx ); err != nil {
233+ t .Fatalf ("Compile failed: %v" , err )
234+ }
235+
236+ result , err := engine .ParseAndReturn (ctx , "main" )
237+ if err != nil {
238+ t .Fatalf ("ParseAndReturn failed: %v" , err )
239+ }
240+
241+ if result != tt .expected {
242+ t .Errorf ("got %q, want %q" , result , tt .expected )
243+ }
244+ })
245+ }
246+ }
247+
248+ func TestComparisonOperatorsInt (t * testing.T ) {
249+ tests := []struct {
250+ name string
251+ template string
252+ expected string
253+ }{
254+ {"less_than_true" , `{{if (1 < 2)}}yes{{else}}no{{/if}}` , "yes" },
255+ {"less_than_false" , `{{if (2 < 1)}}yes{{else}}no{{/if}}` , "no" },
256+ {"less_equal_true" , `{{if (2 <= 2)}}yes{{else}}no{{/if}}` , "yes" },
257+ {"less_equal_false" , `{{if (3 <= 2)}}yes{{else}}no{{/if}}` , "no" },
258+ {"greater_than_true" , `{{if (3 > 2)}}yes{{else}}no{{/if}}` , "yes" },
259+ {"greater_than_false" , `{{if (1 > 2)}}yes{{else}}no{{/if}}` , "no" },
260+ {"greater_equal_true" , `{{if (2 >= 2)}}yes{{else}}no{{/if}}` , "yes" },
261+ {"greater_equal_false" , `{{if (1 >= 2)}}yes{{else}}no{{/if}}` , "no" },
262+ {"equal_true" , `{{if (5 == 5)}}yes{{else}}no{{/if}}` , "yes" },
263+ {"equal_false" , `{{if (5 == 6)}}yes{{else}}no{{/if}}` , "no" },
264+ {"not_equal_true" , `{{if (5 != 6)}}yes{{else}}no{{/if}}` , "yes" },
265+ {"not_equal_false" , `{{if (5 != 5)}}yes{{else}}no{{/if}}` , "no" },
266+ }
267+
268+ for _ , tt := range tests {
269+ t .Run (tt .name , func (t * testing.T ) {
270+ engine := tpl .New ()
271+ engine .Raw .TemplateData ["main" ] = tt .template
272+
273+ ctx := context .Background ()
274+
275+ if err := engine .Compile (ctx ); err != nil {
276+ t .Fatalf ("Compile failed: %v" , err )
277+ }
278+
279+ result , err := engine .ParseAndReturn (ctx , "main" )
280+ if err != nil {
281+ t .Fatalf ("ParseAndReturn failed: %v" , err )
282+ }
283+
284+ if result != tt .expected {
285+ t .Errorf ("got %q, want %q" , result , tt .expected )
286+ }
287+ })
288+ }
289+ }
290+
291+ func TestLogicalOperators (t * testing.T ) {
292+ tests := []struct {
293+ name string
294+ template string
295+ vars map [string ]any
296+ expected string
297+ }{
298+ {"and_true_true" , `{{if ({{_a}} && {{_b}})}}yes{{else}}no{{/if}}` , map [string ]any {"_a" : true , "_b" : true }, "yes" },
299+ {"and_true_false" , `{{if ({{_a}} && {{_b}})}}yes{{else}}no{{/if}}` , map [string ]any {"_a" : true , "_b" : false }, "no" },
300+ {"and_false_true" , `{{if ({{_a}} && {{_b}})}}yes{{else}}no{{/if}}` , map [string ]any {"_a" : false , "_b" : true }, "no" },
301+ {"and_false_false" , `{{if ({{_a}} && {{_b}})}}yes{{else}}no{{/if}}` , map [string ]any {"_a" : false , "_b" : false }, "no" },
302+ {"or_true_true" , `{{if ({{_a}} || {{_b}})}}yes{{else}}no{{/if}}` , map [string ]any {"_a" : true , "_b" : true }, "yes" },
303+ {"or_true_false" , `{{if ({{_a}} || {{_b}})}}yes{{else}}no{{/if}}` , map [string ]any {"_a" : true , "_b" : false }, "yes" },
304+ {"or_false_true" , `{{if ({{_a}} || {{_b}})}}yes{{else}}no{{/if}}` , map [string ]any {"_a" : false , "_b" : true }, "yes" },
305+ {"or_false_false" , `{{if ({{_a}} || {{_b}})}}yes{{else}}no{{/if}}` , map [string ]any {"_a" : false , "_b" : false }, "no" },
306+ {"not_true" , `{{if (!{{_a}})}}yes{{else}}no{{/if}}` , map [string ]any {"_a" : true }, "no" },
307+ {"not_false" , `{{if (!{{_a}})}}yes{{else}}no{{/if}}` , map [string ]any {"_a" : false }, "yes" },
308+ }
309+
310+ for _ , tt := range tests {
311+ t .Run (tt .name , func (t * testing.T ) {
312+ engine := tpl .New ()
313+ engine .Raw .TemplateData ["main" ] = tt .template
314+
315+ ctx := context .Background ()
316+ ctx = tpl .ValuesCtx (ctx , tt .vars )
317+
318+ if err := engine .Compile (ctx ); err != nil {
319+ t .Fatalf ("Compile failed: %v" , err )
320+ }
321+
322+ result , err := engine .ParseAndReturn (ctx , "main" )
323+ if err != nil {
324+ t .Fatalf ("ParseAndReturn failed: %v" , err )
325+ }
326+
327+ if result != tt .expected {
328+ t .Errorf ("got %q, want %q" , result , tt .expected )
329+ }
330+ })
331+ }
332+ }
333+
334+ func TestMathWithVariables (t * testing.T ) {
335+ tests := []struct {
336+ name string
337+ template string
338+ vars map [string ]any
339+ expected string
340+ }{
341+ {"add_vars" , `{{set _x=({{_a}} + {{_b}})}}{{_x}}{{/set}}` , map [string ]any {"_a" : 3 , "_b" : 4 }, "7" },
342+ {"multiply_vars" , `{{set _x=({{_a}} * {{_b}})}}{{_x}}{{/set}}` , map [string ]any {"_a" : 3 , "_b" : 4 }, "12" },
343+ {"compare_vars" , `{{if ({{_a}} < {{_b}})}}yes{{else}}no{{/if}}` , map [string ]any {"_a" : 3 , "_b" : 5 }, "yes" },
344+ {"float_vars" , `{{set _x=({{_a}} + {{_b}})}}{{_x}}{{/set}}` , map [string ]any {"_a" : 1.5 , "_b" : 2.5 }, "4" },
345+ }
346+
347+ for _ , tt := range tests {
348+ t .Run (tt .name , func (t * testing.T ) {
349+ engine := tpl .New ()
350+ engine .Raw .TemplateData ["main" ] = tt .template
351+
352+ ctx := context .Background ()
353+ ctx = tpl .ValuesCtx (ctx , tt .vars )
354+
355+ if err := engine .Compile (ctx ); err != nil {
356+ t .Fatalf ("Compile failed: %v" , err )
357+ }
358+
359+ result , err := engine .ParseAndReturn (ctx , "main" )
360+ if err != nil {
361+ t .Fatalf ("ParseAndReturn failed: %v" , err )
362+ }
363+
364+ if result != tt .expected {
365+ t .Errorf ("got %q, want %q" , result , tt .expected )
366+ }
367+ })
368+ }
369+ }
370+
0 commit comments