]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-52_1/main/tests/core/src/com/ibm/icu/dev/test/format/MessagePatternUtilTest.java
Clean up imports.
[Dictionary.git] / jars / icu4j-52_1 / main / tests / core / src / com / ibm / icu / dev / test / format / MessagePatternUtilTest.java
1 /*
2 *******************************************************************************
3 *   Copyright (C) 2011-2012, International Business Machines
4 *   Corporation and others.  All Rights Reserved.
5 *******************************************************************************
6 *   created on: 2011aug12
7 *   created by: Markus W. Scherer
8 */
9
10 package com.ibm.icu.dev.test.format;
11
12 import java.util.ArrayList;
13 import java.util.Iterator;
14 import java.util.List;
15 import java.util.Locale;
16
17 import com.ibm.icu.text.MessagePattern;
18 import com.ibm.icu.text.MessagePatternUtil;
19 import com.ibm.icu.text.MessagePatternUtil.ArgNode;
20 import com.ibm.icu.text.MessagePatternUtil.ComplexArgStyleNode;
21 import com.ibm.icu.text.MessagePatternUtil.MessageContentsNode;
22 import com.ibm.icu.text.MessagePatternUtil.MessageNode;
23 import com.ibm.icu.text.MessagePatternUtil.TextNode;
24 import com.ibm.icu.text.MessagePatternUtil.VariantNode;
25
26 /**
27  * Test MessagePatternUtil (MessagePattern-as-tree-of-nodes API)
28  * by building parallel trees of nodes and verifying that they match.
29  */
30 public final class MessagePatternUtilTest extends com.ibm.icu.dev.test.TestFmwk {
31     public static void main(String[] args) throws Exception {
32         new MessagePatternUtilTest().run(args);
33     }
34
35     // The following nested "Expect..." classes are used to build
36     // a tree structure parallel to what the MessagePatternUtil class builds.
37     // These nested test classes are not static so that they have access to TestFmwk methods.
38
39     private class ExpectMessageNode {
40         private ExpectMessageNode expectTextThatContains(String s) {
41             contents.add(new ExpectTextNode(s));
42             return this;
43         }
44         private ExpectMessageNode expectReplaceNumber() {
45             contents.add(new ExpectMessageContentsNode());
46             return this;
47         }
48         private ExpectMessageNode expectNoneArg(Object name) {
49             contents.add(new ExpectArgNode(name));
50             return this;
51         }
52         private ExpectMessageNode expectSimpleArg(Object name, String type) {
53             contents.add(new ExpectArgNode(name, type));
54             return this;
55         }
56         private ExpectMessageNode expectSimpleArg(Object name, String type, String style) {
57             contents.add(new ExpectArgNode(name, type, style));
58             return this;
59         }
60         private ExpectComplexArgNode expectChoiceArg(Object name) {
61             return expectComplexArg(name, MessagePattern.ArgType.CHOICE);
62         }
63         private ExpectComplexArgNode expectPluralArg(Object name) {
64             return expectComplexArg(name, MessagePattern.ArgType.PLURAL);
65         }
66         private ExpectComplexArgNode expectSelectArg(Object name) {
67             return expectComplexArg(name, MessagePattern.ArgType.SELECT);
68         }
69         private ExpectComplexArgNode expectSelectOrdinalArg(Object name) {
70             return expectComplexArg(name, MessagePattern.ArgType.SELECTORDINAL);
71         }
72         private ExpectComplexArgNode expectComplexArg(Object name, MessagePattern.ArgType argType) {
73             ExpectComplexArgNode complexArg = new ExpectComplexArgNode(this, name, argType);
74             contents.add(complexArg);
75             return complexArg;
76         }
77         private ExpectComplexArgNode finishVariant() {
78             return parent;
79         }
80         private void checkMatches(MessageNode msg) {
81             // matches() prints all errors.
82             matches(msg);
83         }
84         private boolean matches(MessageNode msg) {
85             List<MessageContentsNode> msgContents = msg.getContents();
86             boolean ok = assertEquals("different numbers of MessageContentsNode",
87                                       contents.size(), msgContents.size());
88             if (ok) {
89                 Iterator<MessageContentsNode> msgIter = msgContents.iterator();
90                 for (ExpectMessageContentsNode ec : contents) {
91                     ok &= ec.matches(msgIter.next());
92                 }
93             }
94             if (!ok) {
95                 errln("error in message: " + msg.toString());
96             }
97             return ok;
98         }
99         private ExpectComplexArgNode parent;  // for finishVariant()
100         private List<ExpectMessageContentsNode> contents =
101             new ArrayList<ExpectMessageContentsNode>();
102     }
103
104     /**
105      * Base class for message contents nodes.
106      * Used directly for REPLACE_NUMBER nodes, subclassed for others.
107      */
108     private class ExpectMessageContentsNode {
109         protected boolean matches(MessageContentsNode c) {
110             return assertEquals("not a REPLACE_NUMBER node",
111                                 MessageContentsNode.Type.REPLACE_NUMBER, c.getType());
112         }
113     }
114
115     private class ExpectTextNode extends ExpectMessageContentsNode {
116         private ExpectTextNode(String subString) {
117             this.subString = subString;
118         }
119         @Override
120         protected boolean matches(MessageContentsNode c) {
121             return
122                 assertEquals("not a TextNode",
123                              MessageContentsNode.Type.TEXT, c.getType()) &&
124                 assertTrue("TextNode does not contain \"" + subString + "\"",
125                            ((TextNode)c).getText().contains(subString));
126         }
127         private String subString;
128     }
129
130     private class ExpectArgNode extends ExpectMessageContentsNode {
131         private ExpectArgNode(Object name) {
132             this(name, null, null);
133         }
134         private ExpectArgNode(Object name, String type) {
135             this(name, type, null);
136         }
137         private ExpectArgNode(Object name, String type, String style) {
138             if (name instanceof String) {
139                 this.name = (String)name;
140                 this.number = -1;
141             } else {
142                 this.number = (Integer)name;
143                 this.name = Integer.toString(this.number);
144             }
145             if (type == null) {
146                 argType = MessagePattern.ArgType.NONE;
147             } else {
148                 argType = MessagePattern.ArgType.SIMPLE;
149             }
150             this.type = type;
151             this.style = style;
152         }
153         @Override
154         protected boolean matches(MessageContentsNode c) {
155             boolean ok =
156                 assertEquals("not an ArgNode",
157                              MessageContentsNode.Type.ARG, c.getType());
158             if (!ok) {
159                 return ok;
160             }
161             ArgNode arg = (ArgNode)c;
162             ok &= assertEquals("unexpected ArgNode argType",
163                                argType, arg.getArgType());
164             ok &= assertEquals("unexpected ArgNode arg name",
165                                name, arg.getName());
166             ok &= assertEquals("unexpected ArgNode arg number",
167                                number, arg.getNumber());
168             ok &= assertEquals("unexpected ArgNode arg type name",
169                                type, arg.getTypeName());
170             ok &= assertEquals("unexpected ArgNode arg style",
171                                style, arg.getSimpleStyle());
172             if (argType == MessagePattern.ArgType.NONE || argType == MessagePattern.ArgType.SIMPLE) {
173                 ok &= assertNull("unexpected non-null complex style", arg.getComplexStyle());
174             }
175             return ok;
176         }
177         private String name;
178         private int number;
179         protected MessagePattern.ArgType argType;
180         private String type;
181         private String style;
182     }
183
184     private class ExpectComplexArgNode extends ExpectArgNode {
185         private ExpectComplexArgNode(ExpectMessageNode parent,
186                                      Object name, MessagePattern.ArgType argType) {
187             super(name, argType.toString().toLowerCase(Locale.ENGLISH));
188             this.argType = argType;
189             this.parent = parent;
190         }
191         private ExpectComplexArgNode expectOffset(double offset) {
192             this.offset = offset;
193             explicitOffset = true;
194             return this;
195         }
196         private ExpectMessageNode expectVariant(String selector) {
197             ExpectVariantNode variant = new ExpectVariantNode(this, selector);
198             variants.add(variant);
199             return variant.msg;
200         }
201         private ExpectMessageNode expectVariant(String selector, double value) {
202             ExpectVariantNode variant = new ExpectVariantNode(this, selector, value);
203             variants.add(variant);
204             return variant.msg;
205         }
206         private ExpectMessageNode finishComplexArg() {
207             return parent;
208         }
209         @Override
210         protected boolean matches(MessageContentsNode c) {
211             boolean ok = super.matches(c);
212             if (!ok) {
213                 return ok;
214             }
215             ArgNode arg = (ArgNode)c;
216             ComplexArgStyleNode complexStyle = arg.getComplexStyle();
217             ok &= assertNotNull("unexpected null complex style", complexStyle);
218             if (!ok) {
219                 return ok;
220             }
221             ok &= assertEquals("unexpected complex-style argType",
222                                argType, complexStyle.getArgType());
223             ok &= assertEquals("unexpected complex-style hasExplicitOffset()",
224                                explicitOffset, complexStyle.hasExplicitOffset());
225             ok &= assertEquals("unexpected complex-style offset",
226                                offset, complexStyle.getOffset());
227             List<VariantNode> complexVariants = complexStyle.getVariants();
228             ok &= assertEquals("different number of variants",
229                                variants.size(), complexVariants.size());
230             if (!ok) {
231                 return ok;
232             }
233             Iterator<VariantNode> complexIter = complexVariants.iterator();
234             for (ExpectVariantNode variant : variants) {
235                 ok &= variant.matches(complexIter.next());
236             }
237             return ok;
238         }
239         private ExpectMessageNode parent;  // for finishComplexArg()
240         private boolean explicitOffset;
241         private double offset;
242         private List<ExpectVariantNode> variants = new ArrayList<ExpectVariantNode>();
243     }
244
245     private class ExpectVariantNode {
246         private ExpectVariantNode(ExpectComplexArgNode parent, String selector) {
247             this(parent, selector, MessagePattern.NO_NUMERIC_VALUE);
248         }
249         private ExpectVariantNode(ExpectComplexArgNode parent, String selector, double value) {
250             this.selector = selector;
251             numericValue = value;
252             msg = new ExpectMessageNode();
253             msg.parent = parent;
254         }
255         private boolean matches(VariantNode v) {
256             boolean ok = assertEquals("different selector strings",
257                                       selector, v.getSelector());
258             ok &= assertEquals("different selector strings",
259                                isSelectorNumeric(), v.isSelectorNumeric());
260             ok &= assertEquals("different selector strings",
261                                numericValue, v.getSelectorValue());
262             return ok & msg.matches(v.getMessage());
263         }
264         private boolean isSelectorNumeric() {
265             return numericValue != MessagePattern.NO_NUMERIC_VALUE;
266         }
267         private String selector;
268         private double numericValue;
269         private ExpectMessageNode msg;
270     }
271
272     // The actual tests start here. ---------------------------------------- ***
273     // Sample message strings are mostly from the MessagePatternUtilDemo.
274
275     public void TestHello() {
276         // No syntax.
277         MessageNode msg = MessagePatternUtil.buildMessageNode("Hello!");
278         ExpectMessageNode expect = new ExpectMessageNode().expectTextThatContains("Hello");
279         expect.checkMatches(msg);
280     }
281
282     public void TestHelloWithApos() {
283         // Literal ASCII apostrophe.
284         MessageNode msg = MessagePatternUtil.buildMessageNode("Hel'lo!");
285         ExpectMessageNode expect = new ExpectMessageNode().expectTextThatContains("Hel'lo");
286         expect.checkMatches(msg);
287     }
288
289     public void TestHelloWithQuote() {
290         // Apostrophe starts quoted literal text.
291         MessageNode msg = MessagePatternUtil.buildMessageNode("Hel'{o!");
292         ExpectMessageNode expect = new ExpectMessageNode().expectTextThatContains("Hel{o");
293         expect.checkMatches(msg);
294         // Terminating the quote should yield the same result.
295         msg = MessagePatternUtil.buildMessageNode("Hel'{'o!");
296         expect.checkMatches(msg);
297         // Double apostrophe inside quoted literal text still encodes a single apostrophe.
298         msg = MessagePatternUtil.buildMessageNode("a'{bc''de'f");
299         expect = new ExpectMessageNode().expectTextThatContains("a{bc'def");
300         expect.checkMatches(msg);
301     }
302
303     public void TestNoneArg() {
304         // Numbered argument.
305         MessageNode msg = MessagePatternUtil.buildMessageNode("abc{0}def");
306         ExpectMessageNode expect = new ExpectMessageNode().
307             expectTextThatContains("abc").expectNoneArg(0).expectTextThatContains("def");
308         expect.checkMatches(msg);
309         // Named argument.
310         msg = MessagePatternUtil.buildMessageNode("abc{ arg }def");
311         expect = new ExpectMessageNode().
312             expectTextThatContains("abc").expectNoneArg("arg").expectTextThatContains("def");
313         expect.checkMatches(msg);
314         // Numbered and named arguments.
315         msg = MessagePatternUtil.buildMessageNode("abc{1}def{arg}ghi");
316         expect = new ExpectMessageNode().
317             expectTextThatContains("abc").expectNoneArg(1).expectTextThatContains("def").
318             expectNoneArg("arg").expectTextThatContains("ghi");
319         expect.checkMatches(msg);
320     }
321
322     public void TestSimpleArg() {
323         MessageNode msg = MessagePatternUtil.buildMessageNode("a'{bc''de'f{0,number,g'hi''jk'l#}");
324         ExpectMessageNode expect = new ExpectMessageNode().
325             expectTextThatContains("a{bc'def").expectSimpleArg(0, "number", "g'hi''jk'l#");
326         expect.checkMatches(msg);
327     }
328
329     public void TestSelectArg() {
330         MessageNode msg = MessagePatternUtil.buildMessageNode(
331                 "abc{2, number}ghi{3, select, xx {xxx} other {ooo}} xyz");
332         ExpectMessageNode expect = new ExpectMessageNode().
333             expectTextThatContains("abc").expectSimpleArg(2, "number").
334             expectTextThatContains("ghi").
335             expectSelectArg(3).
336                 expectVariant("xx").expectTextThatContains("xxx").finishVariant().
337                 expectVariant("other").expectTextThatContains("ooo").finishVariant().
338                 finishComplexArg().
339             expectTextThatContains(" xyz");
340         expect.checkMatches(msg);
341     }
342
343     public void TestPluralArg() {
344         // Plural with only keywords.
345         MessageNode msg = MessagePatternUtil.buildMessageNode(
346                 "abc{num_people, plural, offset:17 few{fff} other {oooo}}xyz");
347         ExpectMessageNode expect = new ExpectMessageNode().
348             expectTextThatContains("abc").
349             expectPluralArg("num_people").
350                 expectOffset(17).
351                 expectVariant("few").expectTextThatContains("fff").finishVariant().
352                 expectVariant("other").expectTextThatContains("oooo").finishVariant().
353                 finishComplexArg().
354             expectTextThatContains("xyz");
355         expect.checkMatches(msg);
356         // Plural with explicit-value selectors.
357         msg = MessagePatternUtil.buildMessageNode(
358                 "abc{ num , plural , offset: 2 =1 {1} =-1 {-1} =3.14 {3.14} other {oo} }xyz");
359         expect = new ExpectMessageNode().
360             expectTextThatContains("abc").
361             expectPluralArg("num").
362                 expectOffset(2).
363                 expectVariant("=1", 1).expectTextThatContains("1").finishVariant().
364                 expectVariant("=-1", -1).expectTextThatContains("-1").finishVariant().
365                 expectVariant("=3.14", 3.14).expectTextThatContains("3.14").finishVariant().
366                 expectVariant("other").expectTextThatContains("oo").finishVariant().
367                 finishComplexArg().
368             expectTextThatContains("xyz");
369         expect.checkMatches(msg);
370         // Plural with number replacement.
371         msg = MessagePatternUtil.buildMessageNode(
372                 "a_{0,plural,other{num=#'#'=#'#'={1,number,##}!}}_z");
373         expect = new ExpectMessageNode().
374             expectTextThatContains("a_").
375             expectPluralArg(0).
376                 expectVariant("other").
377                     expectTextThatContains("num=").expectReplaceNumber().
378                     expectTextThatContains("#=").expectReplaceNumber().
379                     expectTextThatContains("#=").expectSimpleArg(1, "number", "##").
380                     expectTextThatContains("!").finishVariant().
381                 finishComplexArg().
382             expectTextThatContains("_z");
383         expect.checkMatches(msg);
384         // Plural with explicit offset:0.
385         msg = MessagePatternUtil.buildMessageNode(
386                 "a_{0,plural,offset:0 other{num=#!}}_z");
387         expect = new ExpectMessageNode().
388             expectTextThatContains("a_").
389             expectPluralArg(0).
390                 expectOffset(0).
391                 expectVariant("other").
392                     expectTextThatContains("num=").expectReplaceNumber().
393                     expectTextThatContains("!").finishVariant().
394                 finishComplexArg().
395             expectTextThatContains("_z");
396         expect.checkMatches(msg);
397     }
398
399
400     public void TestSelectOrdinalArg() {
401         MessageNode msg = MessagePatternUtil.buildMessageNode(
402                 "abc{num, selectordinal, offset:17 =0{null} few{fff} other {oooo}}xyz");
403         ExpectMessageNode expect = new ExpectMessageNode().
404             expectTextThatContains("abc").
405             expectSelectOrdinalArg("num").
406                 expectOffset(17).
407                 expectVariant("=0", 0).expectTextThatContains("null").finishVariant().
408                 expectVariant("few").expectTextThatContains("fff").finishVariant().
409                 expectVariant("other").expectTextThatContains("oooo").finishVariant().
410                 finishComplexArg().
411             expectTextThatContains("xyz");
412         expect.checkMatches(msg);
413     }
414
415     public void TestChoiceArg() {
416         MessageNode msg = MessagePatternUtil.buildMessageNode(
417                 "a_{0,choice,-∞ #-inf|  5≤ five | 99 # ninety'|'nine  }_z");
418         ExpectMessageNode expect = new ExpectMessageNode().
419             expectTextThatContains("a_").
420             expectChoiceArg(0).
421                 expectVariant("#", Double.NEGATIVE_INFINITY).
422                     expectTextThatContains("-inf").finishVariant().
423                 expectVariant("≤", 5).expectTextThatContains(" five ").finishVariant().
424                 expectVariant("#", 99).expectTextThatContains(" ninety|nine  ").finishVariant().
425                 finishComplexArg().
426             expectTextThatContains("_z");
427         expect.checkMatches(msg);
428     }
429
430     public void TestComplexArgs() {
431         MessageNode msg = MessagePatternUtil.buildMessageNode(
432                 "I don't {a,plural,other{w'{'on't #'#'}} and "+
433                 "{b,select,other{shan't'}'}} '{'''know'''}' and "+
434                 "{c,choice,0#can't'|'}"+
435                 "{z,number,#'#'###.00'}'}.");
436         ExpectMessageNode expect = new ExpectMessageNode().
437             expectTextThatContains("I don't ").
438             expectPluralArg("a").
439                 expectVariant("other").
440                     expectTextThatContains("w{on't ").expectReplaceNumber().
441                     expectTextThatContains("#").finishVariant().
442                 finishComplexArg().
443             expectTextThatContains(" and ").
444             expectSelectArg("b").
445                 expectVariant("other").expectTextThatContains("shan't}").finishVariant().
446                 finishComplexArg().
447             expectTextThatContains(" {'know'} and ").
448             expectChoiceArg("c").
449                 expectVariant("#", 0).expectTextThatContains("can't|").finishVariant().
450                 finishComplexArg().
451             expectSimpleArg("z", "number", "#'#'###.00'}'").
452             expectTextThatContains(".");
453         expect.checkMatches(msg);
454     }
455
456     /**
457      * @return the text string of the VariantNode's message;
458      *         assumes that its message consists of only text
459      */
460     private String variantText(VariantNode v) {
461         return ((TextNode)v.getMessage().getContents().get(0)).getText();
462     }
463
464     public void TestPluralVariantsByType() {
465         MessageNode msg = MessagePatternUtil.buildMessageNode(
466                 "{p,plural,a{A}other{O}=4{iv}b{B}other{U}=2{ii}}");
467         ExpectMessageNode expect = new ExpectMessageNode().
468         expectPluralArg("p").
469             expectVariant("a").expectTextThatContains("A").finishVariant().
470             expectVariant("other").expectTextThatContains("O").finishVariant().
471             expectVariant("=4", 4).expectTextThatContains("iv").finishVariant().
472             expectVariant("b").expectTextThatContains("B").finishVariant().
473             expectVariant("other").expectTextThatContains("U").finishVariant().
474             expectVariant("=2", 2).expectTextThatContains("ii").finishVariant().
475             finishComplexArg();
476         if (!expect.matches(msg)) {
477             return;
478         }
479         List<VariantNode> numericVariants = new ArrayList<VariantNode>();
480         List<VariantNode> keywordVariants = new ArrayList<VariantNode>();
481         VariantNode other =
482             ((ArgNode)msg.getContents().get(0)).getComplexStyle().
483             getVariantsByType(numericVariants, keywordVariants);
484         assertEquals("'other' selector", "other", other.getSelector());
485         assertEquals("message string of first 'other'", "O", variantText(other));
486
487         assertEquals("numericVariants.size()", 2, numericVariants.size());
488         VariantNode v = numericVariants.get(0);
489         assertEquals("numericVariants[0] selector", "=4", v.getSelector());
490         assertEquals("numericVariants[0] selector value", 4., v.getSelectorValue());
491         assertEquals("numericVariants[0] text", "iv", variantText(v));
492         v = numericVariants.get(1);
493         assertEquals("numericVariants[1] selector", "=2", v.getSelector());
494         assertEquals("numericVariants[1] selector value", 2., v.getSelectorValue());
495         assertEquals("numericVariants[1] text", "ii", variantText(v));
496
497         assertEquals("keywordVariants.size()", 2, keywordVariants.size());
498         v = keywordVariants.get(0);
499         assertEquals("keywordVariants[0] selector", "a", v.getSelector());
500         assertFalse("keywordVariants[0].isSelectorNumeric()", v.isSelectorNumeric());
501         assertEquals("keywordVariants[0] text", "A", variantText(v));
502         v = keywordVariants.get(1);
503         assertEquals("keywordVariants[1] selector", "b", v.getSelector());
504         assertFalse("keywordVariants[1].isSelectorNumeric()", v.isSelectorNumeric());
505         assertEquals("keywordVariants[1] text", "B", variantText(v));
506     }
507
508     public void TestSelectVariantsByType() {
509         MessageNode msg = MessagePatternUtil.buildMessageNode(
510                 "{s,select,a{A}other{O}b{B}other{U}}");
511         ExpectMessageNode expect = new ExpectMessageNode().
512         expectSelectArg("s").
513             expectVariant("a").expectTextThatContains("A").finishVariant().
514             expectVariant("other").expectTextThatContains("O").finishVariant().
515             expectVariant("b").expectTextThatContains("B").finishVariant().
516             expectVariant("other").expectTextThatContains("U").finishVariant().
517             finishComplexArg();
518         if (!expect.matches(msg)) {
519             return;
520         }
521         // Check that we can use numericVariants = null.
522         List<VariantNode> keywordVariants = new ArrayList<VariantNode>();
523         VariantNode other =
524             ((ArgNode)msg.getContents().get(0)).getComplexStyle().
525             getVariantsByType(null, keywordVariants);
526         assertEquals("'other' selector", "other", other.getSelector());
527         assertEquals("message string of first 'other'", "O", variantText(other));
528
529         assertEquals("keywordVariants.size()", 2, keywordVariants.size());
530         VariantNode v = keywordVariants.get(0);
531         assertEquals("keywordVariants[0] selector", "a", v.getSelector());
532         assertFalse("keywordVariants[0].isSelectorNumeric()", v.isSelectorNumeric());
533         assertEquals("keywordVariants[0] text", "A", variantText(v));
534         v = keywordVariants.get(1);
535         assertEquals("keywordVariants[1] selector", "b", v.getSelector());
536         assertFalse("keywordVariants[1].isSelectorNumeric()", v.isSelectorNumeric());
537         assertEquals("keywordVariants[1] text", "B", variantText(v));
538     }
539 }