package html import ( "fmt" "strings" "testing" i18n "dappco.re/go/core/i18n" ) // --- Unicode / RTL edge cases --- func TestText_Emoji(t *testing.T) { svc, _ := i18n.New() i18n.SetDefault(svc) ctx := NewContext() tests := []struct { name string input string }{ {"simple emoji", "\U0001F680"}, {"emoji sequence", "\U0001F468\u200D\U0001F4BB"}, {"mixed text and emoji", "Hello \U0001F30D World"}, {"flag emoji", "\U0001F1EC\U0001F1E7"}, {"emoji in sentence", "Status: \u2705 Complete"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { node := Text(tt.input) got := node.Render(ctx) if got == "" { t.Error("Text with emoji should not produce empty output") } // Emoji should pass through (they are not HTML special chars) if !strings.Contains(got, tt.input) { // Some chars may get escaped, but emoji bytes should survive t.Logf("note: emoji text rendered as %q", got) } }) } } func TestEl_Emoji(t *testing.T) { ctx := NewContext() node := El("span", Raw("\U0001F680 Launch")) got := node.Render(ctx) want := "\U0001F680 Launch" if got != want { t.Errorf("El with emoji = %q, want %q", got, want) } } func TestText_RTL(t *testing.T) { svc, _ := i18n.New() i18n.SetDefault(svc) ctx := NewContext() tests := []struct { name string input string }{ {"Arabic", "\u0645\u0631\u062D\u0628\u0627"}, {"Hebrew", "\u05E9\u05DC\u05D5\u05DD"}, {"mixed LTR and RTL", "Hello \u0645\u0631\u062D\u0628\u0627 World"}, {"Arabic with numbers", "\u0627\u0644\u0639\u062F\u062F 42"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { node := Text(tt.input) got := node.Render(ctx) if got == "" { t.Error("Text with RTL content should not produce empty output") } }) } } func TestEl_RTL(t *testing.T) { ctx := NewContext() node := Attr(El("div", Raw("\u0645\u0631\u062D\u0628\u0627")), "dir", "rtl") got := node.Render(ctx) if !strings.Contains(got, `dir="rtl"`) { t.Errorf("RTL element missing dir attribute in: %s", got) } if !strings.Contains(got, "\u0645\u0631\u062D\u0628\u0627") { t.Errorf("RTL element missing Arabic text in: %s", got) } } func TestText_ZeroWidth(t *testing.T) { svc, _ := i18n.New() i18n.SetDefault(svc) ctx := NewContext() tests := []struct { name string input string }{ {"zero-width space", "hello\u200Bworld"}, {"zero-width joiner", "hello\u200Dworld"}, {"zero-width non-joiner", "hello\u200Cworld"}, {"soft hyphen", "super\u00ADcalifragilistic"}, {"BOM character", "\uFEFFhello"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { node := Text(tt.input) got := node.Render(ctx) if got == "" { t.Error("Text with zero-width characters should not produce empty output") } }) } } func TestText_MixedScripts(t *testing.T) { svc, _ := i18n.New() i18n.SetDefault(svc) ctx := NewContext() tests := []struct { name string input string }{ {"Latin + CJK", "Hello \u4F60\u597D"}, {"Latin + Cyrillic", "Hello \u041F\u0440\u0438\u0432\u0435\u0442"}, {"CJK + Arabic", "\u4F60\u597D \u0645\u0631\u062D\u0628\u0627"}, {"Latin + Devanagari", "Hello \u0928\u092E\u0938\u094D\u0924\u0947"}, {"Latin + Thai", "Hello \u0E2A\u0E27\u0E31\u0E2A\u0E14\u0E35"}, {"all scripts mixed", "EN \u4F60\u597D \u0645\u0631\u062D\u0628\u0627 \u041F\u0440\u0438\u0432\u0435\u0442 \U0001F30D"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { node := Text(tt.input) got := node.Render(ctx) if got == "" { t.Error("Text with mixed scripts should not produce empty output") } }) } } func TestStripTags_Unicode(t *testing.T) { tests := []struct { name string input string want string }{ {"emoji in tags", "\U0001F680", "\U0001F680"}, {"RTL in tags", "
\u4F60\u597D\u4E16\u754C
", "\u4F60\u597D\u4E16\u754C"}, {"mixed unicode regions", "