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