Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 53 additions & 40 deletions .github/workflows/build.yml → .github/workflows/pr-and-push.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: Build
name: PR and push actions
on:
pull_request:
branches: [ main ]
branches: [ "**" ]
types: [ opened, synchronize ]
push:
branches: [ main ]
Expand All @@ -10,14 +10,14 @@ on:
- cron: "0 0 * * 0"

jobs:
test:
name: JDK ${{ matrix.java-version }} on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
build:
name: Build - JDK ${{ matrix.java-version }} - ${{ matrix.os }}
runs-on: ${{ matrix.os }}-latest

strategy:
fail-fast: false
matrix:
os: [ 'ubuntu-latest' ]
os: [ ubuntu ]
java-version:
- 11
- 12
Expand All @@ -32,10 +32,10 @@ jobs:
# - 20-ea
build-script: [ './mvnw' ]
include:
- os: windows-latest
- os: windows
build-script: './mvnw.cmd'
java-version: '11'
- os: macos-latest
- os: macos
build-script: './mvnw'
java-version: '11'

Expand Down Expand Up @@ -85,9 +85,9 @@ jobs:
**/target/site/jacoco/jacoco*.xml
retention-days: 5

report-test-results:
name: Report results
needs: [ test ]
report-test-results-and-coverage:
name: Report test results and coverage
needs: [ build ]
runs-on: ubuntu-latest
if: always()
permissions:
Expand Down Expand Up @@ -130,9 +130,17 @@ jobs:
report_individual_runs: true
time_unit: "milliseconds"

checkstyle:
name: Code style and licenses
javadocs:
name: Generate JavaDocs
runs-on: ubuntu-latest
needs: [ report-test-results-and-coverage, compliance ]
if: github.event_name != 'schedule'

permissions:
contents: read
pages: write
id-token: write

steps:
- name: Checkout repository
uses: actions/checkout@v3
Expand All @@ -141,28 +149,44 @@ jobs:
uses: actions/setup-java@v3
with:
distribution: 'zulu'
# We have to use >= 15 for now, as assertj causes JDK 14 and older to prevent linking
# documentation correctly. I have opened an issue on GitHub with AssertJ to discuss
# this being generated correctly: https://github.com/assertj/assertj-core/issues/2573.
java-version: '19'
cache: 'maven'

- name: Run checks
- name: Generate JavaDocs
run: >-
./mvnw
-B
-T8
-U
-pl java-compiler-testing
--also-make
--no-transfer-progress
-DskipTests=true
-Dmaven.test.skip=true
-Dcheckstyle.skip=true
-Dlicense.skip=true
-Dstyle.color=always
-Dmaven.main.skip
-Dmaven.jar.skip
-Dmaven.resources.skip
-Dmaven.test.skip
-Dmaven.wagon.httpconnectionManager.ttlSeconds=120
verify
clean compile javadoc:jar

- name: Upload JavaDocs to GitHub Pages
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
uses: actions/upload-pages-artifact@v1
with:
path: java-compiler-testing/target/apidocs

- name: Deploy JavaDocs to GitHub Pages
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
id: deployment
uses: actions/deploy-pages@v1

javadoc:
name: Code documentation
compliance:
name: Check Compliance
runs-on: ubuntu-latest
needs: [ build ]
if: ${{ github.event_name != 'schedule' }}

steps:
- name: Checkout repository
Expand All @@ -172,32 +196,21 @@ jobs:
uses: actions/setup-java@v3
with:
distribution: 'zulu'
# We have to use >= 15 for now, as assertj causes JDK 14 and older to prevent linking
# documentation correctly. I have opened an issue on GitHub with AssertJ to discuss
# this being generated correctly: https://github.com/assertj/assertj-core/issues/2573.
java-version: '19'
cache: 'maven'

- name: Generate JavaDoc documentation
- name: Run checks
run: >-
./mvnw
-B
-T8
-U
--no-transfer-progress
-Dmaven.test.skip=true
-Dcheckstyle.skip=true
-Dlicense.skip=true
-DskipTests=true
-Dstyle.color=always
-Dmaven.main.skip
-Dmaven.jar.skip
-Dmaven.resources.skip
-Dmaven.test.skip
-Dmaven.wagon.httpconnectionManager.ttlSeconds=120
clean compile javadoc:jar

- name: Archive JavaDoc artifacts
uses: actions/upload-artifact@v3
continue-on-error: true
if: success()
with:
name: javadocs
path: "**/target/apidocs/io.github.ascopes.*"
retention-days: 5

verify
89 changes: 77 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,37 @@

# java-compiler-testing

Facility for running compilation tests and annotation processing tests
for `javac` and other compliant compilers.
A framework for performing exhaustive integration testing against Java compilers in modern Java
libraries, with a focus on full JPMS support.

I developed this after several months of pulling out my hair trying to
find easy ways to integration test annotation processors for Java. While
one or two tools exist for Java 8, I have yet to find one that works
seamlessly with Java 11 and newer.
The _Java Compiler Testing_ API has a number of facilities for assisting in
testing anything related to the Java compiler. This includes Javac plugins and JSR-199 annotation
processors.

This module comes with full JPMS support. I decided to drop support for
Java 8 due to complexity around implementing this without the ability to
reference modules, and ideally this tool should be forward compatible to
prevent future issues for any projects deciding to use it.
All test cases are designed to be as stateless as possible, with facilities to produce
in-memory file systems (using Google's JIMFS API) or using OS-provided temporary directories.
All file system mechanisms are complimented with a fluent API that enables writing expressive
declarations without unnecessary boilerplate.

Integration test cases can be written to cross-compile against a range of Java compiler
versions, with the ability to provide as much or as little configuration detail as you wish.
Additionally, APIs can be easily extended to integrate with any other JSR-199-compliant compiler
as required.

Compilation results are complimented with a suite of assertion facilities that extend
the AssertJ API to assist in writing fluent and human-readable test cases for your code. Each of
these assertions comes with specially-developed human-readable error messages and formatting.

Full JUnit5 integration is provided to help streamline the development process.

**This module is still under development.** Any contributions or feedback
are always welcome!

## Examples

```java
### In-memory code, using RAM disks for source directories

```java
@DisplayName("Example tests")
class ExampleTest {

Expand Down Expand Up @@ -72,10 +83,64 @@ class ExampleTest {
}
```

Likewise, the following shows an example of compiling a multi-module style application with JPMS
### Compiling and testing with a custom annotation processor

```java
import static io.github.ascopes.jct.assertions.JctAssertions.assertThatCompilation;
import static io.github.ascopes.jct.pathwrappers.RamDirectory.newRamDirectory;

import io.github.ascopes.jct.compilers.JctCompiler;
import io.github.ascopes.jct.junit.JavacCompilerTest;

import org.example.processor.JsonSchemaAnnotationProcessor;
import org.skyscreamer.jsonassert.JSONAssert;

class JsonSchemaAnnotationProcessorTest {

@JavacCompilerTest(minVersion = 11, maxVersion = 19)
void theJsonSchemaIsCreatedFromTheInputCode(JctCompiler<?, ?> compiler) {
// Given
var sources = newRamDirectory("sources")
.createDirectory("org", "example", "tests")
.copyContentsFrom("src", "test", "resources", "code", "schematest");

// When
var compilation = compiler
.addSources(sources)
.addAnnotationProcessors(new JsonSchemaAnnotationProcessor())
.addAnnotationProcessorOptions("jsonschema.verbose=true")
.failOnWarnings(true)
.showDeprecationWarnings(true)
.compile();

// Then
assertThatCompilation(compilation)
.isSuccessfulWithoutWarnings();

assertThatCompilation(compilation)
.diagnostics().notes().singleElement()
.message().isEqualTo(
"Creating JSON schema in Java %s for package org.example.tests",
compiler.getRelease()
);

assertThatCompilation(compilation)
.classOutputs().packages()
.fileExists("json-schemas/UserSchema.json").contents()
.isNotEmpty()
.satisfies(contents -> JSONAssert.assertEquals(...));
}
}
```

### Compiling multi-module sources

The following shows an example of compiling a multi-module style application with JPMS
support, running the Lombok annotation processor over the input. This assumes that the Lombok
JAR is already on the classpath for the JUnit test runner.

Even Maven lacks native support for this, still!

```java

@DisplayName("Example tests")
Expand Down
8 changes: 8 additions & 0 deletions java-compiler-testing/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@

<artifactId>java-compiler-testing</artifactId>

<properties>
<javadoc-excluded-packages>
*.annotations,
*.impl,
*.utils,
</javadoc-excluded-packages>
</properties>

<dependencies>
<dependency>
<groupId>com.google.code.findbugs</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,13 @@
*/
/**
* JSR-305 annotations to assist in IDE integrations and Kotlin compiler support.
*
* <p>These components are part of the internal API and should not be used by external
* modules. As such, they are not covered by the semantic versioning policy and may change
* without notice.
*/
@API(since = "0.0.1", status = Status.INTERNAL)
package io.github.ascopes.jct.annotations;

import org.apiguardian.api.API;
import org.apiguardian.api.API.Status;
Original file line number Diff line number Diff line change
Expand Up @@ -183,11 +183,7 @@ public AbstractStringAssert<?> threadName() {
* Get assertions for the stack trace of the location the diagnostic was reported to.
*
* @return the assertions for the stack trace.
* @deprecated I have put up a pull request for AssertJ to support this functionality in AssertJ
* Core. Once this is merged, this return type will be changed to use the AssertJ
* implementation.
*/
@Deprecated(forRemoval = true)
public StackTraceAssert stackTrace() {
return new StackTraceAssert(actual.getStackTrace());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,13 @@
*/
/**
* Various internal helper types for assertions.
*
* <p>These components are part of the internal API and should not be used by external
* modules. As such, they are not covered by the semantic versioning policy and may change
* without notice.
*/
@API(since = "0.0.1", status = Status.INTERNAL)
package io.github.ascopes.jct.assertions.impl;

import org.apiguardian.api.API;
import org.apiguardian.api.API.Status;
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,8 @@
/**
* Assertions to perform on the result of a compilation.
*/
@API(since = "0.0.1", status = Status.EXPERIMENTAL)
package io.github.ascopes.jct.assertions;

import org.apiguardian.api.API;
import org.apiguardian.api.API.Status;
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,13 @@
*/
/**
* Implementation details for compiler integrations.
*
* <p>These components are part of the internal API and should not be used by external
* modules. As such, they are not covered by the semantic versioning policy and may change
* without notice.
*/
@API(since = "0.0.1", status = Status.INTERNAL)
package io.github.ascopes.jct.compilers.impl;

import org.apiguardian.api.API;
import org.apiguardian.api.API.Status;
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,8 @@
/**
* Compiler frontends that allow invoking compilers easily from tests.
*/
@API(since = "0.0.1", status = Status.EXPERIMENTAL)
package io.github.ascopes.jct.compilers;

import org.apiguardian.api.API;
import org.apiguardian.api.API.Status;
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,13 @@
*/
/**
* Internal implementations of containers and container groups.
*
* <p>These components are part of the internal API and should not be used by external
* modules. As such, they are not covered by the semantic versioning policy and may change
* without notice.
*/
@API(since = "0.0.1", status = Status.INTERNAL)
package io.github.ascopes.jct.containers.impl;

import org.apiguardian.api.API;
import org.apiguardian.api.API.Status;
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,8 @@
/**
* Containers used to integrate with the JSR-199 API in a modular way.
*/
@API(since = "0.0.1", status = Status.EXPERIMENTAL)
package io.github.ascopes.jct.containers;

import org.apiguardian.api.API;
import org.apiguardian.api.API.Status;
Loading