Skip to content

Build a JUnit 5 Extension for the Snapshotmatcher Library #20

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
12 changes: 9 additions & 3 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>io.github.json-snapshot</groupId>
<artifactId>json-snapshot</artifactId>
<version>1.0.17</version>
<version>1.0.18</version>
<packaging>jar</packaging>

<name>json-snapshot</name>
Expand Down Expand Up @@ -47,6 +47,7 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<junit.version>5.4.1</junit.version>
</properties>

<dependencies>
Expand Down Expand Up @@ -74,12 +75,17 @@
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.3.2</version>
<version>${junit.version}</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.3.2</version>
<version>${junit.version}</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>${junit.version}</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
Expand Down
7 changes: 0 additions & 7 deletions src/main/java/io/github/jsonSnapshot/DefaultConfig.java

This file was deleted.

11 changes: 5 additions & 6 deletions src/main/java/io/github/jsonSnapshot/Snapshot.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package io.github.jsonSnapshot;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collection;
import java.util.Set;
Expand All @@ -15,22 +14,22 @@ public class Snapshot {

private Class clazz;

private Method method;
private String testName;

private Function<Object, String> jsonFunction;

private Object[] current;

Snapshot(
public Snapshot(
SnapshotFile snapshotFile,
Class clazz,
Method method,
String method,
Function<Object, String> jsonFunction,
Object... current) {
this.current = current;
this.snapshotFile = snapshotFile;
this.clazz = clazz;
this.method = method;
this.testName = method;
this.jsonFunction = jsonFunction;
}

Expand Down Expand Up @@ -88,6 +87,6 @@ private String takeSnapshot() {
}

public String getSnapshotName() {
return clazz.getName() + "." + method.getName() + "=";
return String.format("%s.%s=", clazz.getName(), testName);
}
}
9 changes: 7 additions & 2 deletions src/main/java/io/github/jsonSnapshot/SnapshotConfig.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
package io.github.jsonSnapshot;

public interface SnapshotConfig {
String getFilePath();
import lombok.Builder;
import lombok.Getter;

@Builder
@Getter
public class SnapshotConfig {
@Builder.Default private final String filePath = "src/test/java/";
}
5 changes: 3 additions & 2 deletions src/main/java/io/github/jsonSnapshot/SnapshotFile.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.github.jsonSnapshot;

import java.io.*;
import java.nio.file.Paths;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;
Expand All @@ -18,9 +19,9 @@ public class SnapshotFile {

@Getter private Set<String> rawSnapshots;

SnapshotFile(String filePath, String fileName) throws IOException {
public SnapshotFile(String filePath, String fileName) throws IOException {

this.fileName = filePath + fileName;
this.fileName = Paths.get(filePath, fileName).toString();

StringBuilder fileContent = new StringBuilder();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

public class SnapshotMatchException extends RuntimeException {

SnapshotMatchException(String message) {
public SnapshotMatchException(String message) {
super(message);
}

SnapshotMatchException(String message, Throwable cause) {
public SnapshotMatchException(String message, Throwable cause) {
super(message, cause);
}
}
92 changes: 7 additions & 85 deletions src/main/java/io/github/jsonSnapshot/SnapshotMatcher.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,44 +10,32 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.assertj.core.util.Arrays;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.jupiter.api.BeforeAll;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.PrettyPrinter;
import com.fasterxml.jackson.core.util.DefaultIndenter;
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter.Indenter;
import com.fasterxml.jackson.core.util.Separators;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

public class SnapshotMatcher {

private static Logger log = LoggerFactory.getLogger(SnapshotMatcher.class);

private static final SnapshotConfig DEFAULT_CONFIG = SnapshotConfig.builder().build();
private static Class clazz = null;
private static SnapshotFile snapshotFile = null;
private static List<Snapshot> calledSnapshots = new ArrayList<>();
private static Function<Object, String> jsonFunction;

public static void start() {
start(new DefaultConfig(), defaultJsonFunction());
start(DEFAULT_CONFIG, SnapshotUtils.defaultJsonFunction());
}

public static void start(SnapshotConfig config) {
start(config, defaultJsonFunction());
start(config, SnapshotUtils.defaultJsonFunction());
}

public static void start(Function<Object, String> jsonFunction) {
start(new DefaultConfig(), jsonFunction);
start(DEFAULT_CONFIG, jsonFunction);
}

public static void start(SnapshotConfig config, Function<Object, String> jsonFunction) {
Expand Down Expand Up @@ -94,72 +82,15 @@ public static Snapshot expect(Object firstObject, Object... others) {
throw new SnapshotMatchException(
"SnapshotTester not yet started! Start it on @BeforeClass/@BeforeAll with SnapshotMatcher.start()");
}
Object[] objects = mergeObjects(firstObject, others);
Object[] objects = SnapshotUtils.mergeObjects(firstObject, others);
StackTraceElement stackElement = findStackElement();
Method method = getMethod(clazz, stackElement.getMethodName());
Snapshot snapshot = new Snapshot(snapshotFile, clazz, method, jsonFunction, objects);
validateExpectCall(snapshot);
Snapshot snapshot = new Snapshot(snapshotFile, clazz, method.getName(), jsonFunction, objects);
SnapshotUtils.validateExpectCall(snapshot, calledSnapshots);
calledSnapshots.add(snapshot);
return snapshot;
}

static Function<Object, String> defaultJsonFunction() {

ObjectMapper objectMapper = buildObjectMapper();

PrettyPrinter pp = buildDefaultPrettyPrinter();

return (object) -> {
try {
return objectMapper.writer(pp).writeValueAsString(object);
} catch (Exception e) {
throw new SnapshotMatchException(e.getMessage());
}
};
}

private static PrettyPrinter buildDefaultPrettyPrinter() {
DefaultPrettyPrinter pp =
new DefaultPrettyPrinter("") {
@Override
public DefaultPrettyPrinter withSeparators(Separators separators) {
this._separators = separators;
this._objectFieldValueSeparatorWithSpaces =
separators.getObjectFieldValueSeparator() + " ";
return this;
}
};
Indenter lfOnlyIndenter = new DefaultIndenter(" ", "\n");
pp.indentArraysWith(lfOnlyIndenter);
pp.indentObjectsWith(lfOnlyIndenter);
return pp;
}

private static ObjectMapper buildObjectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true);
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);

objectMapper.setVisibility(
objectMapper
.getSerializationConfig()
.getDefaultVisibilityChecker()
.withFieldVisibility(JsonAutoDetect.Visibility.ANY)
.withGetterVisibility(JsonAutoDetect.Visibility.NONE)
.withSetterVisibility(JsonAutoDetect.Visibility.NONE)
.withCreatorVisibility(JsonAutoDetect.Visibility.NONE));
return objectMapper;
}

private static void validateExpectCall(Snapshot snapshot) {
for (Snapshot eachSnapshot : calledSnapshots) {
if (eachSnapshot.getSnapshotName().equals(snapshot.getSnapshotName())) {
throw new SnapshotMatchException(
"You can only call 'expect' once per test method. Try using array of arguments on a single 'expect' call");
}
}
}

private static Method getMethod(Class<?> clazz, String methodName) {
try {
return Stream.of(clazz.getDeclaredMethods())
Expand Down Expand Up @@ -211,15 +142,6 @@ private static boolean hasTestAnnotation(Method method) {
|| method.isAnnotationPresent(BeforeAll.class);
}

private static Object[] mergeObjects(Object firstObject, Object[] others) {
Object[] objects = new Object[1];
objects[0] = firstObject;
if (!Arrays.isNullOrEmpty(others)) {
objects = ArrayUtils.addAll(objects, others);
}
return objects;
}

private static Class<?> getClass(String className) {
try {
return Class.forName(className);
Expand Down
78 changes: 78 additions & 0 deletions src/main/java/io/github/jsonSnapshot/SnapshotUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,21 @@
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.function.Function;

import org.apache.commons.lang3.ArrayUtils;
import org.assertj.core.util.Arrays;
import org.mockito.ArgumentCaptor;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.PrettyPrinter;
import com.fasterxml.jackson.core.util.DefaultIndenter;
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
import com.fasterxml.jackson.core.util.Separators;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

public class SnapshotUtils {

public static <T> HashMap<String, List<LinkedHashMap<String, Object>>> extractArgs(
Expand Down Expand Up @@ -88,4 +100,70 @@ private static <T> HashMap<String, List<LinkedHashMap<String, Object>>> process(

return result;
}

public static Function<Object, String> defaultJsonFunction() {

ObjectMapper objectMapper = buildObjectMapper();

PrettyPrinter pp = buildDefaultPrettyPrinter();

return (object) -> {
try {
return objectMapper.writer(pp).writeValueAsString(object);
} catch (Exception e) {
throw new SnapshotMatchException(e.getMessage());
}
};
}

public static PrettyPrinter buildDefaultPrettyPrinter() {
DefaultPrettyPrinter pp =
new DefaultPrettyPrinter("") {
@Override
public DefaultPrettyPrinter withSeparators(Separators separators) {
this._separators = separators;
this._objectFieldValueSeparatorWithSpaces =
separators.getObjectFieldValueSeparator() + " ";
return this;
}
};
DefaultPrettyPrinter.Indenter lfOnlyIndenter = new DefaultIndenter(" ", "\n");
pp.indentArraysWith(lfOnlyIndenter);
pp.indentObjectsWith(lfOnlyIndenter);
return pp;
}

private static ObjectMapper buildObjectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true);
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);

objectMapper.setVisibility(
objectMapper
.getSerializationConfig()
.getDefaultVisibilityChecker()
.withFieldVisibility(JsonAutoDetect.Visibility.ANY)
.withGetterVisibility(JsonAutoDetect.Visibility.NONE)
.withSetterVisibility(JsonAutoDetect.Visibility.NONE)
.withCreatorVisibility(JsonAutoDetect.Visibility.NONE));
return objectMapper;
}

public static void validateExpectCall(Snapshot snapshot, List<Snapshot> calledSnapshots) {
for (Snapshot eachSnapshot : calledSnapshots) {
if (eachSnapshot.getSnapshotName().equals(snapshot.getSnapshotName())) {
throw new SnapshotMatchException(
"You can only call 'expect' once per test method. Try using array of arguments on a single 'expect' call");
}
}
}

public static Object[] mergeObjects(Object firstObject, Object[] others) {
Object[] objects = new Object[1];
objects[0] = firstObject;
if (!Arrays.isNullOrEmpty(others)) {
objects = ArrayUtils.addAll(objects, others);
}
return objects;
}
}
17 changes: 17 additions & 0 deletions src/main/java/io/github/jsonSnapshot/junit5/Constants.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package io.github.jsonSnapshot.junit5;

import org.junit.jupiter.api.extension.ExtensionContext;

public class Constants {

public static final ExtensionContext.Namespace NAMESPACE =
ExtensionContext.Namespace.create(SnapshotMatcher.class);
public static final String SNAPSHOT_FILE = "snapshotFile";
public static final String CALLED_SNAPSHOTS = "calledSnapshots";

// ***************** JVM Config Values *************************
public static final String SNAPSHOT_ROOT_DIR =
"junit.jupiter.extensions.snapshotmatcher.snaps.rootDir";

private Constants() {}
}
Loading