Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
joshka committed Feb 4, 2018
0 parents commit aa5308f
Show file tree
Hide file tree
Showing 8 changed files with 324 additions and 0 deletions.
149 changes: 149 additions & 0 deletions pom.xml
@@ -0,0 +1,149 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>net.joshka</groupId>
<artifactId>junit-javax.json</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<junit.platform.version>1.0.3</junit.platform.version>
<junit.jupiter.version>5.0.3</junit.jupiter.version>
<javax.json.version>1.1.2</javax.json.version>
</properties>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
<version>3.7.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<configuration>
<includes>
<include>**/Test*.java</include>
<include>**/*Test.java</include>
<include>**/*Tests.java</include>
<include>**/*TestCase.java</include>
</includes>
</configuration>
<dependencies>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-surefire-provider</artifactId>
<version>${junit.platform.version}</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.jupiter.version}</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.0</version>
<executions>
<execution>
<id>default-prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>default-report</id>
<goals>
<goal>report</goal>
</goals>
</execution>
<execution>
<id>default-check</id>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
<configuration>
<rules>
<rule>
<element>BUNDLE</element>
<limits>
<limit>
<counter>COMPLEXITY</counter>
<value>COVEREDRATIO</value>
<minimum>0.80</minimum>
</limit>
</limits>
</rule>
</rules>
</configuration>
</plugin>
</plugins>
</build>

<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.jupiter.version}</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>${junit.jupiter.version}</version>
</dependency>
<dependency>
<groupId>javax.json</groupId>
<artifactId>javax.json-api</artifactId>
<version>${javax.json.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.json</artifactId>
<version>${javax.json.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.jupiter.version}</version>
<scope>test</scope>
</dependency>
<!-- To avoid compiler warnings about @API annotations in JUnit code -->
<dependency>
<groupId>org.apiguardian</groupId>
<artifactId>apiguardian-api</artifactId>
<version>1.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.9.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.13.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.0</version>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,60 @@
package net.joshka.junit.javax.json;

import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.ArgumentsProvider;
import org.junit.jupiter.params.support.AnnotationConsumer;
import org.junit.platform.commons.util.Preconditions;

import javax.json.Json;
import javax.json.JsonReader;
import javax.json.JsonStructure;
import javax.json.JsonValue;
import java.io.InputStream;
import java.util.Arrays;
import java.util.function.BiFunction;
import java.util.stream.Stream;

public class JsonFileArgumentsProvider implements AnnotationConsumer<JsonFileSource>, ArgumentsProvider {

private final BiFunction<Class<?>, String, InputStream> inputStreamProvider;

private String[] resources;

public JsonFileArgumentsProvider() {
this(Class::getResourceAsStream);
}

public JsonFileArgumentsProvider(BiFunction<Class<?>, String, InputStream> inputStreamProvider) {
this.inputStreamProvider = inputStreamProvider;
}

private static Stream<JsonValue> values(InputStream inputStream) {
try (JsonReader reader = Json.createReader(inputStream)) {
JsonStructure structure = reader.read();
return structure.getValueType() == JsonValue.ValueType.ARRAY
? structure.asJsonArray().stream()
: Stream.of(structure);
}
}

@Override
public void accept(JsonFileSource jsonFileSource) {
resources = jsonFileSource.resources();
}

@Override
public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
return Arrays.stream(resources)
.map(resource -> openInputStream(context, resource))
.flatMap(JsonFileArgumentsProvider::values)
.map(Arguments::of);
}

private InputStream openInputStream(ExtensionContext context, String resource) {
Class<?> testClass = context.getRequiredTestClass();
InputStream inputStream = inputStreamProvider.apply(testClass, resource);
return Preconditions.notNull(inputStream,
() -> "Classpath resource does not exist: " + resource);
}
}
14 changes: 14 additions & 0 deletions src/main/java/net/joshka/junit/javax/json/JsonFileSource.java
@@ -0,0 +1,14 @@
package net.joshka.junit.javax.json;

import org.junit.jupiter.params.provider.ArgumentsSource;

import java.lang.annotation.*;

@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@ArgumentsSource(JsonFileArgumentsProvider.class)
public @interface JsonFileSource {

String[] resources();
}
@@ -0,0 +1,88 @@
package net.joshka.junit.javax.json;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.platform.commons.util.PreconditionViolationException;

import javax.json.JsonNumber;
import javax.json.JsonObject;
import javax.json.JsonString;
import java.io.InputStream;
import java.util.function.BiFunction;

import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

class JsonFileArgumentsProviderTest {

@Test
@DisplayName("default constructor does not throw")
void defaultConstructor() {
assertThatCode(JsonFileArgumentsProvider::new)
.doesNotThrowAnyException();
}

/**
* When passed <code>{"key":"value"}</code>, is executed a single time
* @param object the parsed JsonObject
*/
@ParameterizedTest
@JsonFileSource(resources = "/single-object.json")
@DisplayName("provides a single object")
void singleObject(JsonObject object) {
assertThat(object.getString("key")).isEqualTo("value");
}

/**
* When passed <code>[{"key":"value1"},{"key","value2"]}</code>, is
* executed once per element of the array
* @param object the parsed JsonObject array element
*/
@ParameterizedTest
@JsonFileSource(resources = "/array-of-objects.json")
@DisplayName("provides an array of objects")
void arrayOfObjects(JsonObject object) {
assertThat(object.getString("key")).startsWith("value");
}

/**
* When passed <code>[1, 2]}</code>, is executed once per array element
* @param number the parsed JsonNumber for each array element
*/
@ParameterizedTest
@JsonFileSource(resources = "/array-of-numbers.json")
@DisplayName("provides an array of numbers")
void arrayOfNumbers(JsonNumber number) {
assertThat(number.intValue()).isGreaterThan(0);
}

/**
* When passed <code>["value1","value2"}</code>, is executed once per array
* element
* @param string the parsed JsonString for each array element
*/
@ParameterizedTest
@JsonFileSource(resources = "/array-of-strings.json")
@DisplayName("provides an array of strings")
void arrayOfStrings(JsonString string) {
assertThat(string.getString()).startsWith("value");
}

@Test
@DisplayName("missing resource throws exception")
void missingResource() {
BiFunction<Class<?>, String, InputStream> inputStreamProvider = (aClass, resource) -> null;
ExtensionContext context = mock(ExtensionContext.class);
JsonFileSource source = mock(JsonFileSource.class);
when(source.resources()).thenReturn(new String[]{"not-found.json"});
JsonFileArgumentsProvider provider = new JsonFileArgumentsProvider(inputStreamProvider);
provider.accept(source);

assertThatExceptionOfType(PreconditionViolationException.class)
.isThrownBy(() -> provider.provideArguments(context).forEach(o -> {}))
.withMessage("Classpath resource does not exist: not-found.json");
}
}
1 change: 1 addition & 0 deletions src/test/resources/array-of-numbers.json
@@ -0,0 +1 @@
[1, 2]
8 changes: 8 additions & 0 deletions src/test/resources/array-of-objects.json
@@ -0,0 +1,8 @@
[
{
"key":"value1"
},
{
"key":"value2"
}
]
1 change: 1 addition & 0 deletions src/test/resources/array-of-strings.json
@@ -0,0 +1 @@
["value1", "value2"]
3 changes: 3 additions & 0 deletions src/test/resources/single-object.json
@@ -0,0 +1,3 @@
{
"key":"value"
}

0 comments on commit aa5308f

Please sign in to comment.