blob: a930e0715da1e628e06e248a7e4b0a9237d27d83 [file] [log] [blame]
/*
* Copyright 2013-present Facebook, 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.facebook.buck.android;
import static org.easymock.EasyMock.anyObject;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.expectLastCall;
import static org.easymock.EasyMock.getCurrentArguments;
import static org.junit.Assert.assertEquals;
import com.facebook.buck.step.ExecutionContext;
import com.facebook.buck.util.ProjectFilesystem;
import com.facebook.buck.util.XmlDomParser;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
import org.easymock.EasyMockSupport;
import org.easymock.IAnswer;
import org.junit.Test;
import org.w3c.dom.NodeList;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
public class CompileStringsStepTest extends EasyMockSupport {
private static final String XML_HEADER = "<?xml version='1.0' encoding='utf-8'?>";
private static final String TESTDATA_DIR = "testdata/com/facebook/buck/android/";
private static final String FIRST_FILE = TESTDATA_DIR + "first/res/values-es/strings.xml";
private static final String SECOND_FILE = TESTDATA_DIR + "second/res/values-es/strings.xml";
private static final String THIRD_FILE = TESTDATA_DIR + "third/res/values-pt/strings.xml";
private static final String FOURTH_FILE = TESTDATA_DIR + "third/res/values-pt-rBR/strings.xml";
@Test
public void testStringFilePattern() {
testStringPathRegex("res/values-es/strings.xml", true, "es", null);
testStringPathRegex("/one/res/values-es/strings.xml", true, "es", null);
testStringPathRegex("/two/res/values-es-rUS/strings.xml", true, "es", "US");
// Not matching strings.
testStringPathRegex("/one/res/values/strings.xml", false, null, null);
testStringPathRegex("/one/res/values-/strings.xml", false, null, null);
testStringPathRegex("/one/res/values-e/strings.xml", false, null, null);
testStringPathRegex("/one/res/values-esc/strings.xml", false, null, null);
testStringPathRegex("/one/res/values-es-rU/strings.xml", false, null, null);
testStringPathRegex("/one/res/values-es-rUSA/strings.xml", false, null, null);
testStringPathRegex("/one/res/values-es-RUS/strings.xml", false, null, null);
testStringPathRegex("/one/res/values-rUS/strings.xml", false, null, null);
}
private void testStringPathRegex(String input, boolean matches, String locale, String country) {
Matcher matcher = CompileStringsStep.STRING_FILE_PATTERN.matcher(input);
assertEquals(matches, matcher.matches());
if (!matches) {
return;
}
assertEquals(locale, matcher.group(1));
assertEquals(country, matcher.group(2));
}
@Test
public void testGroupFilesByLocale() {
ImmutableSet<String> files = ImmutableSet.of(
"/project/dir/res/values-da/strings.xml",
"/project/dir/res/values-da-rAB/strings.xml",
"/project/dir/dontmatch/res/values/strings.xml",
"/project/groupme/res/values-da/strings.xml",
"/project/groupmetoo/res/values-da-rAB/strings.xml",
"/project/foreveralone/res/values-es/strings.xml"
);
ImmutableMultimap<String, String> groupedByLocale =
createNonExecutingStep().groupFilesByLocale(files);
ImmutableMultimap<String, String> expectedMap =
ImmutableMultimap.<String, String>builder()
.putAll("da", ImmutableSet.<String>of(
"/project/dir/res/values-da/strings.xml",
"/project/groupme/res/values-da/strings.xml"))
.putAll("da_AB", ImmutableSet.<String>of(
"/project/dir/res/values-da-rAB/strings.xml",
"/project/groupmetoo/res/values-da-rAB/strings.xml"))
.putAll("es", ImmutableSet.<String>of("/project/foreveralone/res/values-es/strings.xml"))
.build();
assertEquals(expectedMap, groupedByLocale);
}
@Test
public void testScrapeStringNodes() throws IOException {
String xmlInput =
"<string name='name1'>Value1</string>" +
"<string name='name2'>Value with space</string>" +
"<string name='name3'>Value with \"quotes\"</string>" +
"<string name='name4'></string>" +
"<string name='name3'>IGNORE</string>" + // ignored because "name3" already found
"<string name='name5'>Value with %1$s</string>";
NodeList stringNodes = XmlDomParser.parse(createResourcesXml(xmlInput))
.getElementsByTagName("string");
Map<String, String> stringsMap = new HashMap<>();
createNonExecutingStep().scrapeStringNodes(stringNodes, stringsMap);
assertEquals(
ImmutableMap.of(
"name1", "Value1",
"name2", "Value with space",
"name3", "Value with \"quotes\"",
"name4", "",
"name5", "Value with %1$s"),
stringsMap
);
}
@Test
public void testScrapePluralsNodes() throws IOException {
String xmlInput =
"<plurals name='name1'>" +
"<item quantity='zero'>%d people saw this</item>" +
"<item quantity='one'>%d person saw this</item>" +
"<item quantity='many'>%d people saw this</item>" +
"</plurals>" +
"<plurals name='name2'>" +
"<item quantity='zero'>%d people ate this</item>" +
"<item quantity='many'>%d people ate this</item>" +
"</plurals>" +
"<plurals name='name3'></plurals>" + // Test empty array.
"<plurals name='name2'></plurals>"; // Ignored since "name2" already found.
NodeList pluralsNodes = XmlDomParser.parse(createResourcesXml(xmlInput))
.getElementsByTagName("plurals");
Map<String, ImmutableMap<String, String>> pluralsMap = new HashMap<>();
createNonExecutingStep().scrapePluralsNodes(pluralsNodes, pluralsMap);
assertEquals(
ImmutableMap.of(
"name1", ImmutableMap.of(
"zero", "%d people saw this",
"one", "%d person saw this",
"many", "%d people saw this"),
"name2", ImmutableMap.of(
"zero", "%d people ate this",
"many", "%d people ate this"),
"name3", ImmutableMap.of()
),
pluralsMap
);
}
@Test
public void testScrapeStringArrayNodes() throws IOException {
String xmlInput =
"<string-array name='name1'>" +
"<item>Value11</item>" +
"<item>Value12</item>" +
"</string-array>" +
"<string-array name='name2'>" +
"<item>Value21</item>" +
"</string-array>" +
"<string-array name='name3'></string-array>" +
"<string-array name='name2'>" +
"<item>ignored</item>" + // Ignored because "name2" already found above.
"</string-array>";
NodeList arrayNodes = XmlDomParser.parse(createResourcesXml(xmlInput))
.getElementsByTagName("string-array");
Multimap<String, String> arraysMap = ArrayListMultimap.create();
createNonExecutingStep().scrapeStringArrayNodes(arrayNodes, arraysMap);
assertEquals(
ImmutableMultimap.builder()
.put("name1", "Value11")
.put("name1", "Value12")
.put("name2", "Value21")
.build(),
arraysMap
);
}
private CompileStringsStep createNonExecutingStep() {
return new CompileStringsStep(
createMock(FilterResourcesStep.class),
createMock(Path.class),
createMock(ObjectMapper.class));
}
private String createResourcesXml(String contents) {
return XML_HEADER + "<resources>" + contents + "</resources>";
}
@Test
public void testSuccessfulStepExecution() throws IOException {
Path destinationDir = Paths.get("");
ExecutionContext context = createMock(ExecutionContext.class);
ProjectFilesystem filesystem = createMock(ProjectFilesystem.class);
expect(filesystem.getFileForRelativePath(anyObject(Path.class))).andAnswer(new IAnswer<File>() {
@Override
public File answer() throws Throwable {
return ((Path)getCurrentArguments()[0]).toFile();
}
}).times(3);
expect(context.getProjectFilesystem()).andReturn(filesystem);
ObjectMapper mapper = createMock(ObjectMapper.class);
mapper.writeValue(anyObject(File.class), anyObject());
final ImmutableMap.Builder<String, ImmutableMap<String, Object>> capturedResourcesBuilder =
ImmutableMap.builder();
expectLastCall().andAnswer(new IAnswer<Object>() {
@Override
public Object answer() throws Throwable {
File file = (File)getCurrentArguments()[0];
capturedResourcesBuilder.put(file.getName(), getMapFromArgs());
return null;
}
@SuppressWarnings("unchecked")
private ImmutableMap<String, Object> getMapFromArgs() {
return (ImmutableMap<String, Object>) getCurrentArguments()[1];
}
}).times(3);
FilterResourcesStep filterResourcesStep = createMock(FilterResourcesStep.class);
expect(filterResourcesStep.getNonEnglishStringFiles()).andReturn(ImmutableSet.of(
FIRST_FILE,
SECOND_FILE,
THIRD_FILE,
FOURTH_FILE));
replayAll();
CompileStringsStep step = new CompileStringsStep(filterResourcesStep, destinationDir, mapper);
assertEquals(0, step.execute(context));
assertEquals(
ImmutableMap.of(
"es.json", ImmutableMap.of(
"name1_1", "Value11",
"name1_2", "Value12",
"name1_3", "Value13",
"name2_1", "Value21",
"name2_2", "Value22"),
"pt.json", ImmutableMap.of(
"name3_1", "Value31",
"name3_2", "Value32",
"name3_3", "Value33"),
"pt_BR.json", ImmutableMap.of(
"name3_1", "Value311",
"name3_2", "Value32",
"name3_3", "Value33")
),
capturedResourcesBuilder.build());
verifyAll();
}
}