| // Copyright 2014 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package cldr |
| |
| import ( |
| "fmt" |
| "strings" |
| "testing" |
| ) |
| |
| // A recorder implements the RuleProcessor interface, whereby its methods |
| // simply record the invocations. |
| type recorder struct { |
| calls []string |
| } |
| |
| func (r *recorder) Reset(anchor string, before int) error { |
| if before > 5 { |
| return fmt.Errorf("before %d > 5", before) |
| } |
| r.calls = append(r.calls, fmt.Sprintf("R:%s-%d", anchor, before)) |
| return nil |
| } |
| |
| func (r *recorder) Insert(level int, str, context, extend string) error { |
| s := fmt.Sprintf("O:%d:%s", level, str) |
| if context != "" { |
| s += "|" + context |
| } |
| if extend != "" { |
| s += "/" + extend |
| } |
| r.calls = append(r.calls, s) |
| return nil |
| } |
| |
| func (r *recorder) Index(id string) { |
| r.calls = append(r.calls, fmt.Sprintf("I:%s", id)) |
| } |
| |
| func (r *recorder) Error(err error) { |
| r.calls = append(r.calls, fmt.Sprintf("E:%v", err)) |
| } |
| |
| func TestRuleProcessor(t *testing.T) { |
| for _, tt := range []struct { |
| desc string |
| in string |
| out string |
| }{ |
| {desc: "empty"}, |
| {desc: "whitespace and comments only", |
| in: ` |
| |
| |
| # adsfads |
| # adfadf |
| `, |
| }, |
| { |
| desc: "reset anchor", |
| in: ` |
| & a |
| &b # |
| & [ before 3 ] c |
| & [before 4] d & ee |
| & [first tertiary ignorable] |
| &'g' |
| & 'h''h'h'h' |
| &'\u0069' # LATIN SMALL LETTER I |
| `, |
| out: ` |
| R:a-0 |
| R:b-0 |
| R:c-3 |
| R:d-4 |
| R:ee-0 |
| R:<first tertiary ignorable/>-0 |
| R:g-0 |
| R:hhhh-0 |
| R:i-0 |
| `, |
| }, |
| { |
| desc: "ordering", |
| in: ` |
| & 0 |
| < 1 <<''2# |
| <<< 3'3''33'3# |
| <<<<4 |
| = 5 << 6 | s |
| <<<< 7 / z |
| << 8'' | s / ch |
| `, |
| out: ` |
| R:0-0 |
| O:1:1 |
| O:2:'2 |
| O:3:33333 |
| O:4:4 |
| O:5:5 |
| O:2:6|s |
| O:4:7/z |
| O:2:8'|s/ch |
| `, |
| }, |
| { |
| desc: "index", |
| in: "< '\ufdd0'A", |
| out: "I:A", |
| }, |
| { |
| desc: "sequence", |
| in: ` |
| & 0 |
| <<* 1234 |
| <* a-cde-f |
| =* q-q |
| `, |
| out: ` |
| R:0-0 |
| O:2:1 |
| O:2:2 |
| O:2:3 |
| O:2:4 |
| O:1:a |
| O:1:b |
| O:1:c |
| O:1:d |
| O:1:e |
| O:1:f |
| O:5:q |
| `, |
| }, |
| { |
| desc: "compact", |
| in: "&B<t<<<T<s<<<S<e<<<E", |
| out: ` |
| R:B-0 |
| O:1:t |
| O:3:T |
| O:1:s |
| O:3:S |
| O:1:e |
| O:3:E |
| `, |
| }, |
| { |
| desc: "err operator", |
| in: "a", |
| out: "E:1: illegal operator 'a'", |
| }, |
| { |
| desc: "err line number", |
| in: `& a |
| << b |
| a`, |
| out: ` |
| R:a-0 |
| O:2:b |
| E:3: illegal operator 'a'`, |
| }, |
| { |
| desc: "err empty anchor", |
| in: " & ", |
| out: "E:1: missing string", |
| }, |
| { |
| desc: "err anchor invalid special 1", |
| in: " & [ foo ", |
| out: "E:1: unmatched bracket", |
| }, |
| { |
| desc: "err anchor invalid special 2", |
| in: "&[", |
| out: "E:1: unmatched bracket", |
| }, |
| { |
| desc: "err anchor invalid before 1", |
| in: "&[before a]", |
| out: `E:1: strconv.ParseUint: parsing "a": invalid syntax`, |
| }, |
| { |
| desc: "err anchor invalid before 2", |
| in: "&[before 12]", |
| out: `E:1: strconv.ParseUint: parsing "12": value out of range`, |
| }, |
| { |
| desc: "err anchor invalid before 3", |
| in: "&[before 2]", |
| out: "E:1: missing string", |
| }, |
| { |
| desc: "err anchor invalid before 4", |
| in: "&[before 6] a", |
| out: "E:1: before 6 > 5", |
| }, |
| { |
| desc: "err empty order", |
| in: " < ", |
| out: "E:1: missing string", |
| }, |
| { |
| desc: "err empty identity", |
| in: " = ", |
| out: "E:1: missing string", |
| }, |
| { |
| desc: "err empty context", |
| in: " < a | ", |
| out: "E:1: missing string after context", |
| }, |
| { |
| desc: "err empty extend", |
| in: " < a / ", |
| out: "E:1: missing string after extension", |
| }, |
| { |
| desc: "err empty sequence", |
| in: " <* ", |
| out: "E:1: empty sequence", |
| }, |
| { |
| desc: "err sequence 1", |
| in: " <* -a", |
| out: "E:1: range without starter value", |
| }, |
| { |
| desc: "err sequence 3", |
| in: " <* a-a-b", |
| out: `O:1:a |
| E:1: range without starter value |
| `, |
| }, |
| { |
| desc: "err sequence 3", |
| in: " <* b-a", |
| out: `O:1:b |
| E:1: invalid range 'b'-'a' |
| `, |
| }, |
| { |
| desc: "err unmatched quote", |
| in: " < 'b", |
| out: ` E:1: unmatched single quote |
| `, |
| }, |
| } { |
| rec := &recorder{} |
| err := Collation{ |
| Cr: []*Common{ |
| {hidden: hidden{CharData: tt.in}}, |
| }, |
| }.Process(rec) |
| if err != nil { |
| rec.Error(err) |
| } |
| got := rec.calls |
| want := strings.Split(strings.TrimSpace(tt.out), "\n") |
| if tt.out == "" { |
| want = nil |
| } |
| if len(got) != len(want) { |
| t.Errorf("%s: nResults: got %d; want %d", tt.desc, len(got), len(want)) |
| continue |
| } |
| for i, g := range got { |
| if want := strings.TrimSpace(want[i]); g != want { |
| t.Errorf("%s:%d: got %q; want %q", tt.desc, i, g, want) |
| } |
| } |
| } |
| } |