/* * Copyright 2015 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.template.soy.msgs.internal; import static com.google.common.truth.Truth.assertThat; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import com.google.template.soy.SoyFileSetParserBuilder; import com.google.template.soy.error.ErrorReporter; import com.google.template.soy.error.ExplodingErrorReporter; import com.google.template.soy.error.FormattingErrorReporter; import com.google.template.soy.msgs.SoyMsgBundle; import com.google.template.soy.msgs.restricted.SoyMsg; import com.google.template.soy.msgs.restricted.SoyMsgBundleImpl; import com.google.template.soy.msgs.restricted.SoyMsgPart; import com.google.template.soy.msgs.restricted.SoyMsgPlaceholderPart; import com.google.template.soy.msgs.restricted.SoyMsgRawTextPart; import com.google.template.soy.shared.SharedTestUtils; import com.google.template.soy.soytree.MsgFallbackGroupNode; import com.google.template.soy.soytree.MsgHtmlTagNode; import com.google.template.soy.soytree.MsgNode; import com.google.template.soy.soytree.MsgPlaceholderNode; import com.google.template.soy.soytree.PrintNode; import com.google.template.soy.soytree.RawTextNode; import com.google.template.soy.soytree.SoyFileSetNode; import com.google.template.soy.soytree.TemplateNode; import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; /** * Unit tests for {@link InsertMsgsVisitor}. * */ @RunWith(JUnit4.class) public final class InsertMsgsVisitorTest { private static final ErrorReporter FAIL = ExplodingErrorReporter.get(); // ----------------------------------------------------------------------------------------------- // Test basic messages. private static final String BASIC_TEST_FILE_CONTENT = "" + "{namespace boo autoescape=\"deprecated-noncontextual\"}\n" + "\n" + "/** Test template. */\n" + "{template .foo}\n" + " {@param boo: ?}\n" + " {@param foo: ?}\n" + " {@param moo: ?}\n" + " {@param goo: ?}\n" + " {$boo}scary{sp}\n" + " {msg desc=\"Test.\"}\n" + " random{$foo}\n" + " <a href=\"{$goo}\">slimy</a>\n" + " {/msg}{sp}\n" + " {msg desc=\"\"}dairy{$moo}{/msg}\n" + "{/template}\n"; @Test public void testBasicMsgsUsingSoySource() { SoyFileSetNode soyTree = SoyFileSetParserBuilder.forFileContents(BASIC_TEST_FILE_CONTENT).parse().fileSet(); TemplateNode template = (TemplateNode) SharedTestUtils.getNode(soyTree); // Before. assertThat(template.numChildren()).isEqualTo(5); MsgNode msg = ((MsgFallbackGroupNode) template.getChild(2)).getChild(0); assertThat(msg.numChildren()).isEqualTo(5); MsgHtmlTagNode msgHtmlTag2 = (MsgHtmlTagNode) ((MsgPlaceholderNode) msg.getChild(2)).getChild(0); assertThat(msgHtmlTag2.numChildren()).isEqualTo(3); MsgHtmlTagNode msgHtmlTag4 = (MsgHtmlTagNode) ((MsgPlaceholderNode) msg.getChild(4)).getChild(0); assertThat(msgHtmlTag4.numChildren()).isEqualTo(1); assertThat(((RawTextNode) msgHtmlTag4.getChild(0)).getRawText()).isEqualTo("</a>"); // Execute the visitor. new InsertMsgsVisitor(null /* msgBundle */, FAIL).exec(template); // After. assertThat(template.numChildren()).isEqualTo(12); assertThat(((PrintNode) template.getChild(0)).getExprText()).isEqualTo("$boo"); assertThat(((RawTextNode) template.getChild(1)).getRawText()).isEqualTo("scary "); assertThat(((RawTextNode) template.getChild(2)).getRawText()).isEqualTo("random"); assertThat(((PrintNode) template.getChild(3)).getExprText()).isEqualTo("$foo"); assertThat(((RawTextNode) template.getChild(4)).getRawText()).isEqualTo("<a href=\""); assertThat(((PrintNode) template.getChild(5)).getExprText()).isEqualTo("$goo"); assertThat(((RawTextNode) template.getChild(6)).getRawText()).isEqualTo("\">"); assertThat(((RawTextNode) template.getChild(7)).getRawText()).isEqualTo("slimy"); assertThat(((RawTextNode) template.getChild(8)).getRawText()).isEqualTo("</a>"); assertThat(((RawTextNode) template.getChild(9)).getRawText()).isEqualTo(" "); assertThat(((RawTextNode) template.getChild(10)).getRawText()).isEqualTo("dairy"); assertThat(((PrintNode) template.getChild(11)).getExprText()).isEqualTo("$moo"); } @Test public void testBasicMsgsUsingMsgBundle() { SoyFileSetNode soyTree = SoyFileSetParserBuilder.forFileContents(BASIC_TEST_FILE_CONTENT).parse().fileSet(); TemplateNode template = (TemplateNode) SharedTestUtils.getNode(soyTree); // Before. assertThat(template.numChildren()).isEqualTo(5); MsgNode msg = ((MsgFallbackGroupNode) template.getChild(2)).getChild(0); assertThat(msg.numChildren()).isEqualTo(5); MsgHtmlTagNode msgHtmlTag2 = (MsgHtmlTagNode) ((MsgPlaceholderNode) msg.getChild(2)).getChild(0); assertThat(msgHtmlTag2.numChildren()).isEqualTo(3); MsgHtmlTagNode msgHtmlTag4 = (MsgHtmlTagNode) ((MsgPlaceholderNode) msg.getChild(4)).getChild(0); assertThat(msgHtmlTag4.numChildren()).isEqualTo(1); assertThat(((RawTextNode) msgHtmlTag4.getChild(0)).getRawText()).isEqualTo("</a>"); // Build the translated message bundle. List<SoyMsg> translatedMsgs = Lists.newArrayList(); // Original (en): random{{FOO}}{{START_LINK}}slimy{{END_LINK}} // Translation (x-zz): {{START_LINK}}zslimy{{END_LINK}}{{FOO}}zrandom translatedMsgs.add( SoyMsg.builder() .setId(MsgUtils.computeMsgIdForDualFormat(msg)) .setLocaleString("x-zz") .setParts( ImmutableList.of( new SoyMsgPlaceholderPart("START_LINK"), SoyMsgRawTextPart.of("zslimy"), new SoyMsgPlaceholderPart("END_LINK"), new SoyMsgPlaceholderPart("FOO"), SoyMsgRawTextPart.of("zrandom"))) .build()); // Note: This bundle has no translation for the message "dairy{$moo}". SoyMsgBundle msgBundle = new SoyMsgBundleImpl("x-zz", translatedMsgs); // Execute the visitor. new InsertMsgsVisitor(msgBundle, FAIL).exec(template); // After. assertThat(template.numChildren()).isEqualTo(12); assertThat(((PrintNode) template.getChild(0)).getExprText()).isEqualTo("$boo"); assertThat(((RawTextNode) template.getChild(1)).getRawText()).isEqualTo("scary "); assertThat(((RawTextNode) template.getChild(2)).getRawText()).isEqualTo("<a href=\""); assertThat(((PrintNode) template.getChild(3)).getExprText()).isEqualTo("$goo"); assertThat(((RawTextNode) template.getChild(4)).getRawText()).isEqualTo("\">"); assertThat(((RawTextNode) template.getChild(5)).getRawText()).isEqualTo("zslimy"); assertThat(((RawTextNode) template.getChild(6)).getRawText()).isEqualTo("</a>"); assertThat(((PrintNode) template.getChild(7)).getExprText()).isEqualTo("$foo"); assertThat(((RawTextNode) template.getChild(8)).getRawText()).isEqualTo("zrandom"); assertThat(((RawTextNode) template.getChild(9)).getRawText()).isEqualTo(" "); assertThat(((RawTextNode) template.getChild(10)).getRawText()).isEqualTo("dairy"); assertThat(((PrintNode) template.getChild(11)).getExprText()).isEqualTo("$moo"); } // ----------------------------------------------------------------------------------------------- // Test plural/select messages. private static final String PLRSEL_TEST_FILE_CONTENT = "" + "{namespace boo autoescape=\"deprecated-noncontextual\"}\n" + "\n" + "/** Test template with plural/select msgs. */\n" + "{template .foo}\n" + " {@param gender: ?}\n" + " {@param numFriends: ?}\n" + " {msg desc=\"Plural message.\"}\n" + " {plural $numFriends}\n" + " {case 1}Added a friend to your circle.\n" + " {default}Added {$numFriends} friends to your circle.\n" + " {/plural}\n" + " {/msg}\n" + " {msg desc=\"Select message.\"}\n" + " {select $gender}\n" + " {case 'female'}She is in your circles.\n" + " {default}He is in your circles.\n" + " {/select}\n" + " {/msg}\n" + "{/template}\n"; @Test public void testPlrselMsgsUsingSoySource() { SoyFileSetNode soyTree = SoyFileSetParserBuilder.forFileContents(PLRSEL_TEST_FILE_CONTENT).parse().fileSet(); TemplateNode template = (TemplateNode) SharedTestUtils.getNode(soyTree); assertThat(template.numChildren()).isEqualTo(2); // Execute the visitor. FormattingErrorReporter errorReporter = new FormattingErrorReporter(); new InsertMsgsVisitor(null /* msgBundle */, errorReporter).exec(template); assertThat(errorReporter.getErrorMessages()).hasSize(2); assertThat(errorReporter.getErrorMessages().get(0)) .contains( "JS code generation currently only supports plural/select messages when " + "shouldGenerateGoogMsgDefs is true."); assertThat(errorReporter.getErrorMessages().get(1)) .contains( "JS code generation currently only supports plural/select messages when " + "shouldGenerateGoogMsgDefs is true."); } // ----------------------------------------------------------------------------------------------- // Test messages with fallback. private static final String FALLBACK_TEST_FILE_CONTENT = "" + "{namespace boo autoescape=\"deprecated-noncontextual\"}\n" + "\n" + "/** Test template. */\n" + "{template .foo}\n" + " {msg desc=\"\"}\n" + // no trans + no trans " noTrans1\n" + " {fallbackmsg desc=\"\"}\n" + " noTrans2\n" + " {/msg}\n" + " {msg desc=\"\"}\n" + // trans + no trans " trans1\n" + " {fallbackmsg desc=\"\"}\n" + " noTrans2\n" + " {/msg}\n" + " {msg desc=\"\"}\n" + // no trans + trans " noTrans1\n" + " {fallbackmsg desc=\"\"}\n" + " trans2\n" + " {/msg}\n" + " {msg desc=\"\"}\n" + // trans + trans " trans1\n" + " {fallbackmsg desc=\"\"}\n" + " trans2\n" + " {/msg}\n" + "{/template}\n"; @Test public void testFallbackMsgsUsingSoySource() { SoyFileSetNode soyTree = SoyFileSetParserBuilder.forFileContents(FALLBACK_TEST_FILE_CONTENT).parse().fileSet(); TemplateNode template = (TemplateNode) SharedTestUtils.getNode(soyTree); // Before. assertThat(template.numChildren()).isEqualTo(4); assertThat(((MsgFallbackGroupNode) template.getChild(0)).numChildren()).isEqualTo(2); assertThat(((MsgFallbackGroupNode) template.getChild(1)).numChildren()).isEqualTo(2); assertThat(((MsgFallbackGroupNode) template.getChild(2)).numChildren()).isEqualTo(2); assertThat(((MsgFallbackGroupNode) template.getChild(3)).numChildren()).isEqualTo(2); // Execute the visitor. new InsertMsgsVisitor(null /* msgBundle */, FAIL).exec(template); // After. assertThat(template.numChildren()).isEqualTo(4); assertThat(((RawTextNode) template.getChild(0)).getRawText()).isEqualTo("noTrans1"); assertThat(((RawTextNode) template.getChild(1)).getRawText()).isEqualTo("trans1"); assertThat(((RawTextNode) template.getChild(2)).getRawText()).isEqualTo("noTrans1"); assertThat(((RawTextNode) template.getChild(3)).getRawText()).isEqualTo("trans1"); } @Test public void testFallbackMsgsUsingMsgBundle() { SoyFileSetNode soyTree = SoyFileSetParserBuilder.forFileContents(FALLBACK_TEST_FILE_CONTENT).parse().fileSet(); TemplateNode template = (TemplateNode) SharedTestUtils.getNode(soyTree); // Before. assertThat(template.numChildren()).isEqualTo(4); assertThat(((MsgFallbackGroupNode) template.getChild(0)).numChildren()).isEqualTo(2); assertThat(((MsgFallbackGroupNode) template.getChild(1)).numChildren()).isEqualTo(2); assertThat(((MsgFallbackGroupNode) template.getChild(2)).numChildren()).isEqualTo(2); assertThat(((MsgFallbackGroupNode) template.getChild(3)).numChildren()).isEqualTo(2); // Build the translated message bundle. List<SoyMsg> translatedMsgs = Lists.newArrayList(); MsgNode trans1FirstInstance = ((MsgFallbackGroupNode) template.getChild(1)).getChild(0); translatedMsgs.add( SoyMsg.builder() .setId(MsgUtils.computeMsgIdForDualFormat(trans1FirstInstance)) .setLocaleString("x-zz") .setParts(ImmutableList.<SoyMsgPart>of(SoyMsgRawTextPart.of("ztrans1"))) .build()); MsgNode trans2FirstInstance = ((MsgFallbackGroupNode) template.getChild(2)).getChild(1); translatedMsgs.add( SoyMsg.builder() .setId(MsgUtils.computeMsgIdForDualFormat(trans2FirstInstance)) .setLocaleString("x-zz") .setParts(ImmutableList.<SoyMsgPart>of(SoyMsgRawTextPart.of("ztrans2"))) .build()); SoyMsgBundle msgBundle = new SoyMsgBundleImpl("x-zz", translatedMsgs); // Execute the visitor. new InsertMsgsVisitor(msgBundle, FAIL).exec(template); // After. assertThat(template.numChildren()).isEqualTo(4); assertThat(((RawTextNode) template.getChild(0)).getRawText()).isEqualTo("noTrans1"); assertThat(((RawTextNode) template.getChild(1)).getRawText()).isEqualTo("ztrans1"); assertThat(((RawTextNode) template.getChild(2)).getRawText()).isEqualTo("ztrans2"); assertThat(((RawTextNode) template.getChild(3)).getRawText()).isEqualTo("ztrans1"); } }