/* * Copyright 2019-2020 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.bdd.steps; import static com.github.valfirst.slf4jtest.LoggingEvent.error; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.util.List; import java.util.Optional; 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.Mockito; import org.mockito.junit.jupiter.MockitoExtension; import org.vividus.bdd.expression.IExpressionProcessor; import org.vividus.bdd.expression.StringsExpressionProcessor; import org.vividus.util.ILocationProvider; @ExtendWith({ MockitoExtension.class, TestLoggerFactoryExtension.class }) class ExpressionAdapterTests { private static final String EXPRESSION_FORMAT = "#{%s}"; private static final String EXPRESSION_KEYWORD = "target"; private static final String EXPRESSION_KEYWORD_WITH_SEPARATOR = "tar\nget"; private static final String EXPRESSION_RESULT = "target result with \\ and $"; private static final String UNSUPPORTED_EXPRESSION_KEYWORD = "unsupported"; private static final String UNSUPPORTED_EXPRESSION = String.format(EXPRESSION_FORMAT, UNSUPPORTED_EXPRESSION_KEYWORD); private final TestLogger logger = TestLoggerFactory.getTestLogger(ExpressionAdaptor.class); @Mock private IExpressionProcessor mockedTargetProcessor; @Mock private IExpressionProcessor mockedAnotherProcessor; @InjectMocks private ExpressionAdaptor expressionAdaptor; @ParameterizedTest @CsvSource({ "'target', '#{target}', %s, " + EXPRESSION_RESULT, "'target', '{#{target}}', {%s}, " + EXPRESSION_RESULT, "'target', '{#{target} and #{target}}', {%1$s and %1$s}," + EXPRESSION_RESULT, "'target(})', '#{target(})}', %s, " + EXPRESSION_RESULT, "'tar\nget', '#{tar\nget}', %s, " + EXPRESSION_RESULT, "'expr(value{1})', '#{expr(#{expr(#{expr(value{1})})})}', %s, value{1}" }) void testSupportedExpression(String expressionKeyword, String input, String outputFormat, String outputValue) { Mockito.lenient().when(mockedTargetProcessor.execute(EXPRESSION_KEYWORD)) .thenReturn(Optional.of(EXPRESSION_RESULT)); expressionAdaptor.setProcessors(List.of(mockedTargetProcessor, mockedAnotherProcessor)); when(mockedTargetProcessor.execute(expressionKeyword)).thenReturn(Optional.of(outputValue)); String actual = expressionAdaptor.process(input); String output = String.format(outputFormat, outputValue); assertEquals(output, actual); } @Test void testSupportedExpressionNestedExpr() { String input = "#{capitalize(#{trim(#{toLowerCase( VIVIDUS )})})}"; String output = "Vividus"; ILocationProvider locationProvider = mock(ILocationProvider.class); IExpressionProcessor processor = new StringsExpressionProcessor(locationProvider); expressionAdaptor.setProcessors(List.of(processor)); String actual = expressionAdaptor.process(input); assertEquals(output, actual); } @Test void testUnsupportedExpression() { when(mockedAnotherProcessor.execute(UNSUPPORTED_EXPRESSION_KEYWORD)).thenReturn(Optional.empty()); when(mockedTargetProcessor.execute(UNSUPPORTED_EXPRESSION_KEYWORD)).thenReturn(Optional.empty()); expressionAdaptor.setProcessors(List.of(mockedTargetProcessor, mockedAnotherProcessor)); String actual = expressionAdaptor.process(UNSUPPORTED_EXPRESSION); assertEquals(UNSUPPORTED_EXPRESSION, actual, "Unsupported expression, should leave as is"); verify(mockedTargetProcessor, times(2)).execute(UNSUPPORTED_EXPRESSION_KEYWORD); verify(mockedAnotherProcessor, times(2)).execute(UNSUPPORTED_EXPRESSION_KEYWORD); } @ParameterizedTest @CsvSource({"${var}", "'#expr'", "{expr}", "value"}) void testNonExpression(String nonExpression) { String actual = expressionAdaptor.process(nonExpression); assertEquals(nonExpression, actual, "Not expression, should leave as is"); verify(mockedTargetProcessor, never()).execute(nonExpression); verify(mockedAnotherProcessor, never()).execute(nonExpression); } @Test void testValuesInExampleTable() { when(mockedTargetProcessor.execute(EXPRESSION_KEYWORD)).thenReturn(Optional.of(EXPRESSION_RESULT)); when(mockedTargetProcessor.execute(EXPRESSION_KEYWORD_WITH_SEPARATOR)) .thenReturn(Optional.of(EXPRESSION_RESULT)); expressionAdaptor.setProcessors(List.of(mockedTargetProcessor, mockedAnotherProcessor)); String header = "|value1|value2|value3|value4|\n"; String inputTable = header + "|#{target}|simple|#{target}|#{tar\nget}|\n|#{target (something inside#$)}|simple" + "|#{target}|#{tar\nget}|"; String expectedTable = header + "|target result with \\ and $|simple|target result with \\ and $|target result" + " with \\ and $|\n|target result with \\ and $|simple|target result with \\ and $|target result with" + " \\ and $|"; when(mockedTargetProcessor.execute("target (something inside#$)")) .thenReturn(Optional.of(EXPRESSION_RESULT)); String actualTable = expressionAdaptor.process(inputTable); assertEquals(expectedTable, actualTable); verify(mockedTargetProcessor, times(6)).execute(anyString()); } @Test void testUnsupportedValuesInExampleTable() { when(mockedAnotherProcessor.execute(UNSUPPORTED_EXPRESSION_KEYWORD)).thenReturn(Optional.empty()); when(mockedTargetProcessor.execute(UNSUPPORTED_EXPRESSION_KEYWORD)).thenReturn(Optional.empty()); expressionAdaptor.setProcessors(List.of(mockedTargetProcessor, mockedAnotherProcessor)); String inputTable = "|value1|value2|value3|\n|#{unsupported}|simple|#{unsupported}|"; String actualTable = expressionAdaptor.process(inputTable); assertEquals(inputTable, actualTable); } @Test void testMixedValuesInExampleTable() { when(mockedAnotherProcessor.execute(UNSUPPORTED_EXPRESSION_KEYWORD)).thenReturn(Optional.empty()); when(mockedTargetProcessor.execute(UNSUPPORTED_EXPRESSION_KEYWORD)).thenReturn(Optional.empty()); when(mockedTargetProcessor.execute(EXPRESSION_KEYWORD)).thenReturn(Optional.of(EXPRESSION_RESULT)); when(mockedTargetProcessor.execute(EXPRESSION_KEYWORD_WITH_SEPARATOR)) .thenReturn(Optional.of(EXPRESSION_RESULT)); expressionAdaptor.setProcessors(List.of(mockedTargetProcessor, mockedAnotherProcessor)); String anotherExpressionKeyword = "another"; when(mockedAnotherProcessor.execute(anotherExpressionKeyword)).thenReturn(Optional.of("another result")); String header = "|value1|value2|value3|value4|value5|\n"; String inputTable = header + "|#{unsupported}|simple|#{target}|#{tar\nget}|#{another}|"; String expectedTable = header + "|#{unsupported}|simple|target result with \\ and $|target result with \\ and" + " $|another result|"; String actualTable = expressionAdaptor.process(inputTable); assertEquals(expectedTable, actualTable); } @Test void testMixedExpressionsAndVariablesInExampleTable() { when(mockedTargetProcessor.execute(EXPRESSION_KEYWORD)).thenReturn(Optional.of(EXPRESSION_RESULT)); expressionAdaptor.setProcessors(List.of(mockedTargetProcessor, mockedAnotherProcessor)); String inputTable = "|value1|value2|\n|#{target}|${variable}|"; String expectedTable = "|value1|value2|\n|target result with \\ and $|${variable}|"; String actualTable = expressionAdaptor.process(inputTable); assertEquals(expectedTable, actualTable); } @Test void testExpressionProcessingError() { String input = "#{generateLocalized(number.number_between 'a','b', ru)}"; ILocationProvider locationProvider = mock(ILocationProvider.class); IExpressionProcessor processor = new StringsExpressionProcessor(locationProvider); expressionAdaptor.setProcessors(List.of(processor)); assertThrows(RuntimeException.class, () -> expressionAdaptor.process(input)); assertThat(logger.getLoggingEvents(), is(List.of(error("Unable to process expression '{}'", input)))); } }