• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.fasterxml.jackson.core;
2 
3 import java.io.*;
4 import java.util.Arrays;
5 
6 import com.fasterxml.jackson.core.testsupport.MockDataInput;
7 import com.fasterxml.jackson.core.testsupport.ThrottledInputStream;
8 
9 import junit.framework.TestCase;
10 
11 @SuppressWarnings("resource")
12 public abstract class BaseTest
13     extends TestCase
14 {
15     protected final static String FIELD_BASENAME = "f";
16 
17     protected final static int MODE_INPUT_STREAM = 0;
18     protected final static int MODE_INPUT_STREAM_THROTTLED = 1;
19     protected final static int MODE_READER = 2;
20     protected final static int MODE_DATA_INPUT = 3;
21 
22     protected final static int[] ALL_MODES = new int[] {
23         MODE_INPUT_STREAM,
24         MODE_INPUT_STREAM_THROTTLED,
25         MODE_READER,
26         MODE_DATA_INPUT
27     };
28 
29     protected final static int[] ALL_BINARY_MODES = new int[] {
30         MODE_INPUT_STREAM,
31         MODE_INPUT_STREAM_THROTTLED,
32         MODE_DATA_INPUT
33     };
34 
35     protected final static int[] ALL_TEXT_MODES = new int[] {
36         MODE_READER
37     };
38 
39     // DataInput not streaming
40     protected final static int[] ALL_STREAMING_MODES = new int[] {
41         MODE_INPUT_STREAM,
42         MODE_INPUT_STREAM_THROTTLED,
43         MODE_READER
44     };
45 
46     /*
47     /**********************************************************
48     /* Some sample documents:
49     /**********************************************************
50      */
51 
52     protected final static int SAMPLE_SPEC_VALUE_WIDTH = 800;
53     protected final static int SAMPLE_SPEC_VALUE_HEIGHT = 600;
54     protected final static String SAMPLE_SPEC_VALUE_TITLE = "View from 15th Floor";
55     protected final static String SAMPLE_SPEC_VALUE_TN_URL = "http://www.example.com/image/481989943";
56     protected final static int SAMPLE_SPEC_VALUE_TN_HEIGHT = 125;
57     protected final static String SAMPLE_SPEC_VALUE_TN_WIDTH = "100";
58     protected final static int SAMPLE_SPEC_VALUE_TN_ID1 = 116;
59     protected final static int SAMPLE_SPEC_VALUE_TN_ID2 = 943;
60     protected final static int SAMPLE_SPEC_VALUE_TN_ID3 = 234;
61     protected final static int SAMPLE_SPEC_VALUE_TN_ID4 = 38793;
62 
63     protected final static String SAMPLE_DOC_JSON_SPEC =
64         "{\n"
65         +"  \"Image\" : {\n"
66         +"    \"Width\" : "+SAMPLE_SPEC_VALUE_WIDTH+",\n"
67         +"    \"Height\" : "+SAMPLE_SPEC_VALUE_HEIGHT+","
68         +"\"Title\" : \""+SAMPLE_SPEC_VALUE_TITLE+"\",\n"
69         +"    \"Thumbnail\" : {\n"
70         +"      \"Url\" : \""+SAMPLE_SPEC_VALUE_TN_URL+"\",\n"
71         +"\"Height\" : "+SAMPLE_SPEC_VALUE_TN_HEIGHT+",\n"
72         +"      \"Width\" : \""+SAMPLE_SPEC_VALUE_TN_WIDTH+"\"\n"
73         +"    },\n"
74         +"    \"IDs\" : ["+SAMPLE_SPEC_VALUE_TN_ID1+","+SAMPLE_SPEC_VALUE_TN_ID2+","+SAMPLE_SPEC_VALUE_TN_ID3+","+SAMPLE_SPEC_VALUE_TN_ID4+"]\n"
75         +"  }"
76         +"}"
77         ;
78 
79     /*
80     /**********************************************************
81     /* Helper classes (beans)
82     /**********************************************************
83      */
84 
85     /**
86      * Sample class from Jackson tutorial ("JacksonInFiveMinutes")
87      */
88     protected static class FiveMinuteUser {
89         public enum Gender { MALE, FEMALE };
90 
91         public static class Name
92         {
93           private String _first, _last;
94 
Name()95           public Name() { }
Name(String f, String l)96           public Name(String f, String l) {
97               _first = f;
98               _last = l;
99           }
100 
getFirst()101           public String getFirst() { return _first; }
getLast()102           public String getLast() { return _last; }
103 
setFirst(String s)104           public void setFirst(String s) { _first = s; }
setLast(String s)105           public void setLast(String s) { _last = s; }
106 
107           @Override
equals(Object o)108           public boolean equals(Object o)
109           {
110               if (o == this) return true;
111               if (o == null || o.getClass() != getClass()) return false;
112               Name other = (Name) o;
113               return _first.equals(other._first) && _last.equals(other._last);
114           }
115         }
116 
117         private Gender _gender;
118         private Name _name;
119         private boolean _isVerified;
120         private byte[] _userImage;
121 
FiveMinuteUser()122         public FiveMinuteUser() { }
123 
FiveMinuteUser(String first, String last, boolean verified, Gender g, byte[] data)124         public FiveMinuteUser(String first, String last, boolean verified, Gender g, byte[] data)
125         {
126             _name = new Name(first, last);
127             _isVerified = verified;
128             _gender = g;
129             _userImage = data;
130         }
131 
getName()132         public Name getName() { return _name; }
isVerified()133         public boolean isVerified() { return _isVerified; }
getGender()134         public Gender getGender() { return _gender; }
getUserImage()135         public byte[] getUserImage() { return _userImage; }
136 
setName(Name n)137         public void setName(Name n) { _name = n; }
setVerified(boolean b)138         public void setVerified(boolean b) { _isVerified = b; }
setGender(Gender g)139         public void setGender(Gender g) { _gender = g; }
setUserImage(byte[] b)140         public void setUserImage(byte[] b) { _userImage = b; }
141 
142         @Override
equals(Object o)143         public boolean equals(Object o)
144         {
145             if (o == this) return true;
146             if (o == null || o.getClass() != getClass()) return false;
147             FiveMinuteUser other = (FiveMinuteUser) o;
148             if (_isVerified != other._isVerified) return false;
149             if (_gender != other._gender) return false;
150             if (!_name.equals(other._name)) return false;
151             byte[] otherImage = other._userImage;
152             if (otherImage.length != _userImage.length) return false;
153             for (int i = 0, len = _userImage.length; i < len; ++i) {
154                 if (_userImage[i] != otherImage[i]) {
155                     return false;
156                 }
157             }
158             return true;
159         }
160     }
161 
162     protected final JsonFactory JSON_FACTORY = new JsonFactory();
163 
164     /*
165     /**********************************************************
166     /* High-level helpers
167     /**********************************************************
168      */
169 
verifyJsonSpecSampleDoc(JsonParser p, boolean verifyContents)170     protected void verifyJsonSpecSampleDoc(JsonParser p, boolean verifyContents)
171         throws IOException
172     {
173         verifyJsonSpecSampleDoc(p, verifyContents, true);
174     }
175 
verifyJsonSpecSampleDoc(JsonParser p, boolean verifyContents, boolean requireNumbers)176     protected void verifyJsonSpecSampleDoc(JsonParser p, boolean verifyContents,
177             boolean requireNumbers)
178         throws IOException
179     {
180         if (!p.hasCurrentToken()) {
181             p.nextToken();
182         }
183         // first basic check, mostly for test coverage
184         assertNull(p.getTypeId());
185         assertNull(p.getObjectId());
186 
187         assertToken(JsonToken.START_OBJECT, p.currentToken()); // main object
188 
189         assertToken(JsonToken.FIELD_NAME, p.nextToken()); // 'Image'
190         if (verifyContents) {
191             verifyFieldName(p, "Image");
192         }
193 
194         assertToken(JsonToken.START_OBJECT, p.nextToken()); // 'image' object
195 
196         assertToken(JsonToken.FIELD_NAME, p.nextToken()); // 'Width'
197         if (verifyContents) {
198             verifyFieldName(p, "Width");
199         }
200 
201         verifyIntToken(p.nextToken(), requireNumbers);
202         if (verifyContents) {
203             verifyIntValue(p, SAMPLE_SPEC_VALUE_WIDTH);
204         }
205 
206         assertToken(JsonToken.FIELD_NAME, p.nextToken()); // 'Height'
207         if (verifyContents) {
208             verifyFieldName(p, "Height");
209         }
210 
211         verifyIntToken(p.nextToken(), requireNumbers);
212         if (verifyContents) {
213             verifyIntValue(p, SAMPLE_SPEC_VALUE_HEIGHT);
214         }
215         assertToken(JsonToken.FIELD_NAME, p.nextToken()); // 'Title'
216         if (verifyContents) {
217             verifyFieldName(p, "Title");
218         }
219         assertToken(JsonToken.VALUE_STRING, p.nextToken());
220         assertEquals(SAMPLE_SPEC_VALUE_TITLE, getAndVerifyText(p));
221         assertToken(JsonToken.FIELD_NAME, p.nextToken()); // 'Thumbnail'
222         if (verifyContents) {
223             verifyFieldName(p, "Thumbnail");
224         }
225 
226         assertToken(JsonToken.START_OBJECT, p.nextToken()); // 'thumbnail' object
227         assertToken(JsonToken.FIELD_NAME, p.nextToken()); // 'Url'
228         if (verifyContents) {
229             verifyFieldName(p, "Url");
230         }
231         assertToken(JsonToken.VALUE_STRING, p.nextToken());
232         if (verifyContents) {
233             assertEquals(SAMPLE_SPEC_VALUE_TN_URL, getAndVerifyText(p));
234         }
235         assertToken(JsonToken.FIELD_NAME, p.nextToken()); // 'Height'
236         if (verifyContents) {
237             verifyFieldName(p, "Height");
238         }
239         verifyIntToken(p.nextToken(), requireNumbers);
240         if (verifyContents) {
241             verifyIntValue(p, SAMPLE_SPEC_VALUE_TN_HEIGHT);
242         }
243         assertToken(JsonToken.FIELD_NAME, p.nextToken()); // 'Width'
244         if (verifyContents) {
245             verifyFieldName(p, "Width");
246         }
247         // Width value is actually a String in the example
248         assertToken(JsonToken.VALUE_STRING, p.nextToken());
249         if (verifyContents) {
250             assertEquals(SAMPLE_SPEC_VALUE_TN_WIDTH, getAndVerifyText(p));
251         }
252 
253         assertToken(JsonToken.END_OBJECT, p.nextToken()); // 'thumbnail' object
254         assertToken(JsonToken.FIELD_NAME, p.nextToken()); // 'IDs'
255         assertToken(JsonToken.START_ARRAY, p.nextToken()); // 'ids' array
256         verifyIntToken(p.nextToken(), requireNumbers); // ids[0]
257         if (verifyContents) {
258             verifyIntValue(p, SAMPLE_SPEC_VALUE_TN_ID1);
259         }
260         verifyIntToken(p.nextToken(), requireNumbers); // ids[1]
261         if (verifyContents) {
262             verifyIntValue(p, SAMPLE_SPEC_VALUE_TN_ID2);
263         }
264         verifyIntToken(p.nextToken(), requireNumbers); // ids[2]
265         if (verifyContents) {
266             verifyIntValue(p, SAMPLE_SPEC_VALUE_TN_ID3);
267         }
268         verifyIntToken(p.nextToken(), requireNumbers); // ids[3]
269         if (verifyContents) {
270             verifyIntValue(p, SAMPLE_SPEC_VALUE_TN_ID4);
271         }
272         assertToken(JsonToken.END_ARRAY, p.nextToken()); // 'ids' array
273 
274         assertToken(JsonToken.END_OBJECT, p.nextToken()); // 'image' object
275 
276         assertToken(JsonToken.END_OBJECT, p.nextToken()); // main object
277     }
278 
verifyIntToken(JsonToken t, boolean requireNumbers)279     private void verifyIntToken(JsonToken t, boolean requireNumbers)
280     {
281         if (t == JsonToken.VALUE_NUMBER_INT) {
282             return;
283         }
284         if (requireNumbers) { // to get error
285             assertToken(JsonToken.VALUE_NUMBER_INT, t);
286         }
287         // if not number, must be String
288         if (t != JsonToken.VALUE_STRING) {
289             fail("Expected INT or STRING value, got "+t);
290         }
291     }
292 
verifyFieldName(JsonParser p, String expName)293     protected void verifyFieldName(JsonParser p, String expName)
294         throws IOException
295     {
296         assertEquals(expName, p.getText());
297         assertEquals(expName, p.getCurrentName());
298     }
299 
verifyIntValue(JsonParser p, long expValue)300     protected void verifyIntValue(JsonParser p, long expValue)
301         throws IOException
302     {
303         // First, via textual
304         assertEquals(String.valueOf(expValue), p.getText());
305     }
306 
307     /*
308     /**********************************************************
309     /* Parser construction
310     /**********************************************************
311      */
312 
createParser(int mode, String doc)313     protected JsonParser createParser(int mode, String doc) throws IOException {
314         return createParser(JSON_FACTORY, mode, doc);
315     }
316 
createParser(int mode, byte[] doc)317     protected JsonParser createParser(int mode, byte[] doc) throws IOException {
318         return createParser(JSON_FACTORY, mode, doc);
319     }
320 
createParser(JsonFactory f, int mode, String doc)321     protected JsonParser createParser(JsonFactory f, int mode, String doc) throws IOException
322     {
323         switch (mode) {
324         case MODE_INPUT_STREAM:
325             return createParserUsingStream(f, doc, "UTF-8");
326         case MODE_INPUT_STREAM_THROTTLED:
327             {
328                 InputStream in = new ThrottledInputStream(doc.getBytes("UTF-8"), 1);
329                 return f.createParser(in);
330             }
331         case MODE_READER:
332             return createParserUsingReader(f, doc);
333         case MODE_DATA_INPUT:
334             return createParserForDataInput(f, new MockDataInput(doc));
335         default:
336         }
337         throw new RuntimeException("internal error");
338     }
339 
createParser(JsonFactory f, int mode, byte[] doc)340     protected JsonParser createParser(JsonFactory f, int mode, byte[] doc) throws IOException
341     {
342         switch (mode) {
343         case MODE_INPUT_STREAM:
344             return f.createParser(new ByteArrayInputStream(doc));
345         case MODE_INPUT_STREAM_THROTTLED:
346             {
347                 InputStream in = new ThrottledInputStream(doc, 1);
348                 return f.createParser(in);
349             }
350         case MODE_READER:
351             return f.createParser(new StringReader(new String(doc, "UTF-8")));
352         case MODE_DATA_INPUT:
353             return createParserForDataInput(f, new MockDataInput(doc));
354         default:
355         }
356         throw new RuntimeException("internal error");
357     }
358 
createParserUsingReader(String input)359     protected JsonParser createParserUsingReader(String input) throws IOException
360     {
361         return createParserUsingReader(new JsonFactory(), input);
362     }
363 
createParserUsingReader(JsonFactory f, String input)364     protected JsonParser createParserUsingReader(JsonFactory f, String input)
365         throws IOException
366     {
367         return f.createParser(new StringReader(input));
368     }
369 
createParserUsingStream(String input, String encoding)370     protected JsonParser createParserUsingStream(String input, String encoding)
371         throws IOException
372     {
373         return createParserUsingStream(new JsonFactory(), input, encoding);
374     }
375 
createParserUsingStream(JsonFactory f, String input, String encoding)376     protected JsonParser createParserUsingStream(JsonFactory f,
377             String input, String encoding)
378         throws IOException
379     {
380 
381         /* 23-Apr-2008, tatus: UTF-32 is not supported by JDK, have to
382          *   use our own codec too (which is not optimal since there's
383          *   a chance both encoder and decoder might have bugs, but ones
384          *   that cancel each other out or such)
385          */
386         byte[] data;
387         if (encoding.equalsIgnoreCase("UTF-32")) {
388             data = encodeInUTF32BE(input);
389         } else {
390             data = input.getBytes(encoding);
391         }
392         InputStream is = new ByteArrayInputStream(data);
393         return f.createParser(is);
394     }
395 
createParserForDataInput(JsonFactory f, DataInput input)396     protected JsonParser createParserForDataInput(JsonFactory f,
397             DataInput input)
398         throws IOException
399     {
400         return f.createParser(input);
401     }
402 
403     /*
404     /**********************************************************
405     /* Generator construction
406     /**********************************************************
407      */
408 
createGenerator(OutputStream out)409     protected JsonGenerator createGenerator(OutputStream out) throws IOException {
410         return createGenerator(JSON_FACTORY, out);
411     }
412 
createGenerator(TokenStreamFactory f, OutputStream out)413     protected JsonGenerator createGenerator(TokenStreamFactory f, OutputStream out) throws IOException {
414         return f.createGenerator(out);
415     }
416 
createGenerator(Writer w)417     protected JsonGenerator createGenerator(Writer w) throws IOException {
418         return createGenerator(JSON_FACTORY, w);
419     }
420 
createGenerator(TokenStreamFactory f, Writer w)421     protected JsonGenerator createGenerator(TokenStreamFactory f, Writer w) throws IOException {
422         return f.createGenerator(w);
423     }
424 
425     /*
426     /**********************************************************
427     /* Helper read/write methods
428     /**********************************************************
429      */
430 
writeJsonDoc(JsonFactory f, String doc, Writer w)431     protected void writeJsonDoc(JsonFactory f, String doc, Writer w) throws IOException
432     {
433         writeJsonDoc(f, doc, f.createGenerator(w));
434     }
435 
writeJsonDoc(JsonFactory f, String doc, JsonGenerator g)436     protected void writeJsonDoc(JsonFactory f, String doc, JsonGenerator g) throws IOException
437     {
438         JsonParser p = f.createParser(aposToQuotes(doc));
439 
440         while (p.nextToken() != null) {
441             g.copyCurrentStructure(p);
442         }
443         p.close();
444         g.close();
445     }
446 
readAndWrite(JsonFactory f, JsonParser p)447     protected String readAndWrite(JsonFactory f, JsonParser p) throws IOException
448     {
449         StringWriter sw = new StringWriter(100);
450         JsonGenerator g = f.createGenerator(sw);
451         g.disable(JsonGenerator.Feature.AUTO_CLOSE_JSON_CONTENT);
452         try {
453             while (p.nextToken() != null) {
454                 g.copyCurrentEvent(p);
455             }
456         } catch (IOException e) {
457             g.flush();
458             fail("Unexpected problem during `readAndWrite`. Output so far: '"+sw+"'; problem: "+e);
459         }
460         p.close();
461         g.close();
462         return sw.toString();
463     }
464 
465     /*
466     /**********************************************************
467     /* Additional assertion methods
468     /**********************************************************
469      */
470 
assertToken(JsonToken expToken, JsonToken actToken)471     protected void assertToken(JsonToken expToken, JsonToken actToken)
472     {
473         if (actToken != expToken) {
474             fail("Expected token "+expToken+", current token "+actToken);
475         }
476     }
477 
assertToken(JsonToken expToken, JsonParser p)478     protected void assertToken(JsonToken expToken, JsonParser p)
479     {
480         assertToken(expToken, p.currentToken());
481     }
482 
assertType(Object ob, Class<?> expType)483     protected void assertType(Object ob, Class<?> expType)
484     {
485         if (ob == null) {
486             fail("Expected an object of type "+expType.getName()+", got null");
487         }
488         Class<?> cls = ob.getClass();
489         if (!expType.isAssignableFrom(cls)) {
490             fail("Expected type "+expType.getName()+", got "+cls.getName());
491         }
492     }
493 
verifyException(Throwable e, String... matches)494     protected void verifyException(Throwable e, String... matches)
495     {
496         String msg = e.getMessage();
497         String lmsg = (msg == null) ? "" : msg.toLowerCase();
498         for (String match : matches) {
499             String lmatch = match.toLowerCase();
500             if (lmsg.indexOf(lmatch) >= 0) {
501                 return;
502             }
503         }
504         fail("Expected an exception with one of substrings ("+Arrays.asList(matches)+"): got one with message \""+msg+"\"");
505     }
506 
507     /**
508      * Method that gets textual contents of the current token using
509      * available methods, and ensures results are consistent, before
510      * returning them
511      */
getAndVerifyText(JsonParser p)512     protected String getAndVerifyText(JsonParser p) throws IOException
513     {
514         // Ok, let's verify other accessors
515         int actLen = p.getTextLength();
516         char[] ch = p.getTextCharacters();
517         String str2 = new String(ch, p.getTextOffset(), actLen);
518         String str = p.getText();
519 
520         if (str.length() !=  actLen) {
521             fail("Internal problem (p.token == "+p.currentToken()+"): p.getText().length() ['"+str+"'] == "+str.length()+"; p.getTextLength() == "+actLen);
522         }
523         assertEquals("String access via getText(), getTextXxx() must be the same", str, str2);
524 
525         return str;
526     }
527 
528     /*
529     /**********************************************************
530     /* And other helpers
531     /**********************************************************
532      */
533 
quote(String str)534     protected static String quote(String str) {
535         return '"'+str+'"';
536     }
537 
aposToQuotes(String json)538     protected static String aposToQuotes(String json) {
539         return json.replace("'", "\"");
540     }
541 
encodeInUTF32BE(String input)542     protected byte[] encodeInUTF32BE(String input)
543     {
544         int len = input.length();
545         byte[] result = new byte[len * 4];
546         int ptr = 0;
547         for (int i = 0; i < len; ++i, ptr += 4) {
548             char c = input.charAt(i);
549             result[ptr] = result[ptr+1] = (byte) 0;
550             result[ptr+2] = (byte) (c >> 8);
551             result[ptr+3] = (byte) c;
552         }
553         return result;
554     }
555 
556     // @since 2.9.7
utf8Bytes(String str)557     protected static byte[] utf8Bytes(String str) {
558         try {
559             return str.getBytes("UTF-8");
560         } catch (IOException e) {
561             throw new RuntimeException(e);
562         }
563     }
564 
fieldNameFor(StringBuilder sb, int index)565     protected void fieldNameFor(StringBuilder sb, int index)
566     {
567         /* let's do something like "f1.1" to exercise different
568          * field names (important for byte-based codec)
569          * Other name shuffling done mostly just for fun... :)
570          */
571         sb.append(FIELD_BASENAME);
572         sb.append(index);
573         if (index > 50) {
574             sb.append('.');
575             if (index > 200) {
576                 sb.append(index);
577                 if (index > 4000) { // and some even longer symbols...
578                     sb.append(".").append(index);
579                 }
580             } else {
581                 sb.append(index >> 3); // divide by 8
582             }
583         }
584     }
585 
586     // @since 2.9.7
sharedStreamFactory()587     protected JsonFactory sharedStreamFactory() {
588         return JSON_FACTORY;
589     }
590 
591     // @since 2.9.7
newStreamFactory()592     protected JsonFactory newStreamFactory() {
593         return new JsonFactory();
594     }
595 
596     // @since 2.9.8
streamFactoryBuilder()597     protected JsonFactoryBuilder streamFactoryBuilder() {
598         return (JsonFactoryBuilder) JsonFactory.builder();
599     }
600 
fieldNameFor(int index)601     protected String fieldNameFor(int index)
602     {
603         StringBuilder sb = new StringBuilder(16);
604         fieldNameFor(sb, index);
605         return sb.toString();
606     }
607 
calcQuads(byte[] wordBytes)608     protected int[] calcQuads(byte[] wordBytes) {
609         int blen = wordBytes.length;
610         int[] result = new int[(blen + 3) / 4];
611         for (int i = 0; i < blen; ++i) {
612             int x = wordBytes[i] & 0xFF;
613 
614             if (++i < blen) {
615                 x = (x << 8) | (wordBytes[i] & 0xFF);
616                 if (++i < blen) {
617                     x = (x << 8) | (wordBytes[i] & 0xFF);
618                     if (++i < blen) {
619                         x = (x << 8) | (wordBytes[i] & 0xFF);
620                     }
621                 }
622             }
623             result[i >> 2] = x;
624         }
625         return result;
626     }
627 }
628