/*
* Copyright 2012-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 com.facebook.buck.android.aapt.RDotTxtEntry.IdType.INT;
import static com.facebook.buck.android.aapt.RDotTxtEntry.IdType.INT_ARRAY;
import static com.facebook.buck.android.aapt.RDotTxtEntry.RType.ATTR;
import static com.facebook.buck.android.aapt.RDotTxtEntry.RType.ID;
import static com.facebook.buck.android.aapt.RDotTxtEntry.RType.STYLEABLE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertThat;
import com.facebook.buck.android.MergeAndroidResourcesStep.DuplicateResourceException;
import com.facebook.buck.android.aapt.FakeRDotTxtEntryWithID;
import com.facebook.buck.android.aapt.RDotTxtEntry;
import com.facebook.buck.android.aapt.RDotTxtEntry.RType;
import com.facebook.buck.model.BuildTarget;
import com.facebook.buck.model.BuildTargetFactory;
import com.facebook.buck.model.BuildTargets;
import com.facebook.buck.rules.BuildRuleResolver;
import com.facebook.buck.rules.DefaultTargetNodeToBuildRuleTransformer;
import com.facebook.buck.rules.FakeSourcePath;
import com.facebook.buck.rules.SourcePathResolver;
import com.facebook.buck.rules.SourcePathRuleFinder;
import com.facebook.buck.rules.TargetGraph;
import com.facebook.buck.step.ExecutionContext;
import com.facebook.buck.step.StepExecutionResult;
import com.facebook.buck.step.TestExecutionContext;
import com.facebook.buck.testutil.FakeProjectFilesystem;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;
import com.google.common.collect.SortedSetMultimap;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.SortedSet;
import java.util.stream.IntStream;
import org.hamcrest.CoreMatchers;
import org.hamcrest.Matchers;
import org.hamcrest.core.StringContains;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
public class MergeAndroidResourcesStepTest {
@Rule public ExpectedException thrown = ExpectedException.none();
@Test
public void testGenerateRDotJavaForMultipleSymbolsFiles()
throws IOException, DuplicateResourceException {
RDotTxtEntryBuilder entriesBuilder = new RDotTxtEntryBuilder();
// Merge everything into the same package space.
String sharedPackageName = "com.facebook.abc";
entriesBuilder.add(
new RDotTxtFile(
sharedPackageName,
"a-R.txt",
ImmutableList.of(
"int id a1 0x7f010001", "int id a2 0x7f010002", "int string a1 0x7f020001")));
entriesBuilder.add(
new RDotTxtFile(
sharedPackageName,
"b-R.txt",
ImmutableList.of(
"int id b1 0x7f010001", "int id b2 0x7f010002", "int string a1 0x7f020001")));
entriesBuilder.add(
new RDotTxtFile(
sharedPackageName,
"c-R.txt",
ImmutableList.of("int attr c1 0x7f010001", "int[] styleable c1 { 0x7f010001 }")));
SortedSetMultimap<String, RDotTxtEntry> packageNameToResources =
MergeAndroidResourcesStep.sortSymbols(
entriesBuilder.buildFilePathToPackageNameSet(),
Optional.empty(),
ImmutableMap.of(),
/* bannedDuplicateResourceTypes */ EnumSet.noneOf(RType.class),
entriesBuilder.getProjectFilesystem(),
false);
assertEquals(1, packageNameToResources.keySet().size());
SortedSet<RDotTxtEntry> resources = packageNameToResources.get(sharedPackageName);
assertEquals(7, resources.size());
Set<String> uniqueEntries = Sets.newHashSet();
for (RDotTxtEntry resource : resources) {
if (!resource.type.equals(STYLEABLE)) {
assertFalse(
"Duplicate ids should be fixed by renumerate=true; duplicate was: " + resource.idValue,
uniqueEntries.contains(resource.idValue));
uniqueEntries.add(resource.idValue);
}
}
assertEquals(6, uniqueEntries.size());
// All good, no need to further test whether we can write the Java file correctly...
}
@Test
public void testGenerateRDotJavaForWithStyleables()
throws IOException, DuplicateResourceException {
RDotTxtEntryBuilder entriesBuilder = new RDotTxtEntryBuilder();
// Merge everything into the same package space.
String sharedPackageName = "com.facebook.abc";
entriesBuilder.add(
new RDotTxtFile(
sharedPackageName,
"a-R.txt",
ImmutableList.of(
"int attr buttonPanelSideLayout 0x7f01003a",
"int attr listLayout 0x7f01003b",
"int[] styleable AlertDialog { 0x7f01003a, 0x7f01003b, 0x010100f2 }",
"int styleable AlertDialog_android_layout 2",
"int styleable AlertDialog_buttonPanelSideLayout 0",
"int styleable AlertDialog_multiChoiceItemLayout 1")));
entriesBuilder.add(
new RDotTxtFile(
sharedPackageName,
"b-R.txt",
ImmutableList.of(
"int id a1 0x7f010001",
"int id a2 0x7f010002",
"int attr android_layout_gravity 0x7f078008",
"int attr background 0x7f078009",
"int attr backgroundSplit 0x7f078008",
"int attr backgroundStacked 0x7f078010",
"int attr layout_heightPercent 0x7f078012",
"int[] styleable ActionBar { }",
"int styleable ActionBar_background 10",
"int styleable ActionBar_backgroundSplit 12",
"int styleable ActionBar_backgroundStacked 11",
"int[] styleable ActionBarLayout { 0x7f060008 }",
"int styleable ActionBarLayout_android_layout 0",
"int styleable ActionBarLayout_android_layout_gravity 1",
"int[] styleable PercentLayout_Layout { }",
"int styleable PercentLayout_Layout_layout_aspectRatio 9",
"int styleable PercentLayout_Layout_layout_heightPercent 1")));
SortedSetMultimap<String, RDotTxtEntry> packageNameToResources =
MergeAndroidResourcesStep.sortSymbols(
entriesBuilder.buildFilePathToPackageNameSet(),
Optional.empty(),
ImmutableMap.of(),
/* bannedDuplicateResourceTypes */ EnumSet.noneOf(RType.class),
entriesBuilder.getProjectFilesystem(),
false);
assertEquals(23, packageNameToResources.size());
ArrayList<RDotTxtEntry> resources =
new ArrayList<>(packageNameToResources.get(sharedPackageName));
assertEquals(23, resources.size());
System.out.println(resources);
ImmutableList<FakeRDotTxtEntryWithID> fakeRDotTxtEntryWithIDS =
ImmutableList.of(
new FakeRDotTxtEntryWithID(INT, ATTR, "android_layout_gravity", "0x07f01005"),
new FakeRDotTxtEntryWithID(INT, ATTR, "background", "0x07f01006"),
new FakeRDotTxtEntryWithID(INT, ATTR, "backgroundSplit", "0x07f01007"),
new FakeRDotTxtEntryWithID(INT, ATTR, "backgroundStacked", "0x07f01008"),
new FakeRDotTxtEntryWithID(INT, ATTR, "buttonPanelSideLayout", "0x07f01001"),
new FakeRDotTxtEntryWithID(INT, ATTR, "layout_heightPercent", "0x07f01009"),
new FakeRDotTxtEntryWithID(INT, ATTR, "listLayout", "0x07f01002"),
new FakeRDotTxtEntryWithID(INT, ID, "a1", "0x07f01003"),
new FakeRDotTxtEntryWithID(INT, ID, "a2", "0x07f01004"),
new FakeRDotTxtEntryWithID(
INT_ARRAY, STYLEABLE, "ActionBar", "{ 0x07f01006,0x07f01007,0x07f01008 }"),
new FakeRDotTxtEntryWithID(INT, STYLEABLE, "ActionBar_background", "0"),
new FakeRDotTxtEntryWithID(INT, STYLEABLE, "ActionBar_backgroundSplit", "1"),
new FakeRDotTxtEntryWithID(INT, STYLEABLE, "ActionBar_backgroundStacked", "2"),
new FakeRDotTxtEntryWithID(
INT_ARRAY, STYLEABLE, "ActionBarLayout", "{ 0x010100f2,0x07f01005 }"),
new FakeRDotTxtEntryWithID(INT, STYLEABLE, "ActionBarLayout_android_layout", "0"),
new FakeRDotTxtEntryWithID(
INT, STYLEABLE, "ActionBarLayout_android_layout_gravity", "1"),
new FakeRDotTxtEntryWithID(
INT_ARRAY, STYLEABLE, "AlertDialog", "{ 0x010100f2,0x07f01001,0x7f01003b }"),
new FakeRDotTxtEntryWithID(INT, STYLEABLE, "AlertDialog_android_layout", "0"),
new FakeRDotTxtEntryWithID(INT, STYLEABLE, "AlertDialog_buttonPanelSideLayout", "1"),
new FakeRDotTxtEntryWithID(INT, STYLEABLE, "AlertDialog_multiChoiceItemLayout", "2"),
new FakeRDotTxtEntryWithID(
INT_ARRAY, STYLEABLE, "PercentLayout_Layout", "{ 0,0x07f01009 }"),
new FakeRDotTxtEntryWithID(
INT, STYLEABLE, "PercentLayout_Layout_layout_aspectRatio", "0"),
new FakeRDotTxtEntryWithID(
INT, STYLEABLE, "PercentLayout_Layout_layout_heightPercent", "1"));
IntStream.range(0, resources.size())
.forEach(
action -> {
assertEquals(fakeRDotTxtEntryWithIDS.get(action), resources.get(action));
});
}
@Test
public void testGenerateRDotJavaForMultipleSymbolsFilesWithDuplicates()
throws IOException, DuplicateResourceException {
RDotTxtEntryBuilder entriesBuilder = new RDotTxtEntryBuilder();
// Merge everything into the same package space.
String sharedPackageName = "com.facebook.abc";
entriesBuilder.add(
new RDotTxtFile(
sharedPackageName,
"a-R.txt",
ImmutableList.of("int id a1 0x7f010001", "int string a1 0x7f020001")));
entriesBuilder.add(
new RDotTxtFile(
sharedPackageName,
"b-R.txt",
ImmutableList.of(
"int id a1 0x7f010001", "int string a1 0x7f010002", "int string c1 0x7f010003")));
entriesBuilder.add(
new RDotTxtFile(
sharedPackageName,
"c-R.txt",
ImmutableList.of(
"int id a1 0x7f010001",
"int string a1 0x7f010002",
"int string b1 0x7f010003",
"int string c1 0x7f010004")));
thrown.expect(DuplicateResourceException.class);
thrown.expectMessage("Resource 'a1' (string) is duplicated across: ");
thrown.expectMessage("Resource 'c1' (string) is duplicated across: ");
BuildTarget resTarget = BuildTargetFactory.newInstance("//:res1");
SourcePathRuleFinder ruleFinder =
new SourcePathRuleFinder(
new BuildRuleResolver(
TargetGraph.EMPTY, new DefaultTargetNodeToBuildRuleTransformer()));
MergeAndroidResourcesStep.sortSymbols(
entriesBuilder.buildFilePathToPackageNameSet(),
Optional.empty(),
ImmutableMap.of(
entriesBuilder.getProjectFilesystem().getPath("a-R.txt"),
(HasAndroidResourceDeps)
AndroidResourceRuleBuilder.newBuilder()
.setRuleFinder(ruleFinder)
.setBuildTarget(resTarget)
.setRes(new FakeSourcePath("a/res"))
.setRDotJavaPackage("com.res.a")
.build(),
entriesBuilder.getProjectFilesystem().getPath("b-R.txt"),
(HasAndroidResourceDeps)
AndroidResourceRuleBuilder.newBuilder()
.setRuleFinder(ruleFinder)
.setBuildTarget(resTarget)
.setRes(new FakeSourcePath("b/res"))
.setRDotJavaPackage("com.res.b")
.build(),
entriesBuilder.getProjectFilesystem().getPath("c-R.txt"),
(HasAndroidResourceDeps)
AndroidResourceRuleBuilder.newBuilder()
.setRuleFinder(ruleFinder)
.setBuildTarget(resTarget)
.setRes(new FakeSourcePath("c/res"))
.setRDotJavaPackage("com.res.c")
.build()),
/* bannedDuplicateResourceTypes */ EnumSet.of(RType.STRING),
entriesBuilder.getProjectFilesystem(),
false);
}
@Test
public void testGenerateRDotJavaForLibrary() throws IOException {
BuildTarget resTarget = BuildTargetFactory.newInstance("//:res1");
RDotTxtEntryBuilder entriesBuilder = new RDotTxtEntryBuilder();
entriesBuilder.add(
new RDotTxtFile(
"com.res1",
BuildTargets.getGenPath(
entriesBuilder.getProjectFilesystem(), resTarget, "__%s_text_symbols__/R.txt")
.toString(),
ImmutableList.of("int id id1 0x7f020000")));
FakeProjectFilesystem filesystem = entriesBuilder.getProjectFilesystem();
BuildRuleResolver buildRuleResolver =
new BuildRuleResolver(TargetGraph.EMPTY, new DefaultTargetNodeToBuildRuleTransformer());
SourcePathRuleFinder ruleFinder = new SourcePathRuleFinder(buildRuleResolver);
SourcePathResolver resolver = new SourcePathResolver(ruleFinder);
AndroidResource res =
AndroidResourceRuleBuilder.newBuilder()
.setRuleFinder(ruleFinder)
.setBuildTarget(resTarget)
.setRes(new FakeSourcePath("res"))
.setRDotJavaPackage("com.res1")
.build();
buildRuleResolver.addToIndex(res);
MergeAndroidResourcesStep mergeStep =
MergeAndroidResourcesStep.createStepForDummyRDotJava(
filesystem,
resolver,
ImmutableList.of(res),
Paths.get("output"),
/* forceFinalResourceIds */ false,
/* unionPackage */ Optional.empty(),
/* rName */ Optional.empty(),
/* useOldStyleableFormat */ false);
ExecutionContext executionContext = TestExecutionContext.newInstance();
assertEquals(0, mergeStep.execute(executionContext).getExitCode());
// Verify that the correct Java code is generated.
assertThat(
filesystem.readFileIfItExists(Paths.get("output/com/res1/R.java")).get(),
CoreMatchers.containsString("{\n public static int id1=0x07f01001;"));
}
@Test
public void testGenerateRDotJavaForOneSymbolsFile() throws IOException {
BuildTarget target = BuildTargetFactory.newInstance("//android_res/com/facebook/http:res");
RDotTxtEntryBuilder entriesBuilder = new RDotTxtEntryBuilder();
String symbolsFile =
BuildTargets.getGenPath(
entriesBuilder.getProjectFilesystem(), target, "__%s_text_symbols__/R.txt")
.toString();
String rDotJavaPackage = "com.facebook";
final ImmutableList<String> outputTextSymbols =
ImmutableList.<String>builder()
.add("int id placeholder 0x7f020000")
.add("int string debug_http_proxy_dialog_title 0x7f030004")
.add("int string debug_http_proxy_hint 0x7f030005")
.add("int string debug_http_proxy_summary 0x7f030003")
.add("int string debug_http_proxy_title 0x7f030002")
.add("int string debug_ssl_cert_check_summary 0x7f030001")
.add("int string debug_ssl_cert_check_title 0x7f030000")
.add("int styleable SherlockMenuItem_android_visible 4")
.add(
"int[] styleable SherlockMenuView { 0x7f010026, 0x7f010027, 0x7f010028, 0x7f010029, "
+ "0x7f01002a, 0x7f01002b, 0x7f01002c, 0x7f01002d }")
.build();
entriesBuilder.add(new RDotTxtFile(rDotJavaPackage, symbolsFile, outputTextSymbols));
FakeProjectFilesystem filesystem = entriesBuilder.getProjectFilesystem();
Path uberRDotTxt = filesystem.resolve("R.txt").toAbsolutePath();
filesystem.writeLinesToPath(outputTextSymbols, uberRDotTxt);
BuildRuleResolver buildRuleResolver =
new BuildRuleResolver(TargetGraph.EMPTY, new DefaultTargetNodeToBuildRuleTransformer());
SourcePathRuleFinder ruleFinder = new SourcePathRuleFinder(buildRuleResolver);
SourcePathResolver resolver = new SourcePathResolver(ruleFinder);
AndroidResource resource =
AndroidResourceRuleBuilder.newBuilder()
.setRuleFinder(ruleFinder)
.setBuildTarget(target)
.setRes(new FakeSourcePath("res"))
.setRDotJavaPackage("com.facebook")
.build();
buildRuleResolver.addToIndex(resource);
MergeAndroidResourcesStep mergeStep =
new MergeAndroidResourcesStep(
filesystem,
resolver,
ImmutableList.of(resource),
Optional.of(uberRDotTxt),
Paths.get("output"),
/* forceFinalResourceIds */ true,
/* bannedDuplicateResourceTypes */ EnumSet.noneOf(RType.class),
/* unionPackage */ Optional.empty(),
/* rName */ Optional.empty(),
/* useOldStyleableFormat */ false);
ExecutionContext executionContext = TestExecutionContext.newInstance();
assertEquals(0, mergeStep.execute(executionContext).getExitCode());
// Verify that the correct Java code is generated.
assertEquals(
"package com.facebook;\n"
+ "\n"
+ "public class R {\n"
+ " public static class id {\n"
+ " public static final int placeholder=0x7f020000;\n"
+ " }\n"
+ "\n"
+ " public static class string {\n"
+ " public static final int debug_http_proxy_dialog_title=0x7f030004;\n"
+ " public static final int debug_http_proxy_hint=0x7f030005;\n"
+ " public static final int debug_http_proxy_summary=0x7f030003;\n"
+ " public static final int debug_http_proxy_title=0x7f030002;\n"
+ " public static final int debug_ssl_cert_check_summary=0x7f030001;\n"
+ " public static final int debug_ssl_cert_check_title=0x7f030000;\n"
+ " }\n"
+ "\n"
+ " public static class styleable {\n"
+ " public static final int SherlockMenuItem_android_visible=4;\n"
+ " public static final int[] SherlockMenuView={ 0x7f010026, 0x7f010027, 0x7f010028, "
+ "0x7f010029, 0x7f01002a, 0x7f01002b, 0x7f01002c, 0x7f01002d };\n"
+ " }\n"
+ "\n"
+ "}\n",
filesystem
.readFileIfItExists(Paths.get("output/com/facebook/R.java"))
.get()
.replace("\r", ""));
}
@Test
public void testGenerateRDotJavaForCustomDrawables() throws IOException {
BuildTarget target = BuildTargetFactory.newInstance("//android_res/com/facebook/http:res");
RDotTxtEntryBuilder entriesBuilder = new RDotTxtEntryBuilder();
String symbolsFile =
BuildTargets.getGenPath(
entriesBuilder.getProjectFilesystem(), target, "__%s_text_symbols__/R.txt")
.toString();
String rDotJavaPackage = "com.facebook";
final ImmutableList<String> outputTextSymbols =
ImmutableList.<String>builder()
.add("int drawable android_drawable 0x7f010000")
.add("int drawable fb_drawable 0x7f010001 #")
.build();
entriesBuilder.add(new RDotTxtFile(rDotJavaPackage, symbolsFile, outputTextSymbols));
FakeProjectFilesystem filesystem = entriesBuilder.getProjectFilesystem();
Path uberRDotTxt = filesystem.resolve("R.txt").toAbsolutePath();
filesystem.writeLinesToPath(outputTextSymbols, uberRDotTxt);
BuildRuleResolver buildRuleResolver =
new BuildRuleResolver(TargetGraph.EMPTY, new DefaultTargetNodeToBuildRuleTransformer());
SourcePathRuleFinder ruleFinder = new SourcePathRuleFinder(buildRuleResolver);
SourcePathResolver resolver = new SourcePathResolver(ruleFinder);
AndroidResource resource =
AndroidResourceRuleBuilder.newBuilder()
.setRuleFinder(ruleFinder)
.setBuildTarget(target)
.setRes(new FakeSourcePath("res"))
.setRDotJavaPackage("com.facebook")
.build();
buildRuleResolver.addToIndex(resource);
MergeAndroidResourcesStep mergeStep =
new MergeAndroidResourcesStep(
filesystem,
resolver,
ImmutableList.of(resource),
Optional.of(uberRDotTxt),
Paths.get("output"),
/* forceFinalResourceIds */ true,
/* bannedDuplicateResourceTypes */ EnumSet.noneOf(RType.class),
/* unionPackage */ Optional.empty(),
/* rName */ Optional.empty(),
/* useOldStyleableFormat */ false);
ExecutionContext executionContext = TestExecutionContext.newInstance();
assertEquals(0, mergeStep.execute(executionContext).getExitCode());
// Verify that the correct Java code is generated.
assertEquals(
"package com.facebook;\n"
+ "\n"
+ "public class R {\n"
+ " public static class drawable {\n"
+ " public static final int android_drawable=0x7f010000;\n"
+ " public static final int fb_drawable=0x7f010001;\n"
+ " }\n"
+ "\n"
+ " public static final int[] custom_drawables = { 0x7f010001 };\n"
+ "\n"
+ "}\n",
filesystem
.readFileIfItExists(Paths.get("output/com/facebook/R.java"))
.get()
.replace("\r", ""));
}
@Test
public void testGenerateRDotJavaWithResourceUnionPackage() throws IOException {
BuildTarget res1Target = BuildTargetFactory.newInstance("//:res1");
BuildTarget res2Target = BuildTargetFactory.newInstance("//:res2");
RDotTxtEntryBuilder entriesBuilder = new RDotTxtEntryBuilder();
entriesBuilder.add(
new RDotTxtFile(
"com.res1",
BuildTargets.getGenPath(
entriesBuilder.getProjectFilesystem(), res1Target, "__%s_text_symbols__/R.txt")
.toString(),
ImmutableList.of("int id id1 0x7f020000")));
entriesBuilder.add(
new RDotTxtFile(
"com.res2",
BuildTargets.getGenPath(
entriesBuilder.getProjectFilesystem(), res2Target, "__%s_text_symbols__/R.txt")
.toString(),
ImmutableList.of("int id id2 0x7f020000")));
FakeProjectFilesystem filesystem = entriesBuilder.getProjectFilesystem();
BuildRuleResolver buildRuleResolver =
new BuildRuleResolver(TargetGraph.EMPTY, new DefaultTargetNodeToBuildRuleTransformer());
SourcePathRuleFinder ruleFinder = new SourcePathRuleFinder(buildRuleResolver);
SourcePathResolver resolver = new SourcePathResolver(ruleFinder);
AndroidResource res1 =
AndroidResourceRuleBuilder.newBuilder()
.setRuleFinder(ruleFinder)
.setBuildTarget(res1Target)
.setRes(new FakeSourcePath("res1"))
.setRDotJavaPackage("res1")
.build();
buildRuleResolver.addToIndex(res1);
AndroidResource res2 =
AndroidResourceRuleBuilder.newBuilder()
.setRuleFinder(ruleFinder)
.setBuildTarget(res2Target)
.setRes(new FakeSourcePath("res2"))
.setRDotJavaPackage("res2")
.build();
buildRuleResolver.addToIndex(res2);
MergeAndroidResourcesStep mergeStep =
MergeAndroidResourcesStep.createStepForDummyRDotJava(
filesystem,
resolver,
ImmutableList.of(res1, res2),
Paths.get("output"),
/* forceFinalResourceIds */ false,
Optional.of("res1"),
/* rName */ Optional.empty(),
/* useOldStyleableFormat */ false);
ExecutionContext executionContext = TestExecutionContext.newInstance();
assertEquals(0, mergeStep.execute(executionContext).getExitCode());
String res1java = filesystem.readFileIfItExists(Paths.get("output/res1/R.java")).get();
String res2java = filesystem.readFileIfItExists(Paths.get("output/res2/R.java")).get();
assertThat(res1java, StringContains.containsString("id1"));
assertThat(res1java, StringContains.containsString("id2"));
assertThat(res2java, CoreMatchers.not(StringContains.containsString("id1")));
assertThat(res2java, StringContains.containsString("id2"));
}
@Test
public void testGenerateRDotJavaWithPreviouslyEmptyResourceUnionPackage() throws IOException {
BuildTarget res1Target = BuildTargetFactory.newInstance("//:res1");
RDotTxtEntryBuilder entriesBuilder = new RDotTxtEntryBuilder();
entriesBuilder.add(
new RDotTxtFile(
"com.res1",
BuildTargets.getGenPath(
entriesBuilder.getProjectFilesystem(), res1Target, "__%s_text_symbols__/R.txt")
.toString(),
ImmutableList.of("int id id1 0x7f020000")));
FakeProjectFilesystem filesystem = entriesBuilder.getProjectFilesystem();
BuildRuleResolver buildRuleResolver =
new BuildRuleResolver(TargetGraph.EMPTY, new DefaultTargetNodeToBuildRuleTransformer());
SourcePathRuleFinder ruleFinder = new SourcePathRuleFinder(buildRuleResolver);
SourcePathResolver resolver = new SourcePathResolver(ruleFinder);
AndroidResource res1 =
AndroidResourceRuleBuilder.newBuilder()
.setRuleFinder(ruleFinder)
.setBuildTarget(res1Target)
.setRes(new FakeSourcePath("res1"))
.setRDotJavaPackage("res1")
.build();
buildRuleResolver.addToIndex(res1);
MergeAndroidResourcesStep mergeStep =
MergeAndroidResourcesStep.createStepForDummyRDotJava(
filesystem,
resolver,
ImmutableList.of(res1),
Paths.get("output"),
/* forceFinalResourceIds */ false,
Optional.of("resM"),
/* rName */ Optional.empty(),
/* useOldStyleableFormat */ false);
ExecutionContext executionContext = TestExecutionContext.newInstance();
assertEquals(0, mergeStep.execute(executionContext).getExitCode());
String res1java = filesystem.readFileIfItExists(Paths.get("output/res1/R.java")).get();
String resMjava = filesystem.readFileIfItExists(Paths.get("output/resM/R.java")).get();
assertThat(res1java, StringContains.containsString("id1"));
assertThat(resMjava, StringContains.containsString("id1"));
}
@Test
public void testGenerateRDotJavaWithRName() throws IOException {
BuildTarget res1Target = BuildTargetFactory.newInstance("//:res1");
RDotTxtEntryBuilder entriesBuilder = new RDotTxtEntryBuilder();
entriesBuilder.add(
new RDotTxtFile(
"com.res1",
BuildTargets.getGenPath(
entriesBuilder.getProjectFilesystem(), res1Target, "__%s_text_symbols__/R.txt")
.toString(),
ImmutableList.of("int id id1 0x7f020000", "int id id2 0x7f020002")));
FakeProjectFilesystem filesystem = entriesBuilder.getProjectFilesystem();
BuildRuleResolver buildRuleResolver =
new BuildRuleResolver(TargetGraph.EMPTY, new DefaultTargetNodeToBuildRuleTransformer());
SourcePathRuleFinder ruleFinder = new SourcePathRuleFinder(buildRuleResolver);
SourcePathResolver resolver = new SourcePathResolver(ruleFinder);
AndroidResource res1 =
AndroidResourceRuleBuilder.newBuilder()
.setRuleFinder(ruleFinder)
.setBuildTarget(res1Target)
.setRes(new FakeSourcePath("res1"))
.setRDotJavaPackage("res1")
.build();
buildRuleResolver.addToIndex(res1);
MergeAndroidResourcesStep mergeStep =
MergeAndroidResourcesStep.createStepForDummyRDotJava(
filesystem,
resolver,
ImmutableList.of(res1),
Paths.get("output"),
/* forceFinalResourceIds */ true,
Optional.of("res1"),
Optional.of("R2"),
/* useOldStyleableFormat */ false);
ExecutionContext executionContext = TestExecutionContext.newInstance();
assertEquals(0, mergeStep.execute(executionContext).getExitCode());
String resR2Java = filesystem.readFileIfItExists(Paths.get("output/res1/R2.java")).get();
assertThat(resR2Java, StringContains.containsString("static final int id1=0x07f01001;"));
assertThat(resR2Java, StringContains.containsString("static final int id2=0x07f01002;"));
}
@Test
public void testDuplicateBanning() throws Exception {
BuildTarget res1Target = BuildTargetFactory.newInstance("//:res1");
BuildTarget res2Target = BuildTargetFactory.newInstance("//:res2");
BuildRuleResolver buildRuleResolver =
new BuildRuleResolver(TargetGraph.EMPTY, new DefaultTargetNodeToBuildRuleTransformer());
SourcePathRuleFinder ruleFinder = new SourcePathRuleFinder(buildRuleResolver);
SourcePathResolver resolver = new SourcePathResolver(ruleFinder);
FakeProjectFilesystem filesystem = new FakeProjectFilesystem();
RDotTxtEntryBuilder entriesBuilder = new RDotTxtEntryBuilder(filesystem);
entriesBuilder.add(
new RDotTxtFile(
"package",
BuildTargets.getGenPath(filesystem, res1Target, "__%s_text_symbols__/R.txt").toString(),
ImmutableList.of(
"int string app_name 0x7f020000", "int drawable android_drawable 0x7f010000")));
entriesBuilder.add(
new RDotTxtFile(
"package",
BuildTargets.getGenPath(filesystem, res2Target, "__%s_text_symbols__/R.txt").toString(),
ImmutableList.of(
"int string app_name 0x7f020000", "int drawable android_drawable 0x7f010000")));
AndroidResource res1 =
AndroidResourceRuleBuilder.newBuilder()
.setRuleFinder(ruleFinder)
.setBuildTarget(res1Target)
.setRes(new FakeSourcePath("res1"))
.setRDotJavaPackage("package")
.build();
buildRuleResolver.addToIndex(res1);
AndroidResource res2 =
AndroidResourceRuleBuilder.newBuilder()
.setRuleFinder(ruleFinder)
.setBuildTarget(res2Target)
.setRes(new FakeSourcePath("res2"))
.setRDotJavaPackage("package")
.build();
buildRuleResolver.addToIndex(res2);
ImmutableList<HasAndroidResourceDeps> resourceDeps = ImmutableList.of(res1, res2);
checkDuplicatesDetected(
resolver,
filesystem,
resourceDeps,
EnumSet.noneOf(RType.class),
ImmutableList.of(),
ImmutableList.of("app_name", "android_drawable"));
checkDuplicatesDetected(
resolver,
filesystem,
resourceDeps,
EnumSet.of(RType.STRING),
ImmutableList.of("app_name"),
ImmutableList.of("android_drawable"));
checkDuplicatesDetected(
resolver,
filesystem,
resourceDeps,
EnumSet.allOf(RType.class),
ImmutableList.of("app_name", "android_drawable"),
ImmutableList.of());
}
private void checkDuplicatesDetected(
SourcePathResolver resolver,
FakeProjectFilesystem filesystem,
ImmutableList<HasAndroidResourceDeps> resourceDeps,
EnumSet<RType> rtypes,
ImmutableList<String> duplicateResources,
ImmutableList<String> ignoredDuplicates) {
MergeAndroidResourcesStep mergeStep =
new MergeAndroidResourcesStep(
filesystem,
resolver,
resourceDeps,
/* uberRDotTxt */ Optional.empty(),
Paths.get("output"),
true,
rtypes,
Optional.empty(),
Optional.empty(),
/* useOldStyleableFormat */ false);
StepExecutionResult result = mergeStep.execute(TestExecutionContext.newInstance());
String message = result.getStderr().orElse("");
if (duplicateResources.isEmpty()) {
assertEquals(0, result.getExitCode());
} else {
assertNotEquals(0, result.getExitCode());
assertThat(message, Matchers.containsString("duplicated"));
}
for (String duplicateResource : duplicateResources) {
assertThat(message, Matchers.containsString(duplicateResource));
}
for (String ignoredDuplicate : ignoredDuplicates) {
assertThat(message, Matchers.not(Matchers.containsString(ignoredDuplicate)));
}
}
// sortSymbols has a goofy API. This will help.
private static class RDotTxtEntryBuilder {
private final FakeProjectFilesystem filesystem;
private final ImmutableMap.Builder<Path, String> filePathToPackageName = ImmutableMap.builder();
RDotTxtEntryBuilder() {
this(new FakeProjectFilesystem());
}
RDotTxtEntryBuilder(FakeProjectFilesystem filesystem) {
this.filesystem = filesystem;
}
public void add(RDotTxtFile entry) throws IOException {
filesystem.writeLinesToPath(entry.contents, entry.filePath);
filePathToPackageName.put(entry.filePath, entry.packageName);
}
Map<Path, String> buildFilePathToPackageNameSet() {
return filePathToPackageName.build();
}
public FakeProjectFilesystem getProjectFilesystem() {
return filesystem;
}
}
static class RDotTxtFile {
public ImmutableList<String> contents;
String packageName;
Path filePath;
RDotTxtFile(String packageName, String filePath, ImmutableList<String> contents) {
this.packageName = packageName;
this.filePath = Paths.get(filePath);
this.contents = contents;
}
}
}