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 32package org.jf.smalidea; 33 34import com.intellij.psi.*; 35import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; 36import org.jf.smalidea.psi.impl.SmaliClass; 37import org.jf.smalidea.psi.impl.SmaliFile; 38import org.jf.smalidea.psi.impl.SmaliLiteral; 39import org.jf.smalidea.psi.impl.SmaliMethod; 40import org.junit.Assert; 41 42public class SmaliAnnotationTest extends LightCodeInsightFixtureTestCase { 43 // TODO: test default values 44 45 public void testClassAnnotation() { 46 myFixture.addFileToProject("my/TestAnnotation.smali", 47 ".class public interface abstract annotation Lmy/TestAnnotation;\n" + 48 ".super Ljava/lang/Object;\n" + 49 ".implements Ljava/lang/annotation/Annotation;\n" + 50 "\n" + 51 ".method public abstract testBooleanValue()Z\n" + 52 ".end method\n" + 53 "\n" + 54 ".method public abstract testStringArrayValue()[Ljava/lang/String;\n" + 55 ".end method\n" + 56 "\n" + 57 ".method public abstract testStringValue()Ljava/lang/String;\n" + 58 ".end method"); 59 60 myFixture.addFileToProject("my/TestAnnotation2.smali", 61 ".class public interface abstract annotation Lmy/TestAnnotation2;\n" + 62 ".super Ljava/lang/Object;\n" + 63 ".implements Ljava/lang/annotation/Annotation;\n"); 64 65 SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali", 66 ".class public Lmy/pkg/blah; .super Ljava/lang/Object;\n" + 67 "\n" + 68 ".annotation runtime Lmy/TestAnnotation;\n" + 69 " testBooleanValue = true\n" + 70 " testStringValue = \"blah\"\n" + 71 " testStringArrayValue = {\n" + 72 " \"blah1\",\n" + 73 " \"blah2\"\n" + 74 " }\n" + 75 ".end annotation\n" + 76 "\n" + 77 ".annotation runtime Lmy/TestAnnotation2;\n" + 78 ".end annotation"); 79 80 SmaliClass smaliClass = file.getPsiClass(); 81 Assert.assertEquals("my.pkg.blah", smaliClass.getQualifiedName()); 82 83 doTest(smaliClass); 84 } 85 86 public void testFieldAnnotation() { 87 myFixture.addFileToProject("my/TestAnnotation.smali", 88 ".class public interface abstract annotation Lmy/TestAnnotation;\n" + 89 ".super Ljava/lang/Object;\n" + 90 ".implements Ljava/lang/annotation/Annotation;\n" + 91 "\n" + 92 ".method public abstract testBooleanValue()Z\n" + 93 ".end method\n" + 94 "\n" + 95 ".method public abstract testStringArrayValue()[Ljava/lang/String;\n" + 96 ".end method\n" + 97 "\n" + 98 ".method public abstract testStringValue()Ljava/lang/String;\n" + 99 ".end method"); 100 101 myFixture.addFileToProject("my/TestAnnotation2.smali", 102 ".class public interface abstract annotation Lmy/TestAnnotation2;\n" + 103 ".super Ljava/lang/Object;\n" + 104 ".implements Ljava/lang/annotation/Annotation;\n"); 105 106 SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali", 107 ".class public Lmy/pkg/blah; .super Ljava/lang/Object;\n" + 108 "\n" + 109 ".field public myField:I\n" + 110 " .annotation runtime Lmy/TestAnnotation;\n" + 111 " testBooleanValue = true\n" + 112 " testStringValue = \"blah\"\n" + 113 " testStringArrayValue = {\n" + 114 " \"blah1\",\n" + 115 " \"blah2\"\n" + 116 " }\n" + 117 " .end annotation\n" + 118 " .annotation runtime Lmy/TestAnnotation2;\n" + 119 " .end annotation\n" + 120 ".end field"); 121 122 SmaliClass smaliClass = file.getPsiClass(); 123 Assert.assertEquals("my.pkg.blah", smaliClass.getQualifiedName()); 124 125 PsiField field = smaliClass.findFieldByName("myField", false); 126 doTest((PsiAnnotationOwner)field); 127 } 128 129 public void testMethodAnnotation() { 130 myFixture.addFileToProject("my/TestAnnotation.smali", 131 ".class public interface abstract annotation Lmy/TestAnnotation;\n" + 132 ".super Ljava/lang/Object;\n" + 133 ".implements Ljava/lang/annotation/Annotation;\n" + 134 "\n" + 135 ".method public abstract testBooleanValue()Z\n" + 136 ".end method\n" + 137 "\n" + 138 ".method public abstract testStringArrayValue()[Ljava/lang/String;\n" + 139 ".end method\n" + 140 "\n" + 141 ".method public abstract testStringValue()Ljava/lang/String;\n" + 142 ".end method"); 143 144 myFixture.addFileToProject("my/TestAnnotation2.smali", 145 ".class public interface abstract annotation Lmy/TestAnnotation2;\n" + 146 ".super Ljava/lang/Object;\n" + 147 ".implements Ljava/lang/annotation/Annotation;\n"); 148 149 SmaliFile file = (SmaliFile)myFixture.addFileToProject("my/pkg/blah.smali", 150 ".class public Lmy/pkg/blah; .super Ljava/lang/Object;\n" + 151 "\n" + 152 ".method public myMethod()V\n" + 153 " .annotation runtime Lmy/TestAnnotation;\n" + 154 " testBooleanValue = true\n" + 155 " testStringValue = \"blah\"\n" + 156 " testStringArrayValue = {\n" + 157 " \"blah1\",\n" + 158 " \"blah2\"\n" + 159 " }\n" + 160 " .end annotation\n" + 161 " .annotation runtime Lmy/TestAnnotation2;\n" + 162 " .end annotation\n" + 163 ".end method"); 164 165 SmaliClass smaliClass = file.getPsiClass(); 166 Assert.assertEquals("my.pkg.blah", smaliClass.getQualifiedName()); 167 168 SmaliMethod method = smaliClass.getMethods()[0]; 169 doTest(method); 170 } 171 172 public void doTest(PsiAnnotationOwner annotationOwner) { 173 Assert.assertEquals(2, annotationOwner.getAnnotations().length); 174 175 Assert.assertEquals("my.TestAnnotation", annotationOwner.getAnnotations()[0].getQualifiedName()); 176 PsiJavaCodeReferenceElement annotationNameRef = annotationOwner.getAnnotations()[0].getNameReferenceElement(); 177 Assert.assertNotNull(annotationNameRef); 178 SmaliClass smaliAnnotationClass = (SmaliClass)annotationNameRef.resolve(); 179 Assert.assertNotNull(smaliAnnotationClass); 180 Assert.assertEquals("my.TestAnnotation", smaliAnnotationClass.getQualifiedName()); 181 182 Assert.assertEquals("my.TestAnnotation2", annotationOwner.getAnnotations()[1].getQualifiedName()); 183 annotationNameRef = annotationOwner.getAnnotations()[1].getNameReferenceElement(); 184 Assert.assertNotNull(annotationNameRef); 185 smaliAnnotationClass = (SmaliClass)annotationNameRef.resolve(); 186 Assert.assertNotNull(smaliAnnotationClass); 187 Assert.assertEquals("my.TestAnnotation2", smaliAnnotationClass.getQualifiedName()); 188 189 PsiAnnotation smaliAnnotation = annotationOwner.findAnnotation("my.TestAnnotation"); 190 Assert.assertNotNull(smaliAnnotation); 191 Assert.assertEquals("my.TestAnnotation", smaliAnnotation.getQualifiedName()); 192 PsiAnnotationOwner owner = smaliAnnotation.getOwner(); 193 Assert.assertNotNull(owner); 194 Assert.assertSame(annotationOwner, owner); 195 annotationNameRef = smaliAnnotation.getNameReferenceElement(); 196 Assert.assertNotNull(annotationNameRef); 197 smaliAnnotationClass = (SmaliClass)annotationNameRef.resolve(); 198 Assert.assertNotNull(smaliAnnotationClass); 199 Assert.assertEquals("my.TestAnnotation", smaliAnnotationClass.getQualifiedName()); 200 201 PsiAnnotationParameterList parameterList = smaliAnnotation.getParameterList(); 202 Assert.assertNotNull(parameterList); 203 Assert.assertEquals(3, parameterList.getAttributes().length); 204 Assert.assertEquals("testBooleanValue", parameterList.getAttributes()[0].getName()); 205 PsiAnnotationMemberValue value = parameterList.getAttributes()[0].getValue(); 206 Assert.assertNotNull(value); 207 // TODO: test the values rather than the text 208 Assert.assertEquals("true", value.getText()); 209 Assert.assertEquals("testStringValue", parameterList.getAttributes()[1].getName()); 210 value = parameterList.getAttributes()[1].getValue(); 211 Assert.assertNotNull(value); 212 Assert.assertEquals("\"blah\"", value.getText()); 213 Assert.assertEquals("testStringArrayValue", parameterList.getAttributes()[2].getName()); 214 value = parameterList.getAttributes()[2].getValue(); 215 Assert.assertNotNull(value); 216 // TODO: test the individual values, once the array literal stuff is implemented 217 218 value = smaliAnnotation.findAttributeValue("testBooleanValue"); 219 Assert.assertNotNull(value); 220 Assert.assertEquals("true", value.getText()); 221 222 value = smaliAnnotation.findAttributeValue("testStringValue"); 223 Assert.assertNotNull(value); 224 Assert.assertEquals("\"blah\"", value.getText()); 225 226 value = smaliAnnotation.findAttributeValue("testStringArrayValue"); 227 Assert.assertNotNull(value); 228 229 // TODO: test findAttributeValue vs findDeclaredAttributeValue for default values 230 231 smaliAnnotation = annotationOwner.findAnnotation("my.TestAnnotation2"); 232 Assert.assertNotNull(smaliAnnotation); 233 Assert.assertEquals("my.TestAnnotation2", smaliAnnotation.getQualifiedName()); 234 owner = smaliAnnotation.getOwner(); 235 Assert.assertNotNull(owner); 236 Assert.assertSame(annotationOwner, owner); 237 annotationNameRef = smaliAnnotation.getNameReferenceElement(); 238 Assert.assertNotNull(annotationNameRef); 239 smaliAnnotationClass = (SmaliClass)annotationNameRef.resolve(); 240 Assert.assertNotNull(smaliAnnotationClass); 241 Assert.assertEquals("my.TestAnnotation2", smaliAnnotationClass.getQualifiedName()); 242 243 parameterList = smaliAnnotation.getParameterList(); 244 Assert.assertNotNull(parameterList); 245 Assert.assertEquals(0, parameterList.getAttributes().length); 246 } 247 248 public void testDefaultValue() { 249 SmaliFile file = (SmaliFile)myFixture.addFileToProject("AnnotationWithDefaultValue.smali", "" + 250 ".class public abstract interface annotation LAnnotationWithValues;\n" + 251 ".super Ljava/lang/Object;\n" + 252 ".implements Ljava/lang/annotation/Annotation;\n" + 253 "\n" + 254 ".method public abstract intValue()I\n" + 255 ".end method\n" + 256 "\n" + 257 ".annotation system Ldalvik/annotation/AnnotationDefault;\n" + 258 " value = .subannotation LAnnotationWithValues;\n" + 259 " intValue = 4\n" + 260 " .end subannotation\n" + 261 ".end annotation\n" + 262 "\n"); 263 264 SmaliClass smaliClass = file.getPsiClass(); 265 Assert.assertNotNull(smaliClass); 266 SmaliMethod method = smaliClass.getMethods()[0]; 267 Assert.assertEquals("intValue", method.getName()); 268 269 PsiAnnotationMemberValue defaultValue = method.getDefaultValue(); 270 Assert.assertTrue(defaultValue instanceof SmaliLiteral); 271 Assert.assertEquals(4, ((SmaliLiteral)defaultValue).getIntegralValue()); 272 } 273} 274