1 /** 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * 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, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 17 package com.android.inputmethod.latin.dicttool; 18 19 import com.android.inputmethod.latin.common.FileUtils; 20 import com.android.inputmethod.latin.makedict.BinaryDictDecoderEncoderTests; 21 import com.android.inputmethod.latin.makedict.BinaryDictEncoderFlattenTreeTests; 22 import com.android.inputmethod.latin.makedict.FusionDictionaryTest; 23 24 import java.io.File; 25 import java.io.IOException; 26 import java.lang.reflect.Constructor; 27 import java.lang.reflect.InvocationTargetException; 28 import java.lang.reflect.Method; 29 import java.nio.file.Files; 30 import java.util.ArrayList; 31 32 /** 33 * Dicttool command implementing self-tests. 34 */ 35 public class Test extends Dicttool.Command { 36 private static final String getTmpDir() { 37 try { 38 return Files.createTempDirectory("dicttool").toString(); 39 } catch (IOException e) { 40 throw new RuntimeException("Can't get temporary directory", e); 41 } 42 } 43 private static final String TEST_TMP_DIR_BASE = getTmpDir(); 44 public static final File TEST_TMP_DIR = new File(TEST_TMP_DIR_BASE); 45 public static final String COMMAND = "test"; 46 private static final int DEFAULT_MAX_UNIGRAMS = 1500; 47 private long mSeed = System.currentTimeMillis(); 48 private int mMaxUnigrams = DEFAULT_MAX_UNIGRAMS; 49 50 private static final Class<?>[] sClassesToTest = { 51 BinaryDictOffdeviceUtilsTests.class, 52 FusionDictionaryTest.class, 53 BinaryDictDecoderEncoderTests.class, 54 BinaryDictEncoderFlattenTreeTests.class, 55 }; 56 private ArrayList<Method> mAllTestMethods = new ArrayList<>(); 57 private ArrayList<String> mUsedTestMethods = new ArrayList<>(); 58 59 public Test() { 60 for (final Class<?> c : sClassesToTest) { 61 for (final Method m : c.getDeclaredMethods()) { 62 if (m.getName().startsWith("test") && Void.TYPE == m.getReturnType() 63 && 0 == m.getParameterTypes().length) { 64 mAllTestMethods.add(m); 65 } 66 } 67 } 68 } 69 70 @Override 71 public String getHelp() { 72 final StringBuilder s = new StringBuilder( 73 "test [-s seed] [-m maxUnigrams] [-n] [testName...]\n" 74 + "If seed is not specified, the current time is used.\n" 75 + "If -n option is provided, do not delete temporary files in " 76 + TEST_TMP_DIR_BASE + "/*.\n" 77 + "Test list is:\n"); 78 for (final Method m : mAllTestMethods) { 79 s.append(" "); 80 s.append(m.getName()); 81 s.append("\n"); 82 } 83 return s.toString(); 84 } 85 86 @Override 87 public void run() throws IllegalAccessException, InstantiationException, 88 InvocationTargetException { 89 int i = 0; 90 boolean deleteTmpDir = true; 91 while (i < mArgs.length) { 92 final String arg = mArgs[i++]; 93 if ("-s".equals(arg)) { 94 mSeed = Long.parseLong(mArgs[i++]); 95 } else if ("-m".equals(arg)) { 96 mMaxUnigrams = Integer.parseInt(mArgs[i++]); 97 } else if ("-n".equals(arg)) { 98 deleteTmpDir = false; 99 } else { 100 mUsedTestMethods.add(arg); 101 } 102 } 103 try { 104 runChosenTests(); 105 } finally { 106 if (deleteTmpDir) { 107 FileUtils.deleteRecursively(TEST_TMP_DIR); 108 } 109 } 110 } 111 112 private void runChosenTests() throws IllegalAccessException, InstantiationException, 113 InvocationTargetException { 114 for (final Method m : mAllTestMethods) { 115 final Class<?> declaringClass = m.getDeclaringClass(); 116 if (!mUsedTestMethods.isEmpty() && !mUsedTestMethods.contains(m.getName())) continue; 117 // Some of the test classes expose a two-argument constructor, taking a long as a 118 // seed for Random, and an int for a vocabulary size to test the dictionary with. They 119 // correspond respectively to the -s and -m numerical arguments to this command, which 120 // are stored in mSeed and mMaxUnigrams. If the two-arguments constructor is present, 121 // then invoke it; otherwise, invoke the default constructor. 122 Constructor<?> twoArgsConstructor = null; 123 try { 124 twoArgsConstructor = declaringClass.getDeclaredConstructor(Long.TYPE, Integer.TYPE); 125 } catch (NoSuchMethodException e) { 126 // No constructor with two args 127 } 128 final Object instance = null == twoArgsConstructor ? declaringClass.newInstance() 129 : twoArgsConstructor.newInstance(mSeed, mMaxUnigrams); 130 m.invoke(instance); 131 } 132 } 133 } 134