| /* |
| * Copyright 2014-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.aapt; |
| |
| import static org.hamcrest.Matchers.containsString; |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertThat; |
| import static org.junit.Assert.assertTrue; |
| import static org.junit.Assert.fail; |
| |
| import com.facebook.buck.android.aapt.MiniAapt.ResourceParseException; |
| import com.facebook.buck.android.aapt.RDotTxtEntry.IdType; |
| import com.facebook.buck.android.aapt.RDotTxtEntry.RType; |
| import com.facebook.buck.testutil.FakeProjectFilesystem; |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.ImmutableSet; |
| |
| import org.junit.Test; |
| |
| import java.io.IOException; |
| import java.nio.file.Path; |
| import java.nio.file.Paths; |
| import java.util.Set; |
| |
| import javax.xml.xpath.XPathExpressionException; |
| |
| public class MiniAaptTest { |
| |
| private static final ImmutableList<String> RESOURCES = ImmutableList.<String>builder().add( |
| "<?xml version=\"1.0\" encoding=\"UTF-8\"?>", |
| "<LinearLayout>", |
| "<Button android:id=\"@+id/button1\" ", |
| "android:layout_toLeftOf=\"@id/button2\" ", |
| "android:text=\"@string/text\" />", |
| "<Button android:id=\"@+id/button3\" ", |
| "style:attribute=\"@style/Buck.Theme\" ", |
| "android:background=\"@drawable/some_image\" />", |
| "<TextView android:id=\"@id/android:empty\" />", |
| "</LinearLayout>") |
| .build(); |
| |
| private final FakeProjectFilesystem filesystem = new FakeProjectFilesystem(); |
| |
| @Test |
| public void testFindingResourceIdsInXml() |
| throws IOException, XPathExpressionException, ResourceParseException { |
| filesystem.writeLinesToPath(RESOURCES, Paths.get("resource.xml")); |
| |
| MiniAapt aapt = new MiniAapt(Paths.get("res"), Paths.get("R.txt"), ImmutableSet.<Path>of()); |
| |
| ImmutableSet.Builder<RDotTxtEntry> references = ImmutableSet.builder(); |
| aapt.processXmlFile(filesystem, Paths.get("resource.xml"), references); |
| |
| Set<RDotTxtEntry> definitions = aapt.getResourceCollector().getResources(); |
| |
| assertEquals( |
| definitions, |
| ImmutableSet.<RDotTxtEntry>of( |
| new FakeRDotTxtEntry(IdType.INT, RType.ID, "button1"), |
| new FakeRDotTxtEntry(IdType.INT, RType.ID, "button3"))); |
| |
| assertEquals( |
| references.build(), |
| ImmutableSet.<RDotTxtEntry>of( |
| new FakeRDotTxtEntry(IdType.INT, RType.DRAWABLE, "some_image"), |
| new FakeRDotTxtEntry(IdType.INT, RType.STRING, "text"), |
| new FakeRDotTxtEntry(IdType.INT, RType.STYLE, "Buck_Theme"), |
| new FakeRDotTxtEntry(IdType.INT, RType.ID, "button2"))); |
| } |
| |
| |
| @Test |
| public void testParsingFilesUnderValuesDirectory() throws IOException, ResourceParseException { |
| ImmutableList<String> lines = ImmutableList.<String>builder().add( |
| "<?xml version=\"1.0\" encoding=\"UTF-8\"?>", |
| "<resources>", |
| "<string name=\"hello\">Hello, <xliff:g id=\"name\">%s</xliff:g>!</string>", |
| "<plurals name=\"people\">", |
| " <item quantity=\"zero\">ignore1</item>", |
| " <item quantity=\"many\">ignore2</item>", |
| "</plurals>", |
| "<skip />", |
| "<integer name=\"number\">100</integer>", |
| "<dimen name=\"dimension\">100sp</dimen>", |
| "<declare-styleable name=\"MyNiceView\">", |
| " <attr name=\"titleText\" />", |
| " <attr name=\"subtitleText\" format=\"string\" />", |
| " <attr name=\"complexAttr\">", |
| " <enum name=\"shouldBeIgnored\" value=\"0\" />", |
| " <enum name=\"alsoIgnore\" value=\"1\" />", |
| " <flag name=\"uselessFlag\" value=\"0x00\" />", |
| " </attr>", |
| " <attr name=\"android:layout_gravity\" />", |
| " <item name=\"should_be_ignored\" />", |
| "</declare-styleable>", |
| "<eat-comment />", |
| "<item type=\"id\" name=\"some_id\" />", |
| "<style name=\"Widget.Theme\">", |
| " <item name=\"ignoreMe\" />", |
| "</style>", |
| "</resources>") |
| .build(); |
| |
| filesystem.writeLinesToPath(lines, Paths.get("values.xml")); |
| |
| MiniAapt aapt = new MiniAapt(Paths.get("res"), Paths.get("R.txt"), ImmutableSet.<Path>of()); |
| aapt.processValuesFile(filesystem, Paths.get("values.xml")); |
| |
| Set<RDotTxtEntry> definitions = aapt.getResourceCollector().getResources(); |
| |
| assertEquals( |
| definitions, |
| ImmutableSet.<RDotTxtEntry>of( |
| new FakeRDotTxtEntry(IdType.INT, RType.STRING, "hello"), |
| new FakeRDotTxtEntry(IdType.INT, RType.PLURALS, "people"), |
| new FakeRDotTxtEntry(IdType.INT, RType.INTEGER, "number"), |
| new FakeRDotTxtEntry(IdType.INT, RType.DIMEN, "dimension"), |
| new FakeRDotTxtEntry(IdType.INT_ARRAY, RType.STYLEABLE, "MyNiceView"), |
| new FakeRDotTxtEntry(IdType.INT, RType.STYLEABLE, "MyNiceView_titleText"), |
| new FakeRDotTxtEntry(IdType.INT, RType.STYLEABLE, "MyNiceView_subtitleText"), |
| new FakeRDotTxtEntry(IdType.INT, RType.STYLEABLE, "MyNiceView_complexAttr"), |
| new FakeRDotTxtEntry(IdType.INT, RType.STYLEABLE, "MyNiceView_android_layout_gravity"), |
| new FakeRDotTxtEntry(IdType.INT, RType.ATTR, "titleText"), |
| new FakeRDotTxtEntry(IdType.INT, RType.ATTR, "subtitleText"), |
| new FakeRDotTxtEntry(IdType.INT, RType.ATTR, "complexAttr"), |
| new FakeRDotTxtEntry(IdType.INT, RType.ID, "some_id"), |
| new FakeRDotTxtEntry(IdType.INT, RType.STYLE, "Widget_Theme"))); |
| |
| boolean foundElement = false; |
| for (RDotTxtEntry definition : definitions) { |
| if (definition.name.equals("MyNiceView")) { |
| assertEquals( |
| "{ 0x7f000000,0x7f000000,0x7f000000,0x7f000000 }", |
| definition.idValue); |
| foundElement = true; |
| } |
| } |
| assertTrue(foundElement); |
| } |
| |
| @Test(expected = ResourceParseException.class) |
| public void testInvalidResourceType() throws IOException, ResourceParseException { |
| ImmutableList<String> lines = ImmutableList.<String>builder().add( |
| "<?xml version=\"1.0\" encoding=\"UTF-8\"?>", |
| "<resources>", |
| "<resourcetype name=\"number\">100</resourcetype>", |
| "</resources>") |
| .build(); |
| |
| filesystem.writeLinesToPath(lines, Paths.get("values.xml")); |
| |
| MiniAapt aapt = new MiniAapt(Paths.get("res"), Paths.get("R.txt"), ImmutableSet.<Path>of()); |
| aapt.processValuesFile(filesystem, Paths.get("values.xml")); |
| } |
| |
| @Test |
| public void testInvalidDefinition() throws XPathExpressionException, IOException { |
| ImmutableList<String> lines = ImmutableList.<String>builder().add( |
| "<?xml version=\"1.0\" encoding=\"UTF-8\"?>", |
| "<LinearLayout>", |
| "<Button android:id=\"@+string/button1\" ", |
| "android:layout_toLeftOf=\"@id/button2\" ", |
| "android:text=\"@string/text\" />", |
| "</LinearLayout>") |
| .build(); |
| |
| Path resource = Paths.get("resource.xml"); |
| filesystem.writeLinesToPath(lines, resource); |
| |
| MiniAapt aapt = new MiniAapt(Paths.get("res"), Paths.get("R.txt"), ImmutableSet.<Path>of()); |
| try { |
| aapt.processXmlFile(filesystem, resource, ImmutableSet.<RDotTxtEntry>builder()); |
| fail("MiniAapt should throw parsing '@+string/button1'"); |
| } catch (ResourceParseException e) { |
| assertThat(e.getMessage(), containsString("Invalid definition of a resource")); |
| } |
| } |
| |
| @Test |
| public void testInvalidReference() throws IOException, XPathExpressionException { |
| ImmutableList<String> lines = ImmutableList.<String>builder().add( |
| "<?xml version=\"1.0\" encoding=\"UTF-8\"?>", |
| "<LinearLayout>", |
| "<Button android:id=\"@+id/button1\" ", |
| "android:layout_toLeftOf=\"@someresource/button2\" ", |
| "android:text=\"@string/text\" />", |
| "</LinearLayout>") |
| .build(); |
| |
| Path resource = Paths.get("resource.xml"); |
| filesystem.writeLinesToPath(lines, resource); |
| |
| MiniAapt aapt = new MiniAapt(Paths.get("res"), Paths.get("R.txt"), ImmutableSet.<Path>of()); |
| try { |
| aapt.processXmlFile(filesystem, resource, ImmutableSet.<RDotTxtEntry>builder()); |
| fail("MiniAapt should throw parsing '@someresource/button2'"); |
| } catch (ResourceParseException e) { |
| assertThat(e.getMessage(), containsString("Invalid reference '@someresource/button2'")); |
| } |
| } |
| |
| @Test |
| public void testVerifyReferences() |
| throws IOException, XPathExpressionException, ResourceParseException { |
| filesystem.writeLinesToPath(RESOURCES, Paths.get("resource.xml")); |
| |
| ImmutableList<String> rDotTxt = ImmutableList.of( |
| "int string text 0x07010001", |
| "int style Buck_Theme 0x07020001", |
| "int id button2 0x07030001"); |
| |
| Path depRTxt = Paths.get("dep/R.txt"); |
| filesystem.writeLinesToPath(rDotTxt, depRTxt); |
| |
| MiniAapt aapt = new MiniAapt(Paths.get("res"), Paths.get("R.txt"), ImmutableSet.of(depRTxt)); |
| ImmutableSet.Builder<RDotTxtEntry> references = ImmutableSet.builder(); |
| aapt.processXmlFile(filesystem, Paths.get("resource.xml"), references); |
| |
| Set<RDotTxtEntry> missing = aapt.verifyReferences(filesystem, references.build()); |
| |
| assertEquals( |
| ImmutableSet.<RDotTxtEntry>of( |
| new FakeRDotTxtEntry(IdType.INT, RType.DRAWABLE, "some_image")), |
| missing); |
| } |
| |
| @Test |
| public void testProcessFileNamesInDirectory() throws IOException, ResourceParseException { |
| filesystem.touch(Paths.get("res/drawable/icon.png")); |
| filesystem.touch(Paths.get("res/drawable/another_icon.png.orig")); |
| filesystem.touch(Paths.get("res/drawable-ldpi/nine_patch.9.png")); |
| filesystem.touch(Paths.get("res/drawable-ldpi/.DS_Store")); |
| |
| MiniAapt aapt = new MiniAapt(Paths.get("res"), Paths.get("R.txt"), ImmutableSet.<Path>of()); |
| aapt.processFileNamesInDirectory(filesystem, Paths.get("res/drawable")); |
| aapt.processFileNamesInDirectory(filesystem, Paths.get("res/drawable-ldpi")); |
| |
| assertEquals( |
| ImmutableSet.<RDotTxtEntry>of( |
| new FakeRDotTxtEntry(IdType.INT, RType.DRAWABLE, "icon"), |
| new FakeRDotTxtEntry(IdType.INT, RType.DRAWABLE, "nine_patch")), |
| aapt.getResourceCollector().getResources()); |
| } |
| } |