195 lines
6.8 KiB
Go
195 lines
6.8 KiB
Go
// Copyright (c) 2026 Storm Dragon
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
package punctuation
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"git.stormux.org/storm/fenrir/internal/i18n"
|
|
)
|
|
|
|
func TestTextSubstitutionsAndBoundaries(t *testing.T) {
|
|
processor, _, err := Load([]string{"../../config/punctuation/default.toml"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
options := TextOptions{Emoticons: true, RepeatedSymbols: true, RepeatedSymbolsMin: 4}
|
|
for _, trial := range []struct{ text, want string }{
|
|
{":)", "smile"},
|
|
{":) :) :)", "smile smile smile"},
|
|
{":) :(", "smile frown"},
|
|
{"hello :) there", "hello smile there"},
|
|
{"你好 :) 世界", "你好 smile 世界"},
|
|
{"#####", "5 number"},
|
|
{"#### ####", "4 number 4 number"},
|
|
{"##### title #####", "5 number title 5 number"},
|
|
{"////", "4 slash"},
|
|
{"+++++-----", "5 plus 5 dash"},
|
|
{"+++++--", "5 plus dash dash "},
|
|
{"--+++++", " dash dash 5 plus"},
|
|
{"+++++-----++++", "5 plus 5 dash 4 plus"},
|
|
{"[####)", " 4 number "},
|
|
{"[#####]", " 5 number "},
|
|
{"(#####)", " 5 number "},
|
|
{"{#####}", " 5 number "},
|
|
{"<#####>", " 5 number "},
|
|
{"[#####-----]", " 5 number 5 dash "},
|
|
{"[-----#####]", " 5 dash 5 number "},
|
|
{"[#####----#####]", " 5 number 4 dash 5 number "},
|
|
{"[#####--]", " 5 number dash dash "},
|
|
{"Oo", "WTF?"},
|
|
} {
|
|
if got := processor.Process_text(trial.text, "some", options); got != trial.want {
|
|
t.Errorf("%q: %q, want %q", trial.text, got, trial.want)
|
|
}
|
|
}
|
|
for _, text := range []string{"hello :)!", "path/to:)file", "https://example.invalid/:)", "https://example.invalid/:-/", "(o_O)", "###", "##--##", "a####b", "https://example.invalid/####", "10000", "aaaa", "🙂🙂🙂🙂", "", "[]", "[###]", "[##--##]", "[a####b]", "[https://example.invalid/####]"} {
|
|
for _, level := range Levels() {
|
|
if got, want := processor.Process_text(text, level, options), processor.Text(text, level); got != want {
|
|
t.Errorf("%q, %s changed ordinary processing: %q, want %q", text, level, got, want)
|
|
}
|
|
}
|
|
}
|
|
if got := processor.Process_text("\t:)\u00a0:) \n", "none", options); got != "\tsmile\u00a0smile \n" {
|
|
t.Fatal("whitespace changed", got)
|
|
}
|
|
if got := processor.Process_text("##### ####", "all", options); got != "5 number space 4 number" {
|
|
t.Fatal("generated names were processed again", got)
|
|
}
|
|
if got := processor.Process_text("Oo", "all", options); got != "WTF?" {
|
|
t.Fatal("punctuation in emoticon name processed again", got)
|
|
}
|
|
}
|
|
|
|
func TestSubstitutionOptionsAndProfileNames(t *testing.T) {
|
|
processor, _, err := Load([]string{"../../config/punctuation/default.toml"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
text := ":) #####"
|
|
for _, level := range Levels() {
|
|
if got := processor.Process_text(text, level, TextOptions{}); got != processor.Text(text, level) {
|
|
t.Fatal("disabled substitutions changed text", level, got)
|
|
}
|
|
}
|
|
options := TextOptions{RepeatedSymbols: true, RepeatedSymbolsMin: 5}
|
|
if got := processor.Process_text("####", "some", options); got != processor.Text("####", "some") {
|
|
t.Fatal("minimum ignored", got)
|
|
}
|
|
if got := processor.Process_text("#####", "none", options); got != processor.Text("#####", "none") {
|
|
t.Fatal("summarized unselected symbol", got)
|
|
}
|
|
for _, minimum := range []int{0, 1} {
|
|
options.RepeatedSymbolsMin = minimum
|
|
if got := processor.Process_text("#####", "some", options); got != processor.Text("#####", "some") {
|
|
t.Fatal("invalid options summarized text", got)
|
|
}
|
|
}
|
|
options.RepeatedSymbolsMin = 4
|
|
data, err := os.ReadFile("../../config/punctuation/default.toml")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
data = []byte(strings.Replace(string(data), `"/" = "slash"`, `"/" = "path/separator"`, 1))
|
|
custom, err := Decode(data)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got := custom.Process_text("////", "some", options); got != "4 path/separator" {
|
|
t.Fatal("custom name changed or processed twice", got)
|
|
}
|
|
if got := custom.Process_text("[////####]", "some", options); got != " 4 path/separator 4 number " {
|
|
t.Fatal("mixed summary reprocessed custom name", got)
|
|
}
|
|
if got := custom.Process_text("////####", "some", options); got != "4 path/separator 4 number" {
|
|
t.Fatal("unbracketed summary reprocessed custom name", got)
|
|
}
|
|
french, _, err := Load([]string{"../../config/punctuation/fr.toml"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got := french.Process_text("#####", "most", options); got != "5 dièse" {
|
|
t.Fatal("localized profile name lost", got)
|
|
}
|
|
if got := processor.Character('#'); got != "hash" {
|
|
t.Fatal("summary changed character naming", got)
|
|
}
|
|
}
|
|
|
|
func TestRepeatedSymbolsRespectOptionsAndLevels(t *testing.T) {
|
|
processor, _, err := Load([]string{"../../config/punctuation/default.toml"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, level := range Levels() {
|
|
for _, options := range []TextOptions{
|
|
{},
|
|
{Emoticons: true},
|
|
{RepeatedSymbols: true, RepeatedSymbolsMin: 1},
|
|
{RepeatedSymbols: true, RepeatedSymbolsMin: 6},
|
|
{RepeatedSymbols: true, RepeatedSymbolsMin: 4},
|
|
} {
|
|
for _, text := range []string{"[#####]", "[#####-----]", "+++++-----", "+++++..", "../...."} {
|
|
want := processor.Text(text, level)
|
|
if options.RepeatedSymbols && options.RepeatedSymbolsMin == 4 && level != "none" {
|
|
switch text {
|
|
case "[#####]":
|
|
want = processor.Text("[", level) + "5 number" + processor.Text("]", level)
|
|
case "[#####-----]":
|
|
want = processor.Text("[", level) + "5 number 5 dash" + processor.Text("]", level)
|
|
case "+++++-----":
|
|
want = "5 plus 5 dash"
|
|
case "+++++..":
|
|
want = "5 plus " + processor.Text("..", level)
|
|
case "../....":
|
|
if level == "most" || level == "all" {
|
|
want = processor.Text("..", level) + " " + processor.Text("/", level) + " 4 dot"
|
|
}
|
|
}
|
|
}
|
|
if got := processor.Process_text(text, level, options); got != want {
|
|
t.Errorf("%q, level %s, options %+v: got %q, want %q", text, level, options, got, want)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestTextSubstitutionTranslationsAndFieldOrder(t *testing.T) {
|
|
root := t.TempDir()
|
|
directory := filepath.Join(root, "xx", "LC_MESSAGES")
|
|
if err := os.MkdirAll(directory, 0700); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
catalog := `msgid ""
|
|
msgstr ""
|
|
"Content-Type: text/plain; charset=UTF-8\n"
|
|
|
|
msgid "smile"
|
|
msgstr "translated-smile"
|
|
|
|
msgid "number"
|
|
msgstr "translated-number"
|
|
|
|
msgid "{0} {1}"
|
|
msgstr "{1}: {0}"
|
|
`
|
|
if err := os.WriteFile(filepath.Join(directory, "fenrir.po"), []byte(catalog), 0600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
previous := i18n.Use(i18n.New(root, "xx"))
|
|
t.Cleanup(func() { i18n.Use(previous) })
|
|
processor, _, err := Load([]string{"../../config/punctuation/default.toml"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
options := TextOptions{Emoticons: true, RepeatedSymbols: true, RepeatedSymbolsMin: 4}
|
|
if got := processor.Process_text(":) #####", "some", options); got != "translated-smile translated-number: 5" {
|
|
t.Fatal("translation or positional order lost", got)
|
|
}
|
|
}
|