Home | History | Annotate | Download | only in smalidea
      1 /*
      2  * Copyright 2014, Google Inc.
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are
      7  * met:
      8  *
      9  *     * Redistributions of source code must retain the above copyright
     10  * notice, this list of conditions and the following disclaimer.
     11  *     * Redistributions in binary form must reproduce the above
     12  * copyright notice, this list of conditions and the following disclaimer
     13  * in the documentation and/or other materials provided with the
     14  * distribution.
     15  *     * Neither the name of Google Inc. nor the names of its
     16  * contributors may be used to endorse or promote products derived from
     17  * this software without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 package org.jf.smalidea;
     33 
     34 import com.google.common.collect.Lists;
     35 import com.intellij.debugger.NoDataException;
     36 import com.intellij.debugger.PositionManager;
     37 import com.intellij.debugger.SourcePosition;
     38 import com.intellij.debugger.engine.DebugProcess;
     39 import com.intellij.debugger.engine.DebugProcessListener;
     40 import com.intellij.debugger.engine.evaluation.EvaluateException;
     41 import com.intellij.debugger.engine.evaluation.EvaluationContext;
     42 import com.intellij.debugger.engine.jdi.VirtualMachineProxy;
     43 import com.intellij.debugger.engine.managerThread.DebuggerManagerThread;
     44 import com.intellij.debugger.requests.RequestManager;
     45 import com.intellij.execution.ExecutionResult;
     46 import com.intellij.execution.process.ProcessHandler;
     47 import com.intellij.openapi.project.Project;
     48 import com.intellij.openapi.util.Key;
     49 import com.intellij.psi.search.GlobalSearchScope;
     50 import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
     51 import com.sun.jdi.*;
     52 import org.jetbrains.annotations.NotNull;
     53 import org.jf.dexlib2.Opcode;
     54 import org.jf.smalidea.debugging.SmaliPositionManager;
     55 import org.jf.smalidea.psi.impl.SmaliInstruction;
     56 import org.junit.Assert;
     57 
     58 import java.util.List;
     59 import java.util.Map;
     60 
     61 public class SmaliPositionManagerTest extends LightCodeInsightFixtureTestCase {
     62     private static final String testClass =
     63             "\n\n.class public Lmy/pkg/blah; .super Ljava/lang/Object;\n" +
     64                     ".method public getRandomParentType(I)I\n" +
     65                     "    .registers 4\n" +
     66                     "    .param p1, \"edge\"    # I\n" +
     67                     "\n" +
     68                     "    .prologue\n" +
     69                     "    const/4 v1, 0x2\n" +
     70                     "\n" +
     71                     "    .line 179\n" +
     72                     "    if-nez p1, :cond_5\n" +
     73                     "\n" +
     74                     "    move v0, v1\n" +
     75                     "\n" +
     76                     "    .line 185\n" +
     77                     "    :goto_4\n" +
     78                     "    return v0\n" +
     79                     "\n" +
     80                     "    .line 182\n" +
     81                     "    :cond_5\n" +
     82                     "    if-ne p1, v1, :cond_f\n" +
     83                     "\n" +
     84                     "    .line 183\n" +
     85                     "    sget-object v0, Lorg/jf/Penroser/PenroserApp;->random:Ljava/util/Random;\n" +
     86                     "\n" +
     87                     "    const/4 v1, 0x3\n" +
     88                     "\n" +
     89                     "    invoke-virtual {v0, v1}, Ljava/util/Random;->nextInt(I)I\n" +
     90                     "\n" +
     91                     "    move-result v0\n" +
     92                     "\n" +
     93                     "    goto :goto_4\n" +
     94                     "\n" +
     95                     "    .line 185\n" +
     96                     "    :cond_f\n" +
     97                     "    sget-object v0, Lorg/jf/Penroser/PenroserApp;->random:Ljava/util/Random;\n" +
     98                     "\n" +
     99                     "    invoke-virtual {v0, v1}, Ljava/util/Random;->nextInt(I)I\n" +
    100                     "\n" +
    101                     "    move-result v0\n" +
    102                     "\n" +
    103                     "    goto :goto_4\n" +
    104                     ".end method";
    105 
    106     public void testGetSourcePosition() throws NoDataException {
    107         myFixture.addFileToProject("my/pkg/blah.smali", testClass);
    108 
    109         SmaliPositionManager positionManager = new SmaliPositionManager(new MockDebugProcess());
    110 
    111         SourcePosition sourcePosition = positionManager.getSourcePosition(
    112                 "my.pkg.blah", "getRandomParentType", "(I)I", 0);
    113         Assert.assertEquals(Opcode.CONST_4, ((SmaliInstruction)sourcePosition.getElementAt()).getOpcode());
    114         Assert.assertEquals(0, ((SmaliInstruction)sourcePosition.getElementAt()).getOffset());
    115 
    116         sourcePosition = positionManager.getSourcePosition("my.pkg.blah", "getRandomParentType", "(I)I", 10);
    117         Assert.assertEquals(Opcode.INVOKE_VIRTUAL, ((SmaliInstruction)sourcePosition.getElementAt()).getOpcode());
    118         Assert.assertEquals(20, ((SmaliInstruction)sourcePosition.getElementAt()).getOffset());
    119     }
    120 
    121     public void testGetAllClasses() throws NoDataException {
    122         myFixture.addFileToProject("my/pkg/blah.smali", testClass);
    123 
    124         SmaliPositionManager positionManager = new SmaliPositionManager(new MockDebugProcess());
    125 
    126         List<ReferenceType> classes = positionManager.getAllClasses(positionManager.getSourcePosition(
    127                 "my.pkg.blah", "getRandomParentType", "(I)I", 0));
    128         Assert.assertEquals(1, classes.size());
    129         Assert.assertEquals("my.pkg.blah", classes.get(0).name());
    130     }
    131 
    132     private class MockDebugProcess implements DebugProcess {
    133         @Override public Project getProject() {
    134             return SmaliPositionManagerTest.this.getProject();
    135         }
    136 
    137         @Override public VirtualMachineProxy getVirtualMachineProxy() {
    138             return new VirtualMachineProxy() {
    139                 @Override public List<ReferenceType> classesByName(final String s) {
    140                     return Lists.<ReferenceType>newArrayList(new MockReferenceType(s));
    141                 }
    142 
    143                 @Override public List<ReferenceType> allClasses() { return null; }
    144                 @Override public boolean canGetBytecodes() { return false; }
    145                 @Override public boolean versionHigher(String version) { return false; }
    146                 @Override public boolean canWatchFieldModification() { return false; }
    147                 @Override public boolean canWatchFieldAccess() { return false; }
    148                 @Override public boolean canInvokeMethods() { return false; }
    149                 @Override public DebugProcess getDebugProcess() { return null; }
    150                 @Override public List<ReferenceType> nestedTypes(ReferenceType refType) { return null; }
    151             };
    152         }
    153 
    154         @Override public void addDebugProcessListener(DebugProcessListener listener) {}
    155         @Override public <T> T getUserData(Key<T> key) { return null; }
    156         @Override public <T> void putUserData(Key<T> key, T value) {}
    157         @Override public RequestManager getRequestsManager() { return null; }
    158         @Override public PositionManager getPositionManager() { return null; }
    159         @Override public void removeDebugProcessListener(DebugProcessListener listener) {}
    160         @Override public void appendPositionManager(PositionManager positionManager) {}
    161         @Override public void waitFor() {}
    162         @Override public void waitFor(long timeout) {}
    163         @Override public void stop(boolean forceTerminate) {}
    164         @Override public ExecutionResult getExecutionResult() { return null; }
    165         @Override public DebuggerManagerThread getManagerThread() { return null; }
    166         @Override public Value invokeMethod(EvaluationContext evaluationContext, ObjectReference objRef, Method method, List args) throws EvaluateException { return null; }
    167         @Override public Value invokeMethod(EvaluationContext evaluationContext, ClassType classType, Method method, List args) throws EvaluateException { return null; }
    168         @Override public Value invokeInstanceMethod(EvaluationContext evaluationContext, ObjectReference objRef, Method method, List args, int invocationOptions) throws EvaluateException { return null; }
    169         @Override public ReferenceType findClass(EvaluationContext evaluationContext, String name, ClassLoaderReference classLoader) throws EvaluateException { return null; }
    170         @Override public ArrayReference newInstance(ArrayType arrayType, int dimension) throws EvaluateException { return null; }
    171         @Override public ObjectReference newInstance(EvaluationContext evaluationContext, ClassType classType, Method constructor, List paramList) throws EvaluateException { return null; }
    172         @Override public boolean isAttached() { return false; }
    173         @Override public boolean isDetached() { return false; }
    174         @Override public boolean isDetaching() { return false; }
    175         @NotNull @Override public GlobalSearchScope getSearchScope() { return null; }
    176         @Override public void printToConsole(String text) {}
    177         @Override public ProcessHandler getProcessHandler() { return null; }
    178     }
    179 
    180     private static class MockReferenceType implements ReferenceType {
    181         private final String name;
    182 
    183         public MockReferenceType(String name) {
    184             this.name = name;
    185         }
    186 
    187         @Override public String name() {
    188             return name;
    189         }
    190 
    191         @Override public List<Field> allFields() { return null; }
    192         @Override public String genericSignature() { return null; }
    193         @Override public ClassLoaderReference classLoader() { return null; }
    194         @Override public String sourceName() throws AbsentInformationException { return null; }
    195         @Override public List<String> sourceNames(String s) throws AbsentInformationException { return null; }
    196         @Override public List<String> sourcePaths(String s) throws AbsentInformationException { return null; }
    197         @Override public String sourceDebugExtension() throws AbsentInformationException { return null; }
    198         @Override public boolean isStatic() { return false; }
    199         @Override public boolean isAbstract() { return false; }
    200         @Override public boolean isFinal() { return false; }
    201         @Override public boolean isPrepared() { return false; }
    202         @Override public boolean isVerified() { return false; }
    203         @Override public boolean isInitialized() { return false; }
    204         @Override public boolean failedToInitialize() { return false; }
    205         @Override public List<Field> fields() { return null; }
    206         @Override public List<Field> visibleFields() { return null; }
    207         @Override public Field fieldByName(String s) { return null; }
    208         @Override public List<Method> methods() { return null; }
    209         @Override public List<Method> visibleMethods() { return null; }
    210         @Override public List<Method> allMethods() { return null; }
    211         @Override public List<Method> methodsByName(String s) { return null; }
    212         @Override public List<Method> methodsByName(String s, String s1) { return null; }
    213         @Override public List<ReferenceType> nestedTypes() { return null; }
    214         @Override public Value getValue(Field field) { return null; }
    215         @Override public Map<Field, Value> getValues(List<? extends Field> list) { return null; }
    216         @Override public ClassObjectReference classObject() { return null; }
    217         @Override public List<Location> allLineLocations() throws AbsentInformationException { return null; }
    218         @Override public List<Location> allLineLocations(String s, String s1) throws AbsentInformationException { return null; }
    219         @Override public List<Location> locationsOfLine(int i) throws AbsentInformationException { return null; }
    220         @Override public List<Location> locationsOfLine(String s, String s1, int i) throws AbsentInformationException { return null; }
    221         @Override public List<String> availableStrata() { return null; }
    222         @Override public String defaultStratum() { return null; }
    223         @Override public List<ObjectReference> instances(long l) { return null; }
    224         @Override public int majorVersion() { return 0; }
    225         @Override public int minorVersion() { return 0; }
    226         @Override public int constantPoolCount() { return 0; }
    227         @Override public byte[] constantPool() { return new byte[0]; }
    228         @Override public int modifiers() { return 0; }
    229         @Override public boolean isPrivate() { return false; }
    230         @Override public boolean isPackagePrivate() { return false; }
    231         @Override public boolean isProtected() { return false; }
    232         @Override public boolean isPublic() { return false; }
    233         @Override public int compareTo(ReferenceType o) { return 0; }
    234         @Override public String signature() { return null; }
    235         @Override public VirtualMachine virtualMachine() { return null; }
    236     }
    237 }
    238