1 /***
2 * Redistribution and use of this software and associated documentation
3 * ("Software"), with or without modification, are permitted provided
4 * that the following conditions are met:
5 *
6 * 1. Redistributions of source code must retain copyright
7 * statements and notices. Redistributions must also contain a
8 * copy of this document.
9 *
10 * 2. Redistributions in binary form must reproduce the
11 * above copyright notice, this list of conditions and the
12 * following disclaimer in the documentation and/or other
13 * materials provided with the distribution.
14 *
15 * 3. The name "Exolab" must not be used to endorse or promote
16 * products derived from this Software without prior written
17 * permission of Exoffice Technologies. For written permission,
18 * please contact tma@netspace.net.au.
19 *
20 * 4. Products derived from this Software may not be called "Exolab"
21 * nor may "Exolab" appear in their names without prior written
22 * permission of Exoffice Technologies. Exolab is a registered
23 * trademark of Exoffice Technologies.
24 *
25 * 5. Due credit should be given to the Exolab Project
26 * (http://www.exolab.org/).
27 *
28 * THIS SOFTWARE IS PROVIDED BY EXOFFICE TECHNOLOGIES AND CONTRIBUTORS
29 * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
30 * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
31 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
32 * EXOFFICE TECHNOLOGIES OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
33 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
34 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
35 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
37 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
39 * OF THE POSSIBILITY OF SUCH DAMAGE.
40 *
41 * Copyright 2001-2004 (C) Exoffice Technologies Inc. All Rights Reserved.
42 *
43 * $Id: StreamMessageTest.java,v 1.7 2004/02/03 21:52:10 tanderson Exp $
44 */
45 package org.exolab.jmscts.test.message.stream;
46
47 import java.util.Arrays;
48
49 import javax.jms.MessageEOFException;
50 import javax.jms.MessageFormatException;
51 import javax.jms.StreamMessage;
52
53 import junit.framework.Test;
54
55 import org.exolab.jmscts.core.AbstractMessageTestCase;
56 import org.exolab.jmscts.core.ClassHelper;
57 import org.exolab.jmscts.core.MessagePopulator;
58 import org.exolab.jmscts.core.TestContext;
59 import org.exolab.jmscts.core.TestCreator;
60 import org.exolab.jmscts.test.message.util.Conversions;
61 import org.exolab.jmscts.test.message.util.MessageValues;
62
63
64 /***
65 * This class tests the <code>StreamMessage</code> message type
66 *
67 * @author <a href="mailto:tma@netspace.net.au">Tim Anderson</a>
68 * @version $Revision: 1.7 $
69 * @see javax.jms.StreamMessage
70 * @jmscts.message StreamMessage
71 */
72 public class StreamMessageTest extends AbstractMessageTestCase
73 implements MessageValues {
74
75 /***
76 * Values to test conversions against. String conversions are handled
77 * separately, by the {@link #STRING_CONVERSION_VALUES} attribute
78 */
79 private static final Object[][] CONVERSION_VALUES = {
80 BOOLEANS, BYTES, SHORTS, CHARS, INTS, LONGS, FLOATS, DOUBLES,
81 BYTE_ARRAYS};
82
83 /***
84 * Float values to test string conversions against. String conversions
85 * don't have to support NaN, or +-Infinity, hence the reason they are not
86 * included here
87 */
88 private static final Float[] FLOAT_CONVERSION_VALUES = {
89 new Float(Float.MIN_VALUE), new Float(Float.MAX_VALUE)};
90
91 /***
92 * Double values to test string conversions against. String conversions
93 * don't have to support NaN, or +-Infinity, hence the reason they are not
94 * included here
95 */
96 private static final Double[] DOUBLE_CONVERSION_VALUES = {
97 new Double(Double.MIN_VALUE), new Double(Double.MAX_VALUE)};
98
99 /***
100 * Values to test string conversions against
101 */
102 private static final Object[][] STRING_CONVERSION_VALUES = {
103 BOOLEANS, BYTES, SHORTS, INTS, LONGS, FLOAT_CONVERSION_VALUES,
104 DOUBLE_CONVERSION_VALUES, STRINGS};
105
106 /***
107 * Create an instance of this class for a specific test case
108 *
109 * @param name the name of test case
110 */
111 public StreamMessageTest(String name) {
112 super(name);
113 }
114
115 /***
116 * Sets up the test suite
117 *
118 * @return an instance of this class that may be run by
119 * {@link org.exolab.jmscts.core.JMSTestRunner}
120 */
121 public static Test suite() {
122 return TestCreator.createMessageTest(StreamMessageTest.class);
123 }
124
125 /***
126 * Get the message populator. This implementation always returns null
127 *
128 * @return null
129 */
130 public MessagePopulator getMessagePopulator() {
131 return null;
132 }
133
134 /***
135 * Verifies that if a read method throws MessageFormatException
136 * the current position of the read pointer is not
137 * incremented, and that a subsequent read is capable of recovering from
138 * the exception by re-reading the data as a different type.
139 *
140 * @jmscts.requirement message.stream.read
141 * @throws Exception for any error
142 */
143 public void testReadFailure() throws Exception {
144 TestContext context = getContext();
145 StreamMessage message = (StreamMessage) context.getMessage();
146
147 for (int i = 0; i < ALL_VALUES.length; ++i) {
148 for (int j = 0; j < ALL_VALUES[i].length; ++j) {
149 Object value = ALL_VALUES[i][j];
150 write(message, value);
151 message.reset();
152 Class type = value.getClass();
153 Class[] invalid = Conversions.getInvalidConversions(type);
154 for (int k = 0; k < invalid.length; ++k) {
155 try {
156 read(message, invalid[k]);
157 fail("Expected MessageFormatException to be thrown "
158 + "when reading type="
159 + ClassHelper.getPrimitiveName(invalid[k])
160 + " for type="
161 + ClassHelper.getPrimitiveName(type));
162 } catch (MessageFormatException expected) {
163 // the expected behaviour
164 } catch (Exception exception) {
165 fail("Expected MessageFormatException to be thrown "
166 + "when reading type="
167 + ClassHelper.getPrimitiveName(invalid[k])
168 + " for type="
169 + ClassHelper.getPrimitiveName(type)
170 + ", but got exception="
171 + exception.getClass().getName() + ", message="
172 + exception.getMessage());
173 }
174 }
175 if (value instanceof byte[]) {
176 byte[] v = (byte[]) value;
177 byte[] buffer = new byte[v.length];
178 assertEquals(v.length, message.readBytes(buffer));
179 assertTrue(Arrays.equals(v, buffer));
180 assertEquals(-1, message.readBytes(buffer));
181 } else {
182 Object result = read(message, type);
183 assertEquals(value, result);
184 }
185 message.clearBody();
186 }
187 }
188 }
189
190 /***
191 * Verifies valid conversions for all types except String
192 * (this is handled by testStringConversion()).
193 *
194 * @jmscts.requirement message.stream.conversion
195 * @throws Exception for any error
196 */
197 public void testConversion() throws Exception {
198 TestContext context = getContext();
199 StreamMessage message = (StreamMessage) context.getMessage();
200
201 for (int i = 0; i < CONVERSION_VALUES.length; ++i) {
202 for (int j = 0; j < CONVERSION_VALUES[i].length; ++j) {
203 Object value = CONVERSION_VALUES[i][j];
204 write(message, value);
205 Class type = value.getClass();
206 Class[] valid = Conversions.getValidConversions(type);
207 for (int k = 0; k < valid.length; ++k) {
208 message.reset();
209 Object result = read(message, valid[k]);
210 Object converted = Conversions.convert(value, valid[k]);
211 if (converted instanceof byte[]) {
212 // byte arrays cannot be converted
213 if (!Arrays.equals((byte[]) result,
214 (byte[]) converted)) {
215 fail("Read byte array different to that written");
216 }
217 } else {
218 assertEquals(
219 "Conversion of type="
220 + ClassHelper.getPrimitiveName(type) + " to type="
221 + ClassHelper.getPrimitiveName(valid[k])
222 + " failed.", converted, result);
223 }
224 }
225 message.clearBody();
226 }
227 }
228 }
229
230 /***
231 * Verifies valid string conversions.
232 *
233 * @jmscts.requirement message.stream.conversion
234 * @throws Exception for any error
235 */
236 public void testStringConversion() throws Exception {
237 TestContext context = getContext();
238 StreamMessage message = (StreamMessage) context.getMessage();
239
240 for (int i = 0; i < STRING_CONVERSION_VALUES.length; ++i) {
241 for (int j = 0; j < STRING_CONVERSION_VALUES[i].length; ++j) {
242 Object value = STRING_CONVERSION_VALUES[i][j];
243 write(message, value.toString());
244 Class type = value.getClass();
245 message.reset();
246 Object result = read(message, type);
247 if (!value.equals(result)) {
248 fail("Conversion of type=String to type="
249 + ClassHelper.getPrimitiveName(type)
250 + " failed. Expected value=" + value
251 + ", but got value=" + result);
252 }
253 message.clearBody();
254 }
255 }
256 }
257
258 /***
259 * Verifies invalid string to numeric conversions.
260 *
261 * @jmscts.requirement message.stream.conversion
262 * @throws Exception for any error
263 */
264 public void testInvalidNumericConversion() throws Exception {
265 TestContext context = getContext();
266 StreamMessage message = (StreamMessage) context.getMessage();
267 Class[] numerics = {Byte.class, Short.class, Integer.class, Long.class,
268 Float.class, Double.class};
269 String[] invalidNos = {"a", "0x00", "NaN", "-Infinity", "+Infinity"};
270 for (int i = 0; i < invalidNos.length; ++i) {
271 String value = invalidNos[i];
272 message.writeString(value);
273 message.reset();
274 for (int j = 0; j < numerics.length; ++j) {
275 try {
276 read(message, numerics[j]);
277 fail("Expected NumberFormatException to be thrown when "
278 + "reading value=" + value + " as type="
279 + ClassHelper.getPrimitiveName(numerics[j]));
280 } catch (NumberFormatException expected) {
281 // the expected behaviour
282 } catch (Exception exception) {
283 fail("Expected NumberFormatException to be thrown when "
284 + "reading value=" + value + " as type="
285 + ClassHelper.getPrimitiveName(numerics[j])
286 + ", but got exception="
287 + exception.getClass().getName() + ", message="
288 + exception.getMessage());
289 }
290 }
291 String result = message.readString();
292 assertEquals(value, result);
293 message.clearBody();
294 }
295 }
296
297 /***
298 * Verifies null conversions.
299 *
300 * @jmscts.requirement message.stream.null
301 * @throws Exception for any error
302 */
303 public void testNull() throws Exception {
304 TestContext context = getContext();
305 StreamMessage message = (StreamMessage) context.getMessage();
306
307 try {
308 message.writeObject(null);
309 } catch (Exception exception) {
310 fail("Failed to write a null value to StreamMessage, exception="
311 + exception.getClass().getName() + ", message="
312 + exception.getMessage());
313 }
314 message.reset();
315 Object result = readNull(message, Boolean.class, null);
316 assertEquals(Boolean.FALSE, result);
317 message.reset();
318
319 result = readNull(message, String.class, null);
320 assertEquals(null, result);
321 message.reset();
322
323 byte[] tmp = new byte[0];
324 assertEquals(-1, message.readBytes(tmp));
325 message.reset();
326
327 // no need to call reset() for the following - the message should
328 // do it.
329 readNull(message, Byte.class, NumberFormatException.class);
330 readNull(message, Short.class, NumberFormatException.class);
331 readNull(message, Character.class, NullPointerException.class);
332 readNull(message, Integer.class, NumberFormatException.class);
333 readNull(message, Long.class, NumberFormatException.class);
334 readNull(message, Float.class, NullPointerException.class);
335 readNull(message, Double.class, NullPointerException.class);
336 }
337
338 /***
339 * Verifies that writeObject() can handle all supported types
340 *
341 * @jmscts.requirement message.bytes.method.writeObject
342 * @throws Exception for any error
343 */
344 public void testWriteObject() throws Exception {
345 TestContext context = getContext();
346 StreamMessage message = (StreamMessage) context.getMessage();
347
348 for (int i = 0; i < ALL_VALUES.length; ++i) {
349 for (int j = 0; j < ALL_VALUES[i].length; ++j) {
350 message.writeObject(ALL_VALUES[i][j]);
351 }
352 }
353 message.reset();
354 for (int i = 0; i < ALL_VALUES.length; ++i) {
355 for (int j = 0; j < ALL_VALUES[i].length; ++j) {
356 Object value = message.readObject();
357 if (ALL_VALUES[i][j] instanceof byte[]) {
358 byte[] source = (byte[]) ALL_VALUES[i][j];
359 byte[] result = (byte[]) value;
360 assertTrue(Arrays.equals(source, result));
361 } else {
362 assertEquals(ALL_VALUES[i][j], value);
363 }
364 }
365 }
366 }
367
368 /***
369 * Verifies that an invalid object being written using the writeObject()
370 * method throws <code>MessageFormatException</code>
371 *
372 * @jmscts.requirement message.stream.method.writeObject
373 * @throws Exception for any error
374 */
375 public void testInvalidObject() throws Exception {
376 TestContext context = getContext();
377 StreamMessage message = (StreamMessage) context.getMessage();
378
379 try {
380 message.writeObject(new java.math.BigDecimal(0.0));
381 fail("StreamMessage.writeObject() should only support "
382 + "objectified primitives");
383 } catch (MessageFormatException expected) {
384 // the expected behaviour
385 }
386 }
387
388 /***
389 * Verifies that readBytes returns that written by the writeBytes
390 * methods.
391 *
392 * @jmscts.requirement message.stream.method.writeBytes(1)
393 * @jmscts.requirement message.stream.method.writeBytes(2)
394 * @throws Exception for any error
395 */
396 public void testReadWriteBytes() throws Exception {
397 final int dataSize = 256;
398 TestContext context = getContext();
399 StreamMessage message = (StreamMessage) context.getMessage();
400
401 byte[] bytes = populateByteArray(dataSize, 0);
402 message.writeBytes(bytes);
403 message.reset();
404 byte[] buffer1 = new byte[bytes.length];
405 message.readBytes(buffer1);
406 if (!Arrays.equals(bytes, buffer1)) {
407 fail("Read byte array differs to that written");
408 }
409 int count = message.readBytes(buffer1);
410 if (count != -1) {
411 fail("Expected readBytes to return count=-1 to indicate end of "
412 + "array field, but returned count=" + count);
413
414 }
415
416 message.clearBody();
417 message.writeBytes(bytes, 1, bytes.length - 2);
418 message.reset();
419 byte[] expected = populateByteArray(bytes.length - 2, 1);
420 byte[] buffer2 = new byte[expected.length];
421 message.readBytes(buffer2);
422 if (!Arrays.equals(expected, buffer2)) {
423 fail("Read byte array differs to that written");
424 }
425 count = message.readBytes(buffer2);
426 if (count != -1) {
427 fail("Expected readBytes to return count=-1 to indicate end of "
428 + "array field, but returned count=" + count);
429 }
430 }
431
432 /***
433 * Verifies that invoking readBytes() followed by reset() followed by
434 * readBytes() returns the expected result, when the
435 * first readBytes() call has not completed reading the array field. This
436 * verifies that reset() correctly resets the state of the message.
437 *
438 * @jmscts.requirement message.stream.method.readBytes
439 * @throws Exception for any error
440 */
441 public void testReadBytesReset1() throws Exception {
442 final int dataSize = 256;
443 TestContext context = getContext();
444 StreamMessage message = (StreamMessage) context.getMessage();
445
446 byte[] bytes = populateByteArray(dataSize, 0);
447 message.writeBytes(bytes);
448 message.reset();
449 byte[] buffer = new byte[bytes.length];
450 message.readBytes(buffer);
451 if (!Arrays.equals(bytes, buffer)) {
452 fail("Read byte array differs to that written");
453 }
454
455 message.reset();
456 // NOTE: readBytes() had not completed reading the array field
457
458 message.readBytes(buffer);
459 if (!Arrays.equals(bytes, buffer)) {
460 fail("Read byte array differs to that written");
461 }
462 }
463
464 /***
465 * Verifies that invoking readBytes() followed by reset() followed by
466 * readObject() returns the expected result, when the readBytes() call has
467 * not completed reading the array field. This verifies that reset()
468 * correctly resets the state of the message.
469 *
470 * @jmscts.requirement message.stream.method.readBytes
471 * @throws Exception for any error
472 */
473 public void testReadBytesReset2() throws Exception {
474 final int dataSize = 256;
475 TestContext context = getContext();
476 StreamMessage message = (StreamMessage) context.getMessage();
477
478 byte[] bytes = populateByteArray(dataSize, 0);
479 message.writeBytes(bytes);
480 message.reset();
481 byte[] buffer = new byte[bytes.length];
482 message.readBytes(buffer);
483 if (!Arrays.equals(bytes, buffer)) {
484 fail("Read byte array differs to that written");
485 }
486
487 message.reset();
488 // NOTE: readBytes() had not completed reading the array field
489
490 byte[] result = (byte[]) message.readObject();
491 if (!Arrays.equals(bytes, buffer)) {
492 fail("Read byte array differs to that written");
493 }
494 }
495
496 /***
497 * Verifies that invoking readBytes() followed by clearBody() followed by
498 * readBytes() returns the expected result, when the
499 * first readBytes() call has not completed reading the array field. This
500 * verifies that clearBody() correctly clears the state of the message.
501 *
502 * @jmscts.requirement message.stream.method.readBytes
503 * @throws Exception for any error
504 */
505 public void testReadBytesClearBody1() throws Exception {
506 final int dataSize = 256;
507 TestContext context = getContext();
508 StreamMessage message = (StreamMessage) context.getMessage();
509
510 byte[] bytes = populateByteArray(dataSize, 0);
511 message.writeBytes(bytes);
512 message.reset();
513 byte[] buffer = new byte[bytes.length];
514 message.readBytes(buffer);
515 if (!Arrays.equals(bytes, buffer)) {
516 fail("Read byte array differs to that written");
517 }
518
519 message.clearBody();
520 // NOTE: readBytes() had not completed reading the array field
521
522 bytes = populateByteArray(dataSize, 1);
523 message.writeBytes(bytes);
524 message.reset();
525 message.readBytes(buffer);
526 if (!Arrays.equals(bytes, buffer)) {
527 fail("Read byte array differs to that written");
528 }
529 }
530
531 /***
532 * Verifies that invoking readBytes() followed by clearBody() followed by
533 * readObject() returns the expected result, when the readBytes() call has
534 * not completed reading the array field. This ensures that clearBody()
535 * correctly clears the state of the message.
536 *
537 * @jmscts.requirement message.stream.method.readBytes
538 * @throws Exception for any error
539 */
540 public void testReadBytesClearBody2() throws Exception {
541 final int dataSize = 256;
542 TestContext context = getContext();
543 StreamMessage message = (StreamMessage) context.getMessage();
544
545 byte[] bytes = populateByteArray(dataSize, 0);
546 message.writeBytes(bytes);
547 message.reset();
548 byte[] buffer = new byte[bytes.length];
549 message.readBytes(buffer);
550 if (!Arrays.equals(bytes, buffer)) {
551 fail("Read byte array differs to that written");
552 }
553
554 message.clearBody();
555 // NOTE: readBytes() had not completed reading the array field
556
557 bytes = populateByteArray(dataSize, 1);
558 message.writeBytes(bytes);
559 message.reset();
560 byte[] result = (byte[]) message.readObject();
561 if (!Arrays.equals(bytes, result)) {
562 fail("Read byte array differs to that written");
563 }
564 }
565
566 /***
567 * Verifies that invoking writeBytes does not modify the source array
568 *
569 * @jmscts.requirement message.stream.method.writeBytes(1)
570 * @jmscts.requirement message.stream.method.writeBytes(2)
571 * @throws Exception for any error
572 */
573 public void testWriteBytes() throws Exception {
574 final int dataSize = 256;
575 TestContext context = getContext();
576 StreamMessage message = (StreamMessage) context.getMessage();
577
578 byte[] bytes = populateByteArray(dataSize, 0);
579 byte[] copy = populateByteArray(bytes.length, 0);
580 message.writeBytes(bytes);
581 message.reset();
582 byte[] buffer = new byte[bytes.length];
583 message.readBytes(buffer);
584 if (!Arrays.equals(bytes, copy)) {
585 fail("writeBytes(byte[]) modified the source byte array");
586 }
587
588 message.clearBody();
589 message.writeBytes(bytes, 0, bytes.length);
590 message.reset();
591 message.readBytes(buffer);
592 if (!Arrays.equals(bytes, copy)) {
593 fail("writeBytes(byte[], int, int) modified the source byte "
594 + "array");
595 }
596 }
597
598 /***
599 * Verifies that readBytes can read an entire byte array, and returns -1
600 * on the subsequent call.
601 *
602 * @jmscts.requirement message.stream.method.readBytes
603 * @throws Exception for any error
604 */
605 public void testFullReadBytes() throws Exception {
606 final int dataSize = 256;
607 TestContext context = getContext();
608 StreamMessage message = (StreamMessage) context.getMessage();
609
610 byte[] bytes = populateByteArray(dataSize, 0);
611 message.writeBytes(bytes);
612 message.reset();
613
614 byte[] buffer = new byte[bytes.length];
615 int count = message.readBytes(buffer);
616 if (count != buffer.length) {
617 fail("Expected readBytes to return count=" + buffer.length
618 + ", but returned count=" + count);
619 }
620 if (!Arrays.equals(bytes, buffer)) {
621 fail("Read byte array differs to that written");
622 }
623 count = message.readBytes(buffer);
624 if (count != -1) {
625 fail("Expected readBytes to return count=-1 to indicate end of "
626 + "array field, but returned count=" + count);
627 }
628 }
629
630 /***
631 * Verifies that readBytes can read be invoked incrementally.
632 *
633 * @jmscts.requirement message.stream.method.readBytes
634 * @throws Exception for any error
635 */
636 public void testIncrementalReadBytes() throws Exception {
637 final int chunkSize = 64;
638 final int remainder = (chunkSize / 2);
639 final int chunks = 8; // the number of chunks to read. The last chunk
640 // is only half full
641 final int size = (chunks - 1) * chunkSize + remainder;
642 // the size of the byte array. The result will be read back
643 // incrementally, with the last read only filling a portion of the
644 // buffer
645
646 TestContext context = getContext();
647 StreamMessage message = (StreamMessage) context.getMessage();
648
649 byte[] bytes = populateByteArray(size, 0);
650 message.writeBytes(bytes);
651 message.reset();
652
653 byte[][] buffers = new byte[chunks][chunkSize];
654 int total = 0;
655 int count = 0;
656 for (int i = 0; i < chunks; ++i) {
657 count = message.readBytes(buffers[i]);
658 total += count;
659 int expected = (i < chunks - 1) ? chunkSize : remainder;
660 if (count != expected) {
661 fail("Expected readBytes to return count=" + expected
662 + ", but returned count=" + count);
663 }
664 }
665
666 // concatenate the buffers together, and check that the read array
667 // matches that written
668 byte[] read = new byte[size];
669 for (int i = 0; i < chunks; ++i) {
670 int length = (i < chunks - 1) ? chunkSize : remainder;
671 System.arraycopy(buffers[i], 0, read, i * chunkSize, length);
672 }
673 if (!Arrays.equals(bytes, read)) {
674 fail("Byte array read differs to that written");
675 }
676
677 // verify that MessageEOFException is thrown
678 try {
679 count = message.readBytes(buffers[0]);
680 fail("Expected readBytes to throw MessageEOFException, but "
681 + " returned count=" + count);
682 } catch (MessageEOFException expected) {
683 // the expected behaviour
684 } catch (Exception exception) {
685 fail("Expected MessageFormatException to be thrown, but got "
686 + "exception=" + exception.getClass().getName()
687 + ", message=" + exception.getMessage());
688 }
689 }
690
691 /***
692 * Verifies that invoking any read method when a partial byte array has
693 * been read throws <code>MessageFormatException</code>.
694 *
695 * @jmscts.requirement message.stream.method.readBytes
696 * @throws Exception for any error
697 */
698 public void testPartialReadBytes() throws Exception {
699 final int dataSize = 256;
700 TestContext context = getContext();
701 StreamMessage message = (StreamMessage) context.getMessage();
702
703 byte[] bytes = populateByteArray(dataSize, 0);
704 message.writeBytes(bytes);
705 message.reset();
706 byte[] buffer = new byte[bytes.length];
707 // read the entire byte array, but don't invoke a second time to
708 // complete the read
709 int size = message.readBytes(buffer);
710 if (size != buffer.length) {
711 fail("Expected readBytes() to return count=" + buffer.length
712 + ", but returned count=" + size);
713 }
714 if (!Arrays.equals(bytes, buffer)) {
715 fail("Byte array read differs to that written");
716 }
717
718 Class[] types = {Boolean.class, Byte.class, Short.class,
719 Character.class, Integer.class, Long.class,
720 Float.class, Double.class, String.class,
721 Object.class};
722 for (int i = 0; i < types.length; ++i) {
723 try {
724 read(message, types[i]);
725 fail("Expected MessageFormatException to be thrown when "
726 + "reading type=" + ClassHelper.getPrimitiveName(types[i])
727 + " after an incomplete read of a byte array");
728 } catch (MessageFormatException expected) {
729 // the expected behaviour
730 } catch (Exception exception) {
731 fail("Expected MessageFormatException to be thrown when "
732 + "reading type=" + ClassHelper.getPrimitiveName(types[i])
733 + " after an incomplete read of a byte array, but got "
734 + "exception=" + exception.getClass().getName()
735 + ", message=" + exception.getMessage());
736 }
737 }
738 assertEquals(-1, message.readBytes(buffer));
739 }
740
741 /***
742 * Write an object using the appropriate write<Object>() method
743 *
744 * @param message the message to write to
745 * @param value the value to write
746 * @throws Exception for any error
747 */
748 private void write(StreamMessage message, Object value) throws Exception {
749 if (value instanceof Boolean) {
750 message.writeBoolean(((Boolean) value).booleanValue());
751 } else if (value instanceof Byte) {
752 message.writeByte(((Byte) value).byteValue());
753 } else if (value instanceof Short) {
754 message.writeShort(((Short) value).shortValue());
755 } else if (value instanceof Character) {
756 message.writeChar(((Character) value).charValue());
757 } else if (value instanceof Integer) {
758 message.writeInt(((Integer) value).intValue());
759 } else if (value instanceof Long) {
760 message.writeLong(((Long) value).longValue());
761 } else if (value instanceof Float) {
762 message.writeFloat(((Float) value).floatValue());
763 } else if (value instanceof Double) {
764 message.writeDouble(((Double) value).doubleValue());
765 } else if (value instanceof String) {
766 message.writeString((String) value);
767 } else if (value instanceof byte[]) {
768 message.writeBytes((byte[]) value);
769 } else {
770 // let the message deal with the exception
771 message.writeObject(value);
772 }
773 }
774
775 /***
776 * Read an object of the specified type
777 *
778 * @param message the message to read from
779 * @param type the type of the object to read
780 * @return the read object
781 * @throws Exception for any error
782 */
783 private Object read(StreamMessage message, Class type) throws Exception {
784 final int dataSize = 256;
785 Object result = null;
786 if (type.equals(Boolean.class)) {
787 result = new Boolean(message.readBoolean());
788 } else if (type.equals(Byte.class)) {
789 result = new Byte(message.readByte());
790 } else if (type.equals(Short.class)) {
791 result = new Short(message.readShort());
792 } else if (type.equals(Character.class)) {
793 result = new Character(message.readChar());
794 } else if (type.equals(Integer.class)) {
795 result = new Integer(message.readInt());
796 } else if (type.equals(Long.class)) {
797 result = new Long(message.readLong());
798 } else if (type.equals(Float.class)) {
799 result = new Float(message.readFloat());
800 } else if (type.equals(Double.class)) {
801 result = new Double(message.readDouble());
802 } else if (type.equals(String.class)) {
803 result = message.readString();
804 } else if (type.equals(byte[].class)) {
805 byte[] bytes = null;
806 byte[] buffer = new byte[dataSize];
807 int length = buffer.length;
808 while (length == buffer.length) {
809 length = message.readBytes(buffer);
810 // not particularly efficient, but for our purposes it doesn't
811 // matter
812
813 if (length != -1) {
814 int size = (bytes != null) ? bytes.length : 0;
815 size += length;
816 if (bytes == null) {
817 bytes = new byte[size];
818 System.arraycopy(buffer, 0, bytes, 0, size);
819 } else {
820 byte[] tmp = new byte[size];
821 System.arraycopy(bytes, 0, tmp, 0, bytes.length);
822 System.arraycopy(buffer, 0, tmp, bytes.length, length);
823 System.arraycopy(tmp, 0, bytes, 0, size);
824 bytes = tmp;
825 }
826 }
827 }
828 result = bytes;
829 } else if (type.equals(Object.class)) {
830 result = message.readObject();
831 }
832 return result;
833 }
834
835 /***
836 * Attempt to read a <code>null</code> as a particular type
837 *
838 * @param message the message to read from
839 * @param type the type to read
840 * @param exceptionType the expected exception type, or <code>null</code>
841 * if no exception is epxected
842 * @return the read object
843 * @throws Exception for any error
844 */
845 private Object readNull(StreamMessage message, Class type,
846 Class exceptionType) throws Exception {
847 Object result = null;
848 try {
849 result = read(message, type);
850 if (exceptionType != null) {
851 fail("Expected exception, type=" + exceptionType.getName()
852 + " to be thrown when reading null as type="
853 + ClassHelper.getPrimitiveName(type));
854 }
855 } catch (Exception exception) {
856 if (exceptionType == null) {
857 fail("Did not expect exception to be thrown when reading "
858 + "null as type=" + ClassHelper.getPrimitiveName(type)
859 + " but got exception=" + exception.getClass().getName()
860 + ", message=" + exception.getMessage());
861 } else if (!exceptionType.isAssignableFrom(exception.getClass())) {
862 fail("Expected exception, type=" + exceptionType.getName()
863 + " to be thrown when reading null as type="
864 + ClassHelper.getPrimitiveName(type) + ", but got "
865 + "exception=" + exception.getClass().getName()
866 + ", message=" + exception.getMessage());
867 }
868 }
869 return result;
870 }
871
872 /***
873 * Helper to return a byte array of the specified length, populated with
874 * an incrementing sequence of values
875 *
876 * @param length the length of the array
877 * @param start the number to start the sequence at
878 * @return a new byte array
879 */
880 private byte[] populateByteArray(int length, int start) {
881 byte[] result = new byte[length];
882 byte j = (byte) start;
883 for (int i = 0; i < length; ++i, ++j) {
884 result[i] = j;
885 }
886 return result;
887 }
888
889 }
This page was automatically generated by Maven