1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.monkeyrunner; 17 18 import com.google.common.base.Preconditions; 19 import com.google.common.collect.Maps; 20 21 import com.android.monkeyrunner.doc.MonkeyRunnerExported; 22 23 import junit.framework.TestCase; 24 25 import org.python.core.ArgParser; 26 import org.python.core.ClassDictInit; 27 import org.python.core.PyDictionary; 28 import org.python.core.PyException; 29 import org.python.core.PyObject; 30 import org.python.core.PyString; 31 32 import java.util.List; 33 import java.util.Map; 34 import java.util.Set; 35 36 /** 37 * Unit tests for the JythonUtils class. 38 */ 39 public class JythonUtilsTest extends TestCase { 40 private static final String PACKAGE_NAME = JythonUtilsTest.class.getPackage().getName(); 41 private static final String CLASS_NAME = JythonUtilsTest.class.getSimpleName(); 42 private static final String EXECUTABLE_PATH = "string"; 43 44 private static boolean called = false; 45 private static double floatValue = 0.0; 46 private static List<Object> listValue = null; 47 private static Map<String, Object> mapValue; 48 49 @MonkeyRunnerExported(doc = "", args = {"value"}) 50 public static void floatTest(PyObject[] args, String[] kws) { 51 ArgParser ap = JythonUtils.createArgParser(args, kws); 52 Preconditions.checkNotNull(ap); 53 called = true; 54 55 floatValue = JythonUtils.getFloat(ap, 0); 56 } 57 58 @MonkeyRunnerExported(doc = "", args = {"value"}) 59 public static void listTest(PyObject[] args, String[] kws) { 60 ArgParser ap = JythonUtils.createArgParser(args, kws); 61 Preconditions.checkNotNull(ap); 62 called = true; 63 64 listValue = JythonUtils.getList(ap, 0); 65 } 66 67 @MonkeyRunnerExported(doc = "", args = {"value"}) 68 public static void mapTest(PyObject[] args, String[] kws) { 69 ArgParser ap = JythonUtils.createArgParser(args, kws); 70 Preconditions.checkNotNull(ap); 71 called = true; 72 73 mapValue = JythonUtils.getMap(ap, 0); 74 } 75 76 @MonkeyRunnerExported(doc = "") 77 public static PyDictionary convertMapTest(PyObject[] args, String[] kws) { 78 Map<String, Object> map = Maps.newHashMap(); 79 map.put("string", "value"); 80 map.put("integer", 1); 81 map.put("double", 3.14); 82 return JythonUtils.convertMapToDict(map); 83 } 84 85 @Override 86 protected void setUp() throws Exception { 87 called = false; 88 floatValue = 0.0; 89 } 90 91 private static PyObject call(String method) { 92 return call(method, new String[]{ }); 93 } 94 private static PyObject call(String method, String... args) { 95 StringBuilder sb = new StringBuilder(); 96 sb.append("from ").append(PACKAGE_NAME); 97 sb.append(" import ").append(CLASS_NAME).append("\n"); 98 99 // Exec line 100 sb.append("result = "); 101 sb.append(CLASS_NAME).append(".").append(method); 102 sb.append("("); 103 for (String arg : args) { 104 sb.append(arg).append(","); 105 } 106 sb.append(")"); 107 108 return ScriptRunner.runStringAndGet(EXECUTABLE_PATH, sb.toString(), "result").get("result"); 109 } 110 111 public void testSimpleCall() { 112 call("floatTest", "0.0"); 113 assertTrue(called); 114 } 115 116 public void testMissingFloatArg() { 117 try { 118 call("floatTest"); 119 } catch(PyException e) { 120 return; 121 } 122 fail("Should have thrown exception"); 123 } 124 125 public void testBadFloatArgType() { 126 try { 127 call("floatTest", "\'foo\'"); 128 } catch(PyException e) { 129 return; 130 } 131 fail("Should have thrown exception"); 132 } 133 134 public void testFloatParse() { 135 call("floatTest", "103.2"); 136 assertTrue(called); 137 assertEquals(floatValue, 103.2); 138 } 139 140 public void testFloatParseInteger() { 141 call("floatTest", "103"); 142 assertTrue(called); 143 assertEquals(floatValue, 103.0); 144 } 145 146 public void testParseStringList() { 147 call("listTest", "['a', 'b', 'c']"); 148 assertTrue(called); 149 assertEquals(3, listValue.size()); 150 assertEquals("a", listValue.get(0)); 151 assertEquals("b", listValue.get(1)); 152 assertEquals("c", listValue.get(2)); 153 } 154 155 public void testParseIntList() { 156 call("listTest", "[1, 2, 3]"); 157 assertTrue(called); 158 assertEquals(3, listValue.size()); 159 assertEquals(new Integer(1), listValue.get(0)); 160 assertEquals(new Integer(2), listValue.get(1)); 161 assertEquals(new Integer(3), listValue.get(2)); 162 } 163 164 public void testParseMixedList() { 165 call("listTest", "['a', 1, 3.14]"); 166 assertTrue(called); 167 assertEquals(3, listValue.size()); 168 assertEquals("a", listValue.get(0)); 169 assertEquals(new Integer(1), listValue.get(1)); 170 assertEquals(new Double(3.14), listValue.get(2)); 171 } 172 173 public void testParseOptionalList() { 174 call("listTest"); 175 assertTrue(called); 176 assertEquals(0, listValue.size()); 177 } 178 179 public void testParsingNotAList() { 180 try { 181 call("listTest", "1.0"); 182 } catch (PyException e) { 183 return; 184 } 185 fail("Should have thrown an exception"); 186 } 187 188 public void testParseMap() { 189 call("mapTest", "{'a': 0, 'b': 'bee', 3: 'cee'}"); 190 assertTrue(called); 191 assertEquals(3, mapValue.size()); 192 assertEquals(new Integer(0), mapValue.get("a")); 193 assertEquals("bee", mapValue.get("b")); 194 // note: coerced key type 195 assertEquals("cee", mapValue.get("3")); 196 } 197 198 public void testParsingNotAMap() { 199 try { 200 call("mapTest", "1.0"); 201 } catch (PyException e) { 202 return; 203 } 204 fail("Should have thrown an exception"); 205 } 206 207 public void testParseOptionalMap() { 208 call("mapTest"); 209 assertTrue(called); 210 assertEquals(0, mapValue.size()); 211 } 212 213 public void testConvertMap() { 214 PyDictionary result = (PyDictionary) call("convertMapTest"); 215 PyObject stringPyObject = result.__getitem__(new PyString("string")); 216 String string = (String) stringPyObject.__tojava__(String.class); 217 assertEquals("value", string); 218 219 PyObject intPyObject = result.__getitem__(new PyString("integer")); 220 int i = (Integer) intPyObject.__tojava__(Integer.class); 221 assertEquals(i, 1); 222 223 PyObject doublePyObject = result.__getitem__(new PyString("double")); 224 double d = (Double) doublePyObject.__tojava__(Double.class); 225 assertEquals(3.14, d); 226 } 227 228 /** 229 * Base class to test overridden methods. 230 */ 231 static class PythonMethodsClass extends PyObject implements ClassDictInit { 232 public static void classDictInit(PyObject dict) { 233 JythonUtils.convertDocAnnotationsForClass(PythonMethodsClass.class, dict); 234 } 235 236 @MonkeyRunnerExported(doc = "The first method.") 237 public void firstMethod(PyObject[] args, String[] kws) { 238 } 239 240 @MonkeyRunnerExported(doc = "The second method.") 241 public void secondMethod(PyObject[] args, String[] kws) { 242 } 243 244 public void unattributedMethod() { 245 } 246 } 247 248 public void testGetPythonMethods() { 249 Set<String> methods = JythonUtils.getMethodNames(PythonMethodsClass.class); 250 assertEquals(2, methods.size()); 251 assertTrue(methods.contains("firstMethod")); 252 assertTrue(methods.contains("secondMethod")); 253 254 // Make sure it works on non-Jython objects. 255 assertTrue(JythonUtils.getMethodNames(String.class).isEmpty()); 256 } 257 } 258