Skip to content

Commit

Permalink
JBEHAVE-1603 Apply transformers from table file at its loading (#80)
Browse files Browse the repository at this point in the history
  • Loading branch information
draker94 authored Nov 5, 2024
1 parent 25c3b96 commit 3a9c82c
Show file tree
Hide file tree
Showing 7 changed files with 149 additions and 58 deletions.
17 changes: 16 additions & 1 deletion distribution/src/site/content/tabular-parameters.html
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ <h2>Using values with line breaks</h2>
</pre>
</p>

<h2>Using table transformers</h2>
<h2 id="transformers">Using table transformers</h2>

<p>
Table transformers allow the table to be transformed via an inlined property. E.g. to transform from a landscape table form we can to use the pre-registered transformer:
Expand Down Expand Up @@ -382,6 +382,21 @@ <h2>Loading tabular parameter from an external resource</h2>
]]>
</script>

<p>If the external tabular parameters contains <a href="#transformers">transformers</a>, they will be applied immediately after the resource is loaded. Consequently, transformers from the current story/scenario will be applied subsequently.</p>
Scenario:
<pre class="brush: bdd">
Then `https://www.url3.com` is equal to `&lt;urls&gt;`
Examples:
{transformer=REPLACING, replacing=url2, replacement=url3}
/data/links.table
</pre>
<b>links.table</b> file:
<pre class="brush: plain">
{transformer=REPLACING, replacing=url1, replacement=url2}
|urls |
|https://www.url1.com |
</pre>

<p>We need to enable theExamplesTable parameter converter to find
the resource with the appropriate resource loader configured via the <a
href="javadoc/core/org/jbehave/core/model/ExamplesTableFactory.html">ExamplesTableFactory</a></p>:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,6 @@ public class ExamplesTable {

private Map<String, String> namedParameters = Collections.emptyMap();
private ParameterControls parameterControls;
private TableTransformerMonitor tableTransformerMonitor;

public ExamplesTable(String tableAsString) {
this(tableAsString, new TableTransformers());
Expand Down Expand Up @@ -195,8 +194,8 @@ private ExamplesTable(String tableAsString, ParameterConverters parameterConvert
this.parameterControls = parameterControls;
this.defaults = new ConvertedParameters(EMPTY_MAP, parameterConverters);
this.tablePropertiesQueue.addAll(tablePropertiesQueue.getProperties());
this.tableTransformerMonitor = tableTransformerMonitor;
String transformedTable = applyTransformers(tableTransformers, tablePropertiesQueue.getTable(), tableParsers);
String transformedTable = TableTransformersExecutor.applyTransformers(tableTransformers,
tablePropertiesQueue.getTable(), tableParsers, this.tablePropertiesQueue, tableTransformerMonitor);
this.tableRows = tableParsers.parseRows(transformedTable, lastTableProperties());
}

Expand All @@ -212,25 +211,6 @@ private ExamplesTable(ExamplesTable other, Row defaults) {
this.defaults = defaults;
}

private String applyTransformers(TableTransformers tableTransformers, String tableAsString,
TableParsers tableParsers) {
String transformedTable = tableAsString;
TableProperties previousProperties = null;
for (TableProperties properties : tablePropertiesQueue) {
String transformer = properties.getTransformer();
if (transformer != null) {
if (previousProperties != null) {
properties.overrideSeparatorsFrom(previousProperties);
}
tableTransformerMonitor.beforeTransformerApplying(transformer, properties, tableAsString);
transformedTable = tableTransformers.transform(transformer, transformedTable, tableParsers, properties);
tableTransformerMonitor.afterTransformerApplying(transformer, properties, transformedTable);
}
previousProperties = properties;
}
return transformedTable;
}

public ExamplesTable withDefaults(Parameters defaults) {
return new ExamplesTable(this, new ChainedRow(defaults, this.defaults));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,14 @@ public ExamplesTable createExamplesTable(String input) {
String loadedTable = resourceLoader.loadResourceAsText(tableAsString.trim());
tablePropertiesQueue = tableParsers.parseProperties(loadedTable);
Deque<TableProperties> target = tablePropertiesQueue.getProperties();

boolean hasTransformers = target.getFirst().getTransformer() != null;
if (hasTransformers) {
loadedTable = TableTransformersExecutor.applyTransformers(tableTransformers,
tablePropertiesQueue.getTable(), tableParsers, target, tableTransformerMonitor);
tablePropertiesQueue = tableParsers.parseProperties(loadedTable);
target = tablePropertiesQueue.getProperties();
}
properties.descendingIterator().forEachRemaining(target::addFirst);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package org.jbehave.core.model;

import static org.jbehave.core.model.ExamplesTable.TableProperties;

import java.util.Deque;

public final class TableTransformersExecutor {

private TableTransformersExecutor() {
}

public static String applyTransformers(TableTransformers tableTransformers, String tableAsString,
TableParsers tableParsers, Deque<TableProperties> tablePropertiesQueue,
TableTransformerMonitor tableTransformerMonitor) {
String transformedTable = tableAsString;
TableProperties previousProperties = null;
for (TableProperties properties : tablePropertiesQueue) {
String transformer = properties.getTransformer();
if (transformer != null) {
if (previousProperties != null) {
properties.overrideSeparatorsFrom(previousProperties);
}
tableTransformerMonitor.beforeTransformerApplying(transformer, properties, transformedTable);
transformedTable = tableTransformers.transform(transformer, transformedTable, tableParsers, properties);
tableTransformerMonitor.afterTransformerApplying(transformer, properties, transformedTable);
}
previousProperties = properties;
}
return transformedTable;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,6 @@
import static org.junit.jupiter.api.Assertions.assertNotSame;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.params.provider.Arguments.arguments;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
Expand Down Expand Up @@ -329,7 +325,7 @@ void shouldParseTableWithSequenceOfTransformers() {
properties.getProperties().setProperty("valueSeparator", "!");
return tableAsString.replace('|', '!');
});
ExamplesTableFactory factory = createFactory(tableTransformers, new NullTableTransformerMonitor());
ExamplesTableFactory factory = createFactory(tableTransformers);
ExamplesTable table = factory.createExamplesTable(tableWithProperties);
Properties properties = table.getProperties();
assertThat(properties.getProperty("transformer"), equalTo("FROM_LANDSCAPE"));
Expand Down Expand Up @@ -705,32 +701,12 @@ void shouldReturnNamedRowFromJaggedTable() {
assertEquals(expected, table.getRow(1));
}

@Test
void shouldUseCustomTableTransformerMonitor() {
String table = "|key|\n|value|";
String transformerName = "ANY_TRANSFORMER";
String propertiesAsString = String.format("transformer=%s, property=any_property", transformerName);

TableTransformers transformers = new TableTransformers();
transformers.useTransformer(transformerName, (input, parser, props) -> input);
TableTransformerMonitor tableTransformerMonitor = mock(TableTransformerMonitor.class);
ExamplesTableFactory factory = createFactory(transformers, tableTransformerMonitor);
factory.createExamplesTable(String.format("{%s}\n%s", propertiesAsString, table));

verify(tableTransformerMonitor).beforeTransformerApplying(eq(transformerName), argThat(
p -> p.getPropertiesAsString().equals(propertiesAsString)), eq(table));
verify(tableTransformerMonitor).afterTransformerApplying(eq(transformerName), argThat(
p -> p.getPropertiesAsString().equals(propertiesAsString)), eq(table));
}

private ExamplesTableFactory createFactory(ParameterConverter... converters) {
TableTransformers tableTransformers = new TableTransformers();
return createFactory(tableTransformers, new NullTableTransformerMonitor(), converters);
return createFactory(tableTransformers, converters);
}

private ExamplesTableFactory createFactory(TableTransformers tableTransformers,
TableTransformerMonitor transformerMonitor,
ParameterConverter... converters) {
private ExamplesTableFactory createFactory(TableTransformers tableTransformers, ParameterConverter... converters) {
LoadFromClasspath resourceLoader = new LoadFromClasspath();
ParameterControls parameterControls = new ParameterControls();
ParameterConverters parameterConverters = new ParameterConverters(resourceLoader, parameterControls,
Expand All @@ -739,7 +715,7 @@ private ExamplesTableFactory createFactory(TableTransformers tableTransformers,
TableParsers tableParsers = new TableParsers(keywords, parameterConverters);
parameterConverters.addConverters(converters);
return new ExamplesTableFactory(keywords, resourceLoader, parameterConverters, parameterControls, tableParsers,
tableTransformers, transformerMonitor);
tableTransformers, new NullTableTransformerMonitor());
}

private void assertTableAsString(String tableAsString, String expectedTableAsString) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,20 +110,36 @@ void shouldCreateExamplesTableFromTableInputWithInlinedSeparatorsHavingSpacesAtS
}

@Test
void shouldTestTransformersOrderForExamplesTableFromResourceInput() {
void shouldLoadAndProperlyApplyTransformersForExamplesTableFromResourceInput() {
// Given
ResourceLoader resourceLoader = mock(ResourceLoader.class);
String lineFromFirstOuterTransformer = "|one|two|";
String lineFromSecondOuterTransformer = "\n|11|12|";
String lineFromFirstInnerTransformer = "\n|13|14|";
String lineFromSecondInnerTransformer = "\n|15|16|\n";
TableTransformers tableTransformers = new TableTransformers();
tableTransformers.useTransformer("CUSTOM_TRANSFORMER1", (input, parser, props) -> input);
tableTransformers.useTransformer("CUSTOM_TRANSFORMER2", (input, parser, props) -> input);
tableTransformers.useTransformer("CUSTOM_TRANSFORMER1", (input, parser, props) ->
input + lineFromFirstOuterTransformer);
tableTransformers.useTransformer("CUSTOM_TRANSFORMER2", (input, parser, props) ->
input + lineFromSecondOuterTransformer);
tableTransformers.useTransformer("CUSTOM_TRANSFORMER3", (input, parser, props) ->
input + lineFromFirstInnerTransformer);
tableTransformers.useTransformer("CUSTOM_TRANSFORMER4", (input, parser, props) ->
input + lineFromSecondInnerTransformer);
ExamplesTableFactory factory = new ExamplesTableFactory(resourceLoader, tableTransformers);
String transformers = "{transformer=CUSTOM_TRANSFORMER1}\n{transformer=CUSTOM_TRANSFORMER2}\n";
String outerTransformers = "{transformer=CUSTOM_TRANSFORMER1}\n{transformer=CUSTOM_TRANSFORMER2}\n";
String innerTransformers = "{transformer=CUSTOM_TRANSFORMER3}\n{transformer=CUSTOM_TRANSFORMER4}\n";

// When
when(resourceLoader.loadResourceAsText(RESOURCE_PATH)).thenReturn(TABLE_AS_STRING);
ExamplesTable examplesTable = factory.createExamplesTable(transformers + RESOURCE_PATH);
when(resourceLoader.loadResourceAsText(RESOURCE_PATH)).thenReturn(outerTransformers);
ExamplesTable examplesTable = factory.createExamplesTable(innerTransformers + RESOURCE_PATH);

// Then
assertThat(examplesTable.asString(), equalTo(transformers + TABLE_AS_STRING));
assertThat(examplesTable.asString(), equalTo(
innerTransformers
+ lineFromFirstOuterTransformer
+ lineFromSecondOuterTransformer
+ lineFromFirstInnerTransformer
+ lineFromSecondInnerTransformer));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package org.jbehave.core.model;

import static org.jbehave.core.model.ExamplesTable.TableProperties;
import static org.jbehave.core.model.ExamplesTable.TablePropertiesQueue;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;

import java.util.Deque;

import org.jbehave.core.i18n.LocalizedKeywords;
import org.jbehave.core.io.LoadFromClasspath;
import org.jbehave.core.steps.ParameterControls;
import org.jbehave.core.steps.ParameterConverters;
import org.junit.jupiter.api.Test;

class TableTransformersExecutorBehaviour {

private static final TableTransformers TRANSFORMERS = new TableTransformers();
private static final ParameterConverters PARAMETER_CONVERTERS = new ParameterConverters(
new LoadFromClasspath(), new ParameterControls(), TRANSFORMERS, true);
private static final TableParsers TABLE_PARSERS = new TableParsers(new LocalizedKeywords(), PARAMETER_CONVERTERS);

@Test
void shouldApplyTransformers() {
String table = "|key|\n!value0!";
String lineFromFirstTransformer = "\n!value1!";
String lineFromSecondTransformer = "\n!value2!";
String tableTransformed = table + lineFromFirstTransformer + lineFromSecondTransformer;
String firstTransformerName = "FIRST_TRANSFORMER";
String firstPropertiesAsString = String.format("transformer=%s, property=any_property1, valueSeparator=!",
firstTransformerName);
String secondTransformerName = "SECOND_TRANSFORMER";
String secondPropertiesAsString = String.format(
"transformer=%s, property=any_property2", secondTransformerName);
TablePropertiesQueue tablePropertiesQueue = TABLE_PARSERS.parseProperties(
"{" + firstPropertiesAsString + "}"
+ "{" + secondPropertiesAsString + "}"
+ "\n"
+ table);
Deque<TableProperties> tableProperties = tablePropertiesQueue.getProperties();


TRANSFORMERS.useTransformer(firstTransformerName, (tableAsString, tableParsers, properties) ->
tableAsString + lineFromFirstTransformer);
TRANSFORMERS.useTransformer(secondTransformerName, (tableAsString, tableParsers, properties) ->
tableAsString + lineFromSecondTransformer);
TableTransformerMonitor tableTransformerMonitor = mock(TableTransformerMonitor.class);
String output = TableTransformersExecutor.applyTransformers(
TRANSFORMERS, table, TABLE_PARSERS, tableProperties, tableTransformerMonitor);

assertEquals(tableTransformed, output);
verify(tableTransformerMonitor).beforeTransformerApplying(eq(firstTransformerName), argThat(
p -> p.getPropertiesAsString().equals(firstPropertiesAsString)), eq(table));
verify(tableTransformerMonitor).afterTransformerApplying(eq(firstTransformerName), argThat(p ->
p.getPropertiesAsString().equals(firstPropertiesAsString)), eq(table + lineFromFirstTransformer));
verify(tableTransformerMonitor).beforeTransformerApplying(eq(secondTransformerName), argThat(p ->
p.getPropertiesAsString().equals(secondPropertiesAsString)), eq(table + lineFromFirstTransformer));
verify(tableTransformerMonitor).afterTransformerApplying(eq(secondTransformerName), argThat(
p -> p.getPropertiesAsString().equals(secondPropertiesAsString)),
eq(table + lineFromFirstTransformer + lineFromSecondTransformer));
}
}

0 comments on commit 3a9c82c

Please sign in to comment.