github.com/go-xe2/third@v1.0.3/golang.org/x/text/internal/catmsg/catmsg_test.go (about)

     1  // Copyright 2017 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 catmsg
     6  
     7  import (
     8  	"errors"
     9  	"strings"
    10  	"testing"
    11  
    12  	"github.com/go-xe2/third/golang.org/x/text/language"
    13  )
    14  
    15  type renderer struct {
    16  	args   []int
    17  	result string
    18  }
    19  
    20  func (r *renderer) Arg(i int) interface{} {
    21  	if i >= len(r.args) {
    22  		return nil
    23  	}
    24  	return r.args[i]
    25  }
    26  
    27  func (r *renderer) Render(s string) {
    28  	if r.result != "" {
    29  		r.result += "|"
    30  	}
    31  	r.result += s
    32  }
    33  
    34  func TestCodec(t *testing.T) {
    35  	type test struct {
    36  		args   []int
    37  		out    string
    38  		decErr string
    39  	}
    40  	single := func(out, err string) []test { return []test{{out: out, decErr: err}} }
    41  	testCases := []struct {
    42  		desc   string
    43  		m      Message
    44  		enc    string
    45  		encErr string
    46  		tests  []test
    47  	}{{
    48  		desc:   "unused variable",
    49  		m:      &Var{"name", String("foo")},
    50  		encErr: errIsVar.Error(),
    51  		tests:  single("", ""),
    52  	}, {
    53  		desc:  "empty",
    54  		m:     empty{},
    55  		tests: single("", ""),
    56  	}, {
    57  		desc:  "sequence with empty",
    58  		m:     seq{empty{}},
    59  		tests: single("", ""),
    60  	}, {
    61  		desc:  "raw string",
    62  		m:     Raw("foo"),
    63  		tests: single("foo", ""),
    64  	}, {
    65  		desc:  "raw string no sub",
    66  		m:     Raw("${foo}"),
    67  		enc:   "\x02${foo}",
    68  		tests: single("${foo}", ""),
    69  	}, {
    70  		desc:  "simple string",
    71  		m:     String("foo"),
    72  		tests: single("foo", ""),
    73  	}, {
    74  		desc:   "missing var",
    75  		m:      String("foo${bar}"),
    76  		enc:    "\x03\x03foo\x02\x03bar",
    77  		encErr: `unknown var "bar"`,
    78  		tests:  single("foo|bar", ""),
    79  	}, {
    80  		desc: "empty var",
    81  		m: seq{
    82  			&Var{"bar", seq{}},
    83  			String("foo${bar}"),
    84  		},
    85  		enc: "\x00\x05\x04\x02bar\x03\x03foo\x00\x00",
    86  		// TODO: recognize that it is cheaper to substitute bar.
    87  		tests: single("foo|bar", ""),
    88  	}, {
    89  		desc: "var after value",
    90  		m: seq{
    91  			String("foo${bar}"),
    92  			&Var{"bar", String("baz")},
    93  		},
    94  		encErr: errIsVar.Error(),
    95  		tests:  single("foo|bar", ""),
    96  	}, {
    97  		desc: "substitution",
    98  		m: seq{
    99  			&Var{"bar", String("baz")},
   100  			String("foo${bar}"),
   101  		},
   102  		tests: single("foo|baz", ""),
   103  	}, {
   104  		desc: "shadowed variable",
   105  		m: seq{
   106  			&Var{"bar", String("baz")},
   107  			seq{
   108  				&Var{"bar", String("BAZ")},
   109  				String("foo${bar}"),
   110  			},
   111  		},
   112  		tests: single("foo|BAZ", ""),
   113  	}, {
   114  		desc:  "nested value",
   115  		m:     nestedLang{nestedLang{empty{}}},
   116  		tests: single("nl|nl", ""),
   117  	}, {
   118  		desc: "not shadowed variable",
   119  		m: seq{
   120  			&Var{"bar", String("baz")},
   121  			seq{
   122  				String("foo${bar}"),
   123  				&Var{"bar", String("BAZ")},
   124  			},
   125  		},
   126  		encErr: errIsVar.Error(),
   127  		tests:  single("foo|baz", ""),
   128  	}, {
   129  		desc: "duplicate variable",
   130  		m: seq{
   131  			&Var{"bar", String("baz")},
   132  			&Var{"bar", String("BAZ")},
   133  			String("${bar}"),
   134  		},
   135  		encErr: "catmsg: duplicate variable \"bar\"",
   136  		tests:  single("baz", ""),
   137  	}, {
   138  		desc: "complete incomplete variable",
   139  		m: seq{
   140  			&Var{"bar", incomplete{}},
   141  			String("${bar}"),
   142  		},
   143  		enc: "\x00\t\b\x01\x01\x04\x04\x02bar\x03\x00\x00\x00",
   144  		// TODO: recognize that it is cheaper to substitute bar.
   145  		tests: single("bar", ""),
   146  	}, {
   147  		desc: "incomplete sequence",
   148  		m: seq{
   149  			incomplete{},
   150  			incomplete{},
   151  		},
   152  		encErr: ErrIncomplete.Error(),
   153  		tests:  single("", ErrNoMatch.Error()),
   154  	}, {
   155  		desc: "compile error variable",
   156  		m: seq{
   157  			&Var{"bar", errorCompileMsg{}},
   158  			String("${bar}"),
   159  		},
   160  		encErr: errCompileTest.Error(),
   161  		tests:  single("bar", ""),
   162  	}, {
   163  		desc:   "compile error message",
   164  		m:      errorCompileMsg{},
   165  		encErr: errCompileTest.Error(),
   166  		tests:  single("", ""),
   167  	}, {
   168  		desc: "compile error sequence",
   169  		m: seq{
   170  			errorCompileMsg{},
   171  			errorCompileMsg{},
   172  		},
   173  		encErr: errCompileTest.Error(),
   174  		tests:  single("", ""),
   175  	}, {
   176  		desc:  "macro",
   177  		m:     String("${exists(1)}"),
   178  		tests: single("you betya!", ""),
   179  	}, {
   180  		desc:  "macro incomplete",
   181  		m:     String("${incomplete(1)}"),
   182  		enc:   "\x03\x00\x01\nincomplete\x01",
   183  		tests: single("incomplete", ""),
   184  	}, {
   185  		desc:  "macro undefined at end",
   186  		m:     String("${undefined(1)}"),
   187  		enc:   "\x03\x00\x01\tundefined\x01",
   188  		tests: single("undefined", "catmsg: undefined macro \"undefined\""),
   189  	}, {
   190  		desc:  "macro undefined with more text following",
   191  		m:     String("${undefined(1)}."),
   192  		enc:   "\x03\x00\x01\tundefined\x01\x01.",
   193  		tests: single("undefined|.", "catmsg: undefined macro \"undefined\""),
   194  	}, {
   195  		desc:   "macro missing paren",
   196  		m:      String("${missing(1}"),
   197  		encErr: "catmsg: missing ')'",
   198  		tests:  single("$!(MISSINGPAREN)", ""),
   199  	}, {
   200  		desc:   "macro bad num",
   201  		m:      String("aa${bad(a)}"),
   202  		encErr: "catmsg: invalid number \"a\"",
   203  		tests:  single("aa$!(BADNUM)", ""),
   204  	}, {
   205  		desc:   "var missing brace",
   206  		m:      String("a${missing"),
   207  		encErr: "catmsg: missing '}'",
   208  		tests:  single("a$!(MISSINGBRACE)", ""),
   209  	}}
   210  	r := &renderer{}
   211  	dec := NewDecoder(language.Und, r, macros)
   212  	for _, tc := range testCases {
   213  		t.Run(tc.desc, func(t *testing.T) {
   214  			// Use a language other than Und so that we can test
   215  			// passing the language to nested values.
   216  			data, err := Compile(language.Dutch, macros, tc.m)
   217  			if failErr(err, tc.encErr) {
   218  				t.Errorf("encoding error: got %+q; want %+q", err, tc.encErr)
   219  			}
   220  			if tc.enc != "" && data != tc.enc {
   221  				t.Errorf("encoding: got %+q; want %+q", data, tc.enc)
   222  			}
   223  			for _, st := range tc.tests {
   224  				t.Run("", func(t *testing.T) {
   225  					*r = renderer{args: st.args}
   226  					if err = dec.Execute(data); failErr(err, st.decErr) {
   227  						t.Errorf("decoding error: got %+q; want %+q", err, st.decErr)
   228  					}
   229  					if r.result != st.out {
   230  						t.Errorf("decode: got %+q; want %+q", r.result, st.out)
   231  					}
   232  				})
   233  			}
   234  		})
   235  	}
   236  }
   237  
   238  func failErr(got error, want string) bool {
   239  	if got == nil {
   240  		return want != ""
   241  	}
   242  	return want == "" || !strings.Contains(got.Error(), want)
   243  }
   244  
   245  type seq []Message
   246  
   247  func (s seq) Compile(e *Encoder) (err error) {
   248  	err = ErrIncomplete
   249  	e.EncodeMessageType(First)
   250  	for _, m := range s {
   251  		// Pass only the last error, but allow erroneous or complete messages
   252  		// here to allow testing different scenarios.
   253  		err = e.EncodeMessage(m)
   254  	}
   255  	return err
   256  }
   257  
   258  type empty struct{}
   259  
   260  func (empty) Compile(e *Encoder) (err error) { return nil }
   261  
   262  var msgIncomplete = Register(
   263  	"github.com/go-xe2/third/golang.org/x/text/internal/catmsg.incomplete",
   264  	func(d *Decoder) bool { return false })
   265  
   266  type incomplete struct{}
   267  
   268  func (incomplete) Compile(e *Encoder) (err error) {
   269  	e.EncodeMessageType(msgIncomplete)
   270  	return ErrIncomplete
   271  }
   272  
   273  var msgNested = Register(
   274  	"github.com/go-xe2/third/golang.org/x/text/internal/catmsg.nested",
   275  	func(d *Decoder) bool {
   276  		d.Render(d.DecodeString())
   277  		d.ExecuteMessage()
   278  		return true
   279  	})
   280  
   281  type nestedLang struct{ Message }
   282  
   283  func (n nestedLang) Compile(e *Encoder) (err error) {
   284  	e.EncodeMessageType(msgNested)
   285  	e.EncodeString(e.Language().String())
   286  	e.EncodeMessage(n.Message)
   287  	return nil
   288  }
   289  
   290  type errorCompileMsg struct{}
   291  
   292  var errCompileTest = errors.New("catmsg: compile error test")
   293  
   294  func (errorCompileMsg) Compile(e *Encoder) (err error) {
   295  	return errCompileTest
   296  }
   297  
   298  type dictionary struct{}
   299  
   300  var (
   301  	macros       = dictionary{}
   302  	dictMessages = map[string]string{
   303  		"exists":     compile(String("you betya!")),
   304  		"incomplete": compile(incomplete{}),
   305  	}
   306  )
   307  
   308  func (d dictionary) Lookup(key string) (data string, ok bool) {
   309  	data, ok = dictMessages[key]
   310  	return
   311  }
   312  
   313  func compile(m Message) (data string) {
   314  	data, _ = Compile(language.Und, macros, m)
   315  	return data
   316  }