21
21
import static com .google .javascript .jscomp .JsMessageVisitor .MESSAGE_TREE_MALFORMED ;
22
22
import static com .google .javascript .rhino .testing .NodeSubject .assertNode ;
23
23
24
+ import com .google .common .collect .ImmutableList ;
25
+ import com .google .javascript .jscomp .JsMessage .Part ;
26
+ import com .google .javascript .jscomp .JsMessage .PlaceholderReference ;
27
+ import com .google .javascript .jscomp .JsMessage .StringPart ;
24
28
import com .google .javascript .rhino .Node ;
25
29
import com .google .javascript .rhino .Node .SideEffectFlags ;
26
30
import java .util .HashMap ;
31
+ import java .util .List ;
27
32
import java .util .Map ;
28
33
import org .junit .Before ;
34
+ import org .junit .Ignore ;
29
35
import org .junit .Test ;
30
36
import org .junit .runner .RunWith ;
31
37
import org .junit .runners .JUnit4 ;
34
40
@ RunWith (JUnit4 .class )
35
41
public final class ReplaceMessagesTest extends CompilerTestCase {
36
42
43
+ // Generate IDs of the form `MEANING_PARTCOUNT[PARTCOUNT...]`
44
+ // PARTCOUNT = 'sN' for a string part with N == string length
45
+ // PARTCOUNT = 'pN' for a placeholder with N == length of the canonical placeholder name
46
+ public static final JsMessage .IdGenerator TEST_ID_GENERATOR =
47
+ new JsMessage .IdGenerator () {
48
+ @ Override
49
+ public String generateId (String meaning , List <Part > messageParts ) {
50
+ StringBuilder idBuilder = new StringBuilder ();
51
+ idBuilder .append (meaning ).append ('_' );
52
+ for (Part messagePart : messageParts ) {
53
+ if (messagePart .isPlaceholder ()) {
54
+ idBuilder .append ('p' ).append (messagePart .getCanonicalPlaceholderName ().length ());
55
+ } else {
56
+ idBuilder .append ('s' ).append (messagePart .getString ().length ());
57
+ }
58
+ }
59
+
60
+ return idBuilder .toString ();
61
+ }
62
+ };
63
+
37
64
/** Indicates which part of the replacement we're currently testing */
38
65
enum TestMode {
39
66
// Test full replacement from `goog.getMsg()` to final message values.
@@ -57,7 +84,12 @@ enum TestMode {
57
84
58
85
// Messages returned from fake bundle, keyed by `JsMessage.id`.
59
86
private Map <String , JsMessage > messages ;
87
+ // If `true` report errors for messages that are not found in the bundle.
60
88
private boolean strictReplacement ;
89
+ // If `true` pass TEST_ID_GENERATOR in to ReplaceMessages via the fake bundle, so it will be
90
+ // used to calculate the message IDs from the meaning and parts instead of just using the message
91
+ // key as its id.
92
+ private boolean useTestIdGenerator ;
61
93
private TestMode testMode = TestMode .FULL_REPLACE ;
62
94
63
95
@ Override
@@ -188,6 +220,7 @@ public void setUp() throws Exception {
188
220
super .setUp ();
189
221
messages = new HashMap <>();
190
222
strictReplacement = false ;
223
+ useTestIdGenerator = false ;
191
224
enableTypeCheck ();
192
225
replaceTypesWithColors ();
193
226
enableTypeInfoValidation ();
@@ -295,18 +328,28 @@ public void testReplaceExternalMessage() {
295
328
}
296
329
297
330
@ Test
331
+ @ Ignore // TODO(b/378574591): fix the bug this test exposes
298
332
public void testReplaceIcuTemplateMessageWithBundleAndJsPlaceholders () {
299
- // Message in the bundle has a placeholder and is NOT in ICU selector format.
300
- //
301
- // (i.e. it does not start with "{WORD,").
302
- //
303
- // Here we want to make sure that messages created with declareIcuTemplate()
304
- // get treated as ICU messages even without that distinguishing feature.
305
- registerMessage (
306
- getTestMessageBuilder ("MSG_SHOW_EMAIL" )
307
- .appendStringPart ("Retpoŝtadreso: " )
308
- .appendCanonicalPlaceholderReference ("EMAIL" )
309
- .build ());
333
+ useTestIdGenerator = true ;
334
+ strictReplacement = true ;
335
+
336
+ String meaning = "MSG_SHOW_EMAIL" ;
337
+ Part originalStringPart = StringPart .create ("Email: " );
338
+ Part originalPlaceholerPart = PlaceholderReference .createForCanonicalName ("EMAIL" );
339
+ String expectedMessageId =
340
+ TEST_ID_GENERATOR .generateId (
341
+ meaning , ImmutableList .of (originalStringPart , originalPlaceholerPart ));
342
+
343
+ // Create and register the translation we expect to find in the message bundle
344
+ final JsMessage showEmailTranslatedMsg =
345
+ new JsMessage .Builder ()
346
+ .setKey (meaning )
347
+ .setMeaning (meaning )
348
+ .appendStringPart ("Retpoŝtadreso: " ) // translated string
349
+ .appendPart (originalPlaceholerPart ) // placeholder is the same as original
350
+ .setId (expectedMessageId ) // message ID was calculated from the original
351
+ .build ();
352
+ registerMessage (showEmailTranslatedMsg );
310
353
311
354
multiPhaseTest (
312
355
lines (
@@ -327,6 +370,12 @@ public void testReplaceIcuTemplateMessageWithBundleAndJsPlaceholders() {
327
370
lines (
328
371
"const {declareIcuTemplate} = goog.require('goog.i18n.messages');" ,
329
372
"" ,
373
+ // TODO(b/378574591): The information gathered here isn't enough to correctly generate
374
+ // the message ID for lookup. Since the "example" information is dropped, we won't
375
+ // know that we need to split the message text into parts, treating "EMAIL" as a
376
+ // placeholder. As a result, we calculate the message ID using just a single string
377
+ // part, so we get a different message ID than we got during extraction, and we
378
+ // won't be able to find the message.
330
379
"const MSG_SHOW_EMAIL =" ,
331
380
" __jscomp_define_msg__(" ,
332
381
" {" ,
@@ -2107,7 +2156,6 @@ private void registerMessage(JsMessage message) {
2107
2156
}
2108
2157
2109
2158
private class SimpleMessageBundle implements MessageBundle {
2110
-
2111
2159
@ Override
2112
2160
public JsMessage getMessage (String id ) {
2113
2161
return messages .get (id );
@@ -2120,7 +2168,7 @@ public Iterable<JsMessage> getAllMessages() {
2120
2168
2121
2169
@ Override
2122
2170
public JsMessage .IdGenerator idGenerator () {
2123
- return null ;
2171
+ return useTestIdGenerator ? TEST_ID_GENERATOR : null ;
2124
2172
}
2125
2173
}
2126
2174
}
0 commit comments