Skip to content

Commit 3e81913

Browse files
authored
Merge pull request #166 from salesforce/more-testing
Add a unit testing workflow, in addition to debug
2 parents f4a9fbd + aa47188 commit 3e81913

File tree

5 files changed

+135
-7
lines changed

5 files changed

+135
-7
lines changed

jprotoc/jprotoc-test/src/test/java/com/salesforce/jprotoc/JavaMethodStubTest.java

Lines changed: 0 additions & 5 deletions
This file was deleted.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.salesforce.jprotoc;
2+
3+
import com.google.protobuf.compiler.PluginProtos;
4+
import com.salesforce.jprotoc.jdk8.Jdk8Generator;
5+
import org.junit.Test;
6+
7+
import static org.assertj.core.api.Assertions.assertThat;
8+
9+
import java.io.File;
10+
import java.io.IOException;
11+
12+
public class UnitTestabilityTest {
13+
@Test
14+
public void verifyMavenDumpFileExists() throws IOException {
15+
File dumpfile = new File(ProtocPluginTesting.MAVEN_DUMP_PATH);
16+
System.out.println(dumpfile.getAbsolutePath());
17+
18+
assertThat(dumpfile.exists()).isTrue();
19+
assertThat(dumpfile.isDirectory()).isFalse();
20+
}
21+
22+
@Test
23+
public void verifyGeneratorWorks() throws IOException {
24+
PluginProtos.CodeGeneratorResponse response = ProtocPluginTesting.test(new Jdk8Generator(), ProtocPluginTesting.MAVEN_DUMP_PATH);
25+
assertThat(response.getError()).isNullOrEmpty();
26+
assertThat(response.getFileList()).isNotEmpty();
27+
}
28+
}

jprotoc/jprotoc/README.md

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,4 +241,19 @@ debugging.
241241
> java -jar myPlugin.jar path/to/descriptor_dump
242242
```
243243

244-
Or, use your IDE to debug, passing in a command line option.
244+
Or, use your IDE to debug, passing in a command line option.
245+
246+
Unit testing protoc plugins
247+
===========================
248+
JProtoc includes a static class called `ProtocPluginTesting` for use in unit tests. Its API is similar to
249+
`ProtocPlugin.debug()`, but it returns a `PluginProtos.CodeGeneratorResponse` instead of writing output to disk
250+
or a stream. An example unit test is:
251+
252+
```java
253+
@Test
254+
public void verifyGeneratorWorks() throws IOException {
255+
PluginProtos.CodeGeneratorResponse response = ProtocPluginTesting.test(new Jdk8Generator(), ProtocPluginTesting.MAVEN_DUMP_PATH);
256+
assertThat(response.getError()).isNullOrEmpty();
257+
assertThat(response.getFileList()).isNotEmpty();
258+
}
259+
```

jprotoc/jprotoc/src/main/java/com/salesforce/jprotoc/ProtocPlugin.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ public static void debug(
174174
}
175175
}
176176

177-
private static PluginProtos.CodeGeneratorResponse generate(
177+
static PluginProtos.CodeGeneratorResponse generate(
178178
@Nonnull List<Generator> generators,
179179
@Nonnull PluginProtos.CodeGeneratorRequest request) {
180180
checkNotNull(generators, "generators");
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
* Copyright (c) 2019, Salesforce.com, Inc.
3+
* All rights reserved.
4+
* Licensed under the BSD 3-Clause license.
5+
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
6+
*/
7+
8+
package com.salesforce.jprotoc;
9+
10+
import com.google.common.io.Files;
11+
import com.google.protobuf.ExtensionRegistry;
12+
import com.google.protobuf.GeneratedMessage;
13+
import com.google.protobuf.compiler.PluginProtos;
14+
15+
import javax.annotation.Nonnull;
16+
import java.io.File;
17+
import java.io.IOException;
18+
import java.util.Collections;
19+
import java.util.List;
20+
21+
import static com.google.common.base.Preconditions.checkArgument;
22+
import static com.google.common.base.Preconditions.checkNotNull;
23+
24+
/**
25+
* This method is designed to be used by unit tests. Unit testing typically works like this:
26+
* 1. Add the Dump protoc plugin to your test code generation build phase, to write out a proto dump file.
27+
* 2. Locate the generated dump file in a unit test.
28+
* 3. Call this method, with the path of the dump file from a test.
29+
* 4. Inspect the generated output.
30+
*/
31+
public final class ProtocPluginTesting {
32+
private ProtocPluginTesting() {
33+
34+
}
35+
36+
public static final String MAVEN_DUMP_PATH = "target/generated-test-sources/protobuf/dump/descriptor_dump";
37+
38+
/**
39+
* Debug a single generator using the parsed proto descriptor.
40+
* @param generator The generator to run.
41+
* @param dumpPath The path to a descriptor dump on the filesystem.
42+
* @return The compiled output from the protoc plugin
43+
*/
44+
public static PluginProtos.CodeGeneratorResponse test(@Nonnull Generator generator, @Nonnull String dumpPath) throws IOException {
45+
checkNotNull(generator, "generator");
46+
return test(Collections.singletonList(generator), dumpPath);
47+
}
48+
49+
/**
50+
* Debug multiple generators using the parsed proto descriptor, aggregating their results.
51+
* @param generators The list of generators to run.
52+
* @param dumpPath The path to a descriptor dump on the filesystem.
53+
* @return The compiled output from the protoc plugin
54+
*/
55+
public static PluginProtos.CodeGeneratorResponse test(@Nonnull List<Generator> generators, @Nonnull String dumpPath) throws IOException {
56+
return test(generators, Collections.emptyList(), dumpPath);
57+
}
58+
59+
/**
60+
* Test multiple generators using the parsed proto descriptor, aggregating their results.
61+
* Also register the given extensions so they may be processed by the generator.
62+
*
63+
* @param generators The list of generators to run.
64+
* @param extensions The list of extensions to register.
65+
* @param dumpPath The path to a descriptor dump on the filesystem.
66+
* @return The compiled output from the protoc plugin
67+
*/
68+
public static PluginProtos.CodeGeneratorResponse test(
69+
@Nonnull List<Generator> generators,
70+
List<GeneratedMessage.GeneratedExtension> extensions,
71+
@Nonnull String dumpPath) throws IOException {
72+
checkNotNull(generators, "generators");
73+
checkArgument(!generators.isEmpty(), "generators.isEmpty()");
74+
checkNotNull(extensions, "extensions");
75+
checkNotNull(dumpPath, "dumpPath");
76+
77+
// As per https://developers.google.com/protocol-buffers/docs/reference/java-generated#extension,
78+
// extensions must be registered in order to be processed.
79+
ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
80+
for (GeneratedMessage.GeneratedExtension extension : extensions) {
81+
extensionRegistry.add(extension);
82+
}
83+
84+
byte[] generatorRequestBytes = Files.toByteArray(new File(dumpPath));
85+
PluginProtos.CodeGeneratorRequest request = PluginProtos.CodeGeneratorRequest.parseFrom(
86+
generatorRequestBytes, extensionRegistry);
87+
88+
return ProtocPlugin.generate(generators, request);
89+
}
90+
}

0 commit comments

Comments
 (0)