View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.juneau.examples.rest;
18  
19  import static org.apache.juneau.commons.utils.IoUtils.*;
20  import static org.apache.juneau.commons.utils.StringUtils.*;
21  
22  import java.io.*;
23  import java.util.regex.*;
24  
25  import org.apache.juneau.json.*;
26  import org.apache.juneau.serializer.*;
27  import org.apache.juneau.swaps.*;
28  import org.apache.juneau.xml.*;
29  import org.junit.*;
30  
31  public class TestUtils {
32  
33  	// @formatter:off
34  	private static JsonSerializer js = JsonSerializer.create()
35  		.json5()
36  		.keepNullProperties()
37  		.build();
38  
39  	private static JsonSerializer jsSorted = JsonSerializer.create()
40  		.json5()
41  		.sortCollections()
42  		.sortMaps()
43  		.keepNullProperties()
44  		.build();
45  
46  	private static JsonSerializer js2 = JsonSerializer.create()
47  		.json5()
48  		.swaps(IteratorSwap.class, EnumerationSwap.class)
49  		.build();
50  
51  	private static JsonSerializer js3 = JsonSerializer.create()
52  		.json5()
53  		.swaps(IteratorSwap.class, EnumerationSwap.class)
54  		.sortProperties()
55  		.build();
56  	// @formatter:on
57  
58  	/**
59  	 * Verifies that two objects are equivalent.
60  	 * Does this by doing a string comparison after converting both to JSON.
61  	 */
62  	public static void assertEqualObjects(Object o1, Object o2) throws SerializeException {
63  		assertEqualObjects(o1, o2, false);
64  	}
65  
66  	/**
67  	 * Verifies that two objects are equivalent.
68  	 * Does this by doing a string comparison after converting both to JSON.
69  	 * @param sort If <jk>true</jk> sort maps and collections before comparison.
70  	 */
71  	public static void assertEqualObjects(Object o1, Object o2, boolean sort) throws SerializeException {
72  		var s = (sort ? jsSorted : js);
73  		var s1 = s.serialize(o1);
74  		var s2 = s.serialize(o2);
75  		if (s1.equals(s2))
76  			return;
77  		throw new ComparisonFailure(null, s1, s2);
78  	}
79  
80  	/**
81  	 * Validates that the whitespace is correct in the specified XML.
82  	 */
83  	public static void checkXmlWhitespace(String out) throws SerializeException {
84  		if (out.indexOf('\u0000') != -1) {
85  			for (var s : out.split("\u0000"))
86  				checkXmlWhitespace(s);
87  			return;
88  		}
89  
90  		int indent = -1;
91  		var startTag = Pattern.compile("^(\\s*)<[^/>]+(\\s+\\S+=['\"]\\S*['\"])*\\s*>$");
92  		var endTag = Pattern.compile("^(\\s*)</[^>]+>$");
93  		var combinedTag = Pattern.compile("^(\\s*)<[^>/]+(\\s+\\S+=['\"]\\S*['\"])*\\s*/>$");
94  		var contentOnly = Pattern.compile("^(\\s*)[^\\s\\<]+$");
95  		var tagWithContent = Pattern.compile("^(\\s*)<[^>]+>.*</[^>]+>$");
96  		var lines = out.split("\n");
97  		try {
98  			for (var i = 0; i < lines.length; i++) {
99  				var line = lines[i];
100 				var m = startTag.matcher(line);
101 				if (m.matches()) {
102 					indent++;
103 					if (m.group(1).length() != indent)
104 						throw new SerializeException("Wrong indentation detected on start tag line ''{0}''", i + 1);
105 					continue;
106 				}
107 				m = endTag.matcher(line);
108 				if (m.matches()) {
109 					if (m.group(1).length() != indent)
110 						throw new SerializeException("Wrong indentation detected on end tag line ''{0}''", i + 1);
111 					indent--;
112 					continue;
113 				}
114 				m = combinedTag.matcher(line);
115 				if (m.matches()) {
116 					indent++;
117 					if (m.group(1).length() != indent)
118 						throw new SerializeException("Wrong indentation detected on combined tag line ''{0}''", i + 1);
119 					indent--;
120 					continue;
121 				}
122 				m = contentOnly.matcher(line);
123 				if (m.matches()) {
124 					indent++;
125 					if (m.group(1).length() != indent)
126 						throw new SerializeException("Wrong indentation detected on content-only line ''{0}''", i + 1);
127 					indent--;
128 					continue;
129 				}
130 				m = tagWithContent.matcher(line);
131 				if (m.matches()) {
132 					indent++;
133 					if (m.group(1).length() != indent)
134 						throw new SerializeException("Wrong indentation detected on tag-with-content line ''{0}''", i + 1);
135 					indent--;
136 					continue;
137 				}
138 				throw new SerializeException("Unmatched whitespace line at line number ''{0}''", i + 1);
139 			}
140 			if (indent != -1)
141 				throw new SerializeException("Possible unmatched tag.  indent=''{0}''", indent);
142 		} catch (SerializeException e) {
143 			printLines(lines);
144 			throw e;
145 		}
146 	}
147 
148 	private static void printLines(String[] lines) {
149 		for (var i = 0; i < lines.length; i++)
150 			System.err.println(String.format("%4s:" + lines[i], i + 1));  // NOT DEBUG
151 	}
152 
153 	public static void validateXml(Object o) throws Exception {
154 		validateXml(o, XmlSerializer.DEFAULT_NS_SQ);
155 	}
156 
157 	/**
158 	 * Test whitespace and generated schema.
159 	 */
160 	public static void validateXml(Object o, XmlSerializer s) throws Exception {
161 		s = s.copy().ws().ns().addNamespaceUrisToRoot().build();
162 		var xml = s.serialize(o);
163 
164 		try {
165 			TestUtils.checkXmlWhitespace(xml);
166 		} catch (Exception e) {
167 			System.err.println("---XML---");  // NOT DEBUG
168 			System.err.println(xml);  // NOT DEBUG
169 			throw e;
170 		}
171 	}
172 
173 	public static String readFile(String p) throws Exception {
174 		var is = TestUtils.class.getResourceAsStream(p);
175 		if (is == null) {
176 			is = new FileInputStream(p);
177 		}
178 		try (InputStream is2 = is) {
179 			var e = read(is2);
180 			e = e.replaceAll("\r", "");
181 			return e;
182 		}
183 	}
184 
185 	final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();
186 
187 	public static String toHex(byte b) {
188 		var c = new char[2];
189 		var v = b & 0xFF;
190 		c[0] = hexArray[v >>> 4];
191 		c[1] = hexArray[v & 0x0F];
192 		return new String(c);
193 	}
194 
195 	public static void debugOut(Object o) {
196 		try {
197 			System.err.println(decodeHex(Json5Serializer.DEFAULT.serialize(o)));  // NOT DEBUG
198 		} catch (SerializeException e) {
199 			e.printStackTrace();
200 		}
201 	}
202 
203 	/**
204 	 * Assert that the object equals the specified string after running it through Json5Serializer.DEFAULT.toString().
205 	 */
206 	public static void assertObjectEquals(String s, Object o) {
207 		assertObjectEquals(s, o, js2);
208 	}
209 
210 	/**
211 	 * Assert that the object equals the specified string after running it through Json5Serializer.DEFAULT.toString()
212 	 * with BEAN_sortProperties set to true.
213 	 */
214 	public static void assertSortedObjectEquals(String s, Object o) {
215 		assertObjectEquals(s, o, js3);
216 	}
217 
218 	/**
219 	 * Assert that the object equals the specified string after running it through ws.toString().
220 	 */
221 	public static void assertObjectEquals(String s, Object o, WriterSerializer ws) {
222 		Assert.assertEquals(s, ws.toString(o));
223 	}
224 
225 	/**
226 	 * Replaces all newlines with pipes, then compares the strings.
227 	 */
228 	public static void assertTextEquals(String s, Object o) {
229 		var s2 = o.toString().replaceAll("\\r?\\n", "|");
230 		Assert.assertEquals(s, s2);
231 	}
232 
233 	/**
234 	 * Tries to turn the serialized output to a String.
235 	 * If it's a byte[], convert it to a UTF-8 encoded String.
236 	 */
237 	public static final String toString(Object o) {
238 		if (o == null)
239 			return null;
240 		if (o instanceof String)
241 			return (String)o;
242 		if (o instanceof byte[])
243 			return new String((byte[])o, UTF8);
244 		return o.toString();
245 	}
246 
247 	public static final void assertContains(Object value, String...substrings) {
248 		for (var substring : substrings)
249 			if (! contains(toString(value), substring)) {
250 				System.err.println("Text did not contain expected substring: '" + toString(substring) + "'");  // NOT DEBUG
251 				System.err.println("=== TEXT ===");  // NOT DEBUG
252 				System.err.println(toString(value));  // NOT DEBUG
253 				System.err.println("============");  // NOT DEBUG
254 				throw new ComparisonFailure("Text did not contain expected substring.", toString(substring), toString(value));  // NOT DEBUG
255 			}
256 	}
257 }