All Downloads are FREE. Search and download functionalities are using the official Maven repository.

pl.pragmatists.concordion.rest.ExpectedJsonResponseCommand Maven / Gradle / Ivy

package pl.pragmatists.concordion.rest;

import java.io.StringReader;
import java.util.Map.Entry;

import org.apache.commons.lang3.StringUtils;
import org.concordion.api.AbstractCommand;
import org.concordion.api.CommandCall;
import org.concordion.api.Element;
import org.concordion.api.Evaluator;
import org.concordion.api.Result;
import org.concordion.api.ResultRecorder;
import org.concordion.api.listener.AssertEqualsListener;
import org.concordion.api.listener.AssertFailureEvent;
import org.concordion.api.listener.AssertSuccessEvent;
import org.concordion.internal.util.Announcer;

import pl.pragmatists.concordion.rest.util.JsonPrettyPrinter;

import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.google.gson.stream.JsonReader;

public class ExpectedJsonResponseCommand extends AbstractCommand {

    private static class EqualsJsonComparator implements JsonComparator {

        @Override
        public boolean assertEqualsJson(String actual, String expected) {

            JsonElement actualJson = parse(actual);
            JsonElement expectedJson = parse(expected);

            return actualJson.equals(expectedJson);
        }

    }

    private static class IncludesJsonComparator implements JsonComparator {

        @Override
        public boolean assertEqualsJson(String actual, String expected) {

            JsonElement actualJson = parse(actual);
            JsonElement expectedJson = parse(expected);

            return includesJson(actualJson, expectedJson);
        }

        private boolean includesJson(JsonElement actualJson, JsonElement expectedJson) {

            if (expectedJson.isJsonObject()) {

                if (!actualJson.isJsonObject()) {
                    return false;
                }

                for (Entry entry : expectedJson.getAsJsonObject().entrySet()) {

                    String property = entry.getKey();
                    JsonElement expectedValue = entry.getValue();

                    if (!actualJson.getAsJsonObject().has(property)) {
                        return false;
                    }

                    JsonElement actualValue = actualJson.getAsJsonObject().get(property);
                    if (!includesJson(actualValue, expectedValue)) {
                        return false;
                    }
                }

                return true;
            }

            if (expectedJson.isJsonArray()) {

                if (!actualJson.isJsonArray()) {
                    return false;
                }

                outer:
                for (JsonElement expectedItem : expectedJson.getAsJsonArray()) {
                    for (JsonElement candidateItem : actualJson.getAsJsonArray()) {
                        if (includesJson(candidateItem, expectedItem)) {
                            continue outer;
                        }
                    }
                    return false;
                }
                return true;
            }

            return actualJson.equals(expectedJson);

        }

    }

    private interface JsonComparator {

        boolean assertEqualsJson(String actual, String expected);
    }

    private static JsonElement parse(String input) {
        JsonReader reader = new JsonReader(new StringReader(input));
        reader.setLenient(true);
        return new JsonParser().parse(reader);
    }

    private Announcer listeners = Announcer.to(AssertEqualsListener.class);
    
    public ExpectedJsonResponseCommand() {
        listeners.addListener(new RestResultRenderer());
    }

    public void verify(CommandCall commandCall, Evaluator evaluator, ResultRecorder resultRecorder) {

        Element element = commandCall.getElement();
        element.addStyleClass("json");
        
        JsonPrettyPrinter printer = new JsonPrettyPrinter();
        
        String expected = printer.prettyPrint(element.getText());
        element.moveChildrenTo(new Element("tmp"));
        element.appendText(expected);
        
        String mode = modeFrom(element);
        String actual = RequestExecutor.fromEvaluator(evaluator).getBody();
        String prettyActual = printer.prettyPrint(actual);

        if (StringUtils.isEmpty(actual)){
            jsonDoesNotEqual(resultRecorder, element, "(not set)", expected);
            return;
        }
        
        try {
            if (comparator(mode).assertEqualsJson(prettyActual, expected)) {
                jsonEquals(resultRecorder, element);
            } else {
                jsonDoesNotEqual(resultRecorder, element, prettyActual, expected);
            }
        } catch (Exception e) {
            e.printStackTrace();
            jsonError(resultRecorder, element, prettyActual, expected);
        }

    }

    private JsonComparator comparator(String mode) {
        
        if("includes".equals(mode)){
            return new IncludesJsonComparator();
        }

        if("equals".equals(mode)){
            return new EqualsJsonComparator();
        }
        
        throw new IllegalArgumentException("Invalid comparition mode: " + mode);
    }

    private String modeFrom(Element element) {
        String mode = element.getAttributeValue("mode");
        return mode == null ? "includes" : mode;
    }
    
    protected void jsonError(ResultRecorder resultRecorder, Element element, String actual, String expected) {
        resultRecorder.record(Result.FAILURE);
        announceFailure(element, expected, actual);
    }

    protected void jsonDoesNotEqual(ResultRecorder resultRecorder, Element element, String actual, String expected) {
        resultRecorder.record(Result.FAILURE);
        announceFailure(element, expected, actual);
    }

    protected void jsonEquals(ResultRecorder resultRecorder, Element element) {
        resultRecorder.record(Result.SUCCESS);
        announceSuccess(element);
    }

    private void announceSuccess(Element element) {
        listeners.announce().successReported(new AssertSuccessEvent(element));
    }

    private void announceFailure(Element element, String expected, Object actual) {
        listeners.announce().failureReported(new AssertFailureEvent(element, expected, actual));
    }

    
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy