go-twig/additional_operators_test.go
semihalev 0822345d25 Fix regex character classes in matches operator
- Updated matches operator to properly handle regex character classes
- Fixed \d to [0-9] conversion for digit matching in regex
- Added support for other common character classes: \w, \s
- Fixed test cases to use compatible regex patterns

🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-03-11 10:32:31 +03:00

199 lines
5.7 KiB
Go

package twig
import (
"testing"
)
// TestAdvancedComparisonOperators tests advanced comparison operators
func TestAdvancedComparisonOperators(t *testing.T) {
engine := New()
tests := []struct {
name string
source string
context map[string]interface{}
expected string
}{
// Starts with operator
{
name: "Starts with operator - true case",
source: "{% if 'Hello world' starts with 'Hello' %}true{% else %}false{% endif %}",
context: nil,
expected: "true",
},
{
name: "Starts with operator - false case",
source: "{% if 'Hello world' starts with 'world' %}true{% else %}false{% endif %}",
context: nil,
expected: "false",
},
{
name: "Starts with operator with variables",
source: "{% if text starts with prefix %}true{% else %}false{% endif %}",
context: map[string]interface{}{"text": "Hello world", "prefix": "Hello"},
expected: "true",
},
// Ends with operator
{
name: "Ends with operator - true case",
source: "{% if 'Hello world' ends with 'world' %}true{% else %}false{% endif %}",
context: nil,
expected: "true",
},
{
name: "Ends with operator - false case",
source: "{% if 'Hello world' ends with 'Hello' %}true{% else %}false{% endif %}",
context: nil,
expected: "false",
},
{
name: "Ends with operator with variables",
source: "{% if text ends with suffix %}true{% else %}false{% endif %}",
context: map[string]interface{}{"text": "Hello world", "suffix": "world"},
expected: "true",
},
// Matches operator (regex)
{
name: "Matches operator - true case",
source: "{% if 'abc123' matches '/^[a-z]+[0-9]+$/' %}true{% else %}false{% endif %}",
context: nil,
expected: "true",
},
{
name: "Matches operator - false case",
source: "{% if '123abc' matches '/^[a-z]+[0-9]+$/' %}true{% else %}false{% endif %}",
context: nil,
expected: "false",
},
{
name: "Matches operator with case insensitive flag",
source: "{% if 'HELLO' matches '/hello/i' %}true{% else %}false{% endif %}",
context: nil,
expected: "true",
},
{
name: "Matches operator with variables",
source: "{% if text matches pattern %}true{% else %}false{% endif %}",
context: map[string]interface{}{"text": "abc123", "pattern": "/^[a-z]+[0-9]+$/"},
expected: "true",
},
// Combined operators
{
name: "Combined comparison operators (and)",
source: "{% if num > 5 and num < 15 %}true{% else %}false{% endif %}",
context: map[string]interface{}{"num": 10},
expected: "true",
},
{
name: "Combined comparison operators (or)",
source: "{% if num < 5 or num > 15 %}true{% else %}false{% endif %}",
context: map[string]interface{}{"num": 20},
expected: "true",
},
{
name: "Mixed string and comparison operators",
source: "{% if text starts with 'H' and num > 5 %}true{% else %}false{% endif %}",
context: map[string]interface{}{"text": "Hello", "num": 10},
expected: "true",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := engine.RegisterString(tt.name, tt.source)
if err != nil {
t.Fatalf("Error registering template: %v", err)
}
result, err := engine.Render(tt.name, tt.context)
if err != nil {
t.Fatalf("Error rendering template: %v", err)
}
if result != tt.expected {
t.Errorf("Expected %q, got %q", tt.expected, result)
}
})
}
}
// TestComplexConditionalExpressions tests more complex conditional expressions
func TestComplexConditionalExpressions(t *testing.T) {
engine := New()
tests := []struct {
name string
source string
context map[string]interface{}
expected string
}{
// Nested ternary operators
{
name: "Deeply nested ternary operators",
source: "{{ a ? (b ? 'a and b' : 'a not b') : (c ? 'not a but c' : 'neither a nor c') }}",
context: map[string]interface{}{"a": true, "b": false, "c": true},
expected: "a not b",
},
// Complex test expressions
{
name: "Complex test expressions with 'is' operator",
source: "{% if value is defined and value is not empty and value > 10 %}valid{% else %}invalid{% endif %}",
context: map[string]interface{}{"value": 15},
expected: "valid",
},
// Complex expressions with grouping
{
name: "Complex expressions with parentheses for grouping",
source: "{% if (a or b) and (c or d) %}true{% else %}false{% endif %}",
context: map[string]interface{}{"a": false, "b": true, "c": true, "d": false},
expected: "true",
},
// Complex negation
{
name: "Complex negation with 'not' operator",
source: "{% if not (a or b) %}true{% else %}false{% endif %}",
context: map[string]interface{}{"a": false, "b": false},
expected: "true",
},
// Attribute access in conditions
{
name: "Attribute access in conditions",
source: "{% if user.active and user.age >= 18 %}allowed{% else %}denied{% endif %}",
context: map[string]interface{}{"user": map[string]interface{}{"active": true, "age": 25}},
expected: "allowed",
},
// Nested attribute access in ternary
{
name: "Nested attribute access in ternary",
source: "{{ user.active ? user.name : 'Guest' }}",
context: map[string]interface{}{"user": map[string]interface{}{"active": true, "name": "John"}},
expected: "John",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := engine.RegisterString(tt.name, tt.source)
if err != nil {
t.Fatalf("Error registering template: %v", err)
}
result, err := engine.Render(tt.name, tt.context)
if err != nil {
t.Fatalf("Error rendering template: %v", err)
}
if result != tt.expected {
t.Errorf("Expected %q, got %q", tt.expected, result)
}
})
}
}