diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 96b0b69..6209e3f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -5,9 +5,13 @@ name: build on: push: - branches: [ master ] + branches: + - master + - 'release/**' pull_request: - branches: [ master ] + branches: + - master + - 'release/**' workflow_dispatch: jobs: diff --git a/README.md b/README.md index b9c861f..ecde228 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,16 @@ [![Build Status](https://github.com/origin-energy/java-snapshot-testing/workflows/build/badge.svg)](https://github.com/origin-energy/java-snapshot-testing/actions) -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.github.origin-energy/java-snapshot-testing-core/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.github.origin-energy/java-snapshot-testing-core) +[![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.github.origin-energy/java-snapshot-testing-core/badge.svg?version=3.2.7)](https://search.maven.org/artifact/io.github.origin-energy/java-snapshot-testing-core/3.2.7/jar) # Java Snapshot Testing - Inspired by [facebook's Jest framework](https://facebook.github.io/jest/docs/en/snapshot-testing.html) -🎉 3.X is live - parallel test support, easily override configuration via `snapshot.properties` yet *.snap format remains unchanged! This release will require some mechanical refactoring for those upgrading as `expect` is no longer a static method. +🎉 4.0.0.Beta1 is live - We need testers +[![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.github.origin-energy/java-snapshot-testing-core/badge.svg?subject=4.0.0-Beta1)](https://maven-badges.herokuapp.com/maven-central/io.github.origin-energy/java-snapshot-testing-core) +- Report bugs to "Issues" clearly marking them as 4.0.0-Beta -Upgrade guide from 2.X to 3.X [here](https://github.com/origin-energy/java-snapshot-testing/discussions/73) +## Upgrading +- Upgrade guild from 3.X to 4.X [here](https://github.com/origin-energy/java-snapshot-testing/discussions/94) +- Upgrade guide from 2.X to 3.X [here](https://github.com/origin-energy/java-snapshot-testing/discussions/73) ## The testing framework loved by ~~lazy~~ __productive__ devs @@ -60,6 +64,7 @@ ci-env-var=CI ```java package au.com.origin.snapshots.docs; +import au.com.origin.snapshots.Expect; import au.com.origin.snapshots.annotations.SnapshotName; import au.com.origin.snapshots.junit5.SnapshotExtension; import org.junit.jupiter.api.Test; @@ -67,29 +72,28 @@ import org.junit.jupiter.api.extension.ExtendWith; import java.util.HashMap; import java.util.Map; -import au.com.origin.snapshots.Expect; @ExtendWith({SnapshotExtension.class}) public class MyFirstSnapshotTest { - private Expect expect; + private Expect expect; - @SnapshotName("i_can_give_custom_names_to_my_snapshots") - @Test - public void toStringSerializationTest() { - expect.toMatchSnapshot("Hello World"); - } + @SnapshotName("i_can_give_custom_names_to_my_snapshots") + @Test + public void toStringSerializationTest() { + expect.toMatchSnapshot("Hello World"); + } - @Test - public void jsonSerializationTest() { - Map map = new HashMap<>(); - map.put("name", "John Doe"); - map.put("age", 40); - - expect - .serializer("json") - .toMatchSnapshot(map); - } + @Test + public void jsonSerializationTest() { + Map map = new HashMap<>(); + map.put("name", "John Doe"); + map.put("age", 40); + + expect + .serializer("json") + .toMatchSnapshot(map); + } } ``` @@ -375,8 +379,8 @@ Here is a JUnit5 example that does not use the JUnit5 extension package au.com.origin.snapshots.docs; import au.com.origin.snapshots.Expect; -import au.com.origin.snapshots.PropertyResolvingSnapshotConfig; import au.com.origin.snapshots.SnapshotVerifier; +import au.com.origin.snapshots.config.PropertyResolvingSnapshotConfig; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -385,23 +389,23 @@ import org.junit.jupiter.api.TestInfo; // Notice we aren't using any framework extensions public class CustomFrameworkExample { - private static SnapshotVerifier snapshotVerifier; + private static SnapshotVerifier snapshotVerifier; - @BeforeAll - static void beforeAll() { - snapshotVerifier = new SnapshotVerifier(new PropertyResolvingSnapshotConfig(), CustomFrameworkExample.class); - } + @BeforeAll + static void beforeAll() { + snapshotVerifier = new SnapshotVerifier(new PropertyResolvingSnapshotConfig(), CustomFrameworkExample.class); + } - @AfterAll - static void afterAll() { - snapshotVerifier.validateSnapshots(); - } + @AfterAll + static void afterAll() { + snapshotVerifier.validateSnapshots(); + } - @Test - void shouldMatchSnapshotOne(TestInfo testInfo) { - Expect expect = Expect.of(snapshotVerifier, testInfo.getTestMethod().get()); - expect.toMatchSnapshot("Hello World"); - } + @Test + void shouldMatchSnapshotOne(TestInfo testInfo) { + Expect expect = Expect.of(snapshotVerifier, testInfo.getTestMethod().get()); + expect.toMatchSnapshot("Hello World"); + } } ``` @@ -444,15 +448,17 @@ Often your IDE has an excellent file comparison tool. This file allows you to conveniently setup global defaults -| key | Description | -|------------------|----------------------------------------------------------------------------------------------------------------| -|serializer | Class name of the [serializer](#supplying-a-custom-snapshotserializer), default serializer | -|serializer.{name} | Class name of the [serializer](#supplying-a-custom-snapshotserializer), accessible via `.serializer("{name}")` | -|comparator | Class name of the [comparator](#supplying-a-custom-snapshotcomparator) | -|reporters | Comma separated list of class names to use as [reporters](#supplying-a-custom-snapshotreporter) | -|snapshot-dir | Name of sub-folder holding your snapshots | -|output-dir | Base directory of your test files (although it can be a different directory if you want) | -|ci-env-var | Name of environment variable used to detect if we are running on a Build Server | +| key | Description | +|------------------|----------------------------------------------------------------------------------------------------------------------------------------| +|serializer | Class name of the [serializer](#supplying-a-custom-snapshotserializer), default serializer | +|serializer.{name} | Class name of the [serializer](#supplying-a-custom-snapshotserializer), accessible via `.serializer("{name}")` | +|comparator | Class name of the [comparator](#supplying-a-custom-snapshotcomparator) | +|comparator.{name} | Class name of the [comparator](#supplying-a-custom-snapshotcomparator), accessible via `.comparator("{name}")` | +|reporters | Comma separated list of class names to use as [reporters](#supplying-a-custom-snapshotreporter) | +|reporters.{name} | Comma separated list of class names to use as [reporters](#supplying-a-custom-snapshotreporter), accessible via `.reporters("{name}")` | +|snapshot-dir | Name of sub-folder holding your snapshots | +|output-dir | Base directory of your test files (although it can be a different directory if you want) | +|ci-env-var | Name of environment variable used to detect if we are running on a Build Server | For example: @@ -549,25 +555,27 @@ import org.junit.jupiter.api.extension.ExtendWith; @UseSnapshotConfig(LowercaseToStringSnapshotConfig.class) public class JUnit5ResolutionHierarchyExample { - @Test - public void aliasMethodTest(Expect expect) { - expect - .serializer("json") // <------ Using snapshot.properties - .toMatchSnapshot(new TestObject()); - } + private Expect expect; - @Test - public void customSerializerTest(Expect expect) { - expect - .serializer(UppercaseToStringSerializer.class) // <------ Using custom serializer - .toMatchSnapshot(new TestObject()); - } + @Test + public void aliasMethodTest() { + expect + .serializer("json") // <------ Using snapshot.properties + .toMatchSnapshot(new TestObject()); + } - // Read from LowercaseToStringSnapshotConfig defined on the class - @Test - public void lowercaseTest(Expect expect) { - expect.toMatchSnapshot(new TestObject()); - } + @Test + public void customSerializerTest() { + expect + .serializer(UppercaseToStringSerializer.class) // <------ Using custom serializer + .toMatchSnapshot(new TestObject()); + } + + // Read from LowercaseToStringSnapshotConfig defined on the class + @Test + public void lowercaseTest() { + expect.toMatchSnapshot(new TestObject()); + } } ``` @@ -588,6 +596,7 @@ import au.com.origin.snapshots.jackson.serializers.DeterministicJacksonSnapshotS import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreType; +import com.fasterxml.jackson.databind.ObjectMapper; import java.time.Instant; import java.util.List; @@ -595,32 +604,32 @@ import java.util.Set; public class HibernateSnapshotSerializer extends DeterministicJacksonSnapshotSerializer { - @Override - public void configure(ObjectMapper objectMapper) { - super.configure(objectMapper); + @Override + public void configure(ObjectMapper objectMapper) { + super.configure(objectMapper); - // Ignore Hibernate Lists to prevent infinite recursion - objectMapper.addMixIn(List.class, IgnoreTypeMixin.class); - objectMapper.addMixIn(Set.class, IgnoreTypeMixin.class); + // Ignore Hibernate Lists to prevent infinite recursion + objectMapper.addMixIn(List.class, IgnoreTypeMixin.class); + objectMapper.addMixIn(Set.class, IgnoreTypeMixin.class); - // Ignore Fields that Hibernate generates for us automatically - objectMapper.addMixIn(BaseEntity.class, IgnoreHibernateEntityFields.class); - } + // Ignore Fields that Hibernate generates for us automatically + objectMapper.addMixIn(BaseEntity.class, IgnoreHibernateEntityFields.class); + } - @JsonIgnoreType - class IgnoreTypeMixin { - } + @JsonIgnoreType + class IgnoreTypeMixin { + } - abstract class IgnoreHibernateEntityFields { - @JsonIgnore - abstract Long getId(); + abstract class IgnoreHibernateEntityFields { + @JsonIgnore + abstract Long getId(); - @JsonIgnore - abstract Instant getCreatedDate(); + @JsonIgnore + abstract Instant getCreatedDate(); - @JsonIgnore - abstract Instant getLastModifiedDate(); - } + @JsonIgnore + abstract Instant getLastModifiedDate(); + } } ``` @@ -650,20 +659,21 @@ and field order are ignored. ```java package au.com.origin.snapshots.docs; +import au.com.origin.snapshots.Snapshot; import au.com.origin.snapshots.comparators.SnapshotComparator; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.SneakyThrows; public class JsonObjectComparator implements SnapshotComparator { - @Override - public boolean matches(String snapshotName, String rawSnapshot, String currentObject) { - return asObject(snapshotName, rawSnapshot).equals(asObject(snapshotName, currentObject)); - } + @Override + public boolean matches(Snapshot previous, Snapshot current) { + return asObject(previous.getName(), previous.getBody()).equals(asObject(current.getName(), current.getBody())); + } - @SneakyThrows - private static Object asObject(String snapshotName, String json) { - return new ObjectMapper().readValue(json.replaceFirst(snapshotName, ""), Object.class); - } + @SneakyThrows + private static Object asObject(String snapshotName, String json) { + return new ObjectMapper().readValue(json.replaceFirst(snapshotName + "=", ""), Object.class); + } } ``` @@ -686,6 +696,7 @@ a custom reporter can be created like the one below. ```java package au.com.origin.snapshots.docs; +import au.com.origin.snapshots.Snapshot; import au.com.origin.snapshots.reporters.SnapshotReporter; import au.com.origin.snapshots.serializers.SerializerType; import lombok.SneakyThrows; @@ -693,16 +704,16 @@ import org.skyscreamer.jsonassert.JSONAssert; import org.skyscreamer.jsonassert.JSONCompareMode; public class JsonAssertReporter implements SnapshotReporter { - @Override - public boolean supportsFormat(String outputFormat) { - return SerializerType.JSON.name().equalsIgnoreCase(outputFormat); - } + @Override + public boolean supportsFormat(String outputFormat) { + return SerializerType.JSON.name().equalsIgnoreCase(outputFormat); + } - @Override - @SneakyThrows - public void report(String snapshotName, String rawSnapshot, String currentObject) { - JSONAssert.assertEquals(rawSnapshot, currentObject, JSONCompareMode.STRICT); - } + @Override + @SneakyThrows + public void report(Snapshot previous, Snapshot current) { + JSONAssert.assertEquals(previous.getBody(), current.getBody(), JSONCompareMode.STRICT); + } } ``` @@ -722,14 +733,30 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @ExtendWith(SnapshotExtension.class) -// apply your custom snapshot configuration to this test class @UseSnapshotConfig(LowercaseToStringSnapshotConfig.class) -public class CustomSnapshotConfigExample { +public class JUnit5ResolutionHierarchyExample { - @Test - public void myTest(Expect expect) { - expect.toMatchSnapshot("hello world"); - } + private Expect expect; + + @Test + public void aliasMethodTest() { + expect + .serializer("json") // <------ Using snapshot.properties + .toMatchSnapshot(new TestObject()); + } + + @Test + public void customSerializerTest() { + expect + .serializer(UppercaseToStringSerializer.class) // <------ Using custom serializer + .toMatchSnapshot(new TestObject()); + } + + // Read from LowercaseToStringSnapshotConfig defined on the class + @Test + public void lowercaseTest() { + expect.toMatchSnapshot(new TestObject()); + } } ``` diff --git a/gradle.properties b/gradle.properties index 65eaf1f..0668f7b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,2 @@ group=io.github.origin-energy -version=3.4.0-SNAPSHOT +version=4.0.0-Beta1-SNAPSHOT diff --git a/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/Expect.java b/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/Expect.java index c889efa..c4246e6 100644 --- a/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/Expect.java +++ b/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/Expect.java @@ -8,7 +8,9 @@ import java.lang.reflect.Method; import java.util.Arrays; +import java.util.HashMap; import java.util.List; +import java.util.Map; @RequiredArgsConstructor public class Expect { @@ -20,6 +22,8 @@ public class Expect { private List snapshotReporters; private String scenario; + private final Map headers = new HashMap<>(); + public static Expect of(SnapshotVerifier snapshotVerifier, Method method) { return new Expect(snapshotVerifier, method); } @@ -34,36 +38,23 @@ public static Expect of(SnapshotVerifier snapshotVerifier, Method method) { * @param object snapshot object */ public void toMatchSnapshot(Object object) { - toMatchSnapshotLegacy(object); - } - - /** - * Make an assertion on the given input parameters against what already exists - * - * Previously called `toMatchSnapshot`, this varargs implementation will be removed - * in future versions of this library. - * - * @param firstObject first snapshot object - * @param objects other snapshot objects - */ - @Deprecated - public void toMatchSnapshotLegacy(Object firstObject, Object... objects) { - Snapshot snapshot = snapshotVerifier.expectCondition(testMethod, firstObject, objects); + SnapshotContext snapshotContext = snapshotVerifier.expectCondition(testMethod, object); if (snapshotSerializer != null) { - snapshot.setSnapshotSerializer(snapshotSerializer); + snapshotContext.setSnapshotSerializer(snapshotSerializer); } if (snapshotComparator != null) { - snapshot.setSnapshotComparator(snapshotComparator); + snapshotContext.setSnapshotComparator(snapshotComparator); } if (snapshotReporters != null) { - snapshot.setSnapshotReporters(snapshotReporters); + snapshotContext.setSnapshotReporters(snapshotReporters); } if (scenario != null) { - snapshot.setScenario(scenario); + snapshotContext.setScenario(scenario); } - snapshot.toMatchSnapshot(); - } + snapshotContext.header.putAll(headers); + snapshotContext.toMatchSnapshot(); + } /** * Normally a snapshot can be applied only once to a test method. @@ -112,6 +103,17 @@ public Expect comparator(SnapshotComparator comparator) { return this; } + /** + * Apply a custom comparator for this snapshot + * + * @param name the {name} attribute comparator.{name} from snapshot.properties + * @return Snapshot + */ + public Expect comparator(String name) { + this.snapshotComparator = SnapshotProperties.getInstance("comparator." + name); + return this; + } + /** * Apply a list of custom reporters for this snapshot * This will replace the default reporters defined in the config @@ -124,6 +126,18 @@ public Expect reporters(SnapshotReporter... reporters) { return this; } + /** + * Apply a list of custom reporters for this snapshot + * This will replace the default reporters defined in the config + * + * @param name the {name} attribute reporters.{name} from snapshot.properties + * @return Snapshot + */ + public Expect reporters(String name) { + this.snapshotReporters = SnapshotProperties.getInstances("reporters." + name); + return this; + } + /** * Apply a custom serializer for this snapshot. * @@ -141,4 +155,19 @@ public Expect serializer(Class serializer) { return this; } + /** + * Add anything you like to the snapshot header. + * + * These custom headers can be used in serializers, comparators or reporters to change + * how they behave. + * + * @param key key + * @param value value + * @return Expect + */ + public Expect header(String key, String value) { + headers.put(key, value); + return this; + } + } diff --git a/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/Snapshot.java b/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/Snapshot.java index b00e648..ed073d2 100644 --- a/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/Snapshot.java +++ b/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/Snapshot.java @@ -1,138 +1,82 @@ package au.com.origin.snapshots; -import au.com.origin.snapshots.annotations.SnapshotName; -import au.com.origin.snapshots.comparators.SnapshotComparator; -import au.com.origin.snapshots.exceptions.SnapshotMatchException; -import au.com.origin.snapshots.reporters.SnapshotReporter; -import au.com.origin.snapshots.serializers.SnapshotSerializer; -import lombok.Setter; -import lombok.extern.slf4j.Slf4j; - -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -@Slf4j -public class Snapshot { - - private final SnapshotConfig snapshotConfig; - private final SnapshotFile snapshotFile; - private final Class testClass; - private final Method testMethod; - private final Object[] current; - private final boolean isCI; - - @Setter - private SnapshotSerializer snapshotSerializer; - @Setter - private SnapshotComparator snapshotComparator; - @Setter - private List snapshotReporters; - @Setter - private String scenario; - - Snapshot( - SnapshotConfig snapshotConfig, - SnapshotFile snapshotFile, - Class testClass, - Method testMethod, - Object... current) { - this.snapshotConfig = snapshotConfig; - this.snapshotFile = snapshotFile; - this.testClass = testClass; - this.testMethod = testMethod; - this.current = current; - - this.isCI = snapshotConfig.isCI(); - this.snapshotSerializer = snapshotConfig.getSerializer(); - this.snapshotComparator = snapshotConfig.getComparator(); - this.snapshotReporters = snapshotConfig.getReporters(); - this.scenario = null; - } - - public void toMatchSnapshot() { - Set rawSnapshots = snapshotFile.getRawSnapshots(); - - String rawSnapshot = getRawSnapshot(rawSnapshots); - String currentObject = takeSnapshot(); - - if (rawSnapshot != null && shouldUpdateSnapshot()) { - snapshotFile.getRawSnapshots().remove(rawSnapshot); - rawSnapshot = null; +import au.com.origin.snapshots.exceptions.LogGithubIssueException; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +@EqualsAndHashCode +@Builder +@Getter +@RequiredArgsConstructor +public class Snapshot implements Comparable { + + private final String name; + private final String scenario; + private final SnapshotHeader header; + private final String body; + + @Override + public int compareTo(Snapshot other) { + return (name + scenario).compareTo(other.name + other.scenario); } - if (rawSnapshot != null) { - snapshotFile.pushDebugSnapshot(currentObject.trim()); - - // Match existing Snapshot - if (!snapshotComparator.matches(getSnapshotName(), rawSnapshot, currentObject)) { - List reporters = snapshotReporters - .stream() - .filter(reporter -> reporter.supportsFormat(snapshotSerializer.getOutputFormat())) - .collect(Collectors.toList()); + public String getIdentifier() { + return scenario == null ? name : String.format("%s[%s]", name, scenario); + } - if (reporters.isEmpty()) { - String comparator = snapshotComparator.getClass().getSimpleName(); - throw new IllegalStateException("No compatible reporters found for comparator " + comparator); + public static Snapshot parse(String rawText) { + String regex = "^(?.*?)(\\[(?.*)\\])?=(?
\\{.*\\})?(?(.*)$)"; + Pattern p = Pattern.compile(regex, Pattern.DOTALL); + Matcher m = p.matcher(rawText); + boolean found = m.find(); + if (!found) { + throw new LogGithubIssueException( + "Corrupt Snapshot (REGEX matches = 0): possibly due to manual editing or our REGEX failing\n" + + "Possible Solutions\n" + + "1. Ensure you have not accidentally manually edited the snapshot file!\n" + + "2. Compare the snapshot with GIT history" + ); } - List errors = new ArrayList<>(); - - for (SnapshotReporter reporter : reporters) { - try { - reporter.report(getSnapshotName(), rawSnapshot, currentObject); - } catch (Throwable t) { - errors.add(t); - } + String name = m.group("name"); + String scenario = m.group("scenario"); + String header = m.group("header"); + String snapshot = m.group("snapshot"); + + if (name == null || snapshot == null) { + throw new LogGithubIssueException( + "Corrupt Snapshot (REGEX name or snapshot group missing): possibly due to manual editing or our REGEX failing\n" + + "Possible Solutions\n" + + "1. Ensure you have not accidentally manually edited the snapshot file\n" + + "2. Compare the snapshot with your version control history" + ); } - if (!errors.isEmpty()) { - throw new SnapshotMatchException("Error(s) matching snapshot(s)", errors); - } - } - } else { - if (this.isCI) { - log.error("We detected you are running on a CI Server - if this is incorrect please override the isCI() method in SnapshotConfig"); - throw new SnapshotMatchException("Snapshot [" + getSnapshotName() + "] not found. Has this snapshot been committed ?"); - } else { - log.warn("We detected you are running on a developer machine - if this is incorrect please override the isCI() method in SnapshotConfig"); - // Create New Snapshot - snapshotFile.pushSnapshot(currentObject); - snapshotFile.pushDebugSnapshot(currentObject.trim()); - } + return Snapshot.builder() + .name(name) + .scenario(scenario) + .header(SnapshotHeader.fromJson(header)) + .body(snapshot) + .build(); } - } - private boolean shouldUpdateSnapshot() { - if (snapshotConfig.updateSnapshot().isPresent()) { - return getSnapshotName().contains(snapshotConfig.updateSnapshot().get()); - } else { - return false; + /** + * The raw string representation of the snapshot as it would appear in the *.snap file. + * + * @return raw snapshot + */ + public String raw() { + String headerJson = (header == null) || (header.size() == 0) ? "" : header.toJson(); + return getIdentifier() + "=" + headerJson + body; } - } - private String getRawSnapshot(Collection rawSnapshots) { - for (String rawSnapshot : rawSnapshots) { - if (rawSnapshot.contains(getSnapshotName())) { - return rawSnapshot; - } + @Override + public String toString() { + return raw(); } - return null; - } - - private String takeSnapshot() { - return getSnapshotName() + snapshotSerializer.apply(current); - } - - String getSnapshotName() { - String scenarioFormat = scenario == null ? "" : "[" + scenario + "]"; - SnapshotName snapshotName = testMethod.getAnnotation(SnapshotName.class); - String pathFormat = snapshotName == null ? - testClass.getName() + "." + testMethod.getName() : - snapshotName.value(); - return pathFormat + scenarioFormat + "="; - } } diff --git a/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/SnapshotContext.java b/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/SnapshotContext.java new file mode 100644 index 0000000..8f1a810 --- /dev/null +++ b/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/SnapshotContext.java @@ -0,0 +1,154 @@ +package au.com.origin.snapshots; + +import au.com.origin.snapshots.annotations.SnapshotName; +import au.com.origin.snapshots.comparators.SnapshotComparator; +import au.com.origin.snapshots.config.SnapshotConfig; +import au.com.origin.snapshots.exceptions.SnapshotMatchException; +import au.com.origin.snapshots.reporters.SnapshotReporter; +import au.com.origin.snapshots.serializers.SnapshotSerializer; +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +@Slf4j +public class SnapshotContext { + + private final SnapshotConfig snapshotConfig; + private final SnapshotFile snapshotFile; + + @Getter + final Class testClass; + + @Getter + final Method testMethod; + + final Object current; + private final boolean isCI; + + @Setter + private SnapshotSerializer snapshotSerializer; + @Setter + private SnapshotComparator snapshotComparator; + @Setter + private List snapshotReporters; + + @Setter + @Getter + String scenario; + + @Getter + SnapshotHeader header = new SnapshotHeader(); + + SnapshotContext( + SnapshotConfig snapshotConfig, + SnapshotFile snapshotFile, + Class testClass, + Method testMethod, + Object current) { + this.snapshotConfig = snapshotConfig; + this.snapshotFile = snapshotFile; + this.testClass = testClass; + this.testMethod = testMethod; + this.current = current; + + this.isCI = snapshotConfig.isCI(); + this.snapshotSerializer = snapshotConfig.getSerializer(); + this.snapshotComparator = snapshotConfig.getComparator(); + this.snapshotReporters = snapshotConfig.getReporters(); + this.scenario = null; + } + + + public void toMatchSnapshot() { + + Set rawSnapshots = snapshotFile.getSnapshots(); + Snapshot previousSnapshot = getRawSnapshot(rawSnapshots); + Snapshot currentSnapshot = takeSnapshot(); + + if (previousSnapshot != null && shouldUpdateSnapshot()) { + snapshotFile.getSnapshots().remove(previousSnapshot); + previousSnapshot = null; + } + + if (previousSnapshot != null) { + snapshotFile.pushDebugSnapshot(currentSnapshot); + + // Match existing Snapshot + if (!snapshotComparator.matches(previousSnapshot, currentSnapshot)) { + snapshotFile.createDebugFile(currentSnapshot); + + List reporters = snapshotReporters + .stream() + .filter(reporter -> reporter.supportsFormat(snapshotSerializer.getOutputFormat())) + .collect(Collectors.toList()); + + if (reporters.isEmpty()) { + String comparator = snapshotComparator.getClass().getSimpleName(); + throw new IllegalStateException("No compatible reporters found for comparator " + comparator); + } + + List errors = new ArrayList<>(); + + for (SnapshotReporter reporter : reporters) { + try { + reporter.report(previousSnapshot, currentSnapshot); + } catch (Throwable t) { + errors.add(t); + } + } + + if (!errors.isEmpty()) { + throw new SnapshotMatchException("Error(s) matching snapshot(s)", errors); + } + } + } else { + if (this.isCI) { + log.error("We detected you are running on a CI Server - if this is incorrect please override the isCI() method in SnapshotConfig"); + throw new SnapshotMatchException("Snapshot [" + resolveSnapshotIdentifier() + "] not found. Has this snapshot been committed ?"); + } else { + log.warn("We detected you are running on a developer machine - if this is incorrect please override the isCI() method in SnapshotConfig"); + // Create New Snapshot + snapshotFile.pushSnapshot(currentSnapshot); + snapshotFile.pushDebugSnapshot(currentSnapshot); + } + } + } + + private boolean shouldUpdateSnapshot() { + if (snapshotConfig.updateSnapshot().isPresent()) { + return resolveSnapshotIdentifier().contains(snapshotConfig.updateSnapshot().get()); + } else { + return false; + } + } + + private Snapshot getRawSnapshot(Collection rawSnapshots) { + for (Snapshot rawSnapshot : rawSnapshots) { + if (rawSnapshot.getIdentifier().equals(resolveSnapshotIdentifier())) { + return rawSnapshot; + } + } + return null; + } + + private Snapshot takeSnapshot() { + SnapshotSerializerContext sg = SnapshotSerializerContext.from(this); + return snapshotSerializer.apply(current, sg); + } + + String resolveSnapshotIdentifier() { + String scenarioFormat = scenario == null ? "" : "[" + scenario + "]"; + SnapshotName snapshotName = testMethod.getAnnotation(SnapshotName.class); + String pathFormat = snapshotName == null ? + testClass.getName() + "." + testMethod.getName() : + snapshotName.value(); + return pathFormat + scenarioFormat; + } +} diff --git a/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/SnapshotFile.java b/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/SnapshotFile.java index 0f0ed89..22cb9d7 100644 --- a/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/SnapshotFile.java +++ b/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/SnapshotFile.java @@ -31,14 +31,12 @@ public class SnapshotFile { private final String fileName; private final Class testClass; - private final BiFunction, String, String> onSaveSnapshotFile; @Getter - private Set rawSnapshots; - private Set rawDebugSnapshots = Collections.synchronizedSortedSet(new TreeSet<>()); + private Set snapshots = Collections.synchronizedSortedSet(new TreeSet<>()); + private Set debugSnapshots = Collections.synchronizedSortedSet(new TreeSet<>()); - SnapshotFile(String srcDirPath, String fileName, Class testClass, BiFunction, String, String> onSaveSnapshotFile) throws IOException { + SnapshotFile(String srcDirPath, String fileName, Class testClass) throws IOException { this.testClass = testClass; - this.onSaveSnapshotFile = onSaveSnapshotFile; this.fileName = srcDirPath + File.separator + fileName; log.info("Snapshot File: " + this.fileName); @@ -54,16 +52,15 @@ public class SnapshotFile { String fileText = fileContent.toString(); if (!"".equals(fileText.trim())) { - rawSnapshots = + snapshots = Collections.synchronizedSortedSet( Stream.of(fileContent.toString().split(SPLIT_STRING)) .map(String::trim) + .map(Snapshot::parse) .collect(Collectors.toCollection(TreeSet::new))); - } else { - rawSnapshots = Collections.synchronizedSortedSet(new TreeSet<>()); } } catch (IOException e) { - rawSnapshots = Collections.synchronizedSortedSet(new TreeSet<>()); + // ... } deleteDebugFile(); @@ -73,6 +70,25 @@ private String getDebugFilename() { return this.fileName + ".debug"; } + public File createDebugFile(Snapshot snapshot) { + File file = null; + try { + file = new File(getDebugFilename()); + file.getParentFile().mkdirs(); + file.createNewFile(); + + try (FileOutputStream fileStream = new FileOutputStream(file, false)) { + fileStream.write(snapshot.raw().getBytes(StandardCharsets.UTF_8)); + } catch (IOException e) { + e.printStackTrace(); + } + } catch (IOException e) { + e.printStackTrace(); + } + + return file; + } + @SneakyThrows public void deleteDebugFile() { Files.deleteIfExists(Paths.get(getDebugFilename())); @@ -93,17 +109,25 @@ public synchronized File createFileIfNotExists(String filename) { return path.toFile(); } - public void pushSnapshot(String snapshot) { - rawSnapshots.add(snapshot); + public synchronized void pushSnapshot(Snapshot snapshot) { + snapshots.add(snapshot); + TreeSet rawSnapshots = snapshots + .stream() + .map(Snapshot::raw) + .collect(Collectors.toCollection(TreeSet::new)); updateFile(this.fileName, rawSnapshots); } - public void pushDebugSnapshot(String snapshot) { - rawDebugSnapshots.add(snapshot); + public synchronized void pushDebugSnapshot(Snapshot snapshot) { + debugSnapshots.add(snapshot); + TreeSet rawDebugSnapshots = debugSnapshots + .stream() + .map(Snapshot::raw) + .collect(Collectors.toCollection(TreeSet::new)); updateFile(getDebugFilename(), rawDebugSnapshots); } - private synchronized void updateFile(String fileName, Set rawSnapshots) { + private void updateFile(String fileName, Set rawSnapshots) { File file = createFileIfNotExists(fileName); try (FileOutputStream fileStream = new FileOutputStream(file, false)) { byte[] myBytes = String.join(SPLIT_STRING, rawSnapshots).getBytes(StandardCharsets.UTF_8); @@ -125,8 +149,7 @@ public void cleanup() { delete(); } else { String content = new String(Files.readAllBytes(Paths.get(this.fileName)), StandardCharsets.UTF_8); - String modified = onSaveSnapshotFile.apply(testClass, content); - Files.write(path, modified.getBytes(StandardCharsets.UTF_8), StandardOpenOption.TRUNCATE_EXISTING); + Files.write(path, content.getBytes(StandardCharsets.UTF_8), StandardOpenOption.TRUNCATE_EXISTING); } } } diff --git a/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/SnapshotHeader.java b/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/SnapshotHeader.java new file mode 100644 index 0000000..fa2a290 --- /dev/null +++ b/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/SnapshotHeader.java @@ -0,0 +1,49 @@ +package au.com.origin.snapshots; + +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; + +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +@RequiredArgsConstructor +public class SnapshotHeader extends HashMap { + + // + // Manual JSON serialization/deserialization as I don't want to + // include another dependency for it + // + @SneakyThrows + public String toJson() { + StringBuilder b = new StringBuilder(); + b.append("{\n"); + final int lastIndex = this.size(); + int currIndex = 0; + for (Map.Entry entry : this.entrySet()) { + currIndex++; + String format = currIndex == lastIndex ? " \"%s\": \"%s\"\n" : " \"%s\": \"%s\",\n"; + b.append(String.format(format, entry.getKey(), entry.getValue())); + } + b.append("}"); + return b.toString(); + } + + @SneakyThrows + public static SnapshotHeader fromJson(String json) { + SnapshotHeader snapshotHeader = new SnapshotHeader(); + + if (json == null) { + return snapshotHeader; + } + + String regex = "\\\"(?.*)\\\": \\\"(?.*)\\\""; + Pattern p = Pattern.compile(regex); + Matcher m = p.matcher(json); + while (m.find()) { + snapshotHeader.put(m.group("key"), m.group("value")); + } + return snapshotHeader; + } +} diff --git a/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/SnapshotSerializerContext.java b/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/SnapshotSerializerContext.java new file mode 100644 index 0000000..6808f23 --- /dev/null +++ b/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/SnapshotSerializerContext.java @@ -0,0 +1,57 @@ +package au.com.origin.snapshots; + +import au.com.origin.snapshots.annotations.SnapshotName; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; + +import java.lang.reflect.Method; + +/** + * Contains details of the pending snapshot that can be modified in the Serializer + * prior to calling toSnapshot(). + */ +@AllArgsConstructor +public class SnapshotSerializerContext { + + @Getter + @Setter + private String name; + + @Getter + @Setter + private String scenario; + + @Getter + @Setter + private SnapshotHeader header; + + @Getter + private Class testClass; + + @Getter + private final Method testMethod; + + public static SnapshotSerializerContext from(SnapshotContext context) { + SnapshotName snapshotName = context.getTestMethod().getAnnotation(SnapshotName.class); + String name = snapshotName == null ? + context.getTestClass().getName() + "." + context.getTestMethod().getName() : + snapshotName.value(); + return new SnapshotSerializerContext( + name, + context.getScenario(), + context.getHeader(), + context.getTestClass(), + context.getTestMethod() + ); + } + + public Snapshot toSnapshot(String body) { + return Snapshot.builder() + .name(name) + .scenario(scenario) + .header(header) + .body(body) + .build(); + } +} diff --git a/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/SnapshotVerifier.java b/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/SnapshotVerifier.java index 43676d9..55a69f0 100644 --- a/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/SnapshotVerifier.java +++ b/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/SnapshotVerifier.java @@ -2,6 +2,7 @@ import au.com.origin.snapshots.annotations.SnapshotName; import au.com.origin.snapshots.annotations.UseSnapshotConfig; +import au.com.origin.snapshots.config.SnapshotConfig; import au.com.origin.snapshots.exceptions.SnapshotExtensionException; import au.com.origin.snapshots.exceptions.SnapshotMatchException; import lombok.RequiredArgsConstructor; @@ -27,7 +28,8 @@ public class SnapshotVerifier { private final SnapshotConfig config; private final boolean failOnOrphans; - private final Collection calledSnapshots = Collections.synchronizedCollection(new ArrayList<>()); + private final Collection calledSnapshots = + Collections.synchronizedCollection(new ArrayList<>()); public SnapshotVerifier(SnapshotConfig frameworkSnapshotConfig, Class testClass) { this(frameworkSnapshotConfig, testClass, false); @@ -59,8 +61,7 @@ public SnapshotVerifier(SnapshotConfig frameworkSnapshotConfig, Class testCla SnapshotFile snapshotFile = new SnapshotFile( testSrcDirNoTrailing, snapshotDir.getPath() + File.separator + fileUnderTest.getName(), - testClass, - snapshotConfig::onSaveSnapshotFile + testClass ); this.testClass = testClass; @@ -91,33 +92,34 @@ private void verifyNoConflictingSnapshotNames(Class testClass) { } @SneakyThrows - public Snapshot expectCondition(Method testMethod, Object firstObject, Object... others) { - Object[] objects = mergeObjects(firstObject, others); - Snapshot snapshot = - new Snapshot(config, snapshotFile, testClass, testMethod, objects); - calledSnapshots.add(snapshot); - return snapshot; + public SnapshotContext expectCondition(Method testMethod, Object object) { + SnapshotContext snapshotContext = + new SnapshotContext(config, snapshotFile, testClass, testMethod, object); + calledSnapshots.add(snapshotContext); + return snapshotContext; } public void validateSnapshots() { - Set rawSnapshots = snapshotFile.getRawSnapshots(); + Set rawSnapshots = snapshotFile.getSnapshots(); Set snapshotNames = - calledSnapshots.stream().map(Snapshot::getSnapshotName).collect(Collectors.toSet()); - List unusedRawSnapshots = new ArrayList<>(); + calledSnapshots.stream().map(SnapshotContext::resolveSnapshotIdentifier).collect(Collectors.toSet()); + List unusedSnapshots = new ArrayList<>(); - for (String rawSnapshot : rawSnapshots) { + for (Snapshot rawSnapshot : rawSnapshots) { boolean foundSnapshot = false; for (String snapshotName : snapshotNames) { - if (rawSnapshot.contains(snapshotName)) { + if (rawSnapshot.getIdentifier().equals(snapshotName)) { foundSnapshot = true; break; } } if (!foundSnapshot) { - unusedRawSnapshots.add(rawSnapshot); + unusedSnapshots.add(rawSnapshot); } } - if (unusedRawSnapshots.size() > 0) { + if (unusedSnapshots.size() > 0) { + List unusedRawSnapshots = + unusedSnapshots.stream().map(Snapshot::raw).collect(Collectors.toList()); String errorMessage = "All unused Snapshots:\n" + String.join("\n", unusedRawSnapshots) + "\n\nHave you deleted tests? Have you renamed a test method?"; @@ -131,13 +133,4 @@ public void validateSnapshots() { snapshotFile.cleanup(); } - private Object[] mergeObjects(Object firstObject, Object[] others) { - Object[] objects = new Object[1]; - objects[0] = firstObject; - if (!isNullOrEmpty(others)) { - objects = Stream.concat(Arrays.stream(objects), Arrays.stream(others)) - .toArray(Object[]::new); - } - return objects; - } } diff --git a/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/annotations/UseSnapshotConfig.java b/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/annotations/UseSnapshotConfig.java index 4408efa..c4db6ee 100644 --- a/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/annotations/UseSnapshotConfig.java +++ b/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/annotations/UseSnapshotConfig.java @@ -1,6 +1,6 @@ package au.com.origin.snapshots.annotations; -import au.com.origin.snapshots.SnapshotConfig; +import au.com.origin.snapshots.config.SnapshotConfig; import java.lang.annotation.*; diff --git a/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/comparators/PlainTextEqualsComparator.java b/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/comparators/PlainTextEqualsComparator.java index 550a646..3faa0e3 100644 --- a/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/comparators/PlainTextEqualsComparator.java +++ b/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/comparators/PlainTextEqualsComparator.java @@ -1,9 +1,11 @@ package au.com.origin.snapshots.comparators; +import au.com.origin.snapshots.Snapshot; + public class PlainTextEqualsComparator implements SnapshotComparator { @Override - public boolean matches(String snapshotName, String rawSnapshot, String currentObject) { - return rawSnapshot.trim().equals(currentObject.trim()); + public boolean matches(Snapshot previous, Snapshot current) { + return previous.getBody().equals(current.getBody()); } } diff --git a/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/comparators/SnapshotComparator.java b/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/comparators/SnapshotComparator.java index b6add4a..84a9899 100644 --- a/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/comparators/SnapshotComparator.java +++ b/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/comparators/SnapshotComparator.java @@ -1,5 +1,7 @@ package au.com.origin.snapshots.comparators; +import au.com.origin.snapshots.Snapshot; + public interface SnapshotComparator { - boolean matches(String snapshotName, String rawSnapshot, String currentObject); + boolean matches(Snapshot previous, Snapshot current); } diff --git a/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/PropertyResolvingSnapshotConfig.java b/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/config/PropertyResolvingSnapshotConfig.java similarity index 91% rename from java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/PropertyResolvingSnapshotConfig.java rename to java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/config/PropertyResolvingSnapshotConfig.java index e2b3e8c..ebcc87d 100644 --- a/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/PropertyResolvingSnapshotConfig.java +++ b/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/config/PropertyResolvingSnapshotConfig.java @@ -1,5 +1,6 @@ -package au.com.origin.snapshots; +package au.com.origin.snapshots.config; +import au.com.origin.snapshots.SnapshotProperties; import au.com.origin.snapshots.comparators.SnapshotComparator; import au.com.origin.snapshots.reporters.SnapshotReporter; import au.com.origin.snapshots.serializers.SnapshotSerializer; diff --git a/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/SnapshotConfig.java b/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/config/SnapshotConfig.java similarity index 87% rename from java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/SnapshotConfig.java rename to java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/config/SnapshotConfig.java index d804385..9705b0b 100644 --- a/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/SnapshotConfig.java +++ b/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/config/SnapshotConfig.java @@ -1,4 +1,4 @@ -package au.com.origin.snapshots; +package au.com.origin.snapshots.config; import au.com.origin.snapshots.comparators.SnapshotComparator; import au.com.origin.snapshots.reporters.SnapshotReporter; @@ -50,18 +50,6 @@ default Optional updateSnapshot() { */ SnapshotSerializer getSerializer(); - /** - * Optional - * Allows you to perform any custom modifications to the file before it is saved - * - * @param testClass target test class - * @param snapshotContent snapshot file as a string - * @return snapshot file contents to be persisted - */ - default String onSaveSnapshotFile(Class testClass, String snapshotContent) { - return snapshotContent; - } - /** * Optional * Override to supply your own custom comparator function @@ -99,4 +87,5 @@ default String onSaveSnapshotFile(Class testClass, String snapshotContent) { * @return boolean indicating if we're running on a CI environment or not */ boolean isCI(); + } diff --git a/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/SnapshotConfigInjector.java b/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/config/SnapshotConfigInjector.java similarity index 67% rename from java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/SnapshotConfigInjector.java rename to java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/config/SnapshotConfigInjector.java index 2757c0b..46d4d01 100644 --- a/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/SnapshotConfigInjector.java +++ b/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/config/SnapshotConfigInjector.java @@ -1,4 +1,4 @@ -package au.com.origin.snapshots; +package au.com.origin.snapshots.config; public interface SnapshotConfigInjector { SnapshotConfig getSnapshotConfig(); diff --git a/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/exceptions/LogGithubIssueException.java b/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/exceptions/LogGithubIssueException.java new file mode 100644 index 0000000..22b6ec0 --- /dev/null +++ b/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/exceptions/LogGithubIssueException.java @@ -0,0 +1,12 @@ +package au.com.origin.snapshots.exceptions; + +public class LogGithubIssueException extends RuntimeException { + + private static final String LOG_SUPPORT_TICKET = + "\n\n*** This exception should never be thrown ***\n" + + "Log a support ticket at https://github.com/origin-energy/java-snapshot-testing/issues with details of the exception\n"; + + public LogGithubIssueException(String message) { + super(message + LOG_SUPPORT_TICKET); + } +} diff --git a/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/reporters/PlainTextSnapshotReporter.java b/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/reporters/PlainTextSnapshotReporter.java index 108a168..195bdcd 100644 --- a/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/reporters/PlainTextSnapshotReporter.java +++ b/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/reporters/PlainTextSnapshotReporter.java @@ -1,5 +1,6 @@ package au.com.origin.snapshots.reporters; +import au.com.origin.snapshots.Snapshot; import org.assertj.core.util.diff.DiffUtils; import org.assertj.core.util.diff.Patch; import org.opentest4j.AssertionFailedError; @@ -27,13 +28,13 @@ public boolean supportsFormat(String outputFormat) { } @Override - public void report(String snapshotName, String rawSnapshot, String currentObject) { + public void report(Snapshot previous, Snapshot current) { Patch patch = DiffUtils.diff( - Arrays.asList(rawSnapshot.trim().split("\n")), - Arrays.asList(currentObject.trim().split("\n"))); + Arrays.asList(previous.raw().split("\n")), + Arrays.asList(current.raw().split("\n"))); - String message = "Error on: \n" + currentObject.trim() + "\n\n" + getDiffString(patch); + String message = "Error on: \n" + current.raw() + "\n\n" + getDiffString(patch); - throw new AssertionFailedError(message, rawSnapshot, currentObject); + throw new AssertionFailedError(message, previous.raw(), current.raw()); } } diff --git a/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/reporters/SnapshotReporter.java b/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/reporters/SnapshotReporter.java index 22047aa..39fd9e9 100644 --- a/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/reporters/SnapshotReporter.java +++ b/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/reporters/SnapshotReporter.java @@ -1,8 +1,10 @@ package au.com.origin.snapshots.reporters; +import au.com.origin.snapshots.Snapshot; + public interface SnapshotReporter { boolean supportsFormat(String outputFormat); - void report(String snapshotName, String rawSnapshot, String currentObject); + void report(Snapshot previous, Snapshot current); } diff --git a/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/serializers/Base64SnapshotSerializer.java b/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/serializers/Base64SnapshotSerializer.java index fb676e9..65932a2 100644 --- a/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/serializers/Base64SnapshotSerializer.java +++ b/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/serializers/Base64SnapshotSerializer.java @@ -1,5 +1,8 @@ package au.com.origin.snapshots.serializers; +import au.com.origin.snapshots.Snapshot; +import au.com.origin.snapshots.SnapshotSerializerContext; + import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Base64; @@ -16,15 +19,13 @@ public class Base64SnapshotSerializer implements SnapshotSerializer { new ToStringSnapshotSerializer(); @Override - public String apply(Object[] objects) { - List encoded = Arrays.stream(objects) - .filter(Objects::nonNull) - .map(it -> { - byte[] bytes = it instanceof byte[] ? (byte[]) it : it.toString().getBytes(StandardCharsets.UTF_8); - return Base64.getEncoder().encodeToString(bytes); - }) - .collect(Collectors.toList()); - return toStringSnapshotSerializer.apply(encoded.toArray()); + public Snapshot apply(Object object, SnapshotSerializerContext gen) { + if (object == null) { + toStringSnapshotSerializer.apply("", gen); + } + byte[] bytes = object instanceof byte[] ? (byte[]) object : object.toString().getBytes(StandardCharsets.UTF_8); + String encoded = Base64.getEncoder().encodeToString(bytes); + return toStringSnapshotSerializer.apply(encoded, gen); } @Override diff --git a/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/serializers/SnapshotSerializer.java b/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/serializers/SnapshotSerializer.java index 8dcbad7..f06609f 100644 --- a/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/serializers/SnapshotSerializer.java +++ b/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/serializers/SnapshotSerializer.java @@ -1,8 +1,10 @@ package au.com.origin.snapshots.serializers; -import java.util.function.Function; +import au.com.origin.snapshots.Snapshot; +import au.com.origin.snapshots.SnapshotSerializerContext; -public interface SnapshotSerializer extends Function { +import java.util.function.BiFunction; +public interface SnapshotSerializer extends BiFunction { String getOutputFormat(); } diff --git a/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/serializers/ToStringSnapshotSerializer.java b/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/serializers/ToStringSnapshotSerializer.java index 2e8d31a..4925ff1 100644 --- a/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/serializers/ToStringSnapshotSerializer.java +++ b/java-snapshot-testing-core/src/main/java/au/com/origin/snapshots/serializers/ToStringSnapshotSerializer.java @@ -1,9 +1,12 @@ package au.com.origin.snapshots.serializers; +import au.com.origin.snapshots.Snapshot; import au.com.origin.snapshots.SnapshotFile; +import au.com.origin.snapshots.SnapshotSerializerContext; import lombok.extern.slf4j.Slf4j; import java.util.Arrays; +import java.util.List; import java.util.stream.Collectors; /** @@ -15,8 +18,9 @@ public class ToStringSnapshotSerializer implements SnapshotSerializer { @Override - public String apply(Object[] objects) { - return "[\n" + Arrays.stream(objects) + public Snapshot apply(Object object, SnapshotSerializerContext gen) { + List objects = Arrays.asList(object); + String body = "[\n" + objects.stream() .map(Object::toString) .map(it -> { if (it.contains(SnapshotFile.SPLIT_STRING)) { @@ -27,6 +31,7 @@ public String apply(Object[] objects) { }) .collect(Collectors.joining("\n")) + "\n]"; + return gen.toSnapshot(body); } @Override diff --git a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/BackwardCompatilbleTest.java b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/BackwardCompatilbleTest.java deleted file mode 100644 index a063e08..0000000 --- a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/BackwardCompatilbleTest.java +++ /dev/null @@ -1,103 +0,0 @@ -package au.com.origin.snapshots; - -import au.com.origin.snapshots.config.BaseSnapshotConfig; -import lombok.ToString; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestInfo; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.junit.jupiter.MockitoExtension; - -import java.util.Arrays; -import java.util.List; - -import static au.com.origin.snapshots.SnapshotUtils.extractArgs; - -@ExtendWith(MockitoExtension.class) -public class BackwardCompatilbleTest { - - @Mock - private FakeObject fakeObject; - - @Test // Snapshot any object - public void shouldShowSnapshotExample(TestInfo testInfo) { - SnapshotVerifier snapshotVerifier = new SnapshotVerifier(new BaseSnapshotConfig(), testInfo.getTestClass().get()); - Expect.of(snapshotVerifier, testInfo.getTestMethod().get()).toMatchSnapshot(""); - snapshotVerifier.validateSnapshots(); - } - - @Test // Snapshot arguments passed to mocked object (from Mockito library) - public void shouldExtractArgsFromMethod(TestInfo testInfo) { - SnapshotVerifier snapshotVerifier = new SnapshotVerifier(new BaseSnapshotConfig(), testInfo.getTestClass().get()); - - fakeObject.fakeMethod("test1", 1L, Arrays.asList("listTest1")); - fakeObject.fakeMethod("test2", 2L, Arrays.asList("listTest1", "listTest2")); - - Expect.of(snapshotVerifier, testInfo.getTestMethod().get()) - .toMatchSnapshot(extractArgs( - fakeObject, - "fakeMethod", - new SnapshotCaptor(String.class), - new SnapshotCaptor(Long.class), - new SnapshotCaptor(List.class))); - - snapshotVerifier.validateSnapshots(); - } - - @Test // Snapshot arguments passed to mocked object support ignore of fields - public void shouldExtractArgsFromFakeMethodWithComplexObject(TestInfo testInfo) { - SnapshotVerifier snapshotVerifier = new SnapshotVerifier(new BaseSnapshotConfig(), testInfo.getTestClass().getClass()); - - FakeObject fake = new FakeObject(); - fake.setId("idMock"); - fake.setName("nameMock"); - - // With Ignore - fakeObject.fakeMethodWithComplexObject(fake); - Object fakeMethodWithComplexObjectWithIgnore = - extractArgs( - fakeObject, - "fakeMethodWithComplexObject", - new SnapshotCaptor(Object.class, FakeObject.class, "name")); - - Mockito.reset(fakeObject); - - // Without Ignore of fields - fakeObject.fakeMethodWithComplexObject(fake); - Object fakeMethodWithComplexObjectWithoutIgnore = - extractArgs( - fakeObject, - "fakeMethodWithComplexObject", - new SnapshotCaptor(Object.class, FakeObject.class)); - - Expect.of(snapshotVerifier, testInfo.getTestMethod().get()) - .toMatchSnapshotLegacy(fakeMethodWithComplexObjectWithIgnore, fakeMethodWithComplexObjectWithoutIgnore); - - snapshotVerifier.validateSnapshots(); - } - - @ToString - class FakeObject { - - private String id; - - private Integer value; - - private String name; - - void fakeMethod(String fakeName, Long fakeNumber, List fakeList) { - } - - void fakeMethodWithComplexObject(Object fakeObj) { - } - - void setId(String id) { - this.id = id; - } - - void setName(String name) { - this.name = name; - } - } -} diff --git a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/DebugSnapshotLineEndingsTest.java b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/DebugSnapshotLineEndingsTest.java index c34b087..5492adb 100644 --- a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/DebugSnapshotLineEndingsTest.java +++ b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/DebugSnapshotLineEndingsTest.java @@ -1,6 +1,7 @@ package au.com.origin.snapshots; import au.com.origin.snapshots.config.BaseSnapshotConfig; +import au.com.origin.snapshots.config.SnapshotConfig; import au.com.origin.snapshots.serializers.SerializerType; import au.com.origin.snapshots.serializers.SnapshotSerializer; import lombok.SneakyThrows; @@ -55,7 +56,7 @@ void existingSnapshotDifferentLineEndings(TestInfo testInfo) { SnapshotVerifier snapshotVerifier = new SnapshotVerifier(CONFIG, testInfo.getTestClass().get()); Expect expect = Expect.of(snapshotVerifier, testInfo.getTestMethod().get()); - expect.toMatchSnapshot(Arrays.asList("a", "b")); + expect.toMatchSnapshot(Arrays.asList("a","b")); snapshotVerifier.validateSnapshots(); assertTrue(Files.notExists(Paths.get(DEBUG_FILE_PATH)), "Debug file should not be created"); @@ -68,17 +69,22 @@ public String getOutputFormat() { } @Override - public String apply(Object[] objects) { - return "[\n" + Arrays.stream(objects) - .flatMap(object -> { - if (object instanceof Collection) { - return ((Collection) object).stream(); - } - return Stream.of(object); - }) - .map(Object::toString) - .collect(Collectors.joining("\n")) + - "\n]"; + public Snapshot apply(Object object, SnapshotSerializerContext snapshotSerializerContext) { + Object body = "[\n" + Arrays.asList(object).stream() + .flatMap(o -> { + if (o instanceof Collection) { + return ((Collection) o).stream(); + } + return Stream.of(o); + }) + .map(Object::toString) + .collect(Collectors.joining("\n")) + + "\n]"; + + return Snapshot.builder() + .name("au.com.origin.snapshots.DebugSnapshotLineEndingsTest.existingSnapshotDifferentLineEndings") + .body(body.toString()) + .build(); } } } diff --git a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/DebugSnapshotTest.java b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/DebugSnapshotTest.java index cef112f..97a5252 100644 --- a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/DebugSnapshotTest.java +++ b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/DebugSnapshotTest.java @@ -1,6 +1,7 @@ package au.com.origin.snapshots; import au.com.origin.snapshots.config.BaseSnapshotConfig; +import au.com.origin.snapshots.config.SnapshotConfig; import au.com.origin.snapshots.exceptions.SnapshotMatchException; import au.com.origin.snapshots.serializers.SnapshotSerializer; import au.com.origin.snapshots.serializers.ToStringSnapshotSerializer; diff --git a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/OnLoadSnapshotFileTest.java b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/OnLoadSnapshotFileTest.java index 2f7bc4d..7d8d1e2 100644 --- a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/OnLoadSnapshotFileTest.java +++ b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/OnLoadSnapshotFileTest.java @@ -3,6 +3,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertTrue; import au.com.origin.snapshots.config.BaseSnapshotConfig; +import au.com.origin.snapshots.config.SnapshotConfig; import au.com.origin.snapshots.serializers.ToStringSnapshotSerializer; import java.io.File; import java.io.FileOutputStream; diff --git a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/OrphanSnapshotTest.java b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/OrphanSnapshotTest.java index cc65f9b..8d8deb6 100644 --- a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/OrphanSnapshotTest.java +++ b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/OrphanSnapshotTest.java @@ -1,6 +1,7 @@ package au.com.origin.snapshots; import au.com.origin.snapshots.config.BaseSnapshotConfig; +import au.com.origin.snapshots.config.SnapshotConfig; import au.com.origin.snapshots.exceptions.SnapshotMatchException; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.DisplayName; diff --git a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/ScenarioTest.java b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/ScenarioTest.java index b1ebb13..6182771 100644 --- a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/ScenarioTest.java +++ b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/ScenarioTest.java @@ -1,6 +1,7 @@ package au.com.origin.snapshots; import au.com.origin.snapshots.config.BaseSnapshotConfig; +import au.com.origin.snapshots.config.SnapshotConfig; import au.com.origin.snapshots.exceptions.SnapshotMatchException; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInfo; diff --git a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/SnapshotTest.java b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/SnapshotContextTest.java similarity index 65% rename from java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/SnapshotTest.java rename to java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/SnapshotContextTest.java index 34e956c..55c7c87 100644 --- a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/SnapshotTest.java +++ b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/SnapshotContextTest.java @@ -1,6 +1,7 @@ package au.com.origin.snapshots; import au.com.origin.snapshots.config.BaseSnapshotConfig; +import au.com.origin.snapshots.config.SnapshotConfig; import au.com.origin.snapshots.exceptions.SnapshotMatchException; import au.com.origin.snapshots.reporters.SnapshotReporter; import au.com.origin.snapshots.serializers.ToStringSnapshotSerializer; @@ -20,7 +21,6 @@ import java.util.HashSet; import java.util.Optional; import java.util.Set; -import java.util.TreeSet; import java.util.function.BiConsumer; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -29,22 +29,22 @@ import static org.junit.jupiter.api.Assertions.assertThrows; @ExtendWith(MockitoExtension.class) -class SnapshotTest { +class SnapshotContextTest { private static final SnapshotConfig DEFAULT_CONFIG = new BaseSnapshotConfig(); private static final String FILE_PATH = "src/test/java/anyFilePath"; - private static final String SNAPSHOT_NAME = "java.lang.String.toString="; + private static final String SNAPSHOT_NAME = "java.lang.String.toString"; private static final String SNAPSHOT = "java.lang.String.toString=[\nanyObject\n]"; private SnapshotFile snapshotFile; - private Snapshot snapshot; + private SnapshotContext snapshotContext; @BeforeEach void setUp() throws NoSuchMethodException, IOException { - snapshotFile = new SnapshotFile(DEFAULT_CONFIG.getOutputDir(), "anyFilePath", SnapshotTest.class, (a, b) -> b); - snapshot = - new Snapshot( + snapshotFile = new SnapshotFile(DEFAULT_CONFIG.getOutputDir(), "anyFilePath", SnapshotContextTest.class); + snapshotContext = + new SnapshotContext( DEFAULT_CONFIG, snapshotFile, String.class, @@ -59,53 +59,49 @@ void tearDown() throws IOException { @Test void shouldGetSnapshotNameSuccessfully() { - String snapshotName = snapshot.getSnapshotName(); + String snapshotName = snapshotContext.resolveSnapshotIdentifier(); assertThat(snapshotName).isEqualTo(SNAPSHOT_NAME); } @Test void shouldMatchSnapshotSuccessfully() { - snapshot.toMatchSnapshot(); - assertThat(snapshotFile.getRawSnapshots()) - .isEqualTo(Stream.of(SNAPSHOT).collect(Collectors.toCollection(TreeSet::new))); + snapshotContext.toMatchSnapshot(); + assertThat(snapshotFile.getSnapshots().stream().findFirst().get().raw()) + .isEqualTo(SNAPSHOT); } @Test void shouldMatchSnapshotWithException() { - snapshotFile.pushSnapshot(SNAPSHOT_NAME + "anyWrongSnapshot"); - - assertThrows(SnapshotMatchException.class, snapshot::toMatchSnapshot); + snapshotFile.pushSnapshot(Snapshot.parse(SNAPSHOT_NAME + "=anyWrongSnapshot")); + assertThrows(SnapshotMatchException.class, snapshotContext::toMatchSnapshot); } @SneakyThrows @Test void shouldRenderScenarioNameWhenSupplied() { - Snapshot snapshotWithScenario = - new Snapshot( + SnapshotContext snapshotContextWithScenario = + new SnapshotContext( DEFAULT_CONFIG, snapshotFile, String.class, String.class.getDeclaredMethod("toString"), - new ToStringSnapshotSerializer(), "anyObject"); - snapshotWithScenario.setScenario("hello world"); - assertThat(snapshotWithScenario.getSnapshotName()) - .isEqualTo("java.lang.String.toString[hello world]="); + snapshotContextWithScenario.setScenario("hello world"); + assertThat(snapshotContextWithScenario.resolveSnapshotIdentifier()) + .isEqualTo("java.lang.String.toString[hello world]"); } @SneakyThrows @Test void shouldNotRenderScenarioNameWhenNull() { - Snapshot snapshotWithoutScenario = - new Snapshot( + SnapshotContext snapshotContextWithoutScenario = + new SnapshotContext( DEFAULT_CONFIG, snapshotFile, String.class, String.class.getDeclaredMethod("toString"), - null, - new ToStringSnapshotSerializer(), "anyObject"); - assertThat(snapshotWithoutScenario.getSnapshotName()).isEqualTo("java.lang.String.toString="); + assertThat(snapshotContextWithoutScenario.resolveSnapshotIdentifier()).isEqualTo("java.lang.String.toString"); } @SneakyThrows @@ -115,21 +111,21 @@ void shouldOverwriteSnapshotsWhenParamIsPassed() { Mockito.when(mockConfig.updateSnapshot()).thenReturn(Optional.of("")); Mockito.when(mockConfig.getSerializer()).thenReturn(new ToStringSnapshotSerializer()); SnapshotFile snapshotFile = Mockito.mock(SnapshotFile.class); - Set set = new HashSet<>(); - set.add("java.lang.String.toString[hello world]=[{" + "\"a\": \"b\"" + "}]"); - Mockito.when(snapshotFile.getRawSnapshots()).thenReturn(set); + Set set = new HashSet<>(); + set.add(Snapshot.parse("java.lang.String.toString[hello world]=[{" + "\"a\": \"b\"" + "}]")); + Mockito.when(snapshotFile.getSnapshots()).thenReturn(set); - Snapshot snapshot = - new Snapshot( + SnapshotContext snapshotContext = + new SnapshotContext( mockConfig, snapshotFile, String.class, String.class.getDeclaredMethod("toString"), "anyObject"); - snapshot.setScenario("hello world"); - snapshot.toMatchSnapshot(); + snapshotContext.setScenario("hello world"); + snapshotContext.toMatchSnapshot(); Mockito.verify(snapshotFile) - .pushSnapshot("java.lang.String.toString[hello world]=[\nanyObject\n]"); + .pushSnapshot(Snapshot.parse("java.lang.String.toString[hello world]=[\nanyObject\n]")); } @SneakyThrows @@ -142,32 +138,32 @@ public boolean isCI() { } }; - Snapshot ciSnapshot = new Snapshot( + SnapshotContext ciSnapshotContext = new SnapshotContext( ciSnapshotConfig, - new SnapshotFile(ciSnapshotConfig.getOutputDir(), "blah", SnapshotTest.class, (a, b) -> b), + new SnapshotFile(ciSnapshotConfig.getOutputDir(), "blah", SnapshotContextTest.class), String.class, String.class.getDeclaredMethod("toString"), "anyObject"); - Assertions.assertThatThrownBy(ciSnapshot::toMatchSnapshot) - .hasMessage("Snapshot [java.lang.String.toString=] not found. Has this snapshot been committed ?"); + Assertions.assertThatThrownBy(ciSnapshotContext::toMatchSnapshot) + .hasMessage("Snapshot [java.lang.String.toString] not found. Has this snapshot been committed ?"); } @SneakyThrows @Test void shouldAggregateMultipleFailures() { SnapshotFile snapshotFile = Mockito.mock(SnapshotFile.class); - Set set = new HashSet<>(); - set.add("java.lang.String.toString=[\n \"hello\"\n]"); - Mockito.when(snapshotFile.getRawSnapshots()).thenReturn(set); + Set set = new HashSet<>(); + set.add(Snapshot.parse("java.lang.String.toString=[\n \"hello\"\n]")); + Mockito.when(snapshotFile.getSnapshots()).thenReturn(set); - Stream> reportingFunctions = Stream.of( + Stream> reportingFunctions = Stream.of( (rawSnapshot, currentObject) -> assertThat(currentObject).isEqualTo(rawSnapshot), // assertj org.junit.jupiter.api.Assertions::assertEquals, // junit jupiter - (rawSnapshot, currentObject) -> { + (previous, current) -> { String message = String.join(System.lineSeparator(), - "Expected : ", rawSnapshot, "Actual : ", currentObject); - throw new AssertionFailedError(message, rawSnapshot, currentObject); // opentest4j + "Expected : ", previous.raw(), "Actual : ", current.raw()); + throw new AssertionFailedError(message, previous, current); // opentest4j } ); @@ -178,23 +174,23 @@ public boolean supportsFormat(String outputFormat) { } @Override - public void report(String snapshotName, String rawSnapshot, String currentObject) { - consumer.accept(rawSnapshot, currentObject); + public void report(Snapshot previous, Snapshot current) { + consumer.accept(previous, current); } }); - Snapshot failingSnapshot = new Snapshot( + SnapshotContext failingSnapshotContext = new SnapshotContext( DEFAULT_CONFIG, snapshotFile, String.class, String.class.getDeclaredMethod("toString"), "hola" ); - failingSnapshot.setSnapshotSerializer(new ToStringSnapshotSerializer()); - failingSnapshot.setSnapshotReporters(reporters.collect(Collectors.toList())); + failingSnapshotContext.setSnapshotSerializer(new ToStringSnapshotSerializer()); + failingSnapshotContext.setSnapshotReporters(reporters.collect(Collectors.toList())); try { - failingSnapshot.toMatchSnapshot(); + failingSnapshotContext.toMatchSnapshot(); } catch (Throwable m) { String cleanMessage = m.getMessage() .replace("<\"", "") diff --git a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/SnapshotHeaders.java b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/SnapshotHeaders.java new file mode 100644 index 0000000..5429a6c --- /dev/null +++ b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/SnapshotHeaders.java @@ -0,0 +1,60 @@ +package au.com.origin.snapshots; + +import au.com.origin.snapshots.config.BaseSnapshotConfig; +import au.com.origin.snapshots.config.SnapshotConfig; +import au.com.origin.snapshots.serializers.LowercaseToStringSerializer; +import au.com.origin.snapshots.serializers.SerializerType; +import lombok.NoArgsConstructor; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInfo; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +public class SnapshotHeaders { + + private static final SnapshotConfig DEFAULT_CONFIG = new BaseSnapshotConfig(); + + static SnapshotVerifier snapshotVerifier; + + @BeforeAll + static void beforeAll() { + SnapshotUtils.copyTestSnapshots(); + snapshotVerifier = new SnapshotVerifier(DEFAULT_CONFIG, SnapshotHeaders.class); + } + + @AfterAll + static void afterAll() { + snapshotVerifier.validateSnapshots(); + } + + @Test + void shouldBeAbleToSnapshotASingleCustomHeader(TestInfo testInfo) { + Expect expect = Expect.of(snapshotVerifier, testInfo.getTestMethod().get()); + expect.serializer(CustomHeadersSerializer.class).toMatchSnapshot("Hello World"); + } + + @Test + void shouldBeAbleToSnapshotMultipleCustomHeader(TestInfo testInfo) { + Expect expect = Expect.of(snapshotVerifier, testInfo.getTestMethod().get()); + expect.serializer(CustomHeadersSerializer.class).toMatchSnapshot("Hello World"); + } + + @NoArgsConstructor + private static class CustomHeadersSerializer extends LowercaseToStringSerializer { + @Override + public String getOutputFormat() { + return SerializerType.JSON.name(); + } + + @Override + public Snapshot apply(Object object, SnapshotSerializerContext snapshotSerializerContext) { + snapshotSerializerContext.getHeader().put("custom", "anything"); + snapshotSerializerContext.getHeader().put("custom2", "anything2"); + return super.apply(object, snapshotSerializerContext); + } + }; + +} diff --git a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/SnapshotIntegrationTest.java b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/SnapshotIntegrationTest.java index 8b28db7..c63d4ec 100644 --- a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/SnapshotIntegrationTest.java +++ b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/SnapshotIntegrationTest.java @@ -1,6 +1,7 @@ package au.com.origin.snapshots; import au.com.origin.snapshots.config.BaseSnapshotConfig; +import au.com.origin.snapshots.config.SnapshotConfig; import au.com.origin.snapshots.exceptions.SnapshotMatchException; import au.com.origin.snapshots.serializers.UppercaseToStringSerializer; import org.junit.jupiter.api.AfterAll; @@ -82,6 +83,7 @@ void shouldSnapshotUsingSerializerPropertyName(TestInfo testInfo) { expect.serializer("lowercase").toMatchSnapshot("Hello World"); } + private void matchInsidePrivate(TestInfo testInfo) { Expect expect = Expect.of(snapshotVerifier, testInfo.getTestMethod().get()); expect diff --git a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/SnapshotMatcherScenarioTest.java b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/SnapshotMatcherScenarioTest.java index 2801ca3..b752a74 100644 --- a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/SnapshotMatcherScenarioTest.java +++ b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/SnapshotMatcherScenarioTest.java @@ -39,7 +39,6 @@ static void afterAll() throws IOException { + "]\n\n\n" + "au.com.origin.snapshots.SnapshotMatcherScenarioTest.should2SecondSnapshotExecutionSuccessfully[Scenario B]=[\n" + "any second type of object\n" - + "any third type of object\n" + "]"); Files.delete(Paths.get(FILE_PATH)); } @@ -59,7 +58,7 @@ void should2SecondSnapshotExecutionSuccessfully(TestInfo testInfo) { Expect expect = Expect.of(snapshotVerifier, testInfo.getTestMethod().get()); expect .scenario("Scenario B") - .toMatchSnapshotLegacy("any second type of object", "any third type of object"); + .toMatchSnapshot("any second type of object"); File f = new File(FILE_PATH); if (!f.exists() || f.isDirectory()) { throw new RuntimeException("File should exist here"); diff --git a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/SnapshotMatcherTest.java b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/SnapshotMatcherTest.java index 4910e0d..495db04 100644 --- a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/SnapshotMatcherTest.java +++ b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/SnapshotMatcherTest.java @@ -39,7 +39,6 @@ static void afterAll() throws IOException { + "]\n\n\n" + "au.com.origin.snapshots.SnapshotMatcherTest.should2SecondSnapshotExecutionSuccessfully=[\n" + "any second type of object\n" - + "any third type of object\n" + "]"); Files.delete(Paths.get(FILE_PATH)); } @@ -57,7 +56,7 @@ void should1ShowSnapshotSuccessfully(TestInfo testInfo) { @Test void should2SecondSnapshotExecutionSuccessfully(TestInfo testInfo) { Expect expect = Expect.of(snapshotVerifier, testInfo.getTestMethod().get()); - expect.toMatchSnapshotLegacy("any second type of object", "any third type of object"); + expect.toMatchSnapshot("any second type of object"); File f = new File(FILE_PATH); if (!f.exists() || f.isDirectory()) { throw new RuntimeException("File should exist here"); diff --git a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/SnapshotNameAnnotationWithDuplicatesTest.java b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/SnapshotNameAnnotationWithDuplicatesTest.java index 6822367..014a4ff 100644 --- a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/SnapshotNameAnnotationWithDuplicatesTest.java +++ b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/SnapshotNameAnnotationWithDuplicatesTest.java @@ -3,8 +3,6 @@ import au.com.origin.snapshots.annotations.SnapshotName; import au.com.origin.snapshots.config.BaseSnapshotConfig; import au.com.origin.snapshots.exceptions.SnapshotExtensionException; -import au.com.origin.snapshots.exceptions.SnapshotMatchException; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInfo; diff --git a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/SnapshotUtilsTest.java b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/SnapshotUtilsTest.java index adbbaba..d9ed166 100644 --- a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/SnapshotUtilsTest.java +++ b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/SnapshotUtilsTest.java @@ -48,17 +48,9 @@ void shouldExtractArgsFromFakeMethodWithComplexObject(TestInfo testInfo) { "fakeMethodWithComplexFakeObject", new SnapshotCaptor(FakeObject.class, "name")); - Mockito.reset(fakeObject); - - // Without Ignore - fakeObject.fakeMethodWithComplexFakeObject(fake); - Object fakeMethodWithComplexObjectWithoutIgnore = - extractArgs( - fakeObject, "fakeMethodWithComplexFakeObject", new SnapshotCaptor(FakeObject.class)); - SnapshotVerifier snapshotVerifier = new SnapshotVerifier(new BaseSnapshotConfig(), testInfo.getTestClass().get()); Expect expect = Expect.of(snapshotVerifier, testInfo.getTestMethod().get()); - expect.toMatchSnapshotLegacy(fakeMethodWithComplexObjectWithIgnore, fakeMethodWithComplexObjectWithoutIgnore); + expect.toMatchSnapshot(fakeMethodWithComplexObjectWithIgnore); snapshotVerifier.validateSnapshots(); } @@ -75,20 +67,10 @@ void shouldExtractArgsFromFakeMethodWithComplexFakeObject(TestInfo testInfo) { "fakeMethodWithComplexObject", new SnapshotCaptor(Object.class, FakeObject.class, "name")); - Mockito.reset(fakeObject); - - // Without Ignore - fakeObject.fakeMethodWithComplexObject(fake); - Object fakeMethodWithComplexObjectWithoutIgnore = - extractArgs( - fakeObject, - "fakeMethodWithComplexObject", - new SnapshotCaptor(Object.class, FakeObject.class)); - SnapshotVerifier snapshotVerifier = new SnapshotVerifier(new BaseSnapshotConfig(), testInfo.getTestClass().get()); Expect expect = Expect.of(snapshotVerifier, testInfo.getTestMethod().get()); expect - .toMatchSnapshotLegacy(fakeMethodWithComplexObjectWithIgnore, fakeMethodWithComplexObjectWithoutIgnore); + .toMatchSnapshot(fakeMethodWithComplexObjectWithIgnore); snapshotVerifier.validateSnapshots(); } } diff --git a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/UpdateSnapshotPropertyTest.java b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/UpdateSnapshotPropertyTest.java index 425682f..2da4e10 100644 --- a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/UpdateSnapshotPropertyTest.java +++ b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/UpdateSnapshotPropertyTest.java @@ -1,6 +1,7 @@ package au.com.origin.snapshots; import au.com.origin.snapshots.config.BaseSnapshotConfig; +import au.com.origin.snapshots.config.SnapshotConfig; import au.com.origin.snapshots.exceptions.SnapshotMatchException; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.*; diff --git a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/UseCustomConfigTest.java b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/UseCustomConfigTest.java index e2f6aa0..d163bcf 100644 --- a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/UseCustomConfigTest.java +++ b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/UseCustomConfigTest.java @@ -2,6 +2,7 @@ import au.com.origin.snapshots.annotations.UseSnapshotConfig; import au.com.origin.snapshots.config.BaseSnapshotConfig; +import au.com.origin.snapshots.config.SnapshotConfig; import au.com.origin.snapshots.config.ToStringSnapshotConfig; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; diff --git a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/UseCustomSerializerTest.java b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/UseCustomSerializerTest.java index 73aaf32..7217a78 100644 --- a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/UseCustomSerializerTest.java +++ b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/UseCustomSerializerTest.java @@ -1,6 +1,7 @@ package au.com.origin.snapshots; import au.com.origin.snapshots.config.BaseSnapshotConfig; +import au.com.origin.snapshots.config.SnapshotConfig; import au.com.origin.snapshots.serializers.UppercaseToStringSerializer; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.DisplayName; diff --git a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/comparators/PlainTextEqualsComparatorTest.java b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/comparators/PlainTextEqualsComparatorTest.java index 5f317b5..e42f8f0 100644 --- a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/comparators/PlainTextEqualsComparatorTest.java +++ b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/comparators/PlainTextEqualsComparatorTest.java @@ -1,5 +1,6 @@ package au.com.origin.snapshots.comparators; +import au.com.origin.snapshots.Snapshot; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; @@ -9,11 +10,31 @@ class PlainTextEqualsComparatorTest { @Test void successfulComparison() { - Assertions.assertThat(COMPARATOR.matches("snap1", "blah", "blah")).isTrue(); + Snapshot snap1 = Snapshot.builder() + .name("snap1") + .scenario("A") + .body("foo") + .build(); + Snapshot snap2 = Snapshot.builder() + .name("snap1") + .scenario("A") + .body("foo") + .build(); + Assertions.assertThat(COMPARATOR.matches(snap1, snap2)).isTrue(); } @Test void failingComparison() { - Assertions.assertThat(COMPARATOR.matches("snap1", "blah", "blahblah")).isFalse(); + Snapshot snap1 = Snapshot.builder() + .name("snap1") + .scenario("A") + .body("foo") + .build(); + Snapshot snap2 = Snapshot.builder() + .name("snap1") + .scenario("A") + .body("bar") + .build(); + Assertions.assertThat(COMPARATOR.matches(snap1, snap2)).isFalse(); } } diff --git a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/config/BaseSnapshotConfig.java b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/config/BaseSnapshotConfig.java index c47fc49..cd0f71f 100644 --- a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/config/BaseSnapshotConfig.java +++ b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/config/BaseSnapshotConfig.java @@ -1,6 +1,5 @@ package au.com.origin.snapshots.config; -import au.com.origin.snapshots.SnapshotConfig; import au.com.origin.snapshots.comparators.PlainTextEqualsComparator; import au.com.origin.snapshots.comparators.SnapshotComparator; import au.com.origin.snapshots.reporters.PlainTextSnapshotReporter; @@ -42,4 +41,5 @@ public List getReporters() { public boolean isCI() { return false; } + } diff --git a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/config/ToStringSnapshotConfig.java b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/config/ToStringSnapshotConfig.java index d5798ed..2c78c49 100644 --- a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/config/ToStringSnapshotConfig.java +++ b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/config/ToStringSnapshotConfig.java @@ -1,5 +1,7 @@ package au.com.origin.snapshots.config; +import au.com.origin.snapshots.Snapshot; +import au.com.origin.snapshots.SnapshotSerializerContext; import au.com.origin.snapshots.serializers.SerializerType; import au.com.origin.snapshots.serializers.SnapshotSerializer; @@ -17,8 +19,8 @@ public String getOutputFormat() { } @Override - public String apply(Object[] objects) { - return Arrays.stream(objects).map(Object::toString).collect(Collectors.joining()); + public Snapshot apply(Object object, SnapshotSerializerContext gen) { + return gen.toSnapshot(object.toString()); } }; } diff --git a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/existing-snapshots/__snapshots__/BackwardCompatilbleTest.snap b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/existing-snapshots/__snapshots__/BackwardCompatilbleTest.snap deleted file mode 100644 index f2b24d8..0000000 --- a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/existing-snapshots/__snapshots__/BackwardCompatilbleTest.snap +++ /dev/null @@ -1,14 +0,0 @@ -au.com.origin.snapshots.BackwardCompatilbleTest.shouldExtractArgsFromFakeMethodWithComplexObject=[ -{FakeObject.fakeMethodWithComplexObject=[{arg0=BackwardCompatilbleTest.FakeObject(id=idMock, value=null, name=null)}]} -{FakeObject.fakeMethodWithComplexObject=[{arg0=BackwardCompatilbleTest.FakeObject(id=idMock, value=null, name=nameMock)}]} -] - - -au.com.origin.snapshots.BackwardCompatilbleTest.shouldExtractArgsFromMethod=[ -{FakeObject.fakeMethod=[{arg0=test1, arg1=1, arg2=[listTest1]}, {arg0=test2, arg1=2, arg2=[listTest1, listTest2]}]} -] - - -au.com.origin.snapshots.BackwardCompatilbleTest.shouldShowSnapshotExample=[ - -] \ No newline at end of file diff --git a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/existing-snapshots/__snapshots__/SnapshotHeaders.snap b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/existing-snapshots/__snapshots__/SnapshotHeaders.snap new file mode 100644 index 0000000..5fa1e53 --- /dev/null +++ b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/existing-snapshots/__snapshots__/SnapshotHeaders.snap @@ -0,0 +1,10 @@ +au.com.origin.snapshots.SnapshotHeaders.shouldBeAbleToSnapshotASingleCustomHeader={ + "custom": "anything", + "custom2": "anything2" +}hello world + + +au.com.origin.snapshots.SnapshotHeaders.shouldBeAbleToSnapshotMultipleCustomHeader={ + "custom": "anything", + "custom2": "anything2" +}hello world \ No newline at end of file diff --git a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/existing-snapshots/__snapshots__/SnapshotUtilsTest.snap b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/existing-snapshots/__snapshots__/SnapshotUtilsTest.snap index e6f7abd..b0128f4 100644 --- a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/existing-snapshots/__snapshots__/SnapshotUtilsTest.snap +++ b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/existing-snapshots/__snapshots__/SnapshotUtilsTest.snap @@ -5,11 +5,9 @@ au.com.origin.snapshots.SnapshotUtilsTest.shouldExtractArgsFromFakeMethod=[ au.com.origin.snapshots.SnapshotUtilsTest.shouldExtractArgsFromFakeMethodWithComplexFakeObject=[ {FakeObject.fakeMethodWithComplexObject=[{arg0=FakeObject(id=idMock, value=null, name=null, fakeObject=null)}]} -{FakeObject.fakeMethodWithComplexObject=[{arg0=FakeObject(id=idMock, value=null, name=nameMock, fakeObject=null)}]} ] au.com.origin.snapshots.SnapshotUtilsTest.shouldExtractArgsFromFakeMethodWithComplexObject=[ {FakeObject.fakeMethodWithComplexFakeObject=[{arg0=FakeObject(id=idMock, value=null, name=null, fakeObject=null)}]} -{FakeObject.fakeMethodWithComplexFakeObject=[{arg0=FakeObject(id=idMock, value=null, name=nameMock, fakeObject=null)}]} ] \ No newline at end of file diff --git a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/onSaveSnapshotFileTest.java b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/onSaveSnapshotFileTest.java deleted file mode 100644 index c5550d0..0000000 --- a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/onSaveSnapshotFileTest.java +++ /dev/null @@ -1,53 +0,0 @@ -package au.com.origin.snapshots; - -import au.com.origin.snapshots.config.BaseSnapshotConfig; -import au.com.origin.snapshots.serializers.ToStringSnapshotSerializer; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestInfo; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertFalse; - -public class onSaveSnapshotFileTest { - - private static final String SNAPSHOT_FILE_PATH = "src/test/java/au/com/origin/snapshots/__snapshots__/onSaveSnapshotFileTest.snap"; - private final SnapshotConfig CUSTOM_SNAPSHOT_CONFIG = new BaseSnapshotConfig() { - @Override - public String onSaveSnapshotFile(Class testClass, String snapshotContent) { - return "HEADER\n" + snapshotContent + "\nFOOTER"; - } - }; - - @BeforeAll - static void beforeAll() throws IOException { - Files.deleteIfExists(Paths.get(SNAPSHOT_FILE_PATH)); - } - - @DisplayName("Should remove empty snapshots") - @Test - public void shouldAllowFileModificationsBeforeFinishingTest(TestInfo testInfo) throws IOException { - assertFalse(Files.exists(Paths.get(SNAPSHOT_FILE_PATH))); - - SnapshotVerifier snapshotVerifier = new SnapshotVerifier(CUSTOM_SNAPSHOT_CONFIG, testInfo.getTestClass().get()); - Expect expect = Expect.of(snapshotVerifier, testInfo.getTestMethod().get()); - expect.serializer(ToStringSnapshotSerializer.class).toMatchSnapshot("Hello Wörld"); - snapshotVerifier.validateSnapshots(); - - File f = new File(SNAPSHOT_FILE_PATH); - assertThat(String.join("\n", Files.readAllLines(f.toPath()))) - .isEqualTo( - "HEADER\n" - + "au.com.origin.snapshots.onSaveSnapshotFileTest.shouldAllowFileModificationsBeforeFinishingTest=[\n" - + "Hello Wörld\n" - + "]\n" - + "FOOTER"); - } - -} diff --git a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/reporters/PlainTextSnapshotReporterTest.java b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/reporters/PlainTextSnapshotReporterTest.java index 5e06a73..d184a01 100644 --- a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/reporters/PlainTextSnapshotReporterTest.java +++ b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/reporters/PlainTextSnapshotReporterTest.java @@ -1,5 +1,6 @@ package au.com.origin.snapshots.reporters; +import au.com.origin.snapshots.Snapshot; import au.com.origin.snapshots.serializers.SerializerType; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; @@ -21,11 +22,21 @@ void shouldSupportAllFormats() { @Test void doReport() { + Snapshot snap1 = Snapshot.builder() + .name("snap1") + .scenario("A") + .body("[\nfoo\n]") + .build(); + Snapshot snap2 = Snapshot.builder() + .name("snap1") + .scenario("A") + .body("[\nbar\n]") + .build(); assertThatExceptionOfType(AssertionFailedError.class) - .isThrownBy(() -> REPORTER.report("snap1", "blah", "bloo")) + .isThrownBy(() -> REPORTER.report(snap1, snap2)) .withMessageContaining("expecting:") - .withMessageContaining("[\"blah\"]") + .withMessageContaining("[\"foo\"]") .withMessageContaining("but was:") - .withMessageContaining("[\"bloo\"]"); + .withMessageContaining("[\"bar\"]"); } } diff --git a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/serializers/Base64SnapshotSerializerTest.java b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/serializers/Base64SnapshotSerializerTest.java index a7e5660..f300fa0 100644 --- a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/serializers/Base64SnapshotSerializerTest.java +++ b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/serializers/Base64SnapshotSerializerTest.java @@ -1,5 +1,8 @@ package au.com.origin.snapshots.serializers; +import au.com.origin.snapshots.Snapshot; +import au.com.origin.snapshots.SnapshotSerializerContext; +import au.com.origin.snapshots.SnapshotHeader; import org.junit.jupiter.api.Test; import java.io.File; @@ -9,18 +12,26 @@ public class Base64SnapshotSerializerTest { + private SnapshotSerializerContext mockSnapshotGenerator = new SnapshotSerializerContext( + "base64Test", + null, + new SnapshotHeader(), + Base64SnapshotSerializerTest.class, + null // it's not used in these scenarios + ); + @Test void shouldSnapshotAByteArray() { Base64SnapshotSerializer serializer = new Base64SnapshotSerializer(); - String result = serializer.apply(new Object[] {"John Doe".getBytes()}); - assertThat(result).isEqualTo("[\nSm9obiBEb2U=\n]"); + Snapshot result = serializer.apply("John Doe".getBytes(), mockSnapshotGenerator); + assertThat(result.getBody()).isEqualTo("[\nSm9obiBEb2U=\n]"); } @Test void shouldSnapshotAnyString() { Base64SnapshotSerializer serializer = new Base64SnapshotSerializer(); - String result = serializer.apply(new Object[] {"John Doe"}); - assertThat(result).isEqualTo("[\nSm9obiBEb2U=\n]"); + Snapshot result = serializer.apply("John Doe", mockSnapshotGenerator); + assertThat(result.getBody()).isEqualTo("[\nSm9obiBEb2U=\n]"); } @Test @@ -29,8 +40,8 @@ void shouldSnapshotAFile() throws Exception { File f = new File("src/test/resources/origin-logo.png"); byte[] content = Files.readAllBytes(f.toPath()); - String result = serializer.apply(new Object[] {content}); - assertThat(result).isEqualTo( + Snapshot result = serializer.apply(content, mockSnapshotGenerator); + assertThat(result.getBody()).isEqualTo( "[\niVBORw0KGgoAAAANSUhEUgAAAFgAAABYCAIAAAD+96djAAAKaklEQVR4nOxce3BcVRk/59zX3t3N5p3m1UeaNLQ2adKaFhDp9MFD3j7Qoqhg1VHpjEMR7CgKyghVQKa24wzSUhQcxwGLU0TsH0AphQLSxKSQJm02aRrSvDbPfd/HOddZ2LLJZp/n3F0aJr/Zf7J77nd+95fvfN85537n8oZhgHkAgD5pAhcK5oUIY16IMOaFCGNeiDD4rPVEpiZ1p1PvceLhITIyQlwuw+c1FMVQFGAYUJKAJEFZ5oqKUUkJKlnAL63mq5dxxcXZoQczmj7xqEtrflc7fUprbSGuEQoLMC9fbFzN1y4X1zRx5RUZ4Hi+o0wIQdxu5Y0jyuuv6p0dwDz73JIqacMmaf0mrrDILJsfw2Qh9L7ewMF/KEdfA5pmotkZQEhcd6l801eE5StNtGqaEHrfWf8z+9T/vWuiCyQGv2Kl7datwoo6U6yZI4Ty9lH/M0/i4UEzKKUB5Mi1bvm2ZfMXAM8a9VmFwMODvn171LZmRh4s4BYusf/gTqF2BYsRBiEwDhw66H/2L6H890kDIiRddb3tlq3QYqG0QCcEcU96//iw9l4LXa8ZAle5KOeu+7lSmixLI4Tu7PTseZCMuij6yzSg1WbftkNsXJf2hekKob7X7Nn1AFA/+eEQF4iz3bbNsunatC5KTwjl7SPevY8CPWNzBPMg33y79YZbUm+fRtZR3n7N+6ffhaYJkIpadhE48GcIoXz9lhTbpyqE2vqW78lHAJwbKnwE//NPAQ7J13w1lcYpCaF1d3gf3wkMAtHckeFDBA7sR3kF0qWbk7ZMLgSZHPM98RAg2hzdu/D9dTcqKhGW1SduliRY4vER3/5H9K73zaaXXUhS3kNPI7sjQZOEQhDi3nOv3tmaEXLZBbdoWe5dDwMp7rwzkbsHj76on24NNZn7H9zf5Xt+b4KbjSsEHh8JHHwqlCM+LR/l2EvaqbjeHTdYBl96xtAVYHaagILIV63ga1bxC2tQSQVy5ENeABACTSN+Dx45hwfO6N3va10njIDP3K5DSeTgPuHuPwDExSAWM0boHzg9j90JDGIiCW5hjXTZdWLDZVC2J2+tKWr7u8obL+rOEyZyAABYv7FdWnfl7O9jC+F54j6987hZfaOSSutN3xdWrKW4VjvTHvjXftzbCYA5G1+oYEHuz/YCLnooxBBC73d6dv3YlH6hbJO/vE1adRngBXorhGi9J/1/f4yMDZnACQDrLdultdFOESNYKq89F4ouzIGaW1ids323tGYDkwof7tYKS+sc23cLK9eZkkGCh58DBCcRgkyNqu3H2DsTVl7suONRrrCMSYJpgLLdfvsvpctvZOdGxvq17ujQEy2E2vwyMDBjouJr19i/dS8QJbNUOE+Ws974Q8umLeypVG15Jcp2dMzQuo4zrqygLdf6xTtmRyOzIG/cop8+jgd7WIzoPW0AY8BF8ugMj8DjQ7ivg0lsBK03b+cKy1lYJoFosd76c2i1sfA0vOPa2RkLqBlC6M5mxuEnXnKdcBFNmkwLXEGZfMOPGKnqXc1xhdC6W1hMw/xi65W3ZVqFjyA2bOSrG1jYat3xhCAE97ax+Ju86ZtAsmZHiFCwuHpraAVAy5a4eolvMoYQeKzf0ALUAqPCMrF+Q9ZUCA2QshrhIoaZBQR4sCuWEENOpujQeEXmMkU8iE3XsnDGg86PTUWo4+EelsQp1K1nvq/0O61qRPY8wz9FdzkeieTgiEcQ9zD1eENFFVx+JlNmPHA8t6SePky4R2IIYXhc1D7GLTKnSIEC/KJ6atqGJyJEZGgQ7yig3afmihebcE/UXdPSNhQP0BQgSDOEMDQfoA0RqCCDZV5Jus4vp6Yd+vcrPjRDCIIB0amlhdZEO+UZBbLmfrifSLt9ooefZp8XQldhSAVKbaGYvXlUNBAHJSnk4VQwooWAiNodQiA6w8XMgICe/PmN3PNCCFLIwWjLiAzVT0vEDBCVOkxAPrxpMm0uKEpAC9KZM7wuAJhquagRSnYsz+iFWUJAW67hphSCTJ2jJcIKMtHPMi6QFH62EBEC5ZRg7zCdQezqouXCCjzcQS0EyimaFSMAQI5iTLtdjodPAqxnf9EVSneDJ+gDRE6k9H+aEHmV9Isu3a8NtAoLmygvpwXxjxNXBzVtlBdZH0W8iiuuYVnS6l3R+8JZgOY8DAChXyIVVn1sappH5FayzFX1wVag+oBoY725dID73mLhjByRxy4Rj0D2YmgroHcK3ad0/pv1ztKBPtiGx04zeDFEhdUxhAiNjvJGltGhnXyeBCayJAPWlOP7WNiioqVIzostBF/ewPSwQPerLfuzo4PSfoBMnWVhy1fOCO0zEh5XtjqUAo3oB6SpQzv7OregTqi5muEekwO7Tqonn2UsYuErL57x5/Q/kJzHVzbhc++wdKC07IX2BXxpI4uRBCA+V/DYoxBgllUidCzkCmumfxNtTKi+isXfQh9DCx7bicczMtc0/KOBI/cZwTFGkkLVxijL0ULwpathTglLEAp9cDBw5Bf6cJu5KhDPgP/wDsM3wEqPF/glyYQAiBOqr2HtCQFAgsE3f612PDu7JIMOev+b/sN3G8FRdm784vVILoiyH6uGSvV6D30XYMqVaBS4guVC7Zf4skuoLeAJp+Z8Qe8/YgofAKC8eTfnWBT9bcxiMqX9aa3rgEkdh8CVNIq1X+OK0jupid29Wtc/9f6jLIksCnzF5y1r75n9fZwSZC3gP7zNCI6b1X24M8divmI9v6AJORJt/xPvOTzSrA8cI+OnzCqmCwPx8sY9yBajoCluLbb2watq224zSUyHlMc5qqC9AooOiMTQZAxrhuo2vOeI+4yhZGp6yi+9UfrM1pg/JSpKD/73V3j001CR/hGgvMB6+S7AyzF/TTQpEevuAILMOq24QD4ISvXb4qmQ/LyG1v+y2vEEIGo60l+IEJd/T1h8fYIGSTbXhMorIOKV9l0m84I8tBRBIQciCXASgBBgxcAK0H0kOAqIyWcpuaK1iVVI6SgTX74Buzv1/kMsVKBcyuXWopwa5KhG1jIo5SUYlYY6RQJDxNND3N3E7SS+syxvIODyV1oafpqcYUrnPokWbPsNmUizUF7M5Ys/h/JXoZylSC5J79ppMFQ38fTgiTY88qYRTO/4MbRWyGseBGJu8papHoDVA4HWew3vmRQ657jCJr50M1ewGiBz97UJnmjXB1/Bo2+lEragVCyt2YmkwlRMp3MSWJ0MnLjf8PXFbcDLfOkVfPm1SC5N1SYVDHVSGzikD/4HqO54baBUIK16AFlTrVdI70i0obmDrTuMYIznHyi3Tlr+EyjmpW6NFbpfcT6OXUdj/MRZLA2/RbY0ylfSf1sADgbadhj+iF9AqUhafg/KqU3PjkkggSH11O+J1zmNT6Glfie0pPfeJqr3R2hu5fRjeKotNBqKN4pV3wF8TtpGTATRtL6/aYMvAIMg+zLponuglPbbq6jfKEK0/gPItpTL/yzV5eYDe06RiXeEyq8DRHNOJrMv5JpDmJvnvTOAeSHCmBcijHkhwpgXIox5IcKYFyKM/wcAAP//h4bYYlJz5AYAAAAASUVORK5CYII=\n]"); } diff --git a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/serializers/LowercaseToStringSerializer.java b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/serializers/LowercaseToStringSerializer.java index 8f29b7b..d660caa 100644 --- a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/serializers/LowercaseToStringSerializer.java +++ b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/serializers/LowercaseToStringSerializer.java @@ -1,12 +1,15 @@ package au.com.origin.snapshots.serializers; +import au.com.origin.snapshots.Snapshot; +import au.com.origin.snapshots.SnapshotSerializerContext; + import java.util.Arrays; import java.util.stream.Collectors; public class LowercaseToStringSerializer implements SnapshotSerializer { @Override - public String apply(Object[] objects) { - return Arrays.stream(objects).map(Object::toString).collect(Collectors.joining()).toLowerCase(); + public Snapshot apply(Object object, SnapshotSerializerContext gen) { + return gen.toSnapshot(object.toString().toLowerCase()); } @Override diff --git a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/serializers/ToStringSnapshotSerializerTest.java b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/serializers/ToStringSnapshotSerializerTest.java index 96b7584..7dcf4eb 100644 --- a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/serializers/ToStringSnapshotSerializerTest.java +++ b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/serializers/ToStringSnapshotSerializerTest.java @@ -1,5 +1,8 @@ package au.com.origin.snapshots.serializers; +import au.com.origin.snapshots.Snapshot; +import au.com.origin.snapshots.SnapshotSerializerContext; +import au.com.origin.snapshots.SnapshotHeader; import lombok.AllArgsConstructor; import lombok.Data; import org.junit.jupiter.api.Test; @@ -9,28 +12,36 @@ public class ToStringSnapshotSerializerTest { ToStringSnapshotSerializer serializer = new ToStringSnapshotSerializer(); + private SnapshotSerializerContext mockSnapshotGenerator = new SnapshotSerializerContext( + "base64Test", + null, + new SnapshotHeader(), + ToStringSnapshotSerializerTest.class, + null // it's not used in these scenarios + ); + @Test void shouldSnapshotAnyString() { - String result = serializer.apply(new Object[] {"John Doe"}); - assertThat(result).isEqualTo("[\nJohn Doe\n]"); + Snapshot result = serializer.apply("John Doe", mockSnapshotGenerator); + assertThat(result.getBody()).isEqualTo("[\nJohn Doe\n]"); } @Test void shouldSnapshotUnicode() { - String result = serializer.apply(new Object[] {"🤔"}); - assertThat(result).isEqualTo("[\n🤔\n]"); + Snapshot result = serializer.apply("🤔", mockSnapshotGenerator); + assertThat(result.getBody()).isEqualTo("[\n🤔\n]"); } @Test void shouldSnapshotAnyObject() { - String result = serializer.apply(new Object[] {new Dummy(1, "John Doe")}); - assertThat(result).isEqualTo("[\nToStringSerializerTest.Dummy(id=1, name=John Doe)\n]"); + Snapshot result = serializer.apply(new Dummy(1, "John Doe"), mockSnapshotGenerator); + assertThat(result.getBody()).isEqualTo("[\nToStringSerializerTest.Dummy(id=1, name=John Doe)\n]"); } @Test void shouldSnapshotMultipleObjects() { - String result = serializer.apply(new Object[] {new Dummy(1, "John Doe"), new Dummy(2, "Sarah Doe")}); - assertThat(result).isEqualTo("[\nToStringSerializerTest.Dummy(id=1, name=John Doe)\nToStringSerializerTest.Dummy(id=2, name=Sarah Doe)\n]"); + Snapshot result = serializer.apply(new Dummy(1, "John Doe"), mockSnapshotGenerator); + assertThat(result.getBody()).isEqualTo("[\nToStringSerializerTest.Dummy(id=1, name=John Doe)\n]"); } @Test @@ -40,8 +51,8 @@ void shouldSupportBase64SerializerType() { @Test void shouldReplaceThreeConsecutiveNewLines() { - String result = serializer.apply(new Object[] {"John\n\n\nDoe"}); - assertThat(result).isEqualTo("[\nJohn\n.\n.\nDoe\n]"); + Snapshot result = serializer.apply("John\n\n\nDoe", mockSnapshotGenerator); + assertThat(result.getBody()).isEqualTo("[\nJohn\n.\n.\nDoe\n]"); } @AllArgsConstructor diff --git a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/serializers/UppercaseToStringSerializer.java b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/serializers/UppercaseToStringSerializer.java index c962a67..e8d1505 100644 --- a/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/serializers/UppercaseToStringSerializer.java +++ b/java-snapshot-testing-core/src/test/java/au/com/origin/snapshots/serializers/UppercaseToStringSerializer.java @@ -1,12 +1,15 @@ package au.com.origin.snapshots.serializers; +import au.com.origin.snapshots.Snapshot; +import au.com.origin.snapshots.SnapshotSerializerContext; + import java.util.Arrays; import java.util.stream.Collectors; public class UppercaseToStringSerializer implements SnapshotSerializer { @Override - public String apply(Object[] objects) { - return Arrays.stream(objects).map(Object::toString).collect(Collectors.joining()).toUpperCase(); + public Snapshot apply(Object object, SnapshotSerializerContext gen) { + return gen.toSnapshot(object.toString().toUpperCase()); } @Override diff --git a/java-snapshot-testing-core/src/test/java/java/util/__snapshots__/Optional.snap b/java-snapshot-testing-core/src/test/java/java/util/__snapshots__/Optional.snap index f149637..54e9ec2 100644 --- a/java-snapshot-testing-core/src/test/java/java/util/__snapshots__/Optional.snap +++ b/java-snapshot-testing-core/src/test/java/java/util/__snapshots__/Optional.snap @@ -1,4 +1,9 @@ java.util.Optional.shouldExtractArgsFromFakeMethodWithComplexObject=[ {FakeObject.fakeMethodWithComplexObject=[{arg0=BackwardCompatilbleTest.FakeObject(id=idMock, value=null, name=null)}]} {FakeObject.fakeMethodWithComplexObject=[{arg0=BackwardCompatilbleTest.FakeObject(id=idMock, value=null, name=nameMock)}]} +] + + +java.util.Optional.shouldExtractArgsFromFakeMethodWithComplexObjectWithIgnoreFields=[ +{FakeObject.fakeMethodWithComplexObject=[{arg0=BackwardCompatilbleTest.FakeObject(id=idMock, value=null, name=nameMock)}]} ] \ No newline at end of file diff --git a/java-snapshot-testing-junit4/src/main/java/au/com/origin/snapshots/junit4/SharedSnapshotHelpers.java b/java-snapshot-testing-junit4/src/main/java/au/com/origin/snapshots/junit4/SharedSnapshotHelpers.java index 83e3f19..6d8e829 100644 --- a/java-snapshot-testing-junit4/src/main/java/au/com/origin/snapshots/junit4/SharedSnapshotHelpers.java +++ b/java-snapshot-testing-junit4/src/main/java/au/com/origin/snapshots/junit4/SharedSnapshotHelpers.java @@ -1,6 +1,9 @@ package au.com.origin.snapshots.junit4; import au.com.origin.snapshots.*; +import au.com.origin.snapshots.config.PropertyResolvingSnapshotConfig; +import au.com.origin.snapshots.config.SnapshotConfig; +import au.com.origin.snapshots.config.SnapshotConfigInjector; import org.junit.runner.Description; import org.junit.runners.model.FrameworkMethod; import org.junit.runners.model.Statement; diff --git a/java-snapshot-testing-junit4/src/test/java/au/com/origin/snapshots/__snapshots__/SnapshotContextRuleUsedTest.snap b/java-snapshot-testing-junit4/src/test/java/au/com/origin/snapshots/__snapshots__/SnapshotContextRuleUsedTest.snap new file mode 100644 index 0000000..cb453d4 --- /dev/null +++ b/java-snapshot-testing-junit4/src/test/java/au/com/origin/snapshots/__snapshots__/SnapshotContextRuleUsedTest.snap @@ -0,0 +1,31 @@ +au.com.origin.snapshots.SnapshotRuleUsedTest.shouldUseExtension=[ +Hello World +] + + +au.com.origin.snapshots.SnapshotRuleUsedTest.shouldUseExtensionAgain=[ +Hello World +Hello World Again +] + + +au.com.origin.snapshots.SnapshotRuleUsedTest.shouldUseExtensionAgainViaInstanceVariable=[ +Hello World +Hello World Again +] + + +au.com.origin.snapshots.SnapshotRuleUsedTest.shouldUseExtensionViaInstanceVariable=[ +Hello World +] + + +hello_world=[ +Hello World +] + + +hello_world_again=[ +Hello World +Hello World Again +] \ No newline at end of file diff --git a/java-snapshot-testing-junit5/src/main/java/au/com/origin/snapshots/junit5/SnapshotExtension.java b/java-snapshot-testing-junit5/src/main/java/au/com/origin/snapshots/junit5/SnapshotExtension.java index a6fe7ad..f86d8ac 100644 --- a/java-snapshot-testing-junit5/src/main/java/au/com/origin/snapshots/junit5/SnapshotExtension.java +++ b/java-snapshot-testing-junit5/src/main/java/au/com/origin/snapshots/junit5/SnapshotExtension.java @@ -1,6 +1,10 @@ package au.com.origin.snapshots.junit5; -import au.com.origin.snapshots.*; +import au.com.origin.snapshots.Expect; +import au.com.origin.snapshots.SnapshotVerifier; +import au.com.origin.snapshots.config.PropertyResolvingSnapshotConfig; +import au.com.origin.snapshots.config.SnapshotConfig; +import au.com.origin.snapshots.config.SnapshotConfigInjector; import au.com.origin.snapshots.exceptions.SnapshotMatchException; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.extension.*; @@ -55,7 +59,7 @@ private boolean shouldFailOnOrphans(ExtensionContext context) { } } catch (Exception e) { log.error( - "FAILED: (Java Snapshot Testing) Unable to get JUnit5 ClassTestDescriptor!\n" + + "FAILED: (Java Snapshot Testing) Unable to get JUnit5 ClassTestDescriptor or ClassBasedTestDescriptor!\n" + "Ensure you are using Junit5 >= 5.3.2\n" + "This may be due to JUnit5 changing their private api as we use reflection to access it\n" + "Log a support ticket https://github.com/origin-energy/java-snapshot-testing/issues and supply your JUnit5 version\n" + diff --git a/java-snapshot-testing-junit5/src/test/java/au/com/origin/snapshots/__snapshots__/SnapshotContextExtensionUsedTest.snap b/java-snapshot-testing-junit5/src/test/java/au/com/origin/snapshots/__snapshots__/SnapshotContextExtensionUsedTest.snap new file mode 100644 index 0000000..4d055ee --- /dev/null +++ b/java-snapshot-testing-junit5/src/test/java/au/com/origin/snapshots/__snapshots__/SnapshotContextExtensionUsedTest.snap @@ -0,0 +1,32 @@ +au.com.origin.snapshots.SnapshotExtensionUsedTest.shouldUseExtension=[ +Hello World +] + + +au.com.origin.snapshots.SnapshotExtensionUsedTest.shouldUseExtensionAgain=[ +Hello World +Hello World Again +] + + +au.com.origin.snapshots.SnapshotExtensionUsedTest.shouldUseExtensionAgainViaInstanceVariable=[ +Hello World +Hello World Again +] + + +au.com.origin.snapshots.SnapshotExtensionUsedTest.shouldUseExtensionViaInstanceVariable=[ +Hello World +] + + +hello_world=[ +Hello World +Hello World +] + + +hello_world_2=[ +Hello World +Hello World Again +] \ No newline at end of file diff --git a/java-snapshot-testing-junit5/src/test/java/au/com/origin/snapshots/docs/CustomFrameworkExample.java b/java-snapshot-testing-junit5/src/test/java/au/com/origin/snapshots/docs/CustomFrameworkExample.java index e36089b..6534977 100644 --- a/java-snapshot-testing-junit5/src/test/java/au/com/origin/snapshots/docs/CustomFrameworkExample.java +++ b/java-snapshot-testing-junit5/src/test/java/au/com/origin/snapshots/docs/CustomFrameworkExample.java @@ -1,8 +1,8 @@ package au.com.origin.snapshots.docs; import au.com.origin.snapshots.Expect; -import au.com.origin.snapshots.PropertyResolvingSnapshotConfig; import au.com.origin.snapshots.SnapshotVerifier; +import au.com.origin.snapshots.config.PropertyResolvingSnapshotConfig; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; diff --git a/java-snapshot-testing-junit5/src/test/java/au/com/origin/snapshots/docs/JUnit5Example.java b/java-snapshot-testing-junit5/src/test/java/au/com/origin/snapshots/docs/JUnit5Example.java index df8628f..392ab6f 100644 --- a/java-snapshot-testing-junit5/src/test/java/au/com/origin/snapshots/docs/JUnit5Example.java +++ b/java-snapshot-testing-junit5/src/test/java/au/com/origin/snapshots/docs/JUnit5Example.java @@ -1,9 +1,9 @@ package au.com.origin.snapshots.docs; +import au.com.origin.snapshots.Expect; import au.com.origin.snapshots.junit5.SnapshotExtension; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import au.com.origin.snapshots.Expect; // Ensure you extend your test class with the SnapshotExtension @ExtendWith({SnapshotExtension.class}) diff --git a/java-snapshot-testing-junit5/src/test/java/au/com/origin/snapshots/docs/LowercaseToStringSerializer.java b/java-snapshot-testing-junit5/src/test/java/au/com/origin/snapshots/docs/LowercaseToStringSerializer.java index 865e336..d333eca 100644 --- a/java-snapshot-testing-junit5/src/test/java/au/com/origin/snapshots/docs/LowercaseToStringSerializer.java +++ b/java-snapshot-testing-junit5/src/test/java/au/com/origin/snapshots/docs/LowercaseToStringSerializer.java @@ -1,15 +1,14 @@ package au.com.origin.snapshots.docs; +import au.com.origin.snapshots.Snapshot; +import au.com.origin.snapshots.SnapshotSerializerContext; import au.com.origin.snapshots.serializers.SerializerType; import au.com.origin.snapshots.serializers.SnapshotSerializer; -import java.util.Arrays; -import java.util.stream.Collectors; - public class LowercaseToStringSerializer implements SnapshotSerializer { @Override - public String apply(Object[] objects) { - return Arrays.stream(objects).map(Object::toString).collect(Collectors.joining()).toLowerCase(); + public Snapshot apply(Object object, SnapshotSerializerContext gen) { + return gen.toSnapshot(object.toString().toLowerCase()); } @Override diff --git a/java-snapshot-testing-junit5/src/test/java/au/com/origin/snapshots/docs/LowercaseToStringSnapshotConfig.java b/java-snapshot-testing-junit5/src/test/java/au/com/origin/snapshots/docs/LowercaseToStringSnapshotConfig.java index 0d122d1..aac8eb5 100644 --- a/java-snapshot-testing-junit5/src/test/java/au/com/origin/snapshots/docs/LowercaseToStringSnapshotConfig.java +++ b/java-snapshot-testing-junit5/src/test/java/au/com/origin/snapshots/docs/LowercaseToStringSnapshotConfig.java @@ -1,6 +1,6 @@ package au.com.origin.snapshots.docs; -import au.com.origin.snapshots.PropertyResolvingSnapshotConfig; +import au.com.origin.snapshots.config.PropertyResolvingSnapshotConfig; import au.com.origin.snapshots.serializers.SnapshotSerializer; public class LowercaseToStringSnapshotConfig extends PropertyResolvingSnapshotConfig { diff --git a/java-snapshot-testing-junit5/src/test/java/au/com/origin/snapshots/docs/MyFirstSnapshotTest.java b/java-snapshot-testing-junit5/src/test/java/au/com/origin/snapshots/docs/MyFirstSnapshotTest.java index ec1deb2..38da1d6 100644 --- a/java-snapshot-testing-junit5/src/test/java/au/com/origin/snapshots/docs/MyFirstSnapshotTest.java +++ b/java-snapshot-testing-junit5/src/test/java/au/com/origin/snapshots/docs/MyFirstSnapshotTest.java @@ -1,5 +1,6 @@ package au.com.origin.snapshots.docs; +import au.com.origin.snapshots.Expect; import au.com.origin.snapshots.annotations.SnapshotName; import au.com.origin.snapshots.junit5.SnapshotExtension; import org.junit.jupiter.api.Test; @@ -7,7 +8,6 @@ import java.util.HashMap; import java.util.Map; -import au.com.origin.snapshots.Expect; @ExtendWith({SnapshotExtension.class}) public class MyFirstSnapshotTest { diff --git a/java-snapshot-testing-junit5/src/test/java/au/com/origin/snapshots/docs/UppercaseToStringSerializer.java b/java-snapshot-testing-junit5/src/test/java/au/com/origin/snapshots/docs/UppercaseToStringSerializer.java index 6988323..c37a86f 100644 --- a/java-snapshot-testing-junit5/src/test/java/au/com/origin/snapshots/docs/UppercaseToStringSerializer.java +++ b/java-snapshot-testing-junit5/src/test/java/au/com/origin/snapshots/docs/UppercaseToStringSerializer.java @@ -1,5 +1,7 @@ package au.com.origin.snapshots.docs; +import au.com.origin.snapshots.Snapshot; +import au.com.origin.snapshots.SnapshotSerializerContext; import au.com.origin.snapshots.serializers.SerializerType; import au.com.origin.snapshots.serializers.SnapshotSerializer; @@ -8,8 +10,8 @@ public class UppercaseToStringSerializer implements SnapshotSerializer { @Override - public String apply(Object[] objects) { - return Arrays.stream(objects).map(Object::toString).collect(Collectors.joining()).toUpperCase(); + public Snapshot apply(Object object, SnapshotSerializerContext gen) { + return gen.toSnapshot(object.toString().toUpperCase()); } @Override diff --git a/java-snapshot-testing-junit5/src/test/java/au/com/origin/snapshots/docs/__snapshots__/CustomSnapshotContextConfigExample.snap b/java-snapshot-testing-junit5/src/test/java/au/com/origin/snapshots/docs/__snapshots__/CustomSnapshotContextConfigExample.snap new file mode 100644 index 0000000..ed598d1 --- /dev/null +++ b/java-snapshot-testing-junit5/src/test/java/au/com/origin/snapshots/docs/__snapshots__/CustomSnapshotContextConfigExample.snap @@ -0,0 +1 @@ +au.com.origin.snapshots.docs.CustomSnapshotConfigExample.myTest=hello world \ No newline at end of file diff --git a/java-snapshot-testing-junit5/src/test/java/au/com/origin/snapshots/docs/__snapshots__/MyFirstSnapshotContextTest.snap b/java-snapshot-testing-junit5/src/test/java/au/com/origin/snapshots/docs/__snapshots__/MyFirstSnapshotContextTest.snap new file mode 100644 index 0000000..1987c84 --- /dev/null +++ b/java-snapshot-testing-junit5/src/test/java/au/com/origin/snapshots/docs/__snapshots__/MyFirstSnapshotContextTest.snap @@ -0,0 +1,11 @@ +au.com.origin.snapshots.docs.MyFirstSnapshotTest.jsonSerializationTest=[ + { + "age": 40, + "name": "John Doe" + } +] + + +i_can_give_custom_names_to_my_snapshots=[ +Hello World +] \ No newline at end of file diff --git a/java-snapshot-testing-plugin-jackson/src/main/java/au/com/origin/snapshots/jackson/serializers/JacksonSnapshotSerializer.java b/java-snapshot-testing-plugin-jackson/src/main/java/au/com/origin/snapshots/jackson/serializers/JacksonSnapshotSerializer.java index 176f271..54f893a 100644 --- a/java-snapshot-testing-plugin-jackson/src/main/java/au/com/origin/snapshots/jackson/serializers/JacksonSnapshotSerializer.java +++ b/java-snapshot-testing-plugin-jackson/src/main/java/au/com/origin/snapshots/jackson/serializers/JacksonSnapshotSerializer.java @@ -1,5 +1,7 @@ package au.com.origin.snapshots.jackson.serializers; +import au.com.origin.snapshots.Snapshot; +import au.com.origin.snapshots.SnapshotSerializerContext; import au.com.origin.snapshots.exceptions.SnapshotExtensionException; import au.com.origin.snapshots.serializers.SerializerType; import au.com.origin.snapshots.serializers.SnapshotSerializer; @@ -12,6 +14,9 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; +import java.util.Arrays; +import java.util.List; + public class JacksonSnapshotSerializer implements SnapshotSerializer { private final PrettyPrinter pp = new DefaultPrettyPrinter("") { @@ -64,9 +69,11 @@ public void configure(ObjectMapper objectMapper) { } @Override - public String apply(Object[] objects) { + public Snapshot apply(Object object, SnapshotSerializerContext gen) { try { - return objectMapper.writer(pp).writeValueAsString(objects); + List objects = Arrays.asList(object); + String body = objectMapper.writer(pp).writeValueAsString(objects); + return gen.toSnapshot(body); } catch (Exception e) { throw new SnapshotExtensionException("Jackson Serialization failed", e); } diff --git a/java-snapshot-testing-plugin-jackson/src/test/java/au/com/origin/snapshots/jackson/docs/CustomSerializerTest.java b/java-snapshot-testing-plugin-jackson/src/test/java/au/com/origin/snapshots/jackson/docs/CustomSerializerTest.java index 0385bdf..8a7be98 100644 --- a/java-snapshot-testing-plugin-jackson/src/test/java/au/com/origin/snapshots/jackson/docs/CustomSerializerTest.java +++ b/java-snapshot-testing-plugin-jackson/src/test/java/au/com/origin/snapshots/jackson/docs/CustomSerializerTest.java @@ -1,8 +1,8 @@ package au.com.origin.snapshots.jackson.docs; import au.com.origin.snapshots.Expect; -import au.com.origin.snapshots.PropertyResolvingSnapshotConfig; import au.com.origin.snapshots.SnapshotVerifier; +import au.com.origin.snapshots.config.PropertyResolvingSnapshotConfig; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInfo; diff --git a/java-snapshot-testing-plugin-jackson/src/test/java/au/com/origin/snapshots/jackson/docs/JsonAssertReporter.java b/java-snapshot-testing-plugin-jackson/src/test/java/au/com/origin/snapshots/jackson/docs/JsonAssertReporter.java index ad091b0..952a811 100644 --- a/java-snapshot-testing-plugin-jackson/src/test/java/au/com/origin/snapshots/jackson/docs/JsonAssertReporter.java +++ b/java-snapshot-testing-plugin-jackson/src/test/java/au/com/origin/snapshots/jackson/docs/JsonAssertReporter.java @@ -1,5 +1,6 @@ package au.com.origin.snapshots.jackson.docs; +import au.com.origin.snapshots.Snapshot; import au.com.origin.snapshots.reporters.SnapshotReporter; import au.com.origin.snapshots.serializers.SerializerType; import lombok.SneakyThrows; @@ -14,7 +15,7 @@ public boolean supportsFormat(String outputFormat) { @Override @SneakyThrows - public void report(String snapshotName, String rawSnapshot, String currentObject) { - JSONAssert.assertEquals(rawSnapshot, currentObject, JSONCompareMode.STRICT); + public void report(Snapshot previous, Snapshot current) { + JSONAssert.assertEquals(previous.getBody(), current.getBody(), JSONCompareMode.STRICT); } } \ No newline at end of file diff --git a/java-snapshot-testing-plugin-jackson/src/test/java/au/com/origin/snapshots/jackson/docs/JsonObjectComparator.java b/java-snapshot-testing-plugin-jackson/src/test/java/au/com/origin/snapshots/jackson/docs/JsonObjectComparator.java index 326717f..f663b96 100644 --- a/java-snapshot-testing-plugin-jackson/src/test/java/au/com/origin/snapshots/jackson/docs/JsonObjectComparator.java +++ b/java-snapshot-testing-plugin-jackson/src/test/java/au/com/origin/snapshots/jackson/docs/JsonObjectComparator.java @@ -1,17 +1,18 @@ package au.com.origin.snapshots.jackson.docs; +import au.com.origin.snapshots.Snapshot; import au.com.origin.snapshots.comparators.SnapshotComparator; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.SneakyThrows; public class JsonObjectComparator implements SnapshotComparator { @Override - public boolean matches(String snapshotName, String rawSnapshot, String currentObject) { - return asObject(snapshotName, rawSnapshot).equals(asObject(snapshotName, currentObject)); + public boolean matches(Snapshot previous, Snapshot current) { + return asObject(previous.getName(), previous.getBody()).equals(asObject(current.getName(), current.getBody())); } @SneakyThrows private static Object asObject(String snapshotName, String json) { - return new ObjectMapper().readValue(json.replaceFirst(snapshotName, ""), Object.class); + return new ObjectMapper().readValue(json.replaceFirst(snapshotName + "=", ""), Object.class); } } diff --git a/java-snapshot-testing-plugin-jackson/src/test/java/au/com/origin/snapshots/jackson/serializers/DeterministicJacksonSnapshotSerializerTest.java b/java-snapshot-testing-plugin-jackson/src/test/java/au/com/origin/snapshots/jackson/serializers/DeterministicJacksonSnapshotSerializerTest.java index d0798dd..920e65e 100644 --- a/java-snapshot-testing-plugin-jackson/src/test/java/au/com/origin/snapshots/jackson/serializers/DeterministicJacksonSnapshotSerializerTest.java +++ b/java-snapshot-testing-plugin-jackson/src/test/java/au/com/origin/snapshots/jackson/serializers/DeterministicJacksonSnapshotSerializerTest.java @@ -1,9 +1,8 @@ package au.com.origin.snapshots.jackson.serializers; import au.com.origin.snapshots.Expect; -import au.com.origin.snapshots.PropertyResolvingSnapshotConfig; import au.com.origin.snapshots.SnapshotVerifier; -import au.com.origin.snapshots.jackson.serializers.DeterministicJacksonSnapshotSerializer; +import au.com.origin.snapshots.config.PropertyResolvingSnapshotConfig; import au.com.origin.snapshots.serializers.SerializerType; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; diff --git a/java-snapshot-testing-plugin-jackson/src/test/java/au/com/origin/snapshots/jackson/serializers/JacksonSnapshotSerializerTest.java b/java-snapshot-testing-plugin-jackson/src/test/java/au/com/origin/snapshots/jackson/serializers/JacksonSnapshotSerializerTest.java index 55cf731..f9d74fb 100644 --- a/java-snapshot-testing-plugin-jackson/src/test/java/au/com/origin/snapshots/jackson/serializers/JacksonSnapshotSerializerTest.java +++ b/java-snapshot-testing-plugin-jackson/src/test/java/au/com/origin/snapshots/jackson/serializers/JacksonSnapshotSerializerTest.java @@ -1,10 +1,8 @@ package au.com.origin.snapshots.jackson.serializers; -import au.com.origin.snapshots.Expect; -import au.com.origin.snapshots.PropertyResolvingSnapshotConfig; -import au.com.origin.snapshots.SnapshotConfig; -import au.com.origin.snapshots.SnapshotVerifier; -import au.com.origin.snapshots.jackson.serializers.JacksonSnapshotSerializer; +import au.com.origin.snapshots.*; +import au.com.origin.snapshots.config.PropertyResolvingSnapshotConfig; +import au.com.origin.snapshots.config.SnapshotConfig; import au.com.origin.snapshots.serializers.SerializerType; import au.com.origin.snapshots.serializers.SnapshotSerializer; import org.assertj.core.api.Assertions; @@ -26,6 +24,14 @@ public SnapshotSerializer getSerializer() { } }; + private SnapshotSerializerContext gen = new SnapshotSerializerContext( + "test", + null, + new SnapshotHeader(), + JacksonSnapshotSerializerTest.class, + null + ); + @Test public void shouldSerializeMap() { Map map = new HashMap<>(); @@ -33,8 +39,8 @@ public void shouldSerializeMap() { map.put("age", 40); SnapshotSerializer serializer = new JacksonSnapshotSerializer(); - String result = serializer.apply(new Object[] {map}); - Assertions.assertThat(result).isEqualTo("[\n" + + Snapshot result = serializer.apply(map, gen); + Assertions.assertThat(result.getBody()).isEqualTo("[\n" + " {\n" + " \"age\": 40,\n" + " \"name\": \"John Doe\"\n" + diff --git a/java-snapshot-testing-spock/src/main/groovy/au/com/origin/snapshots/spock/SnapshotExtension.groovy b/java-snapshot-testing-spock/src/main/groovy/au/com/origin/snapshots/spock/SnapshotExtension.groovy index ca95819..1ec0ae4 100644 --- a/java-snapshot-testing-spock/src/main/groovy/au/com/origin/snapshots/spock/SnapshotExtension.groovy +++ b/java-snapshot-testing-spock/src/main/groovy/au/com/origin/snapshots/spock/SnapshotExtension.groovy @@ -1,9 +1,9 @@ package au.com.origin.snapshots.spock -import au.com.origin.snapshots.PropertyResolvingSnapshotConfig -import au.com.origin.snapshots.SnapshotConfig -import au.com.origin.snapshots.SnapshotConfigInjector import au.com.origin.snapshots.SnapshotVerifier +import au.com.origin.snapshots.config.PropertyResolvingSnapshotConfig +import au.com.origin.snapshots.config.SnapshotConfig +import au.com.origin.snapshots.config.SnapshotConfigInjector import org.spockframework.runtime.extension.AbstractAnnotationDrivenExtension import org.spockframework.runtime.model.SpecInfo diff --git a/java-snapshot-testing-spock/src/test/groovy/au/com/origin/snapshots/docs/SpockExample.groovy b/java-snapshot-testing-spock/src/test/groovy/au/com/origin/snapshots/docs/SpockExample.groovy index a554f0f..d1261d6 100644 --- a/java-snapshot-testing-spock/src/test/groovy/au/com/origin/snapshots/docs/SpockExample.groovy +++ b/java-snapshot-testing-spock/src/test/groovy/au/com/origin/snapshots/docs/SpockExample.groovy @@ -1,11 +1,10 @@ package au.com.origin.snapshots.docs +import au.com.origin.snapshots.Expect import au.com.origin.snapshots.annotations.SnapshotName import au.com.origin.snapshots.spock.EnableSnapshots import spock.lang.Specification -import au.com.origin.snapshots.Expect; - // Ensure you enable snapshot testing support @EnableSnapshots class SpockExample extends Specification {