/*
* SoapUI, Copyright (C) 2004-2016 SmartBear Software
*
* Licensed under the EUPL, Version 1.1 or - as soon as they will be approved by the European Commission - subsequent
* versions of the EUPL (the "Licence");
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at:
*
* http://ec.europa.eu/idabc/eupl
*
* Unless required by applicable law or agreed to in writing, software distributed under the Licence is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the Licence for the specific language governing permissions and limitations
* under the Licence.
*/
package com.eviware.soapui.impl.wsdl.teststeps.assertions.json;
import com.eviware.soapui.SoapUI;
import com.eviware.soapui.config.TestAssertionConfig;
import com.eviware.soapui.impl.wsdl.support.HelpUrls;
import com.eviware.soapui.impl.wsdl.teststeps.assertions.basic.XPathContainsAssertion;
import com.eviware.soapui.model.iface.SubmitContext;
import com.eviware.soapui.model.propertyexpansion.PropertyExpander;
import com.eviware.soapui.model.propertyexpansion.PropertyExpansionContext;
import com.eviware.soapui.model.testsuite.Assertable;
import com.eviware.soapui.model.testsuite.AssertionException;
import com.eviware.soapui.model.testsuite.RequestAssertion;
import com.eviware.soapui.model.testsuite.ResponseAssertion;
import com.eviware.soapui.support.JsonPathFacade;
import com.eviware.soapui.support.StringUtils;
import com.eviware.soapui.support.UISupport;
import com.eviware.soapui.support.xml.XmlObjectConfigurationReader;
import junit.framework.Assert;
import junit.framework.ComparisonFailure;
import javax.swing.JTextArea;
import java.util.regex.Pattern;
public class JsonPathContentAssertion extends JsonPathAssertionBase implements RequestAssertion, ResponseAssertion {
public static final String ID = "JsonPath Match";
public static final String LABEL = "JsonPath Match";
public static final String DESCRIPTION = "Uses an JsonPath expression to existence of a node and compares the result to an expected value. Applicable to any property containing JSON.";
private boolean allowWildcards;
/**
* Compares two string for similarity, allows wildcard.
*
* @param expected
* @param real
* @param wildcard
* @throws ComparisonFailure
*/
public static void assertSimilar(String expected, String real, char wildcard) throws ComparisonFailure {
if (!isSimilar(expected, real, wildcard)) {
throw new ComparisonFailure("Not matched", expected, real);
}
}
public static boolean isSimilar(String expected, String real, char wildcard) throws ComparisonFailure {
// expected == wildcard matches all
if (!expected.equals(String.valueOf(wildcard))) {
StringBuilder sb = new StringBuilder();
if (expected.startsWith(String.valueOf(wildcard))) {
sb.append(".*");
}
boolean first = true;
for (String token : expected.split(Pattern.quote(String.valueOf(wildcard)))) {
if (token.isEmpty()) {
continue;
}
if (!first) {
sb.append(".*");
}
first = false;
sb.append(Pattern.quote(token));
}
if (expected.endsWith(String.valueOf(wildcard))) {
sb.append(".*");
}
if (!Pattern.compile(sb.toString(), Pattern.DOTALL).matcher(real).matches()) {
return false;
}
}
return true;
}
public JsonPathContentAssertion(TestAssertionConfig assertionConfig, Assertable assertable) {
super(assertionConfig, assertable);
XmlObjectConfigurationReader reader = new XmlObjectConfigurationReader(getConfiguration());
allowWildcards = reader.readBoolean("allowWildcards", false);
}
public boolean isAllowWildcards() {
return allowWildcards;
}
public void setAllowWildcards(boolean allowWildcards) {
this.allowWildcards = allowWildcards;
setConfiguration(createConfiguration());
}
@Override
public String getHelpURL() {
return HelpUrls.ASSERTION_JSON_CONTENT;
}
@Override
protected XPathContainsAssertion getAssertion() {
return this;
}
@Override
public String getConfigurationDialogTitle() {
return "JSONPath Match Configuration";
}
@Override
public void selectFromCurrent() {
try {
String assertableContent = getAssertable().getAssertableContent();
if (StringUtils.isNullOrEmpty(assertableContent)) {
UISupport.showErrorMessage("Missing content to select from");
return;
}
String pathString = getPathString();
PropertyExpansionContext context = getPropertyExpansionContext();
String expandedPath = PropertyExpander.expandProperties(context, pathString.trim());
JTextArea contentArea = getContentArea();
if (contentArea != null && contentArea.isVisible()) {
contentArea.setText("");
}
String stringValue = readStringValue(assertableContent, expandedPath);
if (stringValue == null) {
UISupport.showErrorMessage("No match in current response");
} else {
if (contentArea != null && contentArea.isVisible()) {
contentArea.setText(stringValue);
} else {
setExpectedContent(stringValue, false);
}
}
} catch (Throwable e) {
UISupport.showErrorMessage("Invalid JsonPath expression.");
SoapUI.logError(e);
}
}
@Override
public String assertContent(String assertableContent, SubmitContext context, String type) throws AssertionException {
try {
if (getPath() == null) {
return "Missing path for JsonPath assertion";
}
if (getExpectedContent() == null) {
return "Missing content for JsonPath assertion";
}
String expandedPath = PropertyExpander.expandProperties(context, getPath());
JsonPathFacade jsonPathFacade = new JsonPathFacade(assertableContent);
String result = jsonPathFacade.readStringValue(expandedPath);
String expandedResult = PropertyExpander.expandProperties(context, result);
String expandedContent = PropertyExpander.expandProperties(context, getExpectedContent());
if (allowWildcards) {
assertSimilar(expandedContent, expandedResult, '*');
} else {
Assert.assertEquals(expandedContent, expandedResult);
}
} catch (Throwable exception) {
throwAssertionException(getPath(), exception);
}
return type + " matches content for [" + getPath() + "]";
}
public static class Factory extends JsonAssertionFactory {
public Factory() {
super(JsonPathContentAssertion.ID, JsonPathContentAssertion.LABEL, JsonPathContentAssertion.DESCRIPTION,
JsonPathContentAssertion.class);
}
}
}