Add output stream wrapper that always writes a multiple of a fixed number of bytes.
[sonitus.git] / src / test / java / net / pterodactylus / sonitus / io / IntegralWriteOutputStreamTest.java
1 /*
2  * Sonitus - IntegralWriteOutputStreamTest.java - Copyright © 2013 David Roden
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 package net.pterodactylus.sonitus.io;
19
20 import static org.hamcrest.CoreMatchers.is;
21 import static org.junit.Assert.assertThat;
22 import static org.mockito.Matchers.any;
23 import static org.mockito.Matchers.anyInt;
24 import static org.mockito.Mockito.mock;
25 import static org.mockito.Mockito.never;
26 import static org.mockito.Mockito.times;
27 import static org.mockito.Mockito.verify;
28
29 import java.io.ByteArrayOutputStream;
30 import java.io.IOException;
31 import java.io.OutputStream;
32 import java.util.Random;
33
34 import org.testng.annotations.Test;
35
36 /**
37  * Unit tests for {@link IntegralWriteOutputStream}.
38  *
39  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
40  */
41 public class IntegralWriteOutputStreamTest {
42
43         @Test
44         public void testSingleWritesWithSize2() throws IOException {
45                 OutputStream outputStream = mock(OutputStream.class);
46
47                 IntegralWriteOutputStream integralWriteOutputStream = new IntegralWriteOutputStream(outputStream, 2);
48                 integralWriteOutputStream.write(1);
49                 integralWriteOutputStream.write(2);
50                 integralWriteOutputStream.write(3);
51                 integralWriteOutputStream.write(4);
52                 integralWriteOutputStream.write(5);
53
54                 verify(outputStream, never()).write(anyInt());
55                 verify(outputStream, times(2)).write((byte[]) any());
56         }
57
58         @Test
59         public void testLargeWritesWithSize3() throws IOException {
60                 ByteArrayOutputStream byteArrayOutputStream = getOutputStream(3);
61                 IntegralWriteOutputStream integralWriteOutputStream = new IntegralWriteOutputStream(byteArrayOutputStream, 3);
62
63                 byte[] buffer = generateData(18);
64                 integralWriteOutputStream.write(buffer, 0, 7);
65                 integralWriteOutputStream.write(buffer, 7, 7);
66                 integralWriteOutputStream.write(buffer, 14, 4);
67
68                 assertThat(byteArrayOutputStream.toByteArray(), is(buffer));
69         }
70
71         @Test
72         public void testLargeWritesWithSize4() throws IOException {
73                 ByteArrayOutputStream byteArrayOutputStream = getOutputStream(1024);
74                 IntegralWriteOutputStream integralWriteOutputStream = new IntegralWriteOutputStream(byteArrayOutputStream, 1024);
75
76                 byte[] buffer = generateData(32768);
77                 integralWriteOutputStream.write(buffer, 0, 123);
78                 integralWriteOutputStream.write(buffer, 123, 768);
79                 integralWriteOutputStream.write(buffer, 123 + 768, 6285);
80                 integralWriteOutputStream.write(buffer, 123 + 768 + 6285, 1234);
81                 integralWriteOutputStream.write(buffer, 123 + 768 + 6285 + 1234, 21111);
82                 integralWriteOutputStream.write(buffer, 123 + 768 + 6285 + 1234 + 21111, 32768 - (123 + 768 + 6285 + 1234 + 21111));
83
84                 assertThat(byteArrayOutputStream.toByteArray(), is(buffer));
85         }
86
87         //
88         // PRIVATE METHODS
89         //
90
91         /**
92          * Creates a {@link ByteArrayOutputStream} that will throw an {@link
93          * IllegalArgumentException} if its {@link OutputStream#write(byte[], int,
94          * int)} method is called with {@code len} not being a multiple of {@code
95          * integralSize}, or if {@link OutputStream#write(int)} is called.
96          *
97          * @param integralSize
98          *              The number of bytes to write multiples of
99          * @return The created output stream
100          */
101         private static ByteArrayOutputStream getOutputStream(final int integralSize) {
102                 return new ByteArrayOutputStream() {
103
104                         @Override
105                         public synchronized void write(byte[] b, int off, int len) {
106                                 if ((len % integralSize) != 0) {
107                                         throw new IllegalArgumentException(String.format("%d is not a multiple of %d.", len, integralSize));
108                                 }
109                                 super.write(b, off, len);
110                         }
111
112                         @Override
113                         public synchronized void write(int b) {
114                                 throw new IllegalArgumentException("write(int) called.");
115                         }
116
117                 };
118         }
119
120         /**
121          * Generates a random amount of data.
122          *
123          * @param length
124          *              The length of the data
125          * @return The generated random data
126          */
127         private static byte[] generateData(int length) {
128                 Random random = new Random();
129                 byte[] buffer = new byte[length];
130                 random.nextBytes(buffer);
131                 return buffer;
132         }
133
134 }