| /* |
| * 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 org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| |
| import com.facebook.buck.android.MergeAndroidResourcesStep.Resource; |
| import com.facebook.buck.util.BuckConstant; |
| import com.google.common.base.Function; |
| import com.google.common.collect.ImmutableMap; |
| import com.google.common.collect.Sets; |
| import com.google.common.collect.SortedSetMultimap; |
| |
| import org.junit.Test; |
| |
| import java.io.IOException; |
| import java.io.StringReader; |
| import java.util.Iterator; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.SortedSet; |
| |
| public class MergeAndroidResourcesStepTest { |
| @Test |
| public void testGenerateRDotJavaForMultipleSymbolsFiles() throws IOException { |
| RDotTxtEntryBuilder entriesBuilder = new RDotTxtEntryBuilder(); |
| |
| // Merge everything into the same package space. |
| String sharedPackageName = "com.facebook.abc"; |
| entriesBuilder.add(new RDotTxtEntry(sharedPackageName, "a-R.txt", |
| "int id a1 0x7f010001\n" + |
| "int id a2 0x7f010002\n" + |
| "int string a1 0x7f020001\n")); |
| |
| entriesBuilder.add(new RDotTxtEntry(sharedPackageName, "b-R.txt", |
| "int id b1 0x7f010001\n" + |
| "int id b2 0x7f010002\n")); |
| |
| entriesBuilder.add(new RDotTxtEntry(sharedPackageName, "c-R.txt", |
| "int attr c1 0x7f010001\n" + |
| "int[] styleable c1 { 0x7f010001 }\n")); |
| |
| SortedSetMultimap<String, Resource> packageNameToResources = |
| MergeAndroidResourcesStep.sortSymbols( |
| entriesBuilder.buildReadableMapper(), |
| entriesBuilder.buildFilePathToPackageNameSet(), |
| true /* reenumerate */); |
| |
| assertEquals(1, packageNameToResources.keySet().size()); |
| SortedSet<Resource> resources = packageNameToResources.get(sharedPackageName); |
| assertEquals(7, resources.size()); |
| |
| Set<String> uniqueEntries = Sets.newHashSet(); |
| for (Resource resource : resources) { |
| if (!resource.type.equals("styleable")) { |
| assertFalse("Duplicate ids should be fixed by renumerate=true; duplicate was: " + |
| resource.idValueToWrite, uniqueEntries.contains(resource.idValueToWrite)); |
| uniqueEntries.add(resource.idValueToWrite); |
| } |
| } |
| |
| assertEquals(6, uniqueEntries.size()); |
| |
| // All good, no need to further test whether we can write the Java file correctly... |
| } |
| |
| @Test |
| public void testGenerateRDotJavaForOneSymbolsFile() { |
| String symbolsFile = BuckConstant.BIN_DIR + |
| "/android_res/com/facebook/http/__res_resources_text_symbols__/R.txt"; |
| String rDotJavaPackage = "com.facebook"; |
| final String outputTextSymbols = |
| "int id placeholder 0x7f020000\n" + |
| "int string debug_http_proxy_dialog_title 0x7f030004\n" + |
| "int string debug_http_proxy_hint 0x7f030005\n" + |
| "int string debug_http_proxy_summary 0x7f030003\n" + |
| "int string debug_http_proxy_title 0x7f030002\n" + |
| "int string debug_ssl_cert_check_summary 0x7f030001\n" + |
| "int string debug_ssl_cert_check_title 0x7f030000\n" + |
| "int styleable SherlockMenuItem_android_visible 4\n" + |
| "int[] styleable SherlockMenuView { 0x7f010026, 0x7f010027, 0x7f010028, 0x7f010029, 0x7f01002a, 0x7f01002b, 0x7f01002c, 0x7f01002d }\n"; |
| RDotTxtEntryBuilder entriesBuilder = new RDotTxtEntryBuilder(); |
| entriesBuilder.add(new RDotTxtEntry(rDotJavaPackage, symbolsFile, outputTextSymbols)); |
| SortedSetMultimap<String, Resource> rDotJavaPackageToResources = |
| MergeAndroidResourcesStep.sortSymbols( |
| entriesBuilder.buildReadableMapper(), |
| entriesBuilder.buildFilePathToPackageNameSet(), |
| false /* reenumerate */); |
| |
| assertEquals(1, rDotJavaPackageToResources.keySet().size()); |
| |
| // Verify all of the values in the resources collection. |
| SortedSet<Resource> resources = rDotJavaPackageToResources.get(rDotJavaPackage); |
| assertEquals(9, resources.size()); |
| Iterator<Resource> iter = resources.iterator(); |
| assertResource("int", "id", "placeholder", "0x7f020000", iter.next()); |
| assertResource("int", "string", "debug_http_proxy_dialog_title", "0x7f030004", iter.next()); |
| assertResource("int", "string", "debug_http_proxy_hint", "0x7f030005", iter.next()); |
| assertResource("int", "string", "debug_http_proxy_summary", "0x7f030003", iter.next()); |
| assertResource("int", "string", "debug_http_proxy_title", "0x7f030002", iter.next()); |
| assertResource("int", "string", "debug_ssl_cert_check_summary", "0x7f030001", iter.next()); |
| assertResource("int", "string", "debug_ssl_cert_check_title", "0x7f030000", iter.next()); |
| assertResource("int", "styleable", "SherlockMenuItem_android_visible", "4", iter.next()); |
| assertResource("int[]", |
| "styleable", |
| "SherlockMenuView", |
| "{ 0x7f010026, 0x7f010027, 0x7f010028, 0x7f010029, 0x7f01002a, 0x7f01002b, 0x7f01002c, 0x7f01002d }", |
| iter.next()); |
| |
| // Verify that the correct Java code is generated. |
| String javaCode = MergeAndroidResourcesStep.generateJavaCodeForPackageAndResources( |
| rDotJavaPackage, resources); |
| assertEquals( |
| "package com.facebook;\n" + |
| "\n" + |
| "public class R {\n" + |
| "\n" + |
| " public static class id {\n" + |
| " public static int placeholder=0x7f020000;\n" + |
| " }\n" + |
| "\n" + |
| " public static class string {\n" + |
| " public static int debug_http_proxy_dialog_title=0x7f030004;\n" + |
| " public static int debug_http_proxy_hint=0x7f030005;\n" + |
| " public static int debug_http_proxy_summary=0x7f030003;\n" + |
| " public static int debug_http_proxy_title=0x7f030002;\n" + |
| " public static int debug_ssl_cert_check_summary=0x7f030001;\n" + |
| " public static int debug_ssl_cert_check_title=0x7f030000;\n" + |
| " }\n" + |
| "\n" + |
| " public static class styleable {\n" + |
| " public static int SherlockMenuItem_android_visible=4;\n" + |
| " public static int[] SherlockMenuView={ 0x7f010026, 0x7f010027, 0x7f010028, 0x7f010029, 0x7f01002a, 0x7f01002b, 0x7f01002c, 0x7f01002d };\n" + |
| " }\n" + |
| "\n" + |
| "}\n", |
| javaCode); |
| } |
| |
| @Test |
| public void testGenerateRDotJavaForEmptyResources() { |
| String packageName = "com.facebook"; |
| String rDotJava = MergeAndroidResourcesStep.generateJavaCodeForPackageWithoutResources( |
| packageName); |
| assertEquals( |
| "package com.facebook;\n" + |
| "\n" + |
| "public class R {\n" + |
| "\n" + |
| "}\n", |
| rDotJava); |
| } |
| |
| /** |
| * A special comparison for two {@link Resource} objects because {@link Resource#equals(Object)} |
| * does not compare all of the fields. |
| */ |
| private void assertResource( |
| String expectedIdType, |
| String expectedType, |
| String expectedName, |
| String expectedIdValue, |
| Resource observedResource) { |
| assertEquals(expectedIdType, observedResource.idType); |
| assertEquals(expectedType, observedResource.type); |
| assertEquals(expectedName, observedResource.name); |
| assertEquals(expectedIdValue, observedResource.originalIdValue); |
| } |
| |
| // sortSymbols has a goofy API. This will help. |
| private static class RDotTxtEntryBuilder { |
| private final ImmutableMap.Builder<String, String> filePathToContents = |
| ImmutableMap.builder(); |
| private final ImmutableMap.Builder<String, String> filePathToPackageName = |
| ImmutableMap.builder(); |
| |
| public RDotTxtEntryBuilder() { |
| } |
| |
| public void add(RDotTxtEntry entry) { |
| filePathToContents.put(entry.filePath, entry.contents); |
| filePathToPackageName.put(entry.filePath, entry.packageName); |
| } |
| |
| public Function<String, Readable> buildReadableMapper() { |
| final ImmutableMap<String, String> builtInstance = filePathToContents.build(); |
| return new Function<String, Readable>() { |
| @Override |
| public Readable apply(String filePath) { |
| String content = builtInstance.get(filePath); |
| if (content == null) { |
| throw new RuntimeException("No content for " + filePath); |
| } else { |
| return new StringReader(content); |
| } |
| } |
| }; |
| } |
| |
| public Map<String, String> buildFilePathToPackageNameSet() { |
| return filePathToPackageName.build(); |
| } |
| } |
| |
| private static class RDotTxtEntry { |
| public String packageName; |
| public String filePath; |
| public String contents; |
| |
| public RDotTxtEntry(String packageName, String filePath, String contents) { |
| this.packageName = packageName; |
| this.filePath = filePath; |
| this.contents = contents; |
| } |
| } |
| } |