Skip to content

Commit

Permalink
Android unittests (#209)
Browse files Browse the repository at this point in the history
This refers to `test` rather than `androidTest`.
  • Loading branch information
zpencer authored Jan 25, 2018
1 parent f828107 commit 6dec496
Show file tree
Hide file tree
Showing 9 changed files with 259 additions and 70 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,9 @@ public class GenerateProtoTask extends DefaultTask {
String getBuildType() {
Preconditions.checkState(Utils.isAndroidProject(project),
'buildType should not be used in a Java project')
Preconditions.checkNotNull(buildType, 'buildType is not set')
Preconditions.checkState(
variant.name == 'test' || buildType,
'buildType is not set and task is not for local unit test variant')
return buildType
}

Expand Down
42 changes: 29 additions & 13 deletions src/main/groovy/com/google/protobuf/gradle/ProtobufPlugin.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -193,11 +193,8 @@ class ProtobufPlugin implements Plugin<Project> {
*/
private addProtoTasks() {
if (Utils.isAndroidProject(project)) {
getNonTestVariants().each { variant ->
addTasksForVariant(variant, false)
}
project.android.testVariants.each { testVariant ->
addTasksForVariant(testVariant, true)
(getNonTestVariants() + project.android.testVariants + project.android.unitTestVariants).each { variant ->
addTasksForVariant(variant)
}
} else {
getSourceSets().each { sourceSet ->
Expand Down Expand Up @@ -235,19 +232,22 @@ class ProtobufPlugin implements Plugin<Project> {
/**
* Creates Protobuf tasks for a variant in an Android project.
*/
private addTasksForVariant(final Object variant, final boolean isTestVariant) {
private addTasksForVariant(final Object variant) {
// The collection of sourceSets that will be compiled for this variant
List sourceSetNames = []
List sourceSets = []
if (isTestVariant) {
// All test variants will include the androidTest sourceSet
sourceSetNames.add 'androidTest'
} else {
boolean isTestVariant = ['ANDROID_TEST', "UNIT_TEST"].contains(variant.variantData.type.toString())
if (!isTestVariant) {
// All non-test variants will include the main sourceSet
sourceSetNames.add 'main'
}
sourceSetNames.add variant.name
sourceSetNames.add variant.buildType.name
// see: https://android.googlesource.com/platform/tools/build/+/master/builder/src/main/java/
// com/android/builder/VariantConfiguration.java
sourceSetNames.add variant.variantData.variantConfiguration.defaultSourceSet.name // e.g. main, androidTest, test
sourceSetNames.add variant.name // e.g. x86FreeappDebug
if (variant.hasProperty('buildType')) {
sourceSetNames.add variant.buildType.name
}
ImmutableList.Builder<String> flavorListBuilder = ImmutableList.builder()
if (variant.hasProperty('productFlavors')) {
variant.productFlavors.each { flavor ->
Expand All @@ -262,7 +262,9 @@ class ProtobufPlugin implements Plugin<Project> {
Task generateProtoTask = addGenerateProtoTask(variant.name, sourceSets)
generateProtoTask.setVariant(variant, isTestVariant)
generateProtoTask.flavors = flavorListBuilder.build()
generateProtoTask.buildType = variant.buildType.name
if (variant.hasProperty('buildType')) {
generateProtoTask.buildType = variant.buildType.name
}
generateProtoTask.doneInitializing()

sourceSetNames.each { sourceSetName ->
Expand Down Expand Up @@ -450,6 +452,20 @@ class ProtobufPlugin implements Plugin<Project> {
Utils.getKotlinAndroidCompileTaskName(project, variant.name), genProtoTask)
}
}

project.android.unitTestVariants.each { variant ->
project.protobuf.generateProtoTasks.ofVariant(variant.name).each { GenerateProtoTask genProtoTask ->
// unit test variants do not implement registerJavaGeneratingTask
Task javaCompileTask = variant.variantData.javaCompilerTask
if (javaCompileTask != null) {
linkGenerateProtoTasksToTask(javaCompileTask, genProtoTask)
}

linkGenerateProtoTasksToTaskName(
Utils.getKotlinAndroidCompileTaskName(project, variant.name),
genProtoTask)
}
}
} else {
project.sourceSets.each { SourceSet sourceSet ->
project.protobuf.generateProtoTasks.ofSourceSet(sourceSet.name).each { GenerateProtoTask genProtoTask ->
Expand Down
3 changes: 2 additions & 1 deletion src/main/groovy/com/google/protobuf/gradle/Utils.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,8 @@ class Utils {
*/
static boolean isTest(String sourceSetOrVariantName) {
return sourceSetOrVariantName == "test" ||
sourceSetOrVariantName.toLowerCase().contains('androidtest')
sourceSetOrVariantName.toLowerCase().contains('androidtest') ||
sourceSetOrVariantName.toLowerCase().contains('unittest')
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package io.grpc.helloworldexample;

public class TestLibrary {
// From src/test/proto/sample.proto
HelloworldActivity activity;

// From src/androidTest/proto/sample.proto
com.example.tutorial.Msg msg;

// From src/main/proto/helloworld.proto
Expand All @@ -13,6 +15,10 @@ public class TestLibrary {
// From lib/protos.jar
com.google.protobuf.gradle.test.External.BlobMessage blobMessage;

// TODO(zpencer): reflectively check that unit test protos are not visible
// This requires figuring out how to get androidTest to run. Currently the sources in androidTest
// are compiled, but test classes are not actually executed.

TestLibrary() {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package io.grpc.helloworldexample;

import static org.junit.Assert.fail;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

@RunWith(JUnit4.class)
public final class UnitTest {
private final HelloworldActivity activity = new HelloworldActivity();
// From src/test/proto/unittest.proto
private com.example.tutorial.UnitTestMsg msg;

// From src/main/proto/helloworld.proto
private Helloworld.HelloRequest request;

// From testProjectLite: src/nano/proto/messages.proto
private io.grpc.testing.Messages.SimpleRequest simpleRequest;

// From lib/protos.jar
private com.google.protobuf.gradle.test.External.BlobMessage blobMessage;

@Test
public void ensureAndroidTestProtosNotVisible() throws Exception {
// we should not see the protos from src/androidTest/proto/
try {
Class<?> ignored = Class.forName("com.example.tutorial.Msg");
fail();
} catch (ClassNotFoundException expected){
// noop
}
}
}
183 changes: 130 additions & 53 deletions testProjectAndroidBase/build_base.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ dependencies {
exclude module: "protobuf-lite"
}
protobuf files('lib/protos.jar')
testCompile 'junit:junit:4.12'
}

def assertJavaCompileHasProtoGeneratedDir(Object variant, Collection<String> codegenPlugins) {
Expand All @@ -118,66 +119,142 @@ afterEvaluate {
}

test.doLast {
assert ['generateArmFreeappDebugAndroidTestProto', 'generateArmFreeappDebugProto',
'generateArmFreeappReleaseProto', 'generateArmRetailappDebugAndroidTestProto',
'generateArmRetailappDebugProto', 'generateArmRetailappReleaseProto',
'generateX86FreeappDebugAndroidTestProto', 'generateX86FreeappDebugProto',
'generateX86FreeappReleaseProto', 'generateX86RetailappDebugAndroidTestProto',
'generateX86RetailappDebugProto', 'generateX86RetailappReleaseProto'] as Set ==
protobuf.generateProtoTasks.all().collect({ it.name }) as Set

assert ['generateArmFreeappDebugAndroidTestProto',
'generateArmRetailappDebugAndroidTestProto',
'generateX86FreeappDebugAndroidTestProto',
'generateX86RetailappDebugAndroidTestProto'] as Set ==
protobuf.generateProtoTasks.ofTest().collect({ it.name }) as Set

assert ['generateArmFreeappDebugProto', 'generateArmFreeappReleaseProto',
'generateArmRetailappDebugProto', 'generateArmRetailappReleaseProto',
'generateX86FreeappDebugProto', 'generateX86FreeappReleaseProto',
'generateX86RetailappDebugProto', 'generateX86RetailappReleaseProto'] as Set ==
protobuf.generateProtoTasks.ofNonTest().collect({ it.name }) as Set

assert ['generateArmFreeappDebugAndroidTestProto', 'generateArmFreeappDebugProto',
'generateArmFreeappReleaseProto',
'generateX86FreeappDebugAndroidTestProto', 'generateX86FreeappDebugProto',
'generateX86FreeappReleaseProto'] as Set ==
protobuf.generateProtoTasks.ofFlavor('freeapp').collect({ it.name }) as Set

assert ['generateArmRetailappDebugAndroidTestProto', 'generateArmRetailappDebugProto',
'generateArmRetailappReleaseProto',
'generateX86RetailappDebugAndroidTestProto', 'generateX86RetailappDebugProto',
'generateX86RetailappReleaseProto'] as Set ==
protobuf.generateProtoTasks.ofFlavor('retailapp').collect({ it.name }) as Set

assert ['generateX86FreeappDebugAndroidTestProto', 'generateX86FreeappDebugProto',
'generateX86FreeappReleaseProto', 'generateX86RetailappDebugAndroidTestProto',
'generateX86RetailappDebugProto', 'generateX86RetailappReleaseProto'] as Set ==
protobuf.generateProtoTasks.ofFlavor('x86').collect({ it.name }) as Set

assert ['generateArmFreeappDebugAndroidTestProto', 'generateArmFreeappDebugProto',
'generateArmFreeappReleaseProto', 'generateArmRetailappDebugAndroidTestProto',
'generateArmRetailappDebugProto', 'generateArmRetailappReleaseProto'] as Set ==
protobuf.generateProtoTasks.ofFlavor('arm').collect({ it.name }) as Set

assert ['generateArmFreeappDebugAndroidTestProto', 'generateArmFreeappDebugProto',
'generateArmRetailappDebugAndroidTestProto',
'generateArmRetailappDebugProto',
'generateX86FreeappDebugAndroidTestProto', 'generateX86FreeappDebugProto',
'generateX86RetailappDebugAndroidTestProto',
'generateX86RetailappDebugProto'] as Set ==
protobuf.generateProtoTasks.ofBuildType('debug').collect({ it.name }) as Set

assert ['generateArmFreeappReleaseProto', 'generateArmRetailappReleaseProto',
'generateX86FreeappReleaseProto', 'generateX86RetailappReleaseProto'] as Set ==
protobuf.generateProtoTasks.ofBuildType('release').collect({ it.name }) as Set
assert [
'generateArmFreeappDebugAndroidTestProto',
'generateArmFreeappDebugUnitTestProto',
'generateArmFreeappReleaseUnitTestProto',
'generateArmFreeappDebugProto',
'generateArmFreeappReleaseProto',
'generateArmRetailappDebugAndroidTestProto',
'generateArmRetailappDebugUnitTestProto',
'generateArmRetailappReleaseUnitTestProto',
'generateArmRetailappDebugProto',
'generateArmRetailappReleaseProto',
'generateX86FreeappDebugAndroidTestProto',
'generateX86FreeappDebugUnitTestProto',
'generateX86FreeappReleaseUnitTestProto',
'generateX86FreeappDebugProto',
'generateX86FreeappReleaseProto',
'generateX86RetailappDebugAndroidTestProto',
'generateX86RetailappDebugUnitTestProto',
'generateX86RetailappReleaseUnitTestProto',
'generateX86RetailappDebugProto',
'generateX86RetailappReleaseProto',
] as Set == protobuf.generateProtoTasks.all().collect({ it.name }) as Set

assert [
'generateArmFreeappDebugAndroidTestProto',
'generateArmFreeappDebugUnitTestProto',
'generateArmFreeappReleaseUnitTestProto',
'generateArmRetailappDebugAndroidTestProto',
'generateArmRetailappDebugUnitTestProto',
'generateArmRetailappReleaseUnitTestProto',
'generateX86FreeappDebugAndroidTestProto',
'generateX86FreeappDebugUnitTestProto',
'generateX86FreeappReleaseUnitTestProto',
'generateX86RetailappDebugAndroidTestProto',
'generateX86RetailappDebugUnitTestProto',
'generateX86RetailappReleaseUnitTestProto',
] as Set == protobuf.generateProtoTasks.ofTest().collect({ it.name }) as Set

assert [
'generateArmFreeappDebugProto',
'generateArmFreeappReleaseProto',
'generateArmRetailappDebugProto',
'generateArmRetailappReleaseProto',
'generateX86FreeappDebugProto',
'generateX86FreeappReleaseProto',
'generateX86RetailappDebugProto',
'generateX86RetailappReleaseProto',
] as Set == protobuf.generateProtoTasks.ofNonTest().collect({ it.name }) as Set

assert [
'generateArmFreeappDebugAndroidTestProto',
'generateArmFreeappDebugUnitTestProto',
'generateArmFreeappReleaseUnitTestProto',
'generateArmFreeappDebugProto',
'generateArmFreeappReleaseProto',
'generateX86FreeappDebugAndroidTestProto',
'generateX86FreeappDebugUnitTestProto',
'generateX86FreeappReleaseUnitTestProto',
'generateX86FreeappDebugProto',
'generateX86FreeappReleaseProto',
] as Set == protobuf.generateProtoTasks.ofFlavor('freeapp').collect({ it.name }) as Set

assert [
'generateArmRetailappDebugAndroidTestProto',
'generateArmRetailappDebugUnitTestProto',
'generateArmRetailappReleaseUnitTestProto',
'generateArmRetailappDebugProto',
'generateArmRetailappReleaseProto',
'generateX86RetailappDebugAndroidTestProto',
'generateX86RetailappDebugUnitTestProto',
'generateX86RetailappReleaseUnitTestProto',
'generateX86RetailappDebugProto',
'generateX86RetailappReleaseProto',
] as Set == protobuf.generateProtoTasks.ofFlavor('retailapp').collect({ it.name }) as Set

assert [
'generateX86FreeappDebugAndroidTestProto',
'generateX86FreeappDebugUnitTestProto',
'generateX86FreeappReleaseUnitTestProto',
'generateX86FreeappDebugProto',
'generateX86FreeappReleaseProto',
'generateX86RetailappDebugAndroidTestProto',
'generateX86RetailappDebugUnitTestProto',
'generateX86RetailappReleaseUnitTestProto',
'generateX86RetailappDebugProto',
'generateX86RetailappReleaseProto',
] as Set == protobuf.generateProtoTasks.ofFlavor('x86').collect({ it.name }) as Set

assert [
'generateArmFreeappDebugAndroidTestProto',
'generateArmFreeappDebugUnitTestProto',
'generateArmFreeappReleaseUnitTestProto',
'generateArmFreeappDebugProto',
'generateArmFreeappReleaseProto',
'generateArmRetailappDebugAndroidTestProto',
'generateArmRetailappDebugUnitTestProto',
'generateArmRetailappReleaseUnitTestProto',
'generateArmRetailappDebugProto',
'generateArmRetailappReleaseProto',
] as Set == protobuf.generateProtoTasks.ofFlavor('arm').collect({ it.name }) as Set

assert [
'generateArmFreeappDebugAndroidTestProto',
'generateArmFreeappDebugUnitTestProto',
'generateArmFreeappDebugProto',
'generateArmRetailappDebugAndroidTestProto',
'generateArmRetailappDebugUnitTestProto',
'generateArmRetailappDebugProto',
'generateX86FreeappDebugAndroidTestProto',
'generateX86FreeappDebugUnitTestProto',
'generateX86FreeappDebugProto',
'generateX86RetailappDebugAndroidTestProto',
'generateX86RetailappDebugUnitTestProto',
'generateX86RetailappDebugProto'
] as Set == protobuf.generateProtoTasks.ofBuildType('debug').collect({ it.name }) as Set

assert [
'generateArmFreeappReleaseProto',
'generateArmFreeappReleaseUnitTestProto',
'generateArmRetailappReleaseProto',
'generateArmRetailappReleaseUnitTestProto',
'generateX86FreeappReleaseProto',
'generateX86FreeappReleaseUnitTestProto',
'generateX86RetailappReleaseProto',
'generateX86RetailappReleaseUnitTestProto',
] as Set == protobuf.generateProtoTasks.ofBuildType('release').collect({ it.name }) as Set

assert ['generateX86FreeappDebugAndroidTestProto'] as Set ==
protobuf.generateProtoTasks.ofVariant('x86FreeappDebugAndroidTest').collect({ it.name }) as Set

// "androidTest" sourceSet is not a flavor
assert [] as Set == protobuf.generateProtoTasks.ofFlavor('androidTest').collect({ it.name }) as Set

// "unitTest" sourceset is not a flavor
assert [] as Set == protobuf.generateProtoTasks.ofFlavor('unitTest').collect({ it.name }) as Set

android.applicationVariants.each { variant ->
assertJavaCompileHasProtoGeneratedDir(variant, ['javalite', 'grpc'])
}
Expand Down
18 changes: 18 additions & 0 deletions testProjectAndroidBase/src/test/proto/unittest.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
syntax = "proto3";

option java_package = "com.example.tutorial";
option java_outer_classname = "OuterLocalTest";
option java_multiple_files = true;

// From the main sourceSet
import "helloworld.proto";

message UnitTestMsg {
string foo = 1;
UnitTestSecondMsg blah = 2;
}

message UnitTestSecondMsg {
int32 blah = 1;
helloworld.HelloReply reply = 2;
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ class LibraryKotlin {
var response = Helloworld.HelloReply.getDefaultInstance()
// From lib/protos.jar
var blob = com.google.protobuf.gradle.test.External.BlobMessage.getDefaultInstance()
// From test proto:
// From androidTest proto:
var msg1 = com.example.tutorial.Msg.getDefaultInstance()
var msg2 = com.example.tutorial.SecondMsg.getDefaultInstance()

// TODO(zpencer): reflectively check that unit test protos are not visible
// This requires figuring out how to get androidTest to run. Currently the sources in androidTest
// are compiled, but test classes are not actually executed.
}
Loading

0 comments on commit 6dec496

Please sign in to comment.