github.com/liquid-dev/text@v0.3.3-liquid/message/message_test.go (about)

     1  // Copyright 2015 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package message
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"io"
    11  	"testing"
    12  
    13  	"github.com/liquid-dev/text/internal"
    14  	"github.com/liquid-dev/text/internal/format"
    15  	"github.com/liquid-dev/text/language"
    16  	"github.com/liquid-dev/text/message/catalog"
    17  )
    18  
    19  type formatFunc func(s fmt.State, v rune)
    20  
    21  func (f formatFunc) Format(s fmt.State, v rune) { f(s, v) }
    22  
    23  func TestBinding(t *testing.T) {
    24  	testCases := []struct {
    25  		tag   string
    26  		value interface{}
    27  		want  string
    28  	}{
    29  		{"en", 1, "1"},
    30  		{"en", "2", "2"},
    31  		{ // Language is passed.
    32  			"en",
    33  			formatFunc(func(fs fmt.State, v rune) {
    34  				s := fs.(format.State)
    35  				io.WriteString(s, s.Language().String())
    36  			}),
    37  			"en",
    38  		},
    39  	}
    40  	for i, tc := range testCases {
    41  		p := NewPrinter(language.MustParse(tc.tag))
    42  		if got := p.Sprint(tc.value); got != tc.want {
    43  			t.Errorf("%d:%s:Sprint(%v) = %q; want %q", i, tc.tag, tc.value, got, tc.want)
    44  		}
    45  		var buf bytes.Buffer
    46  		p.Fprint(&buf, tc.value)
    47  		if got := buf.String(); got != tc.want {
    48  			t.Errorf("%d:%s:Fprint(%v) = %q; want %q", i, tc.tag, tc.value, got, tc.want)
    49  		}
    50  	}
    51  }
    52  
    53  func TestLocalization(t *testing.T) {
    54  	type test struct {
    55  		tag  string
    56  		key  Reference
    57  		args []interface{}
    58  		want string
    59  	}
    60  	args := func(x ...interface{}) []interface{} { return x }
    61  	empty := []interface{}{}
    62  	joe := []interface{}{"Joe"}
    63  	joeAndMary := []interface{}{"Joe", "Mary"}
    64  
    65  	testCases := []struct {
    66  		desc string
    67  		cat  []entry
    68  		test []test
    69  	}{{
    70  		desc: "empty",
    71  		test: []test{
    72  			{"en", "key", empty, "key"},
    73  			{"en", "", empty, ""},
    74  			{"nl", "", empty, ""},
    75  		},
    76  	}, {
    77  		desc: "hierarchical languages",
    78  		cat: []entry{
    79  			{"en", "hello %s", "Hello %s!"},
    80  			{"en-GB", "hello %s", "Hellø %s!"},
    81  			{"en-US", "hello %s", "Howdy %s!"},
    82  			{"en", "greetings %s and %s", "Greetings %s and %s!"},
    83  		},
    84  		test: []test{
    85  			{"und", "hello %s", joe, "hello Joe"},
    86  			{"nl", "hello %s", joe, "hello Joe"},
    87  			{"en", "hello %s", joe, "Hello Joe!"},
    88  			{"en-US", "hello %s", joe, "Howdy Joe!"},
    89  			{"en-GB", "hello %s", joe, "Hellø Joe!"},
    90  			{"en-oxendict", "hello %s", joe, "Hello Joe!"},
    91  			{"en-US-oxendict-u-ms-metric", "hello %s", joe, "Howdy Joe!"},
    92  
    93  			{"und", "greetings %s and %s", joeAndMary, "greetings Joe and Mary"},
    94  			{"nl", "greetings %s and %s", joeAndMary, "greetings Joe and Mary"},
    95  			{"en", "greetings %s and %s", joeAndMary, "Greetings Joe and Mary!"},
    96  			{"en-US", "greetings %s and %s", joeAndMary, "Greetings Joe and Mary!"},
    97  			{"en-GB", "greetings %s and %s", joeAndMary, "Greetings Joe and Mary!"},
    98  			{"en-oxendict", "greetings %s and %s", joeAndMary, "Greetings Joe and Mary!"},
    99  			{"en-US-oxendict-u-ms-metric", "greetings %s and %s", joeAndMary, "Greetings Joe and Mary!"},
   100  		},
   101  	}, {
   102  		desc: "references",
   103  		cat: []entry{
   104  			{"en", "hello", "Hello!"},
   105  		},
   106  		test: []test{
   107  			{"en", "hello", empty, "Hello!"},
   108  			{"en", Key("hello", "fallback"), empty, "Hello!"},
   109  			{"en", Key("xxx", "fallback"), empty, "fallback"},
   110  			{"und", Key("hello", "fallback"), empty, "fallback"},
   111  		},
   112  	}, {
   113  		desc: "zero substitution", // work around limitation of fmt
   114  		cat: []entry{
   115  			{"en", "hello %s", "Hello!"},
   116  			{"en", "hi %s and %s", "Hello %[2]s!"},
   117  		},
   118  		test: []test{
   119  			{"en", "hello %s", joe, "Hello!"},
   120  			{"en", "hello %s", joeAndMary, "Hello!"},
   121  			{"en", "hi %s and %s", joeAndMary, "Hello Mary!"},
   122  			// The following tests resolve to the fallback string.
   123  			{"und", "hello", joeAndMary, "hello"},
   124  			{"und", "hello %%%%", joeAndMary, "hello %%"},
   125  			{"und", "hello %#%%4.2%  ", joeAndMary, "hello %%  "},
   126  			{"und", "hello %s", joeAndMary, "hello Joe%!(EXTRA string=Mary)"},
   127  			{"und", "hello %+%%s", joeAndMary, "hello %Joe%!(EXTRA string=Mary)"},
   128  			{"und", "hello %-42%%s ", joeAndMary, "hello %Joe %!(EXTRA string=Mary)"},
   129  		},
   130  	}, {
   131  		desc: "number formatting",
   132  		cat: []entry{
   133  			{"und", "files", "%d files left"},
   134  			{"und", "meters", "%.2f meters"},
   135  			{"de", "files", "%d Dateien übrig"},
   136  		},
   137  		test: []test{
   138  			{"en", "meters", args(3000.2), "3,000.20 meters"},
   139  			{"en-u-nu-gujr", "files", args(123456), "૧૨૩,૪૫૬ files left"},
   140  			{"de", "files", args(1234), "1.234 Dateien übrig"},
   141  			{"de-CH", "files", args(1234), "1’234 Dateien übrig"},
   142  			{"de-CH-u-nu-mong", "files", args(1234), "᠑’᠒᠓᠔ Dateien übrig"},
   143  		},
   144  	}, {
   145  		desc: "substitute translation",
   146  		cat: []entry{
   147  			{"en", "google", "Google"},
   148  			{"en", "sub", "%s"},
   149  			{"en", "visit", "Lookup: %m."},
   150  		},
   151  		test: []test{
   152  			{"en", "visit", args("google"), "Lookup: Google."},
   153  			{"en", "visit", args("sub"), "Lookup: %s."},
   154  		},
   155  	}}
   156  
   157  	for _, tc := range testCases {
   158  		cat, _ := initCat(tc.cat)
   159  
   160  		for i, pt := range tc.test {
   161  			t.Run(fmt.Sprintf("%s:%d", tc.desc, i), func(t *testing.T) {
   162  				p := NewPrinter(language.MustParse(pt.tag), Catalog(cat))
   163  
   164  				if got := p.Sprintf(pt.key, pt.args...); got != pt.want {
   165  					t.Errorf("Sprintf(%q, %v) = %s; want %s",
   166  						pt.key, pt.args, got, pt.want)
   167  					return // Next error will likely be the same.
   168  				}
   169  
   170  				w := &bytes.Buffer{}
   171  				p.Fprintf(w, pt.key, pt.args...)
   172  				if got := w.String(); got != pt.want {
   173  					t.Errorf("Fprintf(%q, %v) = %s; want %s",
   174  						pt.key, pt.args, got, pt.want)
   175  				}
   176  			})
   177  		}
   178  	}
   179  }
   180  
   181  type entry struct{ tag, key, msg string }
   182  
   183  func initCat(entries []entry) (*catalog.Builder, []language.Tag) {
   184  	tags := []language.Tag{}
   185  	cat := catalog.NewBuilder()
   186  	for _, e := range entries {
   187  		tag := language.MustParse(e.tag)
   188  		tags = append(tags, tag)
   189  		cat.SetString(tag, e.key, e.msg)
   190  	}
   191  	return cat, internal.UniqueTags(tags)
   192  }