Apply regular expression matching with JSON Sassert

There is a library called JSONassert that compares JSON in Java, but this time, when comparing JSON with that library, a regular expression is used for value matching. I would like to briefly introduce how to apply it.

Verification version

Use the standard supported method

Use CustomComparator to specify the item for which you want to treat the expected value as a regular expression as shown below.

JSON to be verified


{
  "array": [
    1,
    2
  ],
  "id": 100,
  "type": "foo",
  "object": {
    "name": "Kazuki",
    "token": "ac648657-797e-49f7-9563-150c9b5c2284"
  }
}

JSON that expresses the expected value


{
  "array": [
    1,
    2
  ],
  "id": 100,
  "type": "foo",
  "object": {
    "name": "Kazuki",
    "token": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"
  }
}

The following is an example of specification when comparing ʻobject.token` using a regular expression.

Comparison method call example


JSONAssert.assertEquals(expectedJson.toString(2), actualJson.toString(2),
    new CustomComparator(JSONCompareMode.STRICT,
        new Customization("object.token", new RegularExpressionValueMatcher<>()) //Match using the pattern specified for the expected value
    )
);

You can also specify a pattern during verification as shown below.

Example of specifying a pattern during verification


JSONAssert.assertEquals(expectedJson.toString(2), actualJson.toString(2),
    new CustomComparator(JSONCompareMode.STRICT,
        new Customization("object.token", new RegularExpressionValueMatcher<>("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}")) //Matching using the pattern specified here without using the value described in the expected value JSON
    )
);

Match all items with regular expressions

In the standard feature, regular expression application is item-by-item (as far as I know) (maybe wildcard-like specification of paths is supported !?). So ... I'd like to create my own JSONComparator that can match all items using regular expressions without using CustomComparator.

Example of creating JSONComparator


public class RegularExpressionComparator extends DefaultComparator {

  private static final RegularExpressionValueMatcher<Object> REGEX_VALUE_MATCHER = new RegularExpressionValueMatcher<>();

  private final ValueMatcher<Object> matcher;

  public RegularExpressionComparator(JSONCompareMode mode) {
    super(mode);
    //Adopt a method of comparing once with an exact match, and in the case of NG, falling back to matching with a regular expression
    //Most items can be exact matches, which can reduce processing costs compared to unconditionally matching with regular expressions (should).
    this.matcher = (actual, expected) -> Objects.equals(actual, expected) ||
        expected instanceof String && REGEX_VALUE_MATCHER.equal(actual, expected);
  }

  @Override
  public void compareValues(String prefix, Object expectedValue, Object actualValue, JSONCompareResult result) throws JSONException {
    if (actualValue instanceof JSONArray || actualValue instanceof JSONObject) {
      //container(Object + array)If it is an object, transfer it to the default implementation
      super.compareValues(prefix, expectedValue, actualValue, result);
    } else {
      //For values (strings, numbers, booleans), call the regular expression support ValueMatcher to compare
      try {
        if (!matcher.equal(actualValue, expectedValue)) {
          //Error handling when it is judged that there is a mismatch when it is not matched by regular expression
          result.fail(prefix, expectedValue, actualValue);
        }
      } catch (ValueMatcherException e) {
        //Error handling when a regular expression matching determines a mismatch
        result.fail(prefix, e);
      }
    }
  }

}

Test case created for verification

For reference, I will also paste the test case created at the time of verification.

package com.example.assertdemo;

import java.util.Objects;
import java.util.UUID;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.junit.Test;
import org.skyscreamer.jsonassert.JSONAssert;
import org.skyscreamer.jsonassert.JSONCompareMode;
import org.skyscreamer.jsonassert.JSONCompareResult;
import org.skyscreamer.jsonassert.RegularExpressionValueMatcher;
import org.skyscreamer.jsonassert.ValueMatcher;
import org.skyscreamer.jsonassert.ValueMatcherException;
import org.skyscreamer.jsonassert.comparator.DefaultComparator;

public class JSONAssertRegexTests {

  @Test
  public void regexAssert() throws JSONException {

    JSONObject expectedJson = new JSONObject();
    {
      JSONArray array = new JSONArray();
      array.put(1);
      array.put(2);
      JSONObject object = new JSONObject();
      object.put("name", "Kazuki");
      object.put("token", "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}");
      expectedJson.put("id", 100);
      expectedJson.put("type", "foo");
      expectedJson.put("array", array);
      expectedJson.put("object", object);
      System.out.println("-----expectedJson------");
      System.out.println(expectedJson.toString(2));
    }

    JSONObject actualJson = new JSONObject();
    {
      JSONArray array = new JSONArray();
      array.put(1);
      array.put(2);
      actualJson.put("id", 100);
      actualJson.put("array", array);
      JSONObject object = new JSONObject();
      object.put("name", "Kazuki");
      object.put("token", UUID.randomUUID().toString());
      actualJson.put("id", 100);
      actualJson.put("type", "foo");
      actualJson.put("array", array);
      actualJson.put("object", object);
      System.out.println("-----actualJson------");
      System.out.println(actualJson.toString(2));
    }

    JSONAssert.assertEquals(expectedJson.toString(2),
        actualJson.toString(2),
        new RegularExpressionComparator(JSONCompareMode.STRICT));

  }

  public static class RegularExpressionComparator extends DefaultComparator {

    private static final RegularExpressionValueMatcher<Object> REGEX_VALUE_MATCHER = new RegularExpressionValueMatcher<>();

    private final ValueMatcher<Object> matcher;

    public RegularExpressionComparator(JSONCompareMode mode) {
      super(mode);
      this.matcher = (actual, expected) -> Objects.equals(actual, expected) ||
          expected instanceof String && REGEX_VALUE_MATCHER.equal(actual, expected);
    }

    @Override
    public void compareValues(String prefix, Object expectedValue, Object actualValue, JSONCompareResult result) throws JSONException {
      if (actualValue instanceof JSONArray || actualValue instanceof JSONObject) {
        super.compareValues(prefix, expectedValue, actualValue, result);
      } else {
        try {
          if (!matcher.equal(actualValue, expectedValue)) {
            result.fail(prefix, expectedValue, actualValue);
          }
        } catch (ValueMatcherException e) {
          result.fail(prefix, e);
        }
      }
    }

  }

}

Summary

There is no problem with the standard function alone, but I wanted an implementation that "matches all items with regular expressions" ...- JSON expected when verifying the response BODY of the Web API Is prepared as a file, and in order to adopt a mechanism that compares the actual response data with the JSON read from the expected value file, use CustomComparator in each test case to set the target item. I thought it would be (a little) difficult to specify, and I wanted to be able to apply it automatically by specifying a regular expression in the expected value file.

Reference site

Recommended Posts

Apply regular expression matching with JSON Sassert
Diffed with JSON
Regular expression basics
JS regular expression
Ruby regular expression
/ Mask delimited user ID / password password with regular expression
Import JSON with SolrJ
JSON validation with JSON schema
Handle JSON with minimal-json
^, $ in Rails regular expression
unicode regular expression sample
Regular expression for password
Format JSON with org.json
java regular expression summary
Extract a string starting with a capital letter with a regular expression (Ruby)