diff options
Diffstat (limited to 'src/com/google/android/testing/mocking/AndroidFrameworkMockGenerator.java')
-rw-r--r-- | src/com/google/android/testing/mocking/AndroidFrameworkMockGenerator.java | 170 |
1 files changed, 170 insertions, 0 deletions
diff --git a/src/com/google/android/testing/mocking/AndroidFrameworkMockGenerator.java b/src/com/google/android/testing/mocking/AndroidFrameworkMockGenerator.java new file mode 100644 index 0000000..d634c24 --- /dev/null +++ b/src/com/google/android/testing/mocking/AndroidFrameworkMockGenerator.java @@ -0,0 +1,170 @@ +/* + * Copyright 2010 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.google.android.testing.mocking; + +import javassist.CannotCompileException; +import javassist.CtClass; +import javassist.NotFoundException; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +/** + * Mock Generator for Android Framework classes. + * + * <p> + * This class will pull pre-defined mocks for Android framework classes. This is + * needed because a project might build against version X and then run against + * version Y, where the specification of the class being mocked will have + * changed, rendering the mock invalid. + * + * @author swoodward@google.com (Stephen Woodward) + */ +public class AndroidFrameworkMockGenerator { + private static final String LIB_FOLDER = "lib"; + private static final String JAR_NAME = "android_"; + + /** + * Returns a set of mock support classes for the specified Class for all versions of + * the Android SDK. If the requested class is not part of the Android framework, then the class + * will not be found and an exception will be thrown. + * + * @param clazz the class to mock. + * @return All available mock support classes (for all known Android SDKs) for + * the requested Class. + */ + public List<GeneratedClassFile> getMocksForClass(Class<?> clazz) throws ClassNotFoundException, + IOException { + List<Class<?>> prebuiltClasses = getPrebuiltClassesFor(clazz); + List<GeneratedClassFile> classList = new ArrayList<GeneratedClassFile>(); + for (Class<?> prebuiltClass : prebuiltClasses) { + try { + CtClass ctClass = AndroidMockGenerator.getClassPool().get(prebuiltClass.getName()); + classList.add(new GeneratedClassFile(ctClass.getName(), ctClass.toBytecode())); + } catch (NotFoundException e) { + throw new ClassNotFoundException("Missing class while fetching prebuilt mocks: " + + prebuiltClass.getName(), e); + } catch (CannotCompileException e) { + throw new RuntimeException("Internal Error copying a prebuilt mock: " + + prebuiltClass.getName(), e); + } + } + return classList; + } + + private List<Class<?>> getPrebuiltClassesFor(Class<?> clazz) throws ClassNotFoundException { + List<Class<?>> classes = new ArrayList<Class<?>>(); + SdkVersion[] versions = SdkVersion.getAllVersions(); + for (SdkVersion sdkVersion : versions) { + classes.add(Class.forName(FileUtils.getSubclassNameFor(clazz, sdkVersion))); + classes.add(Class.forName(FileUtils.getInterfaceNameFor(clazz, sdkVersion))); + } + return classes; + } + + /** + * @return a List of {@link GeneratedClassFile} objects representing the mocks for the specified + * class for a single version of the Android SDK. + */ + public List<GeneratedClassFile> createMocksForClass(Class<?> clazz, SdkVersion version) + throws ClassNotFoundException, IOException, CannotCompileException { + AndroidMockGenerator mockGenerator = new AndroidMockGenerator(); + List<GeneratedClassFile> mocks = new ArrayList<GeneratedClassFile>(); + mocks.addAll(mockGenerator.createMocksForClass(clazz, version)); + return mocks; + } + + /** + * @return A list of all class files inside the provided jar file. + */ + List<Class<?>> getClassList(JarFile jar) throws ClassNotFoundException { + return getClassList(Collections.list(jar.entries())); + } + + List<Class<?>> getClassList(Collection<JarEntry> jarEntries) throws ClassNotFoundException { + List<Class<?>> classList = new ArrayList<Class<?>>(); + for (JarEntry jarEntry : jarEntries) { + if (jarEntryIsClassFile(jarEntry)) { + classList.add(Class.forName(FileUtils.getClassNameFor(jarEntry.getName()))); + } + } + return classList; + } + + /** + * @return true if the provided JarEntry represents a class file. + */ + boolean jarEntryIsClassFile(JarEntry jarEntry) { + return jarEntry.getName().endsWith(".class"); + } + + /** + * @return the Android framework jar file for the specified {@link SdkVersion}. + */ + static String getJarFileNameForVersion(SdkVersion version) { + return new StringBuilder() + .append(LIB_FOLDER) + .append(File.separator) + .append("android") + .append(File.separator) + .append(JAR_NAME) + .append(version.getVersionName()) + .append(".jar").toString(); + } + + private static Set<GeneratedClassFile> generateMocks( + SdkVersion version, JarFile jar) + throws ClassNotFoundException, IOException, CannotCompileException { + AndroidFrameworkMockGenerator mockGenerator = new AndroidFrameworkMockGenerator(); + List<Class<?>> classList = mockGenerator.getClassList(jar); + Set<GeneratedClassFile> classes = new HashSet<GeneratedClassFile>(); + for (Class<?> clazz : classList) { + classes.addAll(mockGenerator.createMocksForClass(clazz, version)); + } + return classes; + } + + private static JarFile getJarFile(SdkVersion version) throws IOException { + File jarFile = new File(getJarFileNameForVersion(version)).getAbsoluteFile(); + System.out.println("Using Jar File: " + jarFile.getAbsolutePath()); + return new JarFile(jarFile); + } + + public static void main(String[] args) { + try { + String outputFolderName = args[0]; + SdkVersion version = SdkVersion.getVersionFor(Integer.parseInt(args[1])); + System.out.println("Generating files for " + version.getPackagePrefix()); + + JarFile jar = getJarFile(version); + + Set<GeneratedClassFile> classes = generateMocks(version, jar); + for (GeneratedClassFile clazz : classes) { + FileUtils.saveClassToFolder(clazz, outputFolderName); + } + } catch (Exception e) { + throw new RuntimeException("Internal error generating framework mocks", e); + } + } +} |