8000 [vividus] Publish unified diff for strings comparison by ikalinin1 · Pull Request #2564 · vividus-framework/vividus · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

[vividus] Publish unified diff for strings comparison #2564

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/modules/ROOT/pages/tests-configuration.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ NOTE: The properties marked with *bold* are mandatory.
|`statistics.print-failures`
|`false`
|If set to `true` prints table of failures including: story, scenario, step and error message

|`report.text-length-diff-threshold`
|`100`
|Defines text threshold length to enable unified diff report publishing on failure, for variable comparisons. If you want to have this report despite the size of the compared data set 0.
|===

== Known Issues
Expand Down
40 changes: 40 additions & 0 deletions docs/modules/commons/pages/vividus-steps.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -221,3 +221,43 @@ Then `<column>` is equal to `value`
Examples:
file:///${examples-table-temporary-file}
----


=== Compare variables

Compare the value from the first *variable* with the value from the second *variable* in accordance with the *condition*. Could compare Maps and Lists of maps using EQUAL_TO comparison rule.
Other rules will fallback to strings comparison.

INFO: The step prints the comparison results in the unified diff format for the strings with the legth more than specified in the property xref:ROOT:tests-configuration.adoc#_configuration_properties[report.text-length-diff-threshold].

WARNING: If the variables contain valid numbers than they will be converted into https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/math/BigInteger.html[BigInteger] and compared as numbers.

[source,gherkin]
----
Then `$variable1` is $comaprisonRule `$variable2`
----

* `$variable1` - The first variable.
* `$comparisonRule` - xref:parameters:comparison-rule.adoc[The comparison rule].
* `$variable1` - The second variable.


.Compare Strings
[source,gherkin]
----
Then `Duke` is != `Leto`
----

.Compare numbers
[source,gherkin]
----
Then `10` is = `10.0`
----

.Compare list of maps
[source,gherkin]
----
When I execute SQL query `SELECT * FROM test.launch_rockets WHERE name='Proton'` against `preprod` and save result to scenario variable `preprod-date`
When I execute SQL query `SELECT * FROM test.launch_rockets WHERE name='Proton'` against `prod` and save result to scenario variable `prod-data`
Then `${preprod-data}` is = `${prod-data}`
----

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions vividus/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ dependencies {
implementation(group: 'org.hamcrest', name: 'hamcrest', version: versions.hamcrest)
implementation(group: 'com.google.guava', name: 'guava', version: versions.guava)
implementation(group: 'io.github.classgraph', name: 'classgraph', version: '4.8.137')
implementation(group: 'io.github.java-diff-utils', name: 'java-diff-utils', version: '4.5')
implementation(group: 'org.apache.commons', name: 'commons-jexl3', version: '3.2.1')
implementation(group: 'net.datafaker', name: 'datafaker', version: '1.2.0')

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* Copyright 2019-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.vividus.publishing;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.github.difflib.DiffUtils;
import com.github.difflib.UnifiedDiffUtils;
import com.github.difflib.algorithm.DiffException;
import com.github.difflib.patch.Patch;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.vividus.reporter.event.AttachmentPublisher;

public class DiffAttachmentPublisher
{
private static final String VARIABLE = "variable";
private static final Logger LOGGER = LoggerFactory.getLogger(DiffAttachmentPublisher.class);
private static final int CONTEXT_SIZE = 10;
private final AttachmentPublisher attachmentPublisher;
private int textLengthDiffThreshold;

public DiffAttachmentPublisher(AttachmentPublisher attachmentPublisher)
{
this.attachmentPublisher = attachmentPublisher;
}

public void publishDiff(Object expected, Object actual)
{
String expectedString = String.valueOf(expected);
String actualString = String.valueOf(actual);
if (expectedString.length() < textLengthDiffThreshold && actualString.length() < textLengthDiffThreshold)
{
return;
}
List<String> expectedLines = toLines(expectedString);
List<String> actualLines = toLines(actualString);
try
{
Patch<String> diff = DiffUtils.diff(expectedLines, actualLines);
String uDiff = UnifiedDiffUtils.generateUnifiedDiff(VARIABLE, VARIABLE, expectedLines, diff, CONTEXT_SIZE)
.stream()
.collect(Collectors.joining("\n"));
attachmentPublisher.publishAttachment("/templates/udiff.ftl", Map.of("udiff", uDiff), "Comparison result");
}
catch (DiffException e)
{
LOGGER.atWarn().setCause(e).log("Unable to publish variables difference");
}
}

private List<String> toLines(String toConvert)
{
return toConvert.lines().collect(Collectors.toList());
}

public void setTextLengthDiffThreshold(int textLengthDiffThreshold)
{
this.textLengthDiffThreshold = textLengthDiffThreshold;
}
}
12 changes: 9 additions & 3 deletions vividus/src/main/java/org/vividus/steps/VariablesSteps.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2021 the original author or authors.
* Copyright 2019-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -31,6 +31,7 @@
import org.jbehave.core.model.ExamplesTable;
import org.jbehave.core.steps.Parameters;
import org.vividus.context.VariableContext;
import org.vividus.publishing.DiffAttachmentPublisher;
import org.vividus.reporter.event.IAttachmentPublisher;
import org.vividus.softassert.ISoftAssert;
import org.vividus.util.EnumUtils;
Expand All @@ -48,7 +49,7 @@ public class VariablesSteps
private final VariableComparator variableComparator;

public VariablesSteps(VariableContext variableContext, ISoftAssert softAssert,
IAttachmentPublisher attachmentPublisher)
IAttachmentPublisher attachmentPublisher, DiffAttachmentPublisher diffAttachmentPublisher)
{
this.variableContext = variableContext;
this.softAssert = softAssert;
Expand All @@ -60,7 +61,12 @@ protected <T extends Comparable<T>> boolean compareValues(T value1, ComparisonRu
{
String readableCondition = EnumUtils.toHumanReadableForm(condition);
String description = "Checking if \"" + value1 + "\" is " + readableCondition + " \"" + value2 + "\"";
return softAssert.assertThat(description, value1, condition.getComparisonRule(value2));
boolean passed = softAssert.assertThat(description, value1, condition.getComparisonRule(value2));
if (!passed)
{
diffAttachmentPublisher.publishDiff(value1, value2);
}
return passed;
}

@Override
Expand Down
4 changes: 4 additions & 0 deletions vividus/src/main/resources/org/vividus/spring-steps.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@
<bean id="fileSteps" class="org.vividus.steps.FileSteps" />
<bean id="setupSteps" class="org.vividus.steps.SetupSteps" />

<bean class="org.vividus.publishing.DiffAttachmentPublisher">
<property name="textLengthDiffThreshold" value="${report.text-length-diff-threshold}" />
</bean>

<util:list id="stepBeanNames-Vividus">
<idref bean="assertSteps" />
<idref bean="variablesSteps" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,5 @@ template-processor.resolve-bdd-variables=false

statistics.folder=${output.directory}/statistics
statistics.print-failures=false

report.text-length-diff-threshold=100
47 changes: 47 additions & 0 deletions vividus/src/main/resources/templates/udiff.ftl
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<#ftl output_format="HTML">
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="utf-8" />
<link rel="stylesheet" href="../../webjars/highlight.js.9.12.0/highlight.min.js" />
<link
rel="stylesheet"
type="text/css"
href="../../webjars/diff2html/css/diff2html.min.css"
/>
<script type="text/javascript" src="../../webjars/diff2html/js/diff2html-ui.min.js"></script>
</head>
<script>
document.addEventListener('DOMContentLoaded', function () {
const fileLine = `
<span class="d2h-file-name-wrapper">
{{>fileIcon}}
<span class="d2h-file-name">Expected<=>Actual</span>
{{>fileTag}}
</span>
<label class="d2h-file-collapse">
<input class="d2h-file-collapse-input" type="checkbox" name="viewed" value="viewed">
Viewed
</label>`;
let targetElement = document.getElementById('myDiffElement');
let configuration = {
drawFileList: false,
fileListToggle: false,
fileListStartVisible: false,
fileContentToggle: false,
matching: 'lines',
outputFormat: 'side-by-side',
synchronisedScroll: true,
highlight: true,
renderNothingWhenEmpty: false,
rawTemplates: { "generic-file-path": fileLine, "tag-file-changed": "<span/>"},
};
let diff2htmlUi = new Diff2HtmlUI(targetElement, `${udiff?no_esc}`, configuration);
diff2htmlUi.draw();
diff2htmlUi.highlightCode();
});
</script>
<body>
<div id="myDiffElement"></div>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright 2019-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.vividus.publishing;

import static com.github.valfirst.slf4jtest.LoggingEvent.warn;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

import java.util.List;
import java.util.Map;

import com.github.difflib.DiffUtils;
import com.github.difflib.algorithm.DiffException;
import com.github.valfirst.slf4jtest.TestLogger;
import com.github.valfirst.slf4jtest.TestLoggerFactory;
import com.github.valfirst.slf4jtest.TestLoggerFactoryExtension;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.vividus.reporter.event.AttachmentPublisher;

@ExtendWith({ MockitoExtension.class, TestLoggerFactoryExtension.class })
class DiffAttachmentPublisherTests
{
private static final TestLogger LOGGER = TestLoggerFactory.getTestLogger(DiffAttachmentPublisher.class);

@Mock private AttachmentPublisher attachmentPublisher;

@InjectMocks private DiffAttachmentPublisher diffAttachmentPublisher;

@ParameterizedTest
@CsvSource({ "10, 0, '1\n2\n3', '4\n3\n2\n', '--- variable\n+++ variable\n@@ -1,3 +1,3 @@\n-1\n-2\n+4\n 3\n+2'",
"6, 1, '1\n2\n3', '4\n3\n2\n', '--- variable\n+++ variable\n@@ -1,3 +1,3 @@\n-1\n-2\n+4\n 3\n+2'",
"6, 1, '4\n3\n2\n', '1\n2\n3', '--- variable\n+++ variable\n@@ -1,3 +1,3 @@\n-4\n-3\n+1\n 2\n+3'"
})
void shouldPublishAttachment(int textLengthDiffThreshold, int expectedPublisherInvocations,
String left, String right, String udiff)
{
diffAttachmentPublisher.setTextLengthDiffThreshold(textLengthDiffThreshold);
diffAttachmentPublisher.publishDiff(left, right);
verify(attachmentPublisher, times(expectedPublisherInvocations)).publishAttachment("/templates/udiff.ftl",
Map.of("udiff", udiff), "Comparison result");
}

@Test
void shouldLogExceptionIfAny()
{
DiffException exception = new DiffException();
try (MockedStatic<DiffUtils> diffUtils = Mockito.mockStatic(DiffUtils.class))
{
var strings = List.of();
diffUtils.when(() -> DiffUtils.diff(strings, strings)).thenThrow(exception);
diffAttachmentPublisher.publishDiff("", "");
}
assertEquals(List.of(warn(exception, "Unable to publish variables difference")), LOGGER.getLoggingEvents());
}
}
Loading
0