View Javadoc

1   package uk.co.datumedge.hamcrest.json;
2   
3   import static uk.co.datumedge.hamcrest.json.JSONArrayComparatorFactory.jsonArrayComparison;
4   import static uk.co.datumedge.hamcrest.json.JSONAssertComparator.modalComparatorFor;
5   import static uk.co.datumedge.hamcrest.json.JSONObjectComparatorFactory.jsonObjectComparison;
6   import static uk.co.datumedge.hamcrest.json.StringComparatorFactory.stringComparison;
7   
8   import java.io.PrintWriter;
9   import java.io.StringWriter;
10  
11  import org.hamcrest.Description;
12  import org.hamcrest.Factory;
13  import org.hamcrest.TypeSafeDiagnosingMatcher;
14  import org.json.JSONArray;
15  import org.json.JSONException;
16  import org.json.JSONObject;
17  
18  /**
19   * Matcher that asserts that one JSON document is the same as another.
20   *
21   * @param <T>
22   *            the type of the JSON document. This is typically {@code JSONObject}, {@code JSONArray} or {@code String}.
23   */
24  public final class SameJSONAs<T> extends TypeSafeDiagnosingMatcher<T> {
25  	private final T expected;
26  	private final JSONModalComparator<T> comparator;
27  
28  	public SameJSONAs(T expected, JSONModalComparator<T> comparator) {
29  		this.expected = expected;
30  		this.comparator = comparator;
31  	}
32  
33  	@Override
34  	public void describeTo(Description description) {
35  		description.appendValue(expected.toString());
36  	}
37  
38  	@Override
39  	protected boolean matchesSafely(T actual, Description mismatchDescription) {
40  		try {
41  			JSONComparisonResult result = comparator.compare(expected, actual);
42  			if (result.failed()) {
43  				mismatchDescription.appendDescriptionOf(result);
44  			}
45  			return result.passed();
46  		} catch (JSONException e) {
47  			StringWriter out = new StringWriter();
48  			e.printStackTrace(new PrintWriter(out));
49  			mismatchDescription.appendText(out.toString());
50  			return false;
51  		}
52  	}
53  
54  	/**
55  	 * Creates a matcher that allows any element ordering within JSON arrays. For example,
56  	 * <code>{"fib":[0,1,1,2,3]}</code> will match <code>{"fib":[3,1,0,2,1]}</code>.
57  	 *
58  	 * @return the configured matcher
59  	 */
60  	public SameJSONAs<T> allowingAnyArrayOrdering() {
61  		return new SameJSONAs<T>(expected, comparator.butAllowingAnyArrayOrdering());
62  	}
63  
64  	/**
65  	 * Creates a matcher that allows fields not present in the expected JSON document.  For example, if the expected
66  	 * document is
67  <pre>{
68      "name" : "John Smith",
69      "address" : {
70          "street" : "29 Acacia Road"
71      }
72  }</pre>
73  	 * then the following document will match:
74  <pre>{
75      "name" : "John Smith",
76      "age" : 34,
77      "address" : {
78          "street" : "29 Acacia Road",
79          "city" : "Huddersfield"
80      }
81  }</pre>
82  	 *
83  	 * All array elements must exist in both documents, so the expected document
84  <pre>[
85      { "name" : "John Smith" }
86  ]</pre>
87  	 *  will not match the actual document
88  <pre>[
89      { "name" : "John Smith" },
90      { "name" : "Bob Jones" }
91  ]</pre>
92  	 *
93  	 * @return the configured matcher
94  	 */
95  	public SameJSONAs<T> allowingExtraUnexpectedFields() {
96  		return new SameJSONAs<T>(expected, comparator.butAllowingExtraUnexpectedFields());
97  	}
98  
99  	/**
100 	 * Creates a matcher that compares {@code JSONObject}s.
101 	 *
102 	 * @param expected the expected {@code JSONObject} instance
103 	 * @return the {@code Matcher} instance
104 	 */
105 	@Factory
106 	public static SameJSONAs<JSONObject> sameJSONObjectAs(JSONObject expected) {
107 		return new SameJSONAs<JSONObject>(expected, modalComparatorFor(jsonObjectComparison()));
108 	}
109 
110 	@Factory
111 	public static SameJSONAs<JSONObject> sameJSONObjectAs(JSONObject expected, JSONModalComparator<JSONObject> comparator) {
112 		return new SameJSONAs<JSONObject>(expected, comparator);
113 	}
114 
115 	/**
116 	 * Creates a matcher that compares {@code JSONArray}s.
117 	 *
118 	 * @param expected the expected {@code JSONArray} instance
119 	 * @return the {@code Matcher} instance
120 	 */
121 	@Factory
122 	public static SameJSONAs<JSONArray> sameJSONArrayAs(JSONArray expected) {
123 		return new SameJSONAs<JSONArray>(expected, modalComparatorFor(jsonArrayComparison()));
124 	}
125 
126 	@Factory
127 	public static SameJSONAs<? super JSONArray> sameJSONArrayAs(JSONArray expected, JSONModalComparator<JSONArray> comparator) {
128 		return new SameJSONAs<JSONArray>(expected, comparator);
129 	}
130 
131 	/**
132 	 * Creates a matcher that compares JSONObjects or JSONArrays.
133 	 *
134 	 * @param expected the expected JSON document
135 	 * @return the {@code Matcher} instance
136 	 */
137 	@Factory
138 	public static SameJSONAs<? super String> sameJSONAs(String expected) {
139 		return new SameJSONAs<String>(expected, modalComparatorFor(stringComparison()));
140 	}
141 	
142 	@Factory
143 	public static SameJSONAs<? super String> sameJSONAs(String expected, JSONModalComparator<String> comparator) {
144 		return new SameJSONAs<String>(expected, comparator);
145 	}
146 }