1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.codec.net;
19
20 import static org.junit.jupiter.api.Assertions.assertEquals;
21 import static org.junit.jupiter.api.Assertions.assertNull;
22 import static org.junit.jupiter.api.Assertions.assertThrows;
23
24 import java.nio.charset.StandardCharsets;
25 import java.nio.charset.UnsupportedCharsetException;
26
27 import org.apache.commons.codec.CharEncoding;
28 import org.apache.commons.codec.DecoderException;
29 import org.apache.commons.codec.EncoderException;
30 import org.junit.jupiter.api.Test;
31
32
33
34
35 public class QuotedPrintableCodecTest {
36
37 static final int SWISS_GERMAN_STUFF_UNICODE[] = { 0x47, 0x72, 0xFC, 0x65, 0x7A, 0x69, 0x5F, 0x7A, 0xE4, 0x6D, 0xE4 };
38
39 static final int RUSSIAN_STUFF_UNICODE[] = { 0x412, 0x441, 0x435, 0x43C, 0x5F, 0x43F, 0x440, 0x438, 0x432, 0x435, 0x442 };
40
41 private String constructString(final int[] unicodeChars) {
42 final StringBuilder buffer = new StringBuilder();
43 if (unicodeChars != null) {
44 for (final int unicodeChar : unicodeChars) {
45 buffer.append((char) unicodeChar);
46 }
47 }
48 return buffer.toString();
49 }
50
51 @Test
52 public void testBasicEncodeDecode() throws Exception {
53 final QuotedPrintableCodec qpcodec = new QuotedPrintableCodec();
54 final String plain = "= Hello there =\r\n";
55 final String encoded = qpcodec.encode(plain);
56 assertEquals("=3D Hello there =3D=0D=0A", encoded, "Basic quoted-printable encoding test");
57 assertEquals(plain, qpcodec.decode(encoded), "Basic quoted-printable decoding test");
58 }
59
60 @Test
61 public void testDecodeInvalid() {
62 final QuotedPrintableCodec qpcodec = new QuotedPrintableCodec();
63 assertThrows(DecoderException.class, () -> qpcodec.decode("="));
64 assertThrows(DecoderException.class, () -> qpcodec.decode("=A"));
65 assertThrows(DecoderException.class, () -> qpcodec.decode("=WW"));
66 }
67
68 @Test
69 public void testDecodeObjects() throws Exception {
70 final QuotedPrintableCodec qpcodec = new QuotedPrintableCodec();
71 final String plain = "1+1 =3D 2";
72 String decoded = (String) qpcodec.decode((Object) plain);
73 assertEquals("1+1 = 2", decoded, "Basic quoted-printable decoding test");
74
75 final byte[] plainBA = plain.getBytes(StandardCharsets.UTF_8);
76 final byte[] decodedBA = (byte[]) qpcodec.decode((Object) plainBA);
77 decoded = new String(decodedBA);
78 assertEquals("1+1 = 2", decoded, "Basic quoted-printable decoding test");
79
80 final Object result = qpcodec.decode((Object) null);
81 assertNull(result, "Decoding a null Object should return null");
82
83 assertThrows(DecoderException.class, () -> qpcodec.decode(Double.valueOf(3.0d)), "Trying to url encode a Double object should cause an exception.");
84 }
85
86 @Test
87 public void testDecodeStringWithNull() throws Exception {
88 final QuotedPrintableCodec qpcodec = new QuotedPrintableCodec();
89 final String test = null;
90 final String result = qpcodec.decode(test, "charset");
91 assertNull(result, "Result should be null");
92 }
93
94 @Test
95 public void testDecodeWithNullArray() throws Exception {
96 final byte[] plain = null;
97 final byte[] result = QuotedPrintableCodec.decodeQuotedPrintable(plain);
98 assertNull(result, "Result should be null");
99 }
100
101 @Test
102 public void testDefaultEncoding() throws Exception {
103 final String plain = "Hello there!";
104 final QuotedPrintableCodec qpcodec = new QuotedPrintableCodec("UnicodeBig");
105 qpcodec.encode(plain);
106 final String encoded1 = qpcodec.encode(plain, "UnicodeBig");
107 final String encoded2 = qpcodec.encode(plain);
108 assertEquals(encoded1, encoded2);
109 }
110
111 @Test
112 public void testEncodeDecodeNull() throws Exception {
113 final QuotedPrintableCodec qpcodec = new QuotedPrintableCodec();
114 assertNull(qpcodec.encode((String) null), "Null string quoted-printable encoding test");
115 assertNull(qpcodec.decode((String) null), "Null string quoted-printable decoding test");
116 }
117
118 @Test
119 public void testEncodeNull() throws Exception {
120 final QuotedPrintableCodec qpcodec = new QuotedPrintableCodec();
121 final byte[] plain = null;
122 final byte[] encoded = qpcodec.encode(plain);
123 assertNull(encoded, "Encoding a null string should return null");
124 }
125
126 @Test
127 public void testEncodeObjects() throws Exception {
128 final QuotedPrintableCodec qpcodec = new QuotedPrintableCodec();
129 final String plain = "1+1 = 2";
130 String encoded = (String) qpcodec.encode((Object) plain);
131
132 assertEquals("1+1 =3D 2", encoded, "Basic quoted-printable encoding test");
133 final byte[] plainBA = plain.getBytes(StandardCharsets.UTF_8);
134 final byte[] encodedBA = (byte[]) qpcodec.encode((Object) plainBA);
135 encoded = new String(encodedBA);
136 assertEquals("1+1 =3D 2", encoded, "Basic quoted-printable encoding test");
137
138 final Object result = qpcodec.encode((Object) null);
139 assertNull(result, "Encoding a null Object should return null");
140
141 assertThrows(EncoderException.class, () -> qpcodec.encode(Double.valueOf(3.0d)), "Trying to url encode a Double object should cause an exception.");
142 }
143
144 @Test
145 public void testEncodeStringWithNull() throws Exception {
146 final QuotedPrintableCodec qpcodec = new QuotedPrintableCodec();
147 final String test = null;
148 final String result = qpcodec.encode(test, "charset");
149 assertNull(result, "Result should be null");
150 }
151
152 @Test
153 public void testEncodeUrlWithNullBitSet() throws Exception {
154 final QuotedPrintableCodec qpcodec = new QuotedPrintableCodec();
155 final String plain = "1+1 = 2";
156 final String encoded = new String(QuotedPrintableCodec.encodeQuotedPrintable(null, plain.getBytes(StandardCharsets.UTF_8)));
157 assertEquals("1+1 =3D 2", encoded, "Basic quoted-printable encoding test");
158 assertEquals(plain, qpcodec.decode(encoded), "Basic quoted-printable decoding test");
159 }
160
161 @Test
162 public void testFinalBytes() throws Exception {
163
164 final String plain = "This is a example of a quoted=printable text file. There is no tt";
165 final String expected = "This is a example of a quoted=3Dprintable text file. There is no tt";
166
167 assertEquals(expected, new QuotedPrintableCodec(true).encode(plain));
168 }
169
170 @Test
171 public void testInvalidEncoding() {
172 assertThrows(UnsupportedCharsetException.class, () -> new QuotedPrintableCodec("NONSENSE"));
173 }
174
175 @Test
176 public void testSafeCharEncodeDecode() throws Exception {
177 final QuotedPrintableCodec qpcodec = new QuotedPrintableCodec();
178 final String plain = "abc123_-.*~!@#$%^&()+{}\"\\;:`,/[]";
179 final String encoded = qpcodec.encode(plain);
180 assertEquals(plain, encoded, "Safe chars quoted-printable encoding test");
181 assertEquals(plain, qpcodec.decode(encoded), "Safe chars quoted-printable decoding test");
182 }
183
184 @Test
185 public void testSkipNotEncodedCRLF() throws Exception {
186 final String qpdata = "CRLF in an\n encoded text should be=20=\r\n\rskipped in the\r decoding.";
187 final String expected = "CRLF in an encoded text should be skipped in the decoding.";
188
189 final QuotedPrintableCodec qpcodec = new QuotedPrintableCodec(true);
190 assertEquals(expected, qpcodec.decode(qpdata));
191
192 final String encoded = qpcodec.encode(expected);
193 assertEquals(expected, qpcodec.decode(encoded));
194 }
195
196 @Test
197 public void testSoftLineBreakDecode() throws Exception {
198 final String qpdata = "If you believe that truth=3Dbeauty, then surely=20=\r\nmathematics is the most beautiful branch of philosophy.";
199 final String expected = "If you believe that truth=beauty, then surely mathematics is the most beautiful branch of philosophy.";
200
201 final QuotedPrintableCodec qpcodec = new QuotedPrintableCodec();
202 assertEquals(expected, qpcodec.decode(qpdata));
203
204 final String encoded = qpcodec.encode(expected);
205 assertEquals(expected, qpcodec.decode(encoded));
206 }
207
208 @Test
209 public void testSoftLineBreakEncode() throws Exception {
210 final String qpdata = "If you believe that truth=3Dbeauty, then surely mathematics is the most b=\r\neautiful branch of philosophy.";
211 final String expected = "If you believe that truth=beauty, then surely mathematics is the most beautiful branch of philosophy.";
212
213 final QuotedPrintableCodec qpcodec = new QuotedPrintableCodec(true);
214 assertEquals(qpdata, qpcodec.encode(expected));
215
216 final String decoded = qpcodec.decode(qpdata);
217 assertEquals(qpdata, qpcodec.encode(decoded));
218 }
219
220 @Test
221 public void testTooShortByteArray() throws Exception {
222 final QuotedPrintableCodec qpcodec = new QuotedPrintableCodec(true);
223 assertNull(qpcodec.encode("AA"), "Result should be null.");
224 }
225
226 @Test
227 public void testTrailingSpecial() throws Exception {
228 final QuotedPrintableCodec qpcodec = new QuotedPrintableCodec(true);
229
230 String plain = "This is a example of a quoted-printable text file. This might contain sp=cial chars.";
231 String expected = "This is a example of a quoted-printable text file. This might contain sp=3D=\r\ncial chars.";
232 assertEquals(expected, qpcodec.encode(plain));
233
234 plain = "This is a example of a quoted-printable text file. This might contain ta\tbs as well.";
235 expected = "This is a example of a quoted-printable text file. This might contain ta=09=\r\nbs as well.";
236 assertEquals(expected, qpcodec.encode(plain));
237 }
238
239 @Test
240 public void testUltimateSoftBreak() throws Exception {
241 final QuotedPrintableCodec qpcodec = new QuotedPrintableCodec(true);
242
243 String plain = "This is a example of a quoted-printable text file. There is no end to it\t";
244 String expected = "This is a example of a quoted-printable text file. There is no end to i=\r\nt=09";
245
246 assertEquals(expected, qpcodec.encode(plain));
247
248 plain = "This is a example of a quoted-printable text file. There is no end to it ";
249 expected = "This is a example of a quoted-printable text file. There is no end to i=\r\nt=20";
250
251 assertEquals(expected, qpcodec.encode(plain));
252
253
254 plain = "This is a example of a quoted-printable text file. There is no end to ";
255 expected = "This is a example of a quoted-printable text file. There is no end to=20=\r\n =20";
256
257 assertEquals(expected, qpcodec.encode(plain));
258
259
260 plain = "This is a example of a quoted-printable text file. There is no end to= ";
261 expected = "This is a example of a quoted-printable text file. There is no end to=3D=\r\n =20";
262
263 assertEquals(expected, qpcodec.encode(plain));
264 }
265
266 @Test
267 public void testUnsafeEncodeDecode() throws Exception {
268 final QuotedPrintableCodec qpcodec = new QuotedPrintableCodec();
269 final String plain = "=\r\n";
270 final String encoded = qpcodec.encode(plain);
271 assertEquals("=3D=0D=0A", encoded, "Unsafe chars quoted-printable encoding test");
272 assertEquals(plain, qpcodec.decode(encoded), "Unsafe chars quoted-printable decoding test");
273 }
274
275 @Test
276 public void testUTF8RoundTrip() throws Exception {
277
278 final String ru_msg = constructString(RUSSIAN_STUFF_UNICODE);
279 final String ch_msg = constructString(SWISS_GERMAN_STUFF_UNICODE);
280
281 final QuotedPrintableCodec qpcodec = new QuotedPrintableCodec();
282
283 assertEquals("=D0=92=D1=81=D0=B5=D0=BC_=D0=BF=D1=80=D0=B8=D0=B2=D0=B5=D1=82", qpcodec.encode(ru_msg, CharEncoding.UTF_8));
284 assertEquals("Gr=C3=BCezi_z=C3=A4m=C3=A4", qpcodec.encode(ch_msg, CharEncoding.UTF_8));
285
286 assertEquals(ru_msg, qpcodec.decode(qpcodec.encode(ru_msg, CharEncoding.UTF_8), CharEncoding.UTF_8));
287 assertEquals(ch_msg, qpcodec.decode(qpcodec.encode(ch_msg, CharEncoding.UTF_8), CharEncoding.UTF_8));
288 }
289 }