com.facebook.buck.testutil.JsonMatcher.java Source code

Java tutorial

Introduction

Here is the source code for com.facebook.buck.testutil.JsonMatcher.java

Source

/*
 * Copyright 2016-present Facebook, Inc.
 *
 * 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
 *
 *     http://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 com.facebook.buck.testutil;

import com.facebook.buck.util.ObjectMappers;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Sets;

import org.hamcrest.Description;
import org.hamcrest.TypeSafeDiagnosingMatcher;

import java.io.IOException;
import java.util.HashSet;

public class JsonMatcher extends TypeSafeDiagnosingMatcher<String> {

    private String expectedJson;
    private static final ObjectMapper MAPPER = ObjectMappers.newDefaultInstance();

    public JsonMatcher(String json) {
        this.expectedJson = json;
    }

    @Override
    protected boolean matchesSafely(String actualJson, Description description) {
        try {
            JsonFactory factory = MAPPER.getFactory();
            JsonParser jsonParser = factory.createParser(String.format(expectedJson));
            JsonNode expectedObject = MAPPER.readTree(jsonParser);
            jsonParser = factory.createParser(actualJson);
            JsonNode actualObject = MAPPER.readTree(jsonParser);

            if (!matchJsonObjects("/", expectedObject, actualObject, description)) {
                description.appendText(String.format(" in <%s>", actualJson));
                return false;
            }
        } catch (IOException e) {
            description.appendText(
                    String.format("could not parse the following into a json object: <%s>", actualJson));
            return false;
        }
        return true;
    }

    /**
     * Static method which tries to match 2 JsonNode objects recursively.
     *
     * @param path:        Path to start matching the objects from.
     * @param expected:    First JsonNode.
     * @param actual:      Second JsonNode.
     * @param description: The Description to be appended to.
     * @return true if the 2 objects match, false otherwise.
     */
    private static boolean matchJsonObjects(String path, JsonNode expected, JsonNode actual,
            Description description) {
        if (expected != null && actual != null && expected.isObject()) {
            if (!actual.isObject()) {
                description.appendText(String.format("the JsonNodeType is not OBJECT at path [%s]", path));
                return false;
            }
            HashSet<String> expectedFields = Sets.newHashSet(expected.fieldNames());
            HashSet<String> actualFields = Sets.newHashSet(actual.fieldNames());

            for (String field : expectedFields) {
                if (!actualFields.contains(field)) {
                    description.appendText(String.format("expecting field [%s] at path [%s]", field, path));
                    return false;
                }
                if (!matchJsonObjects(path + "/" + field, expected.get(field), actual.get(field), description)) {
                    return false;
                }
            }
            if (!Sets.newHashSet().equals(Sets.difference(actualFields, expectedFields))) {
                description.appendText(String.format("found unexpected fields %s at path [%s]",
                        Sets.difference(actualFields, expectedFields).toString(), path));
                return false;
            }
        }
        if (!expected.equals(actual)) {
            description.appendText(String.format("mismatch at path [%s]", path));
            return false;
        }
        return true;
    }

    @Override
    public void describeTo(Description description) {
        description.appendText(String.format("Json string: <%s>", expectedJson));
    }

}