| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * https://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.commons.net.util; |
| |
| import static org.junit.jupiter.api.Assertions.assertArrayEquals; |
| import static org.junit.jupiter.api.Assertions.assertEquals; |
| import static org.junit.jupiter.api.Assertions.assertFalse; |
| import static org.junit.jupiter.api.Assertions.assertNotNull; |
| import static org.junit.jupiter.api.Assertions.assertNull; |
| import static org.junit.jupiter.api.Assertions.assertSame; |
| import static org.junit.jupiter.api.Assertions.assertThrows; |
| import static org.junit.jupiter.api.Assertions.assertTrue; |
| |
| import java.math.BigInteger; |
| import java.nio.charset.StandardCharsets; |
| import java.util.Base64.Decoder; |
| import java.util.Base64.Encoder; |
| |
| import org.apache.commons.lang3.ArrayFill; |
| import org.apache.commons.lang3.ArrayUtils; |
| import org.junit.jupiter.api.Test; |
| |
| @SuppressWarnings({ "deprecation" }) |
| class Base64Test { |
| |
| private static String toString(final byte[] encodedData) { |
| return encodedData != null ? new String(encodedData, StandardCharsets.UTF_8) : null; |
| } |
| |
| private void checkDecoders(final String expected, final byte[] actual) { |
| final byte[] decoded = Base64.decodeBase64(actual); |
| assertEquals(expected, toString(decoded)); |
| assertEquals(expected, toString(actual != null ? getJreDecoder().decode(actual) : null)); |
| assertEquals(expected, toString(new Base64().decode(actual))); |
| } |
| |
| private void checkDecoders(final String expected, final String actual) { |
| final byte[] decoded = Base64.decodeBase64(actual); |
| assertEquals(expected, new String(decoded)); |
| assertEquals(expected, toString(decoded)); |
| assertEquals(expected, toString(actual != null ? getJreDecoder().decode(actual) : null)); |
| assertEquals(expected, toString(new Base64().decode(actual))); |
| } |
| |
| private Decoder getJreDecoder() { |
| return java.util.Base64.getDecoder(); |
| } |
| |
| private Encoder getJreEncoder() { |
| return java.util.Base64.getEncoder(); |
| } |
| |
| private Encoder getJreMimeEncoder() { |
| return java.util.Base64.getMimeEncoder(); |
| } |
| |
| private Encoder getJreMimeEncoder(final int lineLength, final byte[] lineSeparator) { |
| return java.util.Base64.getMimeEncoder(lineLength, lineSeparator); |
| } |
| |
| private Encoder getJreUrlEncoder() { |
| return java.util.Base64.getUrlEncoder(); |
| } |
| |
| @Test |
| void testBase64() { |
| final Base64 b64 = new Base64(); |
| assertFalse(b64.isUrlSafe()); |
| } |
| |
| @Test |
| void testBase64Boolean() { |
| final Base64 b64 = new Base64(true); |
| assertTrue(b64.isUrlSafe()); |
| assertArrayEquals(new byte[] {}, b64.getLineSeparator()); |
| } |
| |
| @Test |
| void testBase64Int() { |
| Base64 b64; |
| b64 = new Base64(8); |
| assertFalse(b64.isUrlSafe()); |
| assertEquals(8, b64.getLineLength()); |
| b64 = new Base64(11); |
| assertEquals(8, b64.getLineLength()); |
| } |
| |
| @Test |
| void testBase64IntByteArray() { |
| final Base64 b64; |
| b64 = new Base64(8, new byte[] {}); |
| assertFalse(b64.isUrlSafe()); |
| assertArrayEquals(new byte[] {}, b64.getLineSeparator()); |
| final String stringToEncode = "<<???>><<???>><<???>><<???>><<???>><<???>><<???>><<???>><<???>><<???>><<???>>"; |
| final byte[] encodedData = new Base64(Base64.CHUNK_SIZE, Base64.CHUNK_SEPARATOR).encode(stringToEncode.getBytes()); |
| assertEquals("PDw/Pz8+Pjw8Pz8/Pj48PD8/Pz4+PDw/Pz8+Pjw8Pz8/Pj48PD8/Pz4+PDw/Pz8+Pjw8Pz8/Pj48\r\nPD8/Pz4+PDw/Pz8+Pjw8Pz8/Pj4=\r\n", toString(encodedData)); |
| assertEquals(getJreMimeEncoder().encodeToString(stringToEncode.getBytes()) + "\r\n", toString(encodedData)); |
| assertEquals("PDw/Pz8+Pjw8Pz8/Pj48PD8/Pz4+PDw/Pz8+Pjw8Pz8/Pj48PD8/Pz4+PDw/Pz8+Pjw8Pz8/Pj48~PD8/Pz4+PDw/Pz8+Pjw8Pz8/Pj4=~", |
| toString(new Base64(Base64.CHUNK_SIZE, "~".getBytes()).encode(stringToEncode.getBytes()))); |
| assertEquals(getJreMimeEncoder(Base64.CHUNK_SIZE, "~".getBytes()).encodeToString(stringToEncode.getBytes()) + "~", |
| toString(new Base64(Base64.CHUNK_SIZE, "~".getBytes()).encode(stringToEncode.getBytes()))); |
| assertEquals(getJreMimeEncoder(Base64.CHUNK_SIZE - 2, "~~".getBytes()).encodeToString(stringToEncode.getBytes()) + "~~", |
| toString(new Base64(Base64.CHUNK_SIZE - 2, "~~".getBytes()).encode(stringToEncode.getBytes()))); |
| assertEquals(getJreMimeEncoder(Base64.CHUNK_SIZE + 2, "~~~".getBytes()).encodeToString(stringToEncode.getBytes()) + "~~~", |
| toString(new Base64(Base64.CHUNK_SIZE + 2, "~~~".getBytes()).encode(stringToEncode.getBytes()))); |
| } |
| |
| @Test |
| void testBase64IntByteArrayBoolean() { |
| Base64 b64; |
| b64 = new Base64(8, new byte[] {}, false); |
| assertFalse(b64.isUrlSafe()); |
| b64 = new Base64(8, new byte[] {}, true); |
| assertTrue(b64.isUrlSafe()); |
| assertThrows(IllegalArgumentException.class, () -> new Base64(8, new byte[] { 'A' }, false)); |
| } |
| |
| @Test |
| void testDecodeBase64ByteArray() { |
| checkDecoders("light w", new byte[] { 'b', 'G', 'l', 'n', 'a', 'H', 'Q', 'g', 'd', 'w', '=', '=' }); |
| } |
| |
| @Test |
| void testDecodeBase64String() { |
| checkDecoders("light w", "bGlnaHQgdw=="); |
| } |
| |
| @Test |
| void testDecodeByteArray() { |
| checkDecoders("foobar", new byte[] { 'Z', 'm', '9', 'v', 'Y', 'm', 'F', 'y' }); |
| } |
| |
| @Test |
| void testDecodeByteArrayEmpty() { |
| checkDecoders("", new byte[] {}); |
| checkDecoders(null, (byte[]) null); |
| |
| } |
| |
| @Test |
| void testDecodeByteArrayNull() { |
| assertNull(new Base64().decode((byte[]) null)); |
| } |
| |
| @Test |
| void testDecodeInteger() { |
| testDecodeInteger(BigInteger.ONE); |
| testDecodeInteger(BigInteger.TEN); |
| testDecodeInteger(BigInteger.ZERO); |
| } |
| |
| private void testDecodeInteger(final BigInteger bi) { |
| assertEquals(bi, Base64.decodeInteger(getJreEncoder().encode(bi.toByteArray()))); |
| } |
| |
| @Test |
| void testDecodeNullString() { |
| final Base64 base64 = new Base64(); |
| assertThrows(NullPointerException.class, () -> base64.decode((String) null)); |
| } |
| |
| @Test |
| void testDecodeString() { |
| checkDecoders("Hello World!", "SGVsbG8gV29ybGQh"); |
| } |
| |
| @Test |
| void testEncodeBase64ByteArrayBoolean() { |
| final byte[] binaryData = { '1', '2', '3' }; |
| final byte[] urlUnsafeData = "<<???>>".getBytes(); |
| final byte[] urlUnsafeDataChunky = "<<???>><<???>><<???>><<???>><<???>><<???>><<???>><<???>><<???>><<???>><<???>>".getBytes(); |
| byte[] encoded; |
| // Boolean parameter: "isChunked". |
| // |
| // isChunked false |
| encoded = Base64.encodeBase64(binaryData, false); |
| assertNotNull(encoded); |
| assertEquals(4, encoded.length); |
| assertEquals(Base64.getEncodeLength(binaryData, Base64.CHUNK_SIZE, Base64.CHUNK_SEPARATOR) - 2, encoded.length); |
| assertEquals(getJreEncoder().encodeToString(binaryData), toString(encoded)); |
| assertEquals("MTIz", toString(encoded)); |
| // URL unsafe |
| // <<???>> |
| encoded = Base64.encodeBase64(urlUnsafeData, false); |
| assertEquals("PDw/Pz8+Pg==", toString(encoded)); |
| encoded = Base64.encodeBase64(urlUnsafeDataChunky, false); |
| assertEquals(getJreEncoder().encodeToString(urlUnsafeDataChunky), toString(encoded)); |
| // |
| // isChunked false |
| encoded = Base64.encodeBase64(binaryData, false); |
| assertNotNull(encoded); |
| assertEquals(4, encoded.length); |
| assertEquals(Base64.getEncodeLength(binaryData, Base64.CHUNK_SIZE, Base64.CHUNK_SEPARATOR) - 2, encoded.length); |
| assertEquals("MTIz", toString(encoded)); |
| // |
| // isChunked true |
| encoded = Base64.encodeBase64(binaryData, true); |
| assertNotNull(encoded); |
| assertEquals(6, encoded.length); // always adds trailer |
| assertEquals(Base64.getEncodeLength(binaryData, Base64.CHUNK_SIZE, Base64.CHUNK_SEPARATOR), encoded.length); |
| assertEquals("MTIz\r\n", toString(encoded)); |
| // URL unsafe |
| // <<???>> |
| encoded = Base64.encodeBase64(urlUnsafeData, true); |
| assertEquals("PDw/Pz8+Pg==\r\n", toString(encoded)); |
| encoded = Base64.encodeBase64(urlUnsafeDataChunky, true); |
| assertEquals(getJreMimeEncoder().encodeToString(urlUnsafeDataChunky) + "\r\n", toString(encoded)); |
| // |
| // isChunked true |
| encoded = Base64.encodeBase64(binaryData, true); |
| assertNotNull(encoded); |
| assertEquals(6, encoded.length); |
| assertEquals(Base64.getEncodeLength(binaryData, Base64.CHUNK_SIZE, Base64.CHUNK_SEPARATOR), encoded.length); |
| assertEquals("MTIz\r\n", toString(encoded)); |
| } |
| |
| @Test |
| void testEncodeBase64ByteArrayBooleanBoolean() { |
| final byte[] binaryData = { '1', '2', '3' }; |
| byte[] encoded; |
| encoded = Base64.encodeBase64(binaryData, false, false); |
| assertNotNull(encoded); |
| assertEquals(4, encoded.length); |
| encoded = Base64.encodeBase64(binaryData, false, false); |
| assertNotNull(encoded); |
| assertEquals(4, encoded.length); |
| encoded = Base64.encodeBase64(binaryData, true, false); |
| assertNotNull(encoded); |
| assertEquals(6, encoded.length); // always adds trailer |
| encoded = Base64.encodeBase64(binaryData, true, false); |
| assertNotNull(encoded); |
| assertEquals(6, encoded.length); |
| } |
| |
| @Test |
| void testEncodeBase64ByteArrayBooleanBooleanInt() { |
| final byte[] binaryData = { '1', '2', '3' }; |
| byte[] encoded; |
| encoded = Base64.encodeBase64(binaryData, false, false); |
| assertNotNull(encoded); |
| assertEquals(4, encoded.length); |
| assertThrows(IllegalArgumentException.class, () -> Base64.encodeBase64(binaryData, false, false, 3)); |
| encoded = Base64.encodeBase64(binaryData, false, false, 4); // NET-483 |
| assertNotNull(encoded); |
| assertEquals(4, encoded.length); |
| encoded = Base64.encodeBase64(binaryData, true, false); |
| assertNotNull(encoded); |
| assertEquals(6, encoded.length); // always adds trailer |
| assertThrows(IllegalArgumentException.class, () -> Base64.encodeBase64(binaryData, true, false, 5)); |
| encoded = Base64.encodeBase64(binaryData, true, false, 6); |
| assertNotNull(encoded); |
| assertEquals(6, encoded.length); |
| } |
| |
| @Test |
| void testEncodeBase64ByteArrayEdges() { |
| final byte[] binaryData = null; |
| assertArrayEquals(binaryData, Base64.encodeBase64(binaryData)); |
| final byte[] binaryData2 = {}; |
| assertArrayEquals(binaryData2, Base64.encodeBase64(binaryData2)); |
| } |
| |
| @Test |
| void testEncodeBase64Chunked() { |
| byte[] bytesToEncode = { 'f', 'o', 'o', 'b', 'a', 'r' }; |
| byte[] encodedData = Base64.encodeBase64Chunked(bytesToEncode); |
| assertEquals("Zm9vYmFy\r\n", toString(encodedData)); |
| // URL unsafe data |
| // <<???>> |
| bytesToEncode = "<<???>>".getBytes(); |
| encodedData = Base64.encodeBase64Chunked(bytesToEncode); |
| assertEquals("PDw/Pz8+Pg==\r\n", toString(encodedData)); |
| // > 76 |
| final byte[] chunkMe = ArrayFill.fill(new byte[Base64.CHUNK_SIZE * 2], (byte) 'A'); |
| final byte[] chunked = Base64.encodeBase64Chunked(chunkMe); |
| assertEquals('\r', chunked[chunked.length - 2]); |
| assertEquals('\n', chunked[chunked.length - 1]); |
| assertArrayEquals(ArrayUtils.addAll(getJreMimeEncoder().encode(chunkMe), Base64.CHUNK_SEPARATOR), chunked); |
| } |
| |
| @Test |
| void testEncodeBase64StringByteArray() { |
| String stringToEncode = "Many hands make light work."; |
| String encodedData = Base64.encodeBase64String(stringToEncode.getBytes()); |
| assertEquals("TWFueSBoYW5kcyBtYWtlIGxpZ2h0IHdvcmsu\r\n", encodedData); |
| // URL unsafe data |
| // <<???>> |
| stringToEncode = "<<???>>"; |
| encodedData = Base64.encodeBase64String(stringToEncode.getBytes()); |
| assertEquals("PDw/Pz8+Pg==\r\n", encodedData); |
| // > 76 |
| final byte[] chunkMe = ArrayFill.fill(new byte[Base64.CHUNK_SIZE * 2], (byte) 'A'); |
| final String chunked = Base64.encodeBase64String(chunkMe); |
| assertEquals('\r', chunked.charAt(chunked.length() - 2)); |
| assertEquals('\n', chunked.charAt(chunked.length() - 1)); |
| assertEquals(getJreMimeEncoder().encodeToString(chunkMe) + "\r\n", chunked); |
| } |
| |
| @Test |
| void testEncodeBase64StringByteArrayBoolean() { |
| final byte[] bytesToEncode = "light work.".getBytes(); |
| final String chunkedResult = Base64.encodeBase64String(bytesToEncode, true); |
| assertEquals("bGlnaHQgd29yay4=\r\n", chunkedResult); |
| final String unchunkedResult = Base64.encodeBase64String(bytesToEncode, false); |
| assertEquals("bGlnaHQgd29yay4=", unchunkedResult); |
| } |
| |
| @Test |
| void testEncodeBase64StringUnChunked() { |
| byte[] bytesToEncode = "Many hands make light work.".getBytes(); |
| String encodedData = Base64.encodeBase64StringUnChunked(bytesToEncode); |
| assertEquals("TWFueSBoYW5kcyBtYWtlIGxpZ2h0IHdvcmsu", encodedData); |
| // URL unsafe data |
| // <<???>> |
| bytesToEncode = "<<???>>".getBytes(); |
| encodedData = Base64.encodeBase64StringUnChunked(bytesToEncode); |
| assertEquals("PDw/Pz8+Pg==", encodedData); |
| // > 76 |
| final byte[] chunkMe = ArrayFill.fill(new byte[Base64.CHUNK_SIZE * 2], (byte) 'A'); |
| final String chunked = Base64.encodeBase64StringUnChunked(chunkMe); |
| assertEquals(getJreEncoder().encodeToString(chunkMe), chunked); |
| } |
| |
| @Test |
| void testEncodeBase64URLSafe() { |
| byte[] bytesToEncode = "Many hands make light work.".getBytes(); |
| byte[] encodedData = Base64.encodeBase64URLSafe(bytesToEncode); |
| assertEquals("TWFueSBoYW5kcyBtYWtlIGxpZ2h0IHdvcmsu", toString(encodedData)); |
| // URL unsafe data |
| // <<???>> |
| bytesToEncode = "<<???>>".getBytes(); |
| encodedData = Base64.encodeBase64URLSafe(bytesToEncode); |
| assertEquals("PDw_Pz8-Pg", toString(encodedData)); |
| // > 76 line length |
| bytesToEncode = "<<???>><<???>><<???>><<???>><<???>><<???>><<???>><<???>><<???>><<???>><<???>>".getBytes(); |
| encodedData = Base64.encodeBase64URLSafe(bytesToEncode); |
| assertEquals(getJreUrlEncoder().withoutPadding().encodeToString(bytesToEncode), toString(encodedData)); |
| final String encodedUrlSafe = "PDw_Pz8-Pjw8Pz8_Pj48PD8_Pz4-PDw_Pz8-Pjw8Pz8_Pj48PD8_Pz4-PDw_Pz8-Pjw8Pz8_Pj48PD8_Pz4-PDw_Pz8-Pjw8Pz8_Pj4"; |
| assertEquals(encodedUrlSafe, toString(encodedData)); |
| // instance |
| assertEquals(encodedUrlSafe, toString(new Base64(0, null, true).encode(bytesToEncode))); |
| assertEquals(encodedUrlSafe, toString(new Base64(1, null, true).encode(bytesToEncode))); |
| assertEquals(encodedUrlSafe, toString(new Base64(999, null, true).encode(bytesToEncode))); |
| assertEquals(encodedUrlSafe, toString(new Base64(0, new byte[0], true).encode(bytesToEncode))); |
| assertEquals(encodedUrlSafe, toString(new Base64(0, new byte[10], true).encode(bytesToEncode))); |
| assertEquals(encodedUrlSafe, toString(new Base64(0, Base64.CHUNK_SEPARATOR, true).encode(bytesToEncode))); |
| assertEquals(encodedUrlSafe, toString(new Base64(Base64.CHUNK_SIZE, Base64.CHUNK_SEPARATOR, true).encode(bytesToEncode))); |
| assertEquals(encodedUrlSafe, toString(new Base64(999, Base64.CHUNK_SEPARATOR, true).encode(bytesToEncode))); |
| assertEquals(encodedUrlSafe, toString(new Base64(true).encode(bytesToEncode))); |
| } |
| |
| @Test |
| void testEncodeBase64URLSafeString() { |
| byte[] bytesToEncode = "Many hands make light work.".getBytes(); |
| String encodedData = Base64.encodeBase64URLSafeString(bytesToEncode); |
| assertEquals("TWFueSBoYW5kcyBtYWtlIGxpZ2h0IHdvcmsu", encodedData); |
| // URL unsafe data |
| // <<???>> |
| bytesToEncode = "<<???>>".getBytes(); |
| encodedData = Base64.encodeBase64URLSafeString(bytesToEncode); |
| assertEquals("PDw_Pz8-Pg", encodedData); |
| // > 76 line length |
| bytesToEncode = "<<???>><<???>><<???>><<???>><<???>><<???>><<???>><<???>><<???>><<???>><<???>>".getBytes(); |
| encodedData = Base64.encodeBase64URLSafeString(bytesToEncode); |
| assertEquals(getJreUrlEncoder().withoutPadding().encodeToString(bytesToEncode), encodedData); |
| assertEquals("PDw_Pz8-Pjw8Pz8_Pj48PD8_Pz4-PDw_Pz8-Pjw8Pz8_Pj48PD8_Pz4-PDw_Pz8-Pjw8Pz8_Pj48PD8_Pz4-PDw_Pz8-Pjw8Pz8_Pj4", encodedData); |
| } |
| |
| @Test |
| void testEncodeByteArray() { |
| final Base64 base64 = new Base64(); |
| final byte[] bytesToEncode = { 'l', 'i', 'g', 'h', 't', ' ', 'w', 'o', 'r' }; |
| assertEquals("bGlnaHQgd29y\r\n", new String(base64.encode(bytesToEncode), StandardCharsets.UTF_8)); |
| } |
| |
| @Test |
| void testEncodeByteArrayEmpty() { |
| assertNull(new Base64().encode((byte[]) null)); |
| final byte[] empty = {}; |
| assertSame(empty, new Base64().encode(empty)); |
| } |
| |
| @Test |
| void testEncodeByteArrayNull() { |
| assertNull(new Base64().encode((byte[]) null)); |
| } |
| |
| @Test |
| void testEncodeInteger() { |
| testEncodeInteger(BigInteger.ONE); |
| testEncodeInteger(BigInteger.TEN); |
| testEncodeInteger(BigInteger.ZERO); |
| } |
| |
| private void testEncodeInteger(final BigInteger bi) { |
| final byte[] decodedBytes = getJreDecoder().decode(Base64.encodeInteger(bi)); |
| final BigInteger decoded = decodedBytes.length == 0 ? BigInteger.ZERO : new BigInteger(decodedBytes); |
| assertEquals(bi, decoded); |
| } |
| |
| @Test |
| void testEncodeToString() { |
| final Base64 base64 = new Base64(); |
| final byte[] bytesToEncode = { 'l', 'i', 'g', 'h', 't', ' ', 'w', 'o', 'r' }; |
| assertEquals("bGlnaHQgd29y\r\n", base64.encodeToString(bytesToEncode)); |
| } |
| |
| @Test |
| void testIsArrayByteBase64() { |
| assertTrue(Base64.isArrayByteBase64(new byte[] { 'b', ' ' })); |
| assertFalse(Base64.isArrayByteBase64(new byte[] { '?' })); |
| } |
| |
| @Test |
| void testIsBase64() { |
| assertTrue(Base64.isBase64((byte) '=')); |
| assertTrue(Base64.isBase64((byte) 'b')); |
| assertFalse(Base64.isBase64((byte) ' ')); |
| assertFalse(Base64.isBase64((byte) -1)); |
| } |
| |
| } |