/* * Copyright 2012 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.passes; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import com.google.common.collect.Iterables; 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.internal.MsgUtils; import com.google.template.soy.shared.SharedTestUtils; import com.google.template.soy.soytree.MsgNode; import com.google.template.soy.soytree.SoyFileSetNode; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; /** * Unit tests for RewriteGenderMsgsVisitor. * */ @RunWith(JUnit4.class) public final class RewriteGenderMsgsVisitorTest { @Test public void testCannotMixGendersAndSelect() { String soyCode = "" + "{@param userGender : ?}\n" + "{@param targetGender : ?}\n" + "{$userGender}\n" + "{msg genders=\"$userGender\" desc=\"Button text.\"}\n" + " {select $targetGender}\n" + " {case 'female'}Reply to her\n" + " {case 'male'}Reply to him\n" + " {default}Reply to them\n" + " {/select}\n" + "{/msg}\n"; FormattingErrorReporter errorReporter = new FormattingErrorReporter(); SoyFileSetParserBuilder.forTemplateContents(soyCode) .errorReporter(errorReporter) .parse() .fileSet(); assertThat(errorReporter.getErrorMessages()).hasSize(1); assertThat(Iterables.getOnlyElement(errorReporter.getErrorMessages())) .contains("Cannot mix 'genders' attribute with 'select' command in the same message."); } @Test public void testErrorIfCannotGenNoncollidingBaseNames() { String soyCode = "" + "{@param userGender : ?}\n" + "{@param gender : ?}\n" + "{@param owner : ?}\n" + "{msg genders=\"$userGender, $gender\" desc=\"Button text.\"}\n" + " You joined {$owner}'s community.\n" + "{/msg}\n"; FormattingErrorReporter errorReporter = new FormattingErrorReporter(); SoyFileSetParserBuilder.forTemplateContents(soyCode) .errorReporter(errorReporter) .parse() .fileSet(); assertThat(errorReporter.getErrorMessages()) .contains( "Cannot generate noncolliding base names for vars. " + "Colliding expressions: '$gender' and '$userGender'. " + "Add explicit base names with the 'phname' attribute."); } @Test public void testMaxThreeGenders() { String soyCode = "" + "{@param userGender : ?}\n" + "{@param targetGender1 : ?}\n" + "{@param targetGender2 : ?}\n" + "{@param groupOwnerGender : ?}\n" + "{@param targetName1 : ?}\n" + "{@param targetName2 : ?}\n" + "{@param groupOwnerName : ?}\n" + "{msg genders=\"$userGender, $targetGender1, $targetGender2, $groupOwnerGender\"" + " desc=\"...\"}\n" + " You added {$targetName1} and {$targetName2} to {$groupOwnerName}'s group.\n" + "{/msg}\n"; FormattingErrorReporter errorReporter = new FormattingErrorReporter(); SoyFileSetParserBuilder.forTemplateContents(soyCode).errorReporter(errorReporter).parse(); assertThat(errorReporter.getErrorMessages()) .containsExactly("Attribute 'genders' does not contain 1-3 expressions"); } @Test public void testMaxTwoGendersWithPlural() { String soyCode = "" + "{@param userGender : ?}\n" + "{@param gender1 : ?}\n" + "{@param gender2 : ?}\n" + "{@param name1 : ?}\n" + "{@param name2 : ?}\n" + "{msg genders=\"$userGender, $gender1, $gender2\" desc=\"\"}\n" + " {plural $numPhotos}\n" + " {case 1}Find {$name1}'s face in {$name2}'s photo\n" + " {default}Find {$name1}'s face in {$name2}'s photos\n" + " {/plural}\n" + "{/msg}\n"; FormattingErrorReporter errorReporter = new FormattingErrorReporter(); SoyFileSetParserBuilder.forTemplateContents(soyCode) .errorReporter(errorReporter) .parse() .fileSet(); assertThat(errorReporter.getErrorMessages()) .contains( "In a msg with 'plural', the 'genders' attribute can contain at most 2 expressions" + " (otherwise, combinatorial explosion would cause a gigantic generated" + " message)."); } @Test public void testRewriteSimple() { String soyCode = "" + "{@param userGender : ?}\n" + "{msg genders=\"$userGender\" desc=\"Button text.\"}\n" + " Save\n" + "{/msg}\n"; ErrorReporter boom = ExplodingErrorReporter.get(); SoyFileSetNode soyTree = SoyFileSetParserBuilder.forTemplateContents(soyCode).errorReporter(boom).parse().fileSet(); // After. MsgNode msgAfterRewrite = (MsgNode) SharedTestUtils.getNode(soyTree, 0, 0); assertEquals( // Note: Still has genders="..." in command text. "{msg genders=\"$userGender\" desc=\"Button text.\"}" + "{select $userGender}{case 'female'}Save{case 'male'}Save{default}Save{/select}", msgAfterRewrite.toSourceString()); // ------ Test that it has same msg id as equivalent msg using 'select'. ------ String soyCodeUsingSelect = "" + "{@param userGender : ?}\n" + "{msg desc=\"Button text.\"}\n" + " {select $userGender}\n" + " {case 'female'}Save\n" + " {case 'male'}Save\n" + " {default}Save\n" + " {/select}\n" + "{/msg}\n"; SoyFileSetNode soyTreeUsingSelect = SoyFileSetParserBuilder.forTemplateContents(soyCodeUsingSelect).parse().fileSet(); MsgNode msgUsingSelect = (MsgNode) SharedTestUtils.getNode(soyTreeUsingSelect, 0, 0); assertThat(MsgUtils.computeMsgIdForDualFormat(msgAfterRewrite)) .isEqualTo(MsgUtils.computeMsgIdForDualFormat(msgUsingSelect)); } @Test public void testRewriteWithPlural() { String soyCode = "" + "{@param num : ?}\n" + "{@param userGender : ?}\n" + "{msg genders=\"$userGender\" desc=\"...\"}\n" + " {plural $num}{case 1}Send it{default}Send {$num}{/plural}\n" + "{/msg}\n"; ErrorReporter boom = ExplodingErrorReporter.get(); SoyFileSetNode soyTree = SoyFileSetParserBuilder.forTemplateContents(soyCode).errorReporter(boom).parse().fileSet(); // After. MsgNode msgAfterRewrite = (MsgNode) SharedTestUtils.getNode(soyTree, 0, 0); assertEquals( // Note: Still has genders="..." in command text. "{msg genders=\"$userGender\" desc=\"...\"}" + "{select $userGender}" + "{case 'female'}{plural $num}{case 1}Send it{default}Send {$num}{/plural}" + "{case 'male'}{plural $num}{case 1}Send it{default}Send {$num}{/plural}" + "{default}{plural $num}{case 1}Send it{default}Send {$num}{/plural}" + "{/select}", msgAfterRewrite.toSourceString()); // ------ Test that it has same msg id as equivalent msg using 'select'. ------ String soyCodeUsingSelect = "" + "{@param num : ?}\n" + "{@param userGender : ?}\n" + "{msg desc=\"...\"}\n" + " {select $userGender}\n" + " {case 'female'}{plural $num}{case 1}Send it{default}Send {$num}{/plural}\n" + " {case 'male'}{plural $num}{case 1}Send it{default}Send {$num}{/plural}\n" + " {default}{plural $num}{case 1}Send it{default}Send {$num}{/plural}\n" + " {/select}\n" + "{/msg}\n"; SoyFileSetNode soyTreeUsingSelect = SoyFileSetParserBuilder.forTemplateContents(soyCodeUsingSelect).parse().fileSet(); MsgNode msgUsingSelect = (MsgNode) SharedTestUtils.getNode(soyTreeUsingSelect, 0, 0); assertThat(MsgUtils.computeMsgIdForDualFormat(msgAfterRewrite)) .isEqualTo(MsgUtils.computeMsgIdForDualFormat(msgUsingSelect)); } @Test public void testRewriteWithThreeGendersAndNoncollidingSelectVarNames() { String soyCode = "" + "{@param target : ?}\n" + "{msg genders=\"$ij.userGender, $target[0].gender, $target[1].gender\" " + "desc=\"...\"}\n" + " You starred {$target[0].name}'s photo in {$target[1].name}'s album.\n" + "{/msg}\n"; ErrorReporter boom = ExplodingErrorReporter.get(); SoyFileSetNode soyTree = SoyFileSetParserBuilder.forTemplateContents(soyCode).errorReporter(boom).parse().fileSet(); // After. MsgNode msgAfterRewrite = (MsgNode) SharedTestUtils.getNode(soyTree, 0, 0); String expectedInnerSelectSrc = "" + "{select $target[1].gender phname=\"TARGET_1_GENDER\"}" + "{case 'female'}You starred {$target[0].name}'s photo in {$target[1].name}'s album." + "{case 'male'}You starred {$target[0].name}'s photo in {$target[1].name}'s album." + "{default}You starred {$target[0].name}'s photo in {$target[1].name}'s album." + "{/select}"; String expectedMsgSrc = "" + // Note: Still has genders="..." in command text. "{msg genders=\"$ij.userGender, $target[0].gender, $target[1].gender\" desc=\"...\"}" + "{select $ij.userGender}" + // note: 'phname' not specified because generated is same "{case 'female'}" + "{select $target[0].gender phname=\"TARGET_0_GENDER\"}" + "{case 'female'}" + expectedInnerSelectSrc + "{case 'male'}" + expectedInnerSelectSrc + "{default}" + expectedInnerSelectSrc + "{/select}" + "{case 'male'}" + "{select $target[0].gender phname=\"TARGET_0_GENDER\"}" + "{case 'female'}" + expectedInnerSelectSrc + "{case 'male'}" + expectedInnerSelectSrc + "{default}" + expectedInnerSelectSrc + "{/select}" + "{default}" + "{select $target[0].gender phname=\"TARGET_0_GENDER\"}" + "{case 'female'}" + expectedInnerSelectSrc + "{case 'male'}" + expectedInnerSelectSrc + "{default}" + expectedInnerSelectSrc + "{/select}" + "{/select}"; assertThat(msgAfterRewrite.toSourceString()).isEqualTo(expectedMsgSrc); } }