1144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin/* 2144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin * Copyright 2015, Google Inc. 3144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin * All rights reserved. 4144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin * 5144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin * Redistribution and use in source and binary forms, with or without 6144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin * modification, are permitted provided that the following conditions are 7144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin * met: 8144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin * 9144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin * * Redistributions of source code must retain the above copyright 10144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin * notice, this list of conditions and the following disclaimer. 11144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin * * Redistributions in binary form must reproduce the above 12144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin * copyright notice, this list of conditions and the following disclaimer 13144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin * in the documentation and/or other materials provided with the 14144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin * distribution. 15144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin * * Neither the name of Google Inc. nor the names of its 16144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin * contributors may be used to endorse or promote products derived from 17144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin * this software without specific prior written permission. 18144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin * 19144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin */ 31144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin 32144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkinpackage org.jf.baksmali; 33144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin 34bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruverimport com.google.common.io.ByteStreams; 35144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkinimport junit.framework.Assert; 36144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin 37144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkinimport org.antlr.runtime.RecognitionException; 38144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkinimport org.jf.baksmali.Adaptors.ClassDefinition; 39144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkinimport org.jf.dexlib2.iface.ClassDef; 40144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkinimport org.jf.smali.SmaliTestUtils; 41144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkinimport org.jf.util.IndentingWriter; 42144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkinimport org.jf.util.TextUtils; 43144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin 44bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruverimport javax.annotation.Nonnull; 45144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkinimport java.io.IOException; 46bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruverimport java.io.InputStream; 47144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkinimport java.io.StringWriter; 48144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin 49144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkinpublic class BaksmaliTestUtils { 50144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin public static void assertSmaliCompiledEquals(String source, String expected, 515a5eafb818cc18baeef8bdae1940401da3735f25Ben Gruver BaksmaliOptions options, boolean stripComments) throws IOException, 52144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin RecognitionException { 53d7d995cc2dbd94e608c8e02778f4361c27b25f4bBen Gruver ClassDef classDef = SmaliTestUtils.compileSmali(source, options.apiLevel); 54144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin 55144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin // Remove unnecessary whitespace and optionally strip all comments from smali file 56bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver String normalizedActual = getNormalizedSmali(classDef, options, stripComments); 57bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver String normalizedExpected = normalizeSmali(expected, stripComments); 58144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin 59144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin // Assert that normalized strings are now equal 60144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin Assert.assertEquals(normalizedExpected, normalizedActual); 61144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin } 62144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin 63144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin public static void assertSmaliCompiledEquals(String source, String expected, 645a5eafb818cc18baeef8bdae1940401da3735f25Ben Gruver BaksmaliOptions options) throws IOException, RecognitionException { 65144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin assertSmaliCompiledEquals(source, expected, options, false); 66144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin } 67144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin 68144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin public static void assertSmaliCompiledEquals(String source, String expected) 69144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin throws IOException, RecognitionException { 705a5eafb818cc18baeef8bdae1940401da3735f25Ben Gruver BaksmaliOptions options = new BaksmaliOptions(); 71144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin assertSmaliCompiledEquals(source, expected, options); 72144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin } 73144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin 74bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver @Nonnull 75bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver public static String normalizeSmali(@Nonnull String smaliText, boolean stripComments) { 76bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver if (stripComments) { 77bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver smaliText = TextUtils.stripComments(smaliText); 78bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver } 79bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver return TextUtils.normalizeWhitespace(smaliText); 80bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver } 81bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver 82bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver @Nonnull 835a5eafb818cc18baeef8bdae1940401da3735f25Ben Gruver public static String getNormalizedSmali(@Nonnull ClassDef classDef, @Nonnull BaksmaliOptions options, 84bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver boolean stripComments) 85bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver throws IOException { 86bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver StringWriter stringWriter = new StringWriter(); 87bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver IndentingWriter writer = new IndentingWriter(stringWriter); 88bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver ClassDefinition classDefinition = new ClassDefinition(options, classDef); 89bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver classDefinition.writeTo(writer); 90bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver writer.close(); 91bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver return normalizeSmali(stringWriter.toString(), stripComments); 92bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver } 93bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver 94bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver @Nonnull 95bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver public static byte[] readResourceBytesFully(@Nonnull String fileName) throws IOException { 96bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver InputStream smaliStream = RoundtripTest.class.getClassLoader(). 97bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver getResourceAsStream(fileName); 98bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver if (smaliStream == null) { 99bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver org.junit.Assert.fail("Could not load " + fileName); 100bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver } 101bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver 102bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver return ByteStreams.toByteArray(smaliStream); 103bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver } 104bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver 105bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver @Nonnull 106bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver public static String readResourceFully(@Nonnull String fileName) throws IOException { 107bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver return readResourceFully(fileName, "UTF-8"); 108bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver } 109bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver 110bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver @Nonnull 111bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver public static String readResourceFully(@Nonnull String fileName, @Nonnull String encoding) 112bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver throws IOException { 113bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver return new String(readResourceBytesFully(fileName), encoding); 114bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver } 115bd6385f06205cdf98269eb4a2412000b35ac9d62Ben Gruver 116144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin // Static helpers class; do not instantiate. 117144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin private BaksmaliTestUtils() { throw new AssertionError(); } 118144951a9e9e6c87866245f2bdeebf0ebedaa0e38Igor Murashkin} 119