mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 14:18:48 +00:00
import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1160164 - Run "all the tests" when invoking xpcshell's mach command with no arguments instead of passing "all" to the test resolver.;r=ahal DONTBUILD (5583e3bce) - Bug 1171602 - Run mochitest using mach from a tests.zip, r=chmanchester (083d01f4c) - Bug 1178850 - Generate naive method bindings in annotation processor; r=snorp (8f8a14e3d) - Bug 1192079 - Support inner classes in generated JNI wrapper; r=snorp (1eefd6a4f)
This commit is contained in:
@@ -15,17 +15,22 @@ import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
|
||||
public class AnnotationProcessor {
|
||||
public static final String OUTFILE = "GeneratedJNIWrappers.cpp";
|
||||
public static final String HEADERFILE = "GeneratedJNIWrappers.h";
|
||||
public static final String SOURCE_FILE = "GeneratedJNIWrappers.cpp";
|
||||
public static final String HEADER_FILE = "GeneratedJNIWrappers.h";
|
||||
public static final String NATIVES_FILE = "GeneratedJNINatives.h";
|
||||
|
||||
public static final String GENERATED_COMMENT =
|
||||
"// GENERATED CODE\n" +
|
||||
"// Generated by the Java program at /build/annotationProcessors at compile time\n" +
|
||||
"// from annotations on Java methods. To update, change the annotations on the\n" +
|
||||
"// corresponding Javamethods and rerun the build. Manually updating this file\n" +
|
||||
"// corresponding Java methods and rerun the build. Manually updating this file\n" +
|
||||
"// will cause your build to fail.\n" +
|
||||
"\n";
|
||||
|
||||
private static final StringBuilder headerFile = new StringBuilder(GENERATED_COMMENT);
|
||||
private static final StringBuilder implementationFile = new StringBuilder(GENERATED_COMMENT);
|
||||
private static final StringBuilder nativesFile = new StringBuilder(GENERATED_COMMENT);
|
||||
|
||||
public static void main(String[] args) {
|
||||
// We expect a list of jars on the commandline. If missing, whinge about it.
|
||||
if (args.length <= 1) {
|
||||
@@ -45,10 +50,9 @@ public class AnnotationProcessor {
|
||||
// Get an iterator over the classes in the jar files given...
|
||||
Iterator<ClassWithOptions> jarClassIterator = IterableJarLoadingURLClassLoader.getIteratorOverJars(args);
|
||||
|
||||
StringBuilder headerFile = new StringBuilder(GENERATED_COMMENT);
|
||||
headerFile.append(
|
||||
"#ifndef GeneratedJNIWrappers_h__\n" +
|
||||
"#define GeneratedJNIWrappers_h__\n" +
|
||||
"#ifndef " + getHeaderGuardName(HEADER_FILE) + "\n" +
|
||||
"#define " + getHeaderGuardName(HEADER_FILE) + "\n" +
|
||||
"\n" +
|
||||
"#include \"mozilla/jni/Refs.h\"\n" +
|
||||
"\n" +
|
||||
@@ -56,7 +60,6 @@ public class AnnotationProcessor {
|
||||
"namespace widget {\n" +
|
||||
"\n");
|
||||
|
||||
StringBuilder implementationFile = new StringBuilder(GENERATED_COMMENT);
|
||||
implementationFile.append(
|
||||
"#include \"GeneratedJNIWrappers.h\"\n" +
|
||||
"#include \"mozilla/jni/Accessors.h\"\n" +
|
||||
@@ -65,37 +68,19 @@ public class AnnotationProcessor {
|
||||
"namespace widget {\n" +
|
||||
"\n");
|
||||
|
||||
nativesFile.append(
|
||||
"#ifndef " + getHeaderGuardName(NATIVES_FILE) + "\n" +
|
||||
"#define " + getHeaderGuardName(NATIVES_FILE) + "\n" +
|
||||
"\n" +
|
||||
"#include \"GeneratedJNIWrappers.h\"\n" +
|
||||
"#include \"mozilla/jni/Natives.h\"\n" +
|
||||
"\n" +
|
||||
"namespace mozilla {\n" +
|
||||
"namespace widget {\n" +
|
||||
"\n");
|
||||
|
||||
while (jarClassIterator.hasNext()) {
|
||||
ClassWithOptions aClassTuple = jarClassIterator.next();
|
||||
|
||||
CodeGenerator generatorInstance;
|
||||
|
||||
// Get an iterator over the appropriately generated methods of this class
|
||||
Iterator<AnnotatableEntity> methodIterator = new GeneratableElementIterator(aClassTuple.wrappedClass);
|
||||
|
||||
if (!methodIterator.hasNext()) {
|
||||
continue;
|
||||
}
|
||||
generatorInstance = new CodeGenerator(aClassTuple);
|
||||
|
||||
// Iterate all annotated members in this class..
|
||||
while (methodIterator.hasNext()) {
|
||||
AnnotatableEntity aElementTuple = methodIterator.next();
|
||||
switch (aElementTuple.mEntityType) {
|
||||
case METHOD:
|
||||
generatorInstance.generateMethod(aElementTuple);
|
||||
break;
|
||||
case FIELD:
|
||||
generatorInstance.generateField(aElementTuple);
|
||||
break;
|
||||
case CONSTRUCTOR:
|
||||
generatorInstance.generateConstructor(aElementTuple);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
headerFile.append(generatorInstance.getHeaderFileContents());
|
||||
implementationFile.append(generatorInstance.getWrapperFileContents());
|
||||
generateClass(jarClassIterator.next());
|
||||
}
|
||||
|
||||
implementationFile.append(
|
||||
@@ -107,38 +92,75 @@ public class AnnotationProcessor {
|
||||
"\n" +
|
||||
"} /* widget */\n" +
|
||||
"} /* mozilla */\n" +
|
||||
"#endif // GeneratedJNIWrappers_h__\n");
|
||||
"#endif // " + getHeaderGuardName(HEADER_FILE) + "\n");
|
||||
|
||||
nativesFile.append(
|
||||
"\n" +
|
||||
"} /* widget */\n" +
|
||||
"} /* mozilla */\n" +
|
||||
"#endif // " + getHeaderGuardName(NATIVES_FILE) + "\n");
|
||||
|
||||
writeOutputFile(SOURCE_FILE, implementationFile);
|
||||
writeOutputFile(HEADER_FILE, headerFile);
|
||||
writeOutputFile(NATIVES_FILE, nativesFile);
|
||||
|
||||
writeOutputFiles(headerFile, implementationFile);
|
||||
long e = System.currentTimeMillis();
|
||||
System.out.println("Annotation processing complete in " + (e - s) + "ms");
|
||||
}
|
||||
|
||||
private static void writeOutputFiles(StringBuilder aHeaderFile, StringBuilder aImplementationFile) {
|
||||
FileOutputStream headerStream = null;
|
||||
try {
|
||||
headerStream = new FileOutputStream(OUTFILE);
|
||||
headerStream.write(aImplementationFile.toString().getBytes());
|
||||
} catch (IOException e) {
|
||||
System.err.println("Unable to write " + OUTFILE + ". Perhaps a permissions issue?");
|
||||
e.printStackTrace(System.err);
|
||||
} finally {
|
||||
if (headerStream != null) {
|
||||
try {
|
||||
headerStream.close();
|
||||
} catch (IOException e) {
|
||||
System.err.println("Unable to close headerStream due to "+e);
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
private static void generateClass(final ClassWithOptions annotatedClass) {
|
||||
// Get an iterator over the appropriately generated methods of this class
|
||||
final GeneratableElementIterator methodIterator
|
||||
= new GeneratableElementIterator(annotatedClass);
|
||||
final ClassWithOptions[] innerClasses = methodIterator.getInnerClasses();
|
||||
|
||||
if (!methodIterator.hasNext() && innerClasses.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
final CodeGenerator generatorInstance = new CodeGenerator(annotatedClass);
|
||||
generatorInstance.generateClasses(innerClasses);
|
||||
|
||||
// Iterate all annotated members in this class..
|
||||
while (methodIterator.hasNext()) {
|
||||
AnnotatableEntity aElementTuple = methodIterator.next();
|
||||
switch (aElementTuple.mEntityType) {
|
||||
case METHOD:
|
||||
generatorInstance.generateMethod(aElementTuple);
|
||||
break;
|
||||
case NATIVE:
|
||||
generatorInstance.generateNative(aElementTuple);
|
||||
break;
|
||||
case FIELD:
|
||||
generatorInstance.generateField(aElementTuple);
|
||||
break;
|
||||
case CONSTRUCTOR:
|
||||
generatorInstance.generateConstructor(aElementTuple);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
headerFile.append(generatorInstance.getHeaderFileContents());
|
||||
implementationFile.append(generatorInstance.getWrapperFileContents());
|
||||
nativesFile.append(generatorInstance.getNativesFileContents());
|
||||
|
||||
for (ClassWithOptions innerClass : innerClasses) {
|
||||
generateClass(innerClass);
|
||||
}
|
||||
}
|
||||
|
||||
private static String getHeaderGuardName(final String name) {
|
||||
return name.replaceAll("\\W", "_");
|
||||
}
|
||||
|
||||
private static void writeOutputFile(final String name,
|
||||
final StringBuilder content) {
|
||||
FileOutputStream outStream = null;
|
||||
try {
|
||||
outStream = new FileOutputStream(HEADERFILE);
|
||||
outStream.write(aHeaderFile.toString().getBytes());
|
||||
outStream = new FileOutputStream(name);
|
||||
outStream.write(content.toString().getBytes());
|
||||
} catch (IOException e) {
|
||||
System.err.println("Unable to write " + HEADERFILE + ". Perhaps a permissions issue?");
|
||||
System.err.println("Unable to write " + name + ". Perhaps a permissions issue?");
|
||||
e.printStackTrace(System.err);
|
||||
} finally {
|
||||
if (outStream != null) {
|
||||
|
||||
@@ -22,6 +22,8 @@ public class CodeGenerator {
|
||||
// Buffers holding the strings to ultimately be written to the output files.
|
||||
private final StringBuilder cpp = new StringBuilder();
|
||||
private final StringBuilder header = new StringBuilder();
|
||||
private final StringBuilder natives = new StringBuilder();
|
||||
private final StringBuilder nativesInits = new StringBuilder();
|
||||
|
||||
private final Class<?> cls;
|
||||
private final String clsName;
|
||||
@@ -33,8 +35,8 @@ public class CodeGenerator {
|
||||
this.clsName = annotatedClass.generatedName;
|
||||
|
||||
header.append(
|
||||
"class " + clsName + " : public mozilla::jni::Class<" + clsName + "> {\n" +
|
||||
"\n" +
|
||||
"class " + clsName + " : public mozilla::jni::Class<" + clsName + ">\n" +
|
||||
"{\n" +
|
||||
"public:\n" +
|
||||
" typedef mozilla::jni::Ref<" + clsName + "> Ref;\n" +
|
||||
" typedef mozilla::jni::LocalRef<" + clsName + "> LocalRef;\n" +
|
||||
@@ -51,6 +53,12 @@ public class CodeGenerator {
|
||||
cpp.append(
|
||||
"constexpr char " + clsName + "::name[];\n" +
|
||||
"\n");
|
||||
|
||||
natives.append(
|
||||
"template<class Impl>\n" +
|
||||
"class " + clsName + "::Natives : " +
|
||||
"public mozilla::jni::NativeImpl<" + clsName + ", Impl>\n" +
|
||||
"{\n");
|
||||
}
|
||||
|
||||
private String getTraitsName(String uniqueName, boolean includeScope) {
|
||||
@@ -72,20 +80,30 @@ public class CodeGenerator {
|
||||
}
|
||||
|
||||
private void generateMember(AnnotationInfo info, Member member,
|
||||
String uniqueName, Class<?> type) {
|
||||
String uniqueName, Class<?> type, Class<?>[] argTypes) {
|
||||
final StringBuilder args = new StringBuilder();
|
||||
for (Class<?> argType : argTypes) {
|
||||
args.append("\n " + getNativeParameterType(argType, info) + ",");
|
||||
}
|
||||
if (args.length() > 0) {
|
||||
args.setLength(args.length() - 1);
|
||||
}
|
||||
|
||||
header.append(
|
||||
"public:\n" +
|
||||
" struct " + getTraitsName(uniqueName, /* includeScope */ false) + " {\n" +
|
||||
" typedef " + clsName + " Owner;\n" +
|
||||
" typedef " + getNativeReturnType(type, info) + " ReturnType;\n" +
|
||||
" typedef " + getNativeParameterType(type, info) + " SetterType;\n" +
|
||||
" typedef mozilla::jni::Args<" + args + "> Args;\n" +
|
||||
" static constexpr char name[] = \"" +
|
||||
Utils.getMemberName(member) + "\";\n" +
|
||||
" static constexpr char signature[] =\n" +
|
||||
" \"" + Utils.getSignature(member) + "\";\n" +
|
||||
" static const bool isStatic = " + Utils.isStatic(member) + ";\n" +
|
||||
" static const bool isMultithreaded = " + info.isMultithreaded + ";\n" +
|
||||
" static const mozilla::jni::ExceptionMode exceptionMode = " + (
|
||||
" static const mozilla::jni::ExceptionMode exceptionMode =\n" +
|
||||
" " + (
|
||||
info.catchException ? "mozilla::jni::ExceptionMode::NSRESULT" :
|
||||
info.noThrow ? "mozilla::jni::ExceptionMode::IGNORE" :
|
||||
"mozilla::jni::ExceptionMode::ABORT") + ";\n" +
|
||||
@@ -248,15 +266,15 @@ public class CodeGenerator {
|
||||
final Method method = annotatedMethod.getMethod();
|
||||
final AnnotationInfo info = annotatedMethod.mAnnotationInfo;
|
||||
final String uniqueName = getUniqueMethodName(info.wrapperName);
|
||||
final Class<?>[] argTypes = method.getParameterTypes();
|
||||
final Class<?> returnType = method.getReturnType();
|
||||
|
||||
if (method.isSynthetic()) {
|
||||
return;
|
||||
}
|
||||
|
||||
generateMember(info, method, uniqueName, returnType);
|
||||
generateMember(info, method, uniqueName, returnType, argTypes);
|
||||
|
||||
final Class<?>[] argTypes = method.getParameterTypes();
|
||||
final boolean isStatic = Utils.isStatic(method);
|
||||
|
||||
header.append(
|
||||
@@ -272,6 +290,35 @@ public class CodeGenerator {
|
||||
"\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Append the appropriate generated code to the buffers for the native method provided.
|
||||
*
|
||||
* @param annotatedMethod The Java native method, plus annotation data.
|
||||
*/
|
||||
public void generateNative(AnnotatableEntity annotatedMethod) {
|
||||
// Unpack the tuple and extract some useful fields from the Method..
|
||||
final Method method = annotatedMethod.getMethod();
|
||||
final AnnotationInfo info = annotatedMethod.mAnnotationInfo;
|
||||
final String uniqueName = getUniqueMethodName(info.wrapperName);
|
||||
final Class<?>[] argTypes = method.getParameterTypes();
|
||||
final Class<?> returnType = method.getReturnType();
|
||||
|
||||
generateMember(info, method, uniqueName, returnType, argTypes);
|
||||
|
||||
final String traits = getTraitsName(uniqueName, /* includeScope */ true);
|
||||
|
||||
if (nativesInits.length() > 0) {
|
||||
nativesInits.append(',');
|
||||
}
|
||||
|
||||
nativesInits.append(
|
||||
"\n" +
|
||||
"\n" +
|
||||
" mozilla::jni::MakeNativeMethod<" + traits + ">(\n" +
|
||||
" mozilla::jni::NativeStub<" + traits + ", Impl>\n" +
|
||||
" ::template Wrap<&Impl::" + info.wrapperName + ">)");
|
||||
}
|
||||
|
||||
private String getLiteral(Object val, AnnotationInfo info) {
|
||||
final Class<?> type = val.getClass();
|
||||
|
||||
@@ -348,7 +395,7 @@ public class CodeGenerator {
|
||||
// Fall back to using accessors if we encounter an exception.
|
||||
}
|
||||
|
||||
generateMember(info, field, uniqueName, type);
|
||||
generateMember(info, field, uniqueName, type, EMPTY_CLASS_ARRAY);
|
||||
|
||||
final Class<?>[] getterArgs = EMPTY_CLASS_ARRAY;
|
||||
|
||||
@@ -389,15 +436,14 @@ public class CodeGenerator {
|
||||
final AnnotationInfo info = annotatedConstructor.mAnnotationInfo;
|
||||
final String wrapperName = "New";
|
||||
final String uniqueName = getUniqueMethodName(wrapperName);
|
||||
final Class<?>[] argTypes = method.getParameterTypes();
|
||||
final Class<?> returnType = cls;
|
||||
|
||||
if (method.isSynthetic()) {
|
||||
return;
|
||||
}
|
||||
|
||||
generateMember(info, method, uniqueName, returnType);
|
||||
|
||||
final Class<?>[] argTypes = method.getParameterTypes();
|
||||
generateMember(info, method, uniqueName, returnType, argTypes);
|
||||
|
||||
header.append(
|
||||
" " + generateDeclaration(wrapperName, argTypes,
|
||||
@@ -439,6 +485,21 @@ public class CodeGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
public void generateClasses(final ClassWithOptions[] classes) {
|
||||
if (classes.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
header.append(
|
||||
"public:\n");
|
||||
for (final ClassWithOptions cls : classes) {
|
||||
// Extract "Inner" from "Outer::Inner".
|
||||
header.append(
|
||||
" class " + Utils.getUnqualifiedName(cls.generatedName) + ";\n");
|
||||
}
|
||||
header.append('\n');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the finalised bytes to go into the generated wrappers file.
|
||||
*
|
||||
@@ -454,9 +515,34 @@ public class CodeGenerator {
|
||||
* @return The bytes to be written to the header file.
|
||||
*/
|
||||
public String getHeaderFileContents() {
|
||||
if (nativesInits.length() > 0) {
|
||||
header.append(
|
||||
"public:\n" +
|
||||
" template<class Impl> class Natives;\n");
|
||||
}
|
||||
header.append(
|
||||
"};\n" +
|
||||
"\n");
|
||||
return header.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the finalised bytes to go into the generated natives header file.
|
||||
*
|
||||
* @return The bytes to be written to the header file.
|
||||
*/
|
||||
public String getNativesFileContents() {
|
||||
if (nativesInits.length() == 0) {
|
||||
return "";
|
||||
}
|
||||
natives.append(
|
||||
"public:\n" +
|
||||
" static constexpr JNINativeMethod methods[] = {" + nativesInits + '\n' +
|
||||
" };\n" +
|
||||
"};\n" +
|
||||
"\n" +
|
||||
"template<class Impl>\n" +
|
||||
"constexpr JNINativeMethod " + clsName + "::Natives<Impl>::methods[];\n");
|
||||
return natives.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,13 +10,14 @@ import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Member;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
/**
|
||||
* Union type to hold either a method, field, or ctor. Allows us to iterate "The generatable stuff", despite
|
||||
* the fact that such things can be of either flavour.
|
||||
*/
|
||||
public class AnnotatableEntity {
|
||||
public enum ENTITY_TYPE {METHOD, FIELD, CONSTRUCTOR}
|
||||
public enum ENTITY_TYPE {METHOD, NATIVE, FIELD, CONSTRUCTOR}
|
||||
|
||||
private final Member mMember;
|
||||
public final ENTITY_TYPE mEntityType;
|
||||
@@ -28,7 +29,11 @@ public class AnnotatableEntity {
|
||||
mAnnotationInfo = aAnnotationInfo;
|
||||
|
||||
if (aObject instanceof Method) {
|
||||
mEntityType = ENTITY_TYPE.METHOD;
|
||||
if (Modifier.isNative(aObject.getModifiers())) {
|
||||
mEntityType = ENTITY_TYPE.NATIVE;
|
||||
} else {
|
||||
mEntityType = ENTITY_TYPE.METHOD;
|
||||
}
|
||||
} else if (aObject instanceof Field) {
|
||||
mEntityType = ENTITY_TYPE.FIELD;
|
||||
} else {
|
||||
@@ -37,7 +42,7 @@ public class AnnotatableEntity {
|
||||
}
|
||||
|
||||
public Method getMethod() {
|
||||
if (mEntityType != ENTITY_TYPE.METHOD) {
|
||||
if (mEntityType != ENTITY_TYPE.METHOD && mEntityType != ENTITY_TYPE.NATIVE) {
|
||||
throw new UnsupportedOperationException("Attempt to cast to unsupported member type.");
|
||||
}
|
||||
return (Method) mMember;
|
||||
|
||||
@@ -28,20 +28,21 @@ public class JarClassIterator implements Iterator<ClassWithOptions> {
|
||||
String className = mTargetClassListIterator.next();
|
||||
try {
|
||||
Class<?> ret = mTarget.loadClass(className);
|
||||
final String canonicalName;
|
||||
|
||||
// Incremental builds can leave stale classfiles in the jar. Such classfiles will cause
|
||||
// an exception at this point. We can safely ignore these classes - they cannot possibly
|
||||
// ever be loaded as they conflict with their parent class and will be killed by Proguard
|
||||
// later on anyway.
|
||||
// ever be loaded as they conflict with their parent class and will be killed by
|
||||
// Proguard later on anyway.
|
||||
final Class<?> enclosingClass;
|
||||
try {
|
||||
canonicalName = ret.getCanonicalName();
|
||||
enclosingClass = ret.getEnclosingClass();
|
||||
} catch (IncompatibleClassChangeError e) {
|
||||
return next();
|
||||
}
|
||||
|
||||
if (canonicalName == null || "null".equals(canonicalName)) {
|
||||
if (enclosingClass != null) {
|
||||
// Anonymous inner class - unsupported.
|
||||
// Or named inner class, which will be processed when we process the outer class.
|
||||
return next();
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ package org.mozilla.gecko.annotationProcessors.utils;
|
||||
|
||||
import org.mozilla.gecko.annotationProcessors.AnnotationInfo;
|
||||
import org.mozilla.gecko.annotationProcessors.classloader.AnnotatableEntity;
|
||||
import org.mozilla.gecko.annotationProcessors.classloader.ClassWithOptions;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
@@ -13,6 +14,7 @@ import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Member;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
@@ -21,13 +23,17 @@ import java.util.Iterator;
|
||||
* parameters) and the argument.
|
||||
*/
|
||||
public class GeneratableElementIterator implements Iterator<AnnotatableEntity> {
|
||||
private final ClassWithOptions mClass;
|
||||
private final Member[] mObjects;
|
||||
private AnnotatableEntity mNextReturnValue;
|
||||
private int mElementIndex;
|
||||
|
||||
private boolean mIterateEveryEntry;
|
||||
|
||||
public GeneratableElementIterator(Class<?> aClass) {
|
||||
public GeneratableElementIterator(ClassWithOptions annotatedClass) {
|
||||
mClass = annotatedClass;
|
||||
|
||||
final Class<?> aClass = annotatedClass.wrappedClass;
|
||||
// Get all the elements of this class as AccessibleObjects.
|
||||
Member[] aMethods = aClass.getDeclaredMethods();
|
||||
Member[] aFields = aClass.getDeclaredFields();
|
||||
@@ -59,6 +65,56 @@ public class GeneratableElementIterator implements Iterator<AnnotatableEntity> {
|
||||
findNextValue();
|
||||
}
|
||||
|
||||
private Class<?>[] getFilteredInnerClasses() {
|
||||
// Go through all inner classes and see which ones we want to generate.
|
||||
final Class<?>[] candidates = mClass.wrappedClass.getDeclaredClasses();
|
||||
int count = 0;
|
||||
|
||||
for (int i = 0; i < candidates.length; ++i) {
|
||||
final GeneratableElementIterator testIterator
|
||||
= new GeneratableElementIterator(new ClassWithOptions(candidates[i], null));
|
||||
if (testIterator.hasNext()
|
||||
|| testIterator.getFilteredInnerClasses() != null) {
|
||||
count++;
|
||||
continue;
|
||||
}
|
||||
// Clear out ones that don't match.
|
||||
candidates[i] = null;
|
||||
}
|
||||
return count > 0 ? candidates : null;
|
||||
}
|
||||
|
||||
public ClassWithOptions[] getInnerClasses() {
|
||||
final Class<?>[] candidates = getFilteredInnerClasses();
|
||||
if (candidates == null) {
|
||||
return new ClassWithOptions[0];
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
for (Class<?> candidate : candidates) {
|
||||
if (candidate != null) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
final ClassWithOptions[] ret = new ClassWithOptions[count];
|
||||
count = 0;
|
||||
for (Class<?> candidate : candidates) {
|
||||
if (candidate != null) {
|
||||
ret[count++] = new ClassWithOptions(
|
||||
candidate, mClass.generatedName + "::" + candidate.getSimpleName());
|
||||
}
|
||||
}
|
||||
assert ret.length == count;
|
||||
|
||||
Arrays.sort(ret, new Comparator<ClassWithOptions>() {
|
||||
@Override public int compare(ClassWithOptions lhs, ClassWithOptions rhs) {
|
||||
return lhs.generatedName.compareTo(rhs.generatedName);
|
||||
}
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find and cache the next appropriately annotated method, plus the annotation parameter, if
|
||||
* one exists. Otherwise cache null, so hasNext returns false.
|
||||
|
||||
@@ -225,6 +225,10 @@ public class Utils {
|
||||
return member.getName();
|
||||
}
|
||||
|
||||
public static String getUnqualifiedName(String name) {
|
||||
return name.substring(name.lastIndexOf(':') + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a member is declared static.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from argparse import Namespace
|
||||
import os
|
||||
|
||||
from mach.decorators import (
|
||||
CommandProvider,
|
||||
Command,
|
||||
)
|
||||
|
||||
|
||||
def run_mochitest(context, **kwargs):
|
||||
args = Namespace(**kwargs)
|
||||
args.certPath = context.certs_dir
|
||||
args.utilityPath = context.bin_dir
|
||||
args.extraProfileFiles.append(os.path.join(context.bin_dir, 'plugins'))
|
||||
|
||||
from runtests import run_test_harness
|
||||
return run_test_harness(args)
|
||||
|
||||
|
||||
def setup_argument_parser():
|
||||
from mochitest_options import MochitestArgumentParser
|
||||
return MochitestArgumentParser(app='generic')
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class MochitestCommands(object):
|
||||
|
||||
def __init__(self, context):
|
||||
self.context = context
|
||||
|
||||
@Command('mochitest', category='testing',
|
||||
description='Run the mochitest harness.',
|
||||
parser=setup_argument_parser)
|
||||
def mochitest(self, **kwargs):
|
||||
return run_mochitest(self.context, **kwargs)
|
||||
@@ -70,7 +70,7 @@ class MochitestArguments(ArgumentContainer):
|
||||
"help": "Override the default binary used to run tests with the path provided, e.g "
|
||||
"/usr/bin/firefox. If you have run ./mach package beforehand, you can "
|
||||
"specify 'dist' to run tests against the distribution bundle's binary.",
|
||||
"suppress": True,
|
||||
"suppress": build_obj is not None,
|
||||
}],
|
||||
[["--utility-path"],
|
||||
{"dest": "utilityPath",
|
||||
@@ -582,7 +582,9 @@ class MochitestArguments(ArgumentContainer):
|
||||
"could not find xre directory, --xre-path must be specified")
|
||||
|
||||
# allow relative paths
|
||||
options.xrePath = self.get_full_path(options.xrePath, parser.oldcwd)
|
||||
if options.xrePath:
|
||||
options.xrePath = self.get_full_path(options.xrePath, parser.oldcwd)
|
||||
|
||||
if options.profilePath:
|
||||
options.profilePath = self.get_full_path(options.profilePath, parser.oldcwd)
|
||||
|
||||
@@ -1140,7 +1142,8 @@ container_map = {
|
||||
|
||||
class MochitestArgumentParser(ArgumentParser):
|
||||
"""
|
||||
Usage instructions for runtests.py.
|
||||
Usage instructions for Mochitest.
|
||||
|
||||
All arguments are optional.
|
||||
If --chrome is specified, chrome tests will be run instead of web content tests.
|
||||
If --browser-chrome is specified, browser-chrome tests will be run instead of web content tests.
|
||||
|
||||
@@ -62,6 +62,7 @@ TEST_HARNESS_FILES.testing.mochitest += [
|
||||
'jetpack-addon-overlay.xul',
|
||||
'jetpack-package-harness.js',
|
||||
'jetpack-package-overlay.xul',
|
||||
'mach_test_package_commands.py',
|
||||
'manifest.webapp',
|
||||
'manifestLibrary.js',
|
||||
'mochitest_options.py',
|
||||
|
||||
@@ -11,11 +11,28 @@ import time
|
||||
|
||||
|
||||
SEARCH_PATHS = [
|
||||
'mochitest',
|
||||
'mozbase/mozcrash',
|
||||
'mozbase/mozdebug',
|
||||
'mozbase/mozdevice',
|
||||
'mozbase/mozfile',
|
||||
'mozbase/mozhttpd',
|
||||
'mozbase/mozlog',
|
||||
'mozbase/moznetwork',
|
||||
'mozbase/mozprocess',
|
||||
'mozbase/mozprofile',
|
||||
'mozbase/mozrunner',
|
||||
'mozbase/mozsystemmonitor',
|
||||
'mozbase/mozinfo',
|
||||
'mozbase/moztest',
|
||||
'mozbase/mozversion',
|
||||
'mozbase/manifestparser',
|
||||
'tools/mach',
|
||||
]
|
||||
|
||||
# Individual files providing mach commands.
|
||||
MACH_MODULES = [
|
||||
'mochitest/mach_test_package_commands.py',
|
||||
'tools/mach/mach/commands/commandinfo.py',
|
||||
]
|
||||
|
||||
@@ -60,6 +77,10 @@ def bootstrap(test_package_root):
|
||||
import mach.main
|
||||
|
||||
def populate_context(context, key=None):
|
||||
context.package_root = test_package_root
|
||||
context.certs_dir = os.path.join(test_package_root, 'certs')
|
||||
context.bin_dir = os.path.join(test_package_root, 'bin')
|
||||
context.modules_dir = os.path.join(test_package_root, 'modules')
|
||||
return context
|
||||
|
||||
mach = mach.main.Mach(os.getcwd())
|
||||
|
||||
@@ -82,7 +82,7 @@ class XPCShellRunner(MozbuildObject):
|
||||
if not os.path.isfile(os.path.join(self.topsrcdir, 'build', 'automationutils.py')):
|
||||
sys.path.append(os.path.join(self.topsrcdir, 'mozilla', 'build'))
|
||||
|
||||
if test_paths == ['all']:
|
||||
if test_paths == 'all':
|
||||
self.run_suite(interactive=interactive,
|
||||
keep_going=keep_going, shuffle=shuffle, sequential=sequential,
|
||||
debugger=debugger, debuggerArgs=debuggerArgs,
|
||||
|
||||
Reference in New Issue
Block a user