/*
* 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");
}
}