From d86909707b1698ee2e239653634cedcfa7503f64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ryszard=20Wi=C5=9Bniewski?= Date: Mon, 2 May 2011 02:05:46 +0200 Subject: [PATCH] apktool-lib: added basic tests for resources building/decoding. --- apktool-lib/pom.xml | 11 ++ .../brut/androlib/BuildAndDecodeTest.java | 113 ++++++++++++++ .../test/java/brut/androlib/TestUtils.java | 138 ++++++++++++++++++ .../brut/apktool/testapp/AndroidManifest.xml | 3 + .../brut/apktool/testapp/apktool.yml | 6 + .../apktool/testapp/res/layout/layout1.xml | 19 +++ .../testapp/res/values-mcc001/strings.xml | 8 + .../testapp/res/values-mcc002/strings.xml | 4 + .../apktool/testapp/res/values/strings.xml | 4 + 9 files changed, 306 insertions(+) create mode 100644 apktool-lib/src/test/java/brut/androlib/BuildAndDecodeTest.java create mode 100644 apktool-lib/src/test/java/brut/androlib/TestUtils.java create mode 100644 apktool-lib/src/test/resources/brut/apktool/testapp/AndroidManifest.xml create mode 100644 apktool-lib/src/test/resources/brut/apktool/testapp/apktool.yml create mode 100644 apktool-lib/src/test/resources/brut/apktool/testapp/res/layout/layout1.xml create mode 100644 apktool-lib/src/test/resources/brut/apktool/testapp/res/values-mcc001/strings.xml create mode 100644 apktool-lib/src/test/resources/brut/apktool/testapp/res/values-mcc002/strings.xml create mode 100644 apktool-lib/src/test/resources/brut/apktool/testapp/res/values/strings.xml diff --git a/apktool-lib/pom.xml b/apktool-lib/pom.xml index 6defecd9..53cf5d65 100644 --- a/apktool-lib/pom.xml +++ b/apktool-lib/pom.xml @@ -34,6 +34,7 @@ src/main/java/com/mindprod/** src/main/java/android/** + src/test/resources/brut/apktool/testapp/** @@ -81,5 +82,15 @@ xpp3 1.1.4c + + junit + junit + 4.8.2 + + + xmlunit + xmlunit + 1.3 + diff --git a/apktool-lib/src/test/java/brut/androlib/BuildAndDecodeTest.java b/apktool-lib/src/test/java/brut/androlib/BuildAndDecodeTest.java new file mode 100644 index 00000000..995d7622 --- /dev/null +++ b/apktool-lib/src/test/java/brut/androlib/BuildAndDecodeTest.java @@ -0,0 +1,113 @@ +/** + * Copyright 2011 Ryszard Wiśniewski + * + * 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 brut.androlib; + +import brut.androlib.res.util.ExtFile; +import brut.common.BrutException; +import brut.util.OS; +import java.io.*; +import java.util.logging.Logger; +import org.custommonkey.xmlunit.*; +import org.junit.*; +import static org.junit.Assert.*; +import org.xml.sax.SAXException; + + +/** + * @author Ryszard Wiśniewski + */ +public class BuildAndDecodeTest { + + @BeforeClass + public static void beforeClass() throws BrutException { + sTmpDir = new ExtFile(OS.createTempDirectory()); + sTestOrigDir = new ExtFile(sTmpDir, "testapp-orig"); + sTestNewDir = new ExtFile(sTmpDir, "testapp-new"); + File testApk = new File(sTmpDir, "testapp.apk"); + + LOGGER.info("Unpacking testapp..."); + TestUtils.copyResourceDir(BuildAndDecodeTest.class, + "brut/apktool/testapp/", sTestOrigDir); + + LOGGER.info("Building testapp.apk..."); + new Androlib().build(sTestOrigDir, testApk, false, false); + + LOGGER.info("Decoding testapp.apk..."); + ApkDecoder apkDecoder = new ApkDecoder(testApk); + apkDecoder.setOutDir(sTestNewDir); + apkDecoder.decode(); + } + + @AfterClass + public static void afterClass() throws BrutException { + OS.rmdir(sTmpDir); + } + + @Test + public void literalStringsTest() throws BrutException { + compareValuesFiles("values-mcc001/strings.xml"); + } + + @Test + public void referenceStringsTest() throws BrutException { + compareValuesFiles("values-mcc002/strings.xml"); + } + + @Test + public void layout1Test() throws BrutException { + compareXmlFiles("res/layout/layout1.xml"); + } + + private void compareValuesFiles(String path) throws BrutException { + compareXmlFiles("res/" + path, + new ElementNameAndAttributeQualifier("name")); + } + + private void compareXmlFiles(String path) throws BrutException { + compareXmlFiles(path, null); + } + + private void compareXmlFiles(String path, + ElementQualifier qualifier) throws BrutException { + DetailedDiff diff; + try { + Reader control = new FileReader( + new File(sTestOrigDir, path)); + Reader test = new FileReader(new File(sTestNewDir, path)); + + diff = new DetailedDiff(new Diff(control, test)); + } catch (SAXException ex) { + throw new BrutException(ex); + } catch (IOException ex) { + throw new BrutException(ex); + } + + if (qualifier != null) { + diff.overrideElementQualifier(qualifier); + } + + assertTrue(path + ": " + + diff.getAllDifferences().toString(), diff.similar()); + } + + private static ExtFile sTmpDir; + private static ExtFile sTestOrigDir; + private static ExtFile sTestNewDir; + + private final static Logger LOGGER = + Logger.getLogger(BuildAndDecodeTest.class.getName()); +} diff --git a/apktool-lib/src/test/java/brut/androlib/TestUtils.java b/apktool-lib/src/test/java/brut/androlib/TestUtils.java new file mode 100644 index 00000000..53d59c87 --- /dev/null +++ b/apktool-lib/src/test/java/brut/androlib/TestUtils.java @@ -0,0 +1,138 @@ +/** + * Copyright 2011 Ryszard Wiśniewski + * + * 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 brut.androlib; + +import brut.common.BrutException; +import brut.directory.*; +import java.io.*; +import java.net.URL; +import java.net.URLDecoder; +import java.util.HashMap; +import java.util.Map; +import org.custommonkey.xmlunit.ElementQualifier; +import org.w3c.dom.Element; +import org.xmlpull.v1.*; + +/** + * @author Ryszard Wiśniewski + */ +public abstract class TestUtils { + + public static Map parseStringsXml(File file) + throws BrutException { + try { + XmlPullParser xpp = XmlPullParserFactory.newInstance().newPullParser(); + xpp.setInput(new FileReader(file)); + + int eventType; + String key = null; + Map map = new HashMap(); + while ((eventType = xpp.next()) != XmlPullParser.END_DOCUMENT) { + switch (eventType) { + case XmlPullParser.START_TAG: + if ("string".equals(xpp.getName())) { + int attrCount = xpp.getAttributeCount(); + for (int i = 0; i < attrCount; i++) { + if ("name".equals(xpp.getAttributeName(i))) { + key = xpp.getAttributeValue(i); + break; + } + } + } + break; + case XmlPullParser.END_TAG: + if ("string".equals(xpp.getName())) { + key = null; + } + break; + case XmlPullParser.TEXT: + if (key != null) { + map.put(key, xpp.getText()); + } + break; + } + } + + return map; + } catch (IOException ex) { + throw new BrutException(ex); + } catch (XmlPullParserException ex) { + throw new BrutException(ex); + } + } + + /* TODO: move to brut.util.Jar - it's not possible for now, because below + * implementation uses brut.dir. I think I should merge all my projects to + * single brut.common . + */ + public static void copyResourceDir(Class class_, String dirPath, File out) + throws BrutException { + if (! out.exists()) { + out.mkdirs(); + } + copyResourceDir(class_, dirPath, new FileDirectory(out)); + } + + public static void copyResourceDir(Class class_, String dirPath, + Directory out) throws BrutException { + if (class_ == null) { + class_ = Class.class; + } + + URL dirURL = class_.getClassLoader().getResource(dirPath); + if (dirURL != null && dirURL.getProtocol().equals("file")) { + DirUtil.copyToDir(new FileDirectory(dirURL.getFile()), out); + return; + } + + if (dirURL == null) { + String className = class_.getName().replace(".", "/") + ".class"; + dirURL = class_.getClassLoader().getResource(className); + } + + + if (dirURL.getProtocol().equals("jar")) { + String jarPath; + try { + jarPath = URLDecoder.decode(dirURL.getPath().substring( + 5, dirURL.getPath().indexOf("!")), "UTF-8"); + } catch (UnsupportedEncodingException ex) { + throw new BrutException(ex); + } + DirUtil.copyToDir(new FileDirectory(jarPath), out); + } + } + + + public static class ResValueElementQualifier implements ElementQualifier { + + public boolean qualifyForComparison(Element control, Element test) { + String controlType = control.getTagName(); + if ("item".equals(controlType)) { + controlType = control.getAttribute("type"); + } + + String testType = test.getTagName(); + if ("item".equals(testType)) { + testType = test.getAttribute("type"); + } + + return controlType.equals(testType) && control.getAttribute("name") + .equals(test.getAttribute("name")); + } + } +} diff --git a/apktool-lib/src/test/resources/brut/apktool/testapp/AndroidManifest.xml b/apktool-lib/src/test/resources/brut/apktool/testapp/AndroidManifest.xml new file mode 100644 index 00000000..c6a6a653 --- /dev/null +++ b/apktool-lib/src/test/resources/brut/apktool/testapp/AndroidManifest.xml @@ -0,0 +1,3 @@ + + diff --git a/apktool-lib/src/test/resources/brut/apktool/testapp/apktool.yml b/apktool-lib/src/test/resources/brut/apktool/testapp/apktool.yml new file mode 100644 index 00000000..555ac244 --- /dev/null +++ b/apktool-lib/src/test/resources/brut/apktool/testapp/apktool.yml @@ -0,0 +1,6 @@ +version: 1.3.2 +apkFileName: testapp.apk +isFrameworkApk: false +usesFramework: + ids: + - 1 diff --git a/apktool-lib/src/test/resources/brut/apktool/testapp/res/layout/layout1.xml b/apktool-lib/src/test/resources/brut/apktool/testapp/res/layout/layout1.xml new file mode 100644 index 00000000..6685f20d --- /dev/null +++ b/apktool-lib/src/test/resources/brut/apktool/testapp/res/layout/layout1.xml @@ -0,0 +1,19 @@ + + + + + diff --git a/apktool-lib/src/test/resources/brut/apktool/testapp/res/values-mcc001/strings.xml b/apktool-lib/src/test/resources/brut/apktool/testapp/res/values-mcc001/strings.xml new file mode 100644 index 00000000..5e9db678 --- /dev/null +++ b/apktool-lib/src/test/resources/brut/apktool/testapp/res/values-mcc001/strings.xml @@ -0,0 +1,8 @@ + + + + Lorem ipsum... + \@ + \? + & + diff --git a/apktool-lib/src/test/resources/brut/apktool/testapp/res/values-mcc002/strings.xml b/apktool-lib/src/test/resources/brut/apktool/testapp/res/values-mcc002/strings.xml new file mode 100644 index 00000000..e0ebc5d9 --- /dev/null +++ b/apktool-lib/src/test/resources/brut/apktool/testapp/res/values-mcc002/strings.xml @@ -0,0 +1,4 @@ + + + @android:string/ok + diff --git a/apktool-lib/src/test/resources/brut/apktool/testapp/res/values/strings.xml b/apktool-lib/src/test/resources/brut/apktool/testapp/res/values/strings.xml new file mode 100644 index 00000000..a8cb8262 --- /dev/null +++ b/apktool-lib/src/test/resources/brut/apktool/testapp/res/values/strings.xml @@ -0,0 +1,4 @@ + + + +