This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-codec.git


The following commit(s) were added to refs/heads/master by this push:
     new b20eaaad Add tests for BaseNCodecOutputStream.close()
b20eaaad is described below

commit b20eaaad36b6562ebccd5afbded7199ffc5b040c
Author: Gary Gregory <[email protected]>
AuthorDate: Sat Mar 7 07:59:10 2026 -0500

    Add tests for BaseNCodecOutputStream.close()
    
    See [CODEC-334] BaseNCodecOutputStream.close() throws on second call —
    violates Closeable idempotency contract
---
 .../binary/AbstractBaseNOutputStreamTest.java      | 39 ++++++++++++++++++++
 .../codec/binary/Base16OutputStreamTest.java       | 20 +++++++---
 .../codec/binary/Base32OutputStreamTest.java       |  7 +++-
 .../codec/binary/Base58OutputStreamTest.java       |  7 +++-
 .../codec/binary/Base64OutputStreamTest.java       |  7 +++-
 .../codec/binary/BaseNCodecOutputStreamTest.java   | 32 ++++++++++++++++
 .../commons/codec/binary/BaseNCodecTest.java       | 25 -------------
 .../commons/codec/binary/NoOpBaseNCodec.java       | 43 ++++++++++++++++++++++
 8 files changed, 147 insertions(+), 33 deletions(-)

diff --git 
a/src/test/java/org/apache/commons/codec/binary/AbstractBaseNOutputStreamTest.java
 
b/src/test/java/org/apache/commons/codec/binary/AbstractBaseNOutputStreamTest.java
new file mode 100644
index 00000000..57e542c7
--- /dev/null
+++ 
b/src/test/java/org/apache/commons/codec/binary/AbstractBaseNOutputStreamTest.java
@@ -0,0 +1,39 @@
+/*
+ * 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.codec.binary;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * Abstract class for {@link BaseNCodecOutputStream} and its subclasses.
+ */
+abstract class AbstractBaseNOutputStreamTest {
+
+    abstract OutputStream newOutputStream();
+
+    @Test
+    void testClose() throws IOException {
+        try (OutputStream out = newOutputStream()) {
+            out.close();
+            out.close();
+        }
+    }
+}
diff --git 
a/src/test/java/org/apache/commons/codec/binary/Base16OutputStreamTest.java 
b/src/test/java/org/apache/commons/codec/binary/Base16OutputStreamTest.java
index 1ab234bd..8bbffd5b 100644
--- a/src/test/java/org/apache/commons/codec/binary/Base16OutputStreamTest.java
+++ b/src/test/java/org/apache/commons/codec/binary/Base16OutputStreamTest.java
@@ -30,10 +30,15 @@ import org.junit.jupiter.api.Test;
 /**
  * Tests {@link Base16OutputStream}.
  */
-class Base16OutputStreamTest {
+class Base16OutputStreamTest extends AbstractBaseNOutputStreamTest {
 
     private static final String STRING_FIXTURE = "Hello World";
 
+    @Override
+    OutputStream newOutputStream() {
+        return new Base16OutputStream(new ByteArrayOutputStream());
+    }
+
     /**
      * Test the Base16OutputStream implementation against empty input.
      *
@@ -132,7 +137,6 @@ class Base16OutputStreamTest {
      * @throws IOException Usually signifies a bug in the Base16 commons-codec 
implementation.
      */
     private void testByChunk(final byte[] encoded, final byte[] decoded, final 
boolean lowerCase) throws IOException {
-
         // Start with encode.
         try (ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
                 OutputStream out = new Base16OutputStream(byteOut, true, 
lowerCase)) {
@@ -140,7 +144,6 @@ class Base16OutputStreamTest {
             final byte[] output = byteOut.toByteArray();
             assertArrayEquals(encoded, output, "Streaming chunked base16 
encode");
         }
-
         // Now let's try to decode.
         try (ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
                 OutputStream out = new Base16OutputStream(byteOut, false, 
lowerCase)) {
@@ -148,7 +151,6 @@ class Base16OutputStreamTest {
             final byte[] output = byteOut.toByteArray();
             assertArrayEquals(decoded, output, "Streaming chunked base16 
decode");
         }
-
         // wrap encoder with decoder
         try (ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
              OutputStream decoderOut = new Base16OutputStream(byteOut, false, 
lowerCase);
@@ -156,7 +158,6 @@ class Base16OutputStreamTest {
 
             encoderOut.write(decoded);
             final byte[] output = byteOut.toByteArray();
-
             assertArrayEquals(decoded, output, "Streaming chunked base16 
wrap-wrap!");
         }
     }
@@ -238,6 +239,15 @@ class Base16OutputStreamTest {
         }
     }
 
+    @Override
+    @Test
+    void testClose() throws IOException {
+        try (OutputStream out = newOutputStream()) {
+            out.close();
+            out.close();
+        }
+    }
+
     /**
      * Tests Base16OutputStream.write for expected IndexOutOfBoundsException 
conditions.
      *
diff --git 
a/src/test/java/org/apache/commons/codec/binary/Base32OutputStreamTest.java 
b/src/test/java/org/apache/commons/codec/binary/Base32OutputStreamTest.java
index a5447458..705a4a1b 100644
--- a/src/test/java/org/apache/commons/codec/binary/Base32OutputStreamTest.java
+++ b/src/test/java/org/apache/commons/codec/binary/Base32OutputStreamTest.java
@@ -32,7 +32,7 @@ import org.junit.jupiter.api.Test;
 /**
  * Tests {@link Base32OutputStream}.
  */
-class Base32OutputStreamTest {
+class Base32OutputStreamTest extends AbstractBaseNOutputStreamTest {
 
     private static final byte[] CR_LF = {(byte) '\r', (byte) '\n'};
 
@@ -61,6 +61,11 @@ class Base32OutputStreamTest {
 //        );
 //    }
 
+    @Override
+    OutputStream newOutputStream() {
+        return new Base32OutputStream(new ByteArrayOutputStream());
+    }
+
     private void testBase32EmptyOutputStream(final int chunkSize) throws 
Exception {
         final byte[] emptyEncoded = {};
         final byte[] emptyDecoded = {};
diff --git 
a/src/test/java/org/apache/commons/codec/binary/Base58OutputStreamTest.java 
b/src/test/java/org/apache/commons/codec/binary/Base58OutputStreamTest.java
index abcaf3eb..266f036a 100644
--- a/src/test/java/org/apache/commons/codec/binary/Base58OutputStreamTest.java
+++ b/src/test/java/org/apache/commons/codec/binary/Base58OutputStreamTest.java
@@ -29,12 +29,17 @@ import org.junit.jupiter.api.Test;
 /**
  * Tests {@link Base58OutputStream}.
  */
-class Base58OutputStreamTest {
+class Base58OutputStreamTest extends AbstractBaseNOutputStreamTest {
 
     private static final byte[] CR_LF = { (byte) '\r', (byte) '\n' };
 
     private static final byte[] LF = { (byte) '\n' };
 
+    @Override
+    OutputStream newOutputStream() {
+        return new Base58OutputStream(new ByteArrayOutputStream());
+    }
+
     private void testBase58EmptyOutputStream(final int chunkSize) throws 
Exception {
         final byte[] emptyEncoded = {};
         final byte[] emptyDecoded = {};
diff --git 
a/src/test/java/org/apache/commons/codec/binary/Base64OutputStreamTest.java 
b/src/test/java/org/apache/commons/codec/binary/Base64OutputStreamTest.java
index 3f11f18b..058e7ac3 100644
--- a/src/test/java/org/apache/commons/codec/binary/Base64OutputStreamTest.java
+++ b/src/test/java/org/apache/commons/codec/binary/Base64OutputStreamTest.java
@@ -33,7 +33,7 @@ import org.junit.jupiter.api.Test;
 /**
  * Tests {@link Base64OutputStream}.
  */
-class Base64OutputStreamTest {
+class Base64OutputStreamTest extends AbstractBaseNOutputStreamTest {
 
     private static final byte[] CR_LF = {(byte) '\r', (byte) '\n'};
 
@@ -41,6 +41,11 @@ class Base64OutputStreamTest {
 
     private static final String STRING_FIXTURE = "Hello World";
 
+    @Override
+    OutputStream newOutputStream() {
+        return new Base64OutputStream(new ByteArrayOutputStream());
+    }
+
     private void testBase64EmptyOutputStream(final int chunkSize) throws 
Exception {
         final byte[] emptyEncoded = {};
         final byte[] emptyDecoded = {};
diff --git 
a/src/test/java/org/apache/commons/codec/binary/BaseNCodecOutputStreamTest.java 
b/src/test/java/org/apache/commons/codec/binary/BaseNCodecOutputStreamTest.java
new file mode 100644
index 00000000..b53e0c1e
--- /dev/null
+++ 
b/src/test/java/org/apache/commons/codec/binary/BaseNCodecOutputStreamTest.java
@@ -0,0 +1,32 @@
+/*
+ * 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.codec.binary;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+
+/**
+ * Tests {@link BaseNCodecOutputStream}.
+ */
+public class BaseNCodecOutputStreamTest extends AbstractBaseNOutputStreamTest {
+
+    @Override
+    OutputStream newOutputStream() {
+        return new BaseNCodecOutputStream(new ByteArrayOutputStream(), new 
NoOpBaseNCodec(), true);
+    }
+}
diff --git a/src/test/java/org/apache/commons/codec/binary/BaseNCodecTest.java 
b/src/test/java/org/apache/commons/codec/binary/BaseNCodecTest.java
index 871d4092..642abe62 100644
--- a/src/test/java/org/apache/commons/codec/binary/BaseNCodecTest.java
+++ b/src/test/java/org/apache/commons/codec/binary/BaseNCodecTest.java
@@ -31,31 +31,6 @@ import org.junit.jupiter.api.Test;
 
 class BaseNCodecTest {
 
-    /**
-     * Extend BaseNCodec without implementation (no operations = NoOp).
-     * Used for testing the memory allocation in {@link 
BaseNCodec#ensureBufferSize(int, Context)}.
-     */
-    private static final class NoOpBaseNCodec extends BaseNCodec {
-        NoOpBaseNCodec() {
-            super(0, 0, 0, 0);
-        }
-
-        @Override
-        void decode(final byte[] array, final int i, final int length, final 
Context context) {
-            // no-op
-        }
-
-        @Override
-        void encode(final byte[] array, final int i, final int length, final 
Context context) {
-            // no-op
-        }
-
-        @Override
-        protected boolean isInAlphabet(final byte value) {
-            return false;
-        }
-    }
-
     private static void assertEnsureBufferSizeExpandsToMaxBufferSize(final 
boolean exceedMaxBufferSize) {
         // This test is memory hungry.
         // By default expansion will double the buffer size.
diff --git a/src/test/java/org/apache/commons/codec/binary/NoOpBaseNCodec.java 
b/src/test/java/org/apache/commons/codec/binary/NoOpBaseNCodec.java
new file mode 100644
index 00000000..f3c6d939
--- /dev/null
+++ b/src/test/java/org/apache/commons/codec/binary/NoOpBaseNCodec.java
@@ -0,0 +1,43 @@
+/*
+ * 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.codec.binary;
+
+/**
+ * Extend BaseNCodec without implementation (no operations = NoOp).
+ * Used for testing the memory allocation in {@link 
BaseNCodec#ensureBufferSize(int, Context)}.
+ */
+final class NoOpBaseNCodec extends BaseNCodec {
+    NoOpBaseNCodec() {
+        super(0, 0, 0, 0);
+    }
+
+    @Override
+    void decode(final byte[] array, final int i, final int length, final 
Context context) {
+        // no-op
+    }
+
+    @Override
+    void encode(final byte[] array, final int i, final int length, final 
Context context) {
+        // no-op
+    }
+
+    @Override
+    protected boolean isInAlphabet(final byte value) {
+        return false;
+    }
+}

Reply via email to