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

exceptionfactory pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi.git


The following commit(s) were added to refs/heads/main by this push:
     new 5cc857b99c NIFI-12017 Added Line Length Properties to EncodeContent
5cc857b99c is described below

commit 5cc857b99c780afb0a28112a73d73ae130b7b1fa
Author: knguyen <yuram...@gmail.com>
AuthorDate: Thu Feb 15 19:35:13 2024 +0000

    NIFI-12017 Added Line Length Properties to EncodeContent
    
    This closes #8417
    
    Signed-off-by: David Handermann <exceptionfact...@apache.org>
---
 .../nifi/processors/standard/EncodeContent.java    | 148 ++++++---
 .../processors/standard/encoding/EncodingMode.java |  47 +++
 .../processors/standard/encoding/EncodingType.java |  50 +++
 .../standard/encoding/LineOutputMode.java          |  47 +++
 .../processors/standard/TestEncodeContent.java     | 348 ++++++++++++++++-----
 5 files changed, 520 insertions(+), 120 deletions(-)

diff --git 
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/EncodeContent.java
 
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/EncodeContent.java
index d6e49725b9..29f23ee3ed 100644
--- 
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/EncodeContent.java
+++ 
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/EncodeContent.java
@@ -16,6 +16,14 @@
  */
 package org.apache.nifi.processors.standard;
 
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
 import org.apache.commons.codec.DecoderException;
 import org.apache.commons.codec.binary.Base32InputStream;
 import org.apache.commons.codec.binary.Base32OutputStream;
@@ -29,25 +37,22 @@ import org.apache.nifi.annotation.behavior.SupportsBatching;
 import org.apache.nifi.annotation.documentation.CapabilityDescription;
 import org.apache.nifi.annotation.documentation.Tags;
 import org.apache.nifi.components.PropertyDescriptor;
+import org.apache.nifi.expression.ExpressionLanguageScope;
 import org.apache.nifi.flowfile.FlowFile;
 import org.apache.nifi.processor.AbstractProcessor;
 import org.apache.nifi.processor.ProcessContext;
 import org.apache.nifi.processor.ProcessSession;
 import org.apache.nifi.processor.Relationship;
 import org.apache.nifi.processor.io.StreamCallback;
+import org.apache.nifi.processor.util.StandardValidators;
+import org.apache.nifi.processors.standard.encoding.EncodingMode;
+import org.apache.nifi.processors.standard.encoding.EncodingType;
+import org.apache.nifi.processors.standard.encoding.LineOutputMode;
 import org.apache.nifi.processors.standard.util.ValidatingBase32InputStream;
 import org.apache.nifi.processors.standard.util.ValidatingBase64InputStream;
 import org.apache.nifi.stream.io.StreamUtils;
 import org.apache.nifi.util.StopWatch;
 
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
 @SideEffectFree
 @SupportsBatching
 @InputRequirement(Requirement.INPUT_REQUIRED)
@@ -55,33 +60,52 @@ import java.util.concurrent.TimeUnit;
 @CapabilityDescription("Encode or decode the contents of a FlowFile using 
Base64, Base32, or hex encoding schemes")
 public class EncodeContent extends AbstractProcessor {
 
-    public static final String ENCODE_MODE = "Encode";
-    public static final String DECODE_MODE = "Decode";
-
-    public static final String BASE64_ENCODING = "base64";
-    public static final String BASE32_ENCODING = "base32";
-    public static final String HEX_ENCODING = "hex";
-
     public static final PropertyDescriptor MODE = new 
PropertyDescriptor.Builder()
             .name("Mode")
-            .description("Specifies whether the content should be encoded or 
decoded")
+            .description("Specifies whether the content should be encoded or 
decoded.")
             .required(true)
-            .allowableValues(ENCODE_MODE, DECODE_MODE)
-            .defaultValue(ENCODE_MODE)
+            .allowableValues(EncodingMode.class)
+            .defaultValue(EncodingMode.ENCODE)
             .build();
 
     public static final PropertyDescriptor ENCODING = new 
PropertyDescriptor.Builder()
             .name("Encoding")
-            .description("Specifies the type of encoding used")
+            .description("Specifies the type of encoding used.")
+            .required(true)
+            .allowableValues(EncodingType.class)
+            .defaultValue(EncodingType.BASE64)
+            .build();
+
+    public static final PropertyDescriptor LINE_OUTPUT_MODE = new 
PropertyDescriptor.Builder()
+            .name("Line Output Mode")
+            .displayName("Line Output Mode")
+            .description("Controls the line formatting for encoded content 
based on selected property values.")
             .required(true)
-            .allowableValues(BASE64_ENCODING, BASE32_ENCODING, HEX_ENCODING)
-            .defaultValue(BASE64_ENCODING)
+            .defaultValue(LineOutputMode.SINGLE_LINE)
+            .allowableValues(LineOutputMode.class)
+            .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
+            .dependsOn(MODE, EncodingMode.ENCODE)
+            .dependsOn(ENCODING, EncodingType.BASE64, EncodingType.BASE32)
+            .build();
+
+    public static final PropertyDescriptor ENCODED_LINE_LENGTH = new 
PropertyDescriptor.Builder()
+            .name("Encoded Line Length")
+            .displayName("Encoded Line Length")
+            .description("Each line of encoded data will contain up to the 
configured number of characters, rounded down to the nearest multiple of 4.")
+            .required(true)
+            .defaultValue("76")
+            
.expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES)
+            .addValidator(StandardValidators.POSITIVE_INTEGER_VALIDATOR)
+            .dependsOn(MODE, EncodingMode.ENCODE)
+            .dependsOn(ENCODING, EncodingType.BASE64, EncodingType.BASE32)
+            .dependsOn(LINE_OUTPUT_MODE, LineOutputMode.MULTIPLE_LINES)
             .build();
 
     public static final Relationship REL_SUCCESS = new Relationship.Builder()
             .name("success")
             .description("Any FlowFile that is successfully encoded or decoded 
will be routed to success")
             .build();
+
     public static final Relationship REL_FAILURE = new Relationship.Builder()
             .name("failure")
             .description("Any FlowFile that cannot be encoded or decoded will 
be routed to failure")
@@ -89,11 +113,16 @@ public class EncodeContent extends AbstractProcessor {
 
     private static final int BUFFER_SIZE = 8192;
 
-    private static final List<PropertyDescriptor> properties = List.of(MODE,
-        ENCODING);
+    private static final String LINE_FEED_SEPARATOR = "\n";
+
+    private static final List<PropertyDescriptor> properties = List.of(
+            MODE,
+            ENCODING,
+            LINE_OUTPUT_MODE,
+            ENCODED_LINE_LENGTH
+    );
 
-    private static final Set<Relationship> relationships = Set.of(REL_SUCCESS,
-        REL_FAILURE);
+    private static final Set<Relationship> relationships = Set.of(REL_SUCCESS, 
REL_FAILURE);
 
     @Override
     public Set<Relationship> getRelationships() {
@@ -112,9 +141,12 @@ public class EncodeContent extends AbstractProcessor {
             return;
         }
 
-        final boolean encode = 
context.getProperty(MODE).getValue().equalsIgnoreCase(ENCODE_MODE);
-        final String encoding = context.getProperty(ENCODING).getValue();
-        final StreamCallback callback = getStreamCallback(encode, encoding);
+        final boolean encode = 
context.getProperty(MODE).getValue().equals(EncodingMode.ENCODE.getValue());
+        final EncodingType encoding = 
getEncodingType(context.getProperty(ENCODING).getValue());
+        final boolean singleLineOutput = 
context.getProperty(LINE_OUTPUT_MODE).getValue().equals(LineOutputMode.SINGLE_LINE.getValue());
+        final int lineLength = singleLineOutput ? -1 : 
context.getProperty(ENCODED_LINE_LENGTH).evaluateAttributeExpressions(flowFile).asInteger();
+
+        final StreamCallback callback = getStreamCallback(encode, encoding, 
lineLength);
 
         try {
             final StopWatch stopWatch = new StopWatch(true);
@@ -129,31 +161,31 @@ public class EncodeContent extends AbstractProcessor {
         }
     }
 
-    private static StreamCallback getStreamCallback(final boolean encode, 
final String encoding) {
-        if (encode) {
-            if (encoding.equalsIgnoreCase(BASE64_ENCODING)) {
-                return new EncodeBase64();
-            } else if (encoding.equalsIgnoreCase(BASE32_ENCODING)) {
-                return new EncodeBase32();
-            } else {
-                return new EncodeHex();
-            }
-        } else {
-            if (encoding.equalsIgnoreCase(BASE64_ENCODING)) {
-                return new DecodeBase64();
-            } else if (encoding.equalsIgnoreCase(BASE32_ENCODING)) {
-                return new DecodeBase32();
-            } else {
-                return new DecodeHex();
-            }
-        }
+    private static StreamCallback getStreamCallback(final boolean encode, 
final EncodingType encoding, final int lineLength) {
+        return switch (encoding) {
+            case BASE64 -> encode ? new EncodeBase64(lineLength, 
LINE_FEED_SEPARATOR) : new DecodeBase64();
+            case BASE32 -> encode ? new EncodeBase32(lineLength, 
LINE_FEED_SEPARATOR) : new DecodeBase32();
+            default -> encode ? new EncodeHex() : new DecodeHex();
+        };
     }
 
     private static class EncodeBase64 implements StreamCallback {
 
+       private final int lineLength;
+       private final String lineSeparator;
+
+        private EncodeBase64(final int lineLength,
+            final String lineSeparator) {
+            this.lineLength = lineLength;
+            this.lineSeparator = lineSeparator;
+        }
+
         @Override
         public void process(final InputStream in, final OutputStream out) 
throws IOException {
-            try (Base64OutputStream bos = new Base64OutputStream(out)) {
+            try (Base64OutputStream bos = new Base64OutputStream(out,
+                true,
+                this.lineLength,
+                this.lineSeparator.getBytes())) {
                 StreamUtils.copy(in, bos);
             }
         }
@@ -171,9 +203,19 @@ public class EncodeContent extends AbstractProcessor {
 
     private static class EncodeBase32 implements StreamCallback {
 
+        private final int lineLength;
+        private final String lineSeparator;
+
+        public EncodeBase32(final int lineLength,
+            final String lineSeparator) {
+
+            this.lineLength = lineLength;
+            this.lineSeparator = lineSeparator;
+        }
+
         @Override
         public void process(final InputStream in, final OutputStream out) 
throws IOException {
-            try (Base32OutputStream bos = new Base32OutputStream(out)) {
+            try (Base32OutputStream bos = new Base32OutputStream(out, true, 
this.lineLength, this.lineSeparator.getBytes())) {
                 StreamUtils.copy(in, bos);
             }
         }
@@ -237,4 +279,14 @@ public class EncodeContent extends AbstractProcessor {
             out.flush();
         }
     }
+
+    private static EncodingType getEncodingType(final String 
encodingTypeValue) {
+        if (EncodingType.BASE64.getValue().equals(encodingTypeValue)) {
+            return EncodingType.BASE64;
+        } else if (EncodingType.BASE32.getValue().equals(encodingTypeValue)) {
+            return EncodingType.BASE32;
+        } else {
+            return EncodingType.HEXADECIMAL;
+        }
+    }
 }
diff --git 
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/encoding/EncodingMode.java
 
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/encoding/EncodingMode.java
new file mode 100644
index 0000000000..710c5ac1b7
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/encoding/EncodingMode.java
@@ -0,0 +1,47 @@
+/*
+ * 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
+ *
+ *     http://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.nifi.processors.standard.encoding;
+
+import org.apache.nifi.components.DescribedValue;
+
+public enum EncodingMode implements DescribedValue {
+    ENCODE("Encode", "Transform original input to encoded representation"),
+    DECODE("Decode", "Transform encoded input to original representation");
+
+    EncodingMode(String value, String description) {
+        this.value = value;
+        this.description = description;
+    }
+
+    private final String value;
+    private final String description;
+
+    @Override
+    public String getValue() {
+        return value;
+    }
+
+    @Override
+    public String getDisplayName() {
+        return value;
+    }
+
+    @Override
+    public String getDescription() {
+        return description;
+    }
+ }
diff --git 
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/encoding/EncodingType.java
 
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/encoding/EncodingType.java
new file mode 100644
index 0000000000..aea183a4d2
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/encoding/EncodingType.java
@@ -0,0 +1,50 @@
+/*
+ * 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
+ *
+ *     http://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.nifi.processors.standard.encoding;
+
+import org.apache.nifi.components.DescribedValue;
+
+public enum EncodingType implements DescribedValue {
+    BASE64("base64", "Base64", "Encode or decode using Base64 set of 
characters"),
+    BASE32("base32", "Base32", "Encode or decode using Base32 set of 
characters"),
+    HEXADECIMAL("hex", "Hexadecimal", "Encode or decode using hexadecimal set 
of characters");
+
+    private final String value;
+    private final String displayName;
+    private final String description;
+
+    EncodingType(String value, String displayName, String description) {
+        this.value = value;
+        this.displayName = displayName;
+        this.description = description;
+    }
+
+    @Override
+    public String getValue() {
+        return value;
+    }
+
+    @Override
+    public String getDisplayName() {
+        return displayName;
+    }
+
+    @Override
+    public String getDescription() {
+        return description;
+    }
+}
diff --git 
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/encoding/LineOutputMode.java
 
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/encoding/LineOutputMode.java
new file mode 100644
index 0000000000..71062cf519
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/encoding/LineOutputMode.java
@@ -0,0 +1,47 @@
+/*
+ * 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
+ *
+ *     http://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.nifi.processors.standard.encoding;
+
+import org.apache.nifi.components.DescribedValue;
+
+public enum LineOutputMode implements DescribedValue {
+    SINGLE_LINE("Single Line", "The encoded content will be written as a 
single line."),
+    MULTIPLE_LINES("Multiple Lines", "The encoded content will be written as 
multiple lines.");
+
+    private final String displayName;
+    private final String description;
+
+    LineOutputMode(String displayName, String description) {
+        this.displayName = displayName;
+        this.description = description;
+    }
+
+    @Override
+    public String getValue() {
+        return name();
+    }
+
+    @Override
+    public String getDisplayName() {
+        return displayName;
+    }
+
+    @Override
+    public String getDescription() {
+        return description;
+    }
+}
diff --git 
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestEncodeContent.java
 
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestEncodeContent.java
index b8da70c754..602b2e8340 100644
--- 
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestEncodeContent.java
+++ 
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestEncodeContent.java
@@ -16,25 +16,59 @@
  */
 package org.apache.nifi.processors.standard;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
 import java.io.IOException;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.stream.Stream;
 
+import org.apache.nifi.components.DescribedValue;
+import org.apache.nifi.processor.Relationship;
+import org.apache.nifi.processors.standard.encoding.EncodingMode;
+import org.apache.nifi.processors.standard.encoding.EncodingType;
+import org.apache.nifi.processors.standard.encoding.LineOutputMode;
 import org.apache.nifi.util.MockFlowFile;
+import org.apache.nifi.util.StringUtils;
 import org.apache.nifi.util.TestRunner;
 import org.apache.nifi.util.TestRunners;
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.EnumSource;
+import org.junit.jupiter.params.provider.MethodSource;
+
+class TestEncodeContent {
 
-public class TestEncodeContent {
+    private static final String LOREM_IPSUM = "Lorem ipsum dolor sit amet, 
consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et 
dolore magna aliqua.";
 
     private static final Path FILE_PATH = 
Paths.get("src/test/resources/hello.txt");
 
+    private TestRunner testRunner;
+
+    @BeforeEach
+    void setUp() {
+        testRunner = TestRunners.newTestRunner(EncodeContent.class);
+    }
+
     @Test
-    public void testBase64RoundTrip() throws IOException {
-        final TestRunner testRunner = TestRunners.newTestRunner(new 
EncodeContent());
+    void testFailDecodeNotBase64ButIsAMultipleOfFourBytes() {
+        testRunner.setProperty(EncodeContent.MODE, EncodingMode.DECODE);
+        testRunner.setProperty(EncodeContent.ENCODING, EncodingType.BASE64);
 
-        testRunner.setProperty(EncodeContent.MODE, EncodeContent.ENCODE_MODE);
-        testRunner.setProperty(EncodeContent.ENCODING, 
EncodeContent.BASE64_ENCODING);
+        testRunner.enqueue("four@@@@multiple".getBytes());
+        testRunner.clearTransferState();
+        testRunner.run();
+
+        testRunner.assertAllFlowFilesTransferred(EncodeContent.REL_FAILURE, 1);
+    }
+
+    @ParameterizedTest
+    @EnumSource(value = EncodingType.class)
+    void testRoundTrip(final EncodingType encoding) throws IOException {
+        testRunner.setProperty(EncodeContent.MODE, EncodingMode.ENCODE);
+        testRunner.setProperty(EncodeContent.ENCODING, encoding);
 
         testRunner.enqueue(FILE_PATH);
         testRunner.clearTransferState();
@@ -45,7 +79,7 @@ public class TestEncodeContent {
         MockFlowFile flowFile = 
testRunner.getFlowFilesForRelationship(EncodeContent.REL_SUCCESS).get(0);
         testRunner.assertQueueEmpty();
 
-        testRunner.setProperty(EncodeContent.MODE, EncodeContent.DECODE_MODE);
+        testRunner.setProperty(EncodeContent.MODE, EncodingMode.DECODE);
         testRunner.enqueue(flowFile);
         testRunner.clearTransferState();
         testRunner.run();
@@ -55,12 +89,11 @@ public class TestEncodeContent {
         flowFile.assertContentEquals(FILE_PATH);
     }
 
-    @Test
-    public void testFailDecodeNotBase64() throws IOException {
-        final TestRunner testRunner = TestRunners.newTestRunner(new 
EncodeContent());
-
-        testRunner.setProperty(EncodeContent.MODE, EncodeContent.DECODE_MODE);
-        testRunner.setProperty(EncodeContent.ENCODING, 
EncodeContent.BASE64_ENCODING);
+    @ParameterizedTest
+    @EnumSource(value = EncodingType.class)
+    void testDecodeFailure(final EncodingType encoding) throws IOException {
+        testRunner.setProperty(EncodeContent.MODE, EncodingMode.DECODE);
+        testRunner.setProperty(EncodeContent.ENCODING, encoding);
 
         testRunner.enqueue(FILE_PATH);
         testRunner.clearTransferState();
@@ -70,96 +103,267 @@ public class TestEncodeContent {
     }
 
     @Test
-    public void testFailDecodeNotBase64ButIsAMultipleOfFourBytes() {
-        final TestRunner testRunner = TestRunners.newTestRunner(new 
EncodeContent());
-
-        testRunner.setProperty(EncodeContent.MODE, EncodeContent.DECODE_MODE);
-        testRunner.setProperty(EncodeContent.ENCODING, 
EncodeContent.BASE64_ENCODING);
+    void testEncodeDecodeSpecialCharsBase64() {
+        final String specialChars = "!@#$%^&*()_+{}:\"<>?[];',./~`-=";
+        final String expectedOutput = 
"IUAjJCVeJiooKV8re306Ijw+P1tdOycsLi9+YC09\n";
 
-        testRunner.enqueue("four@@@@multiple".getBytes());
-        testRunner.clearTransferState();
-        testRunner.run();
+        executeTestSuccessHelper(EncodingMode.ENCODE, EncodingType.BASE64, 
specialChars, expectedOutput);
+        testRunner.clearTransferState(); // clear the state for the next test
+        executeTestSuccessHelper(EncodingMode.DECODE, EncodingType.BASE64, 
expectedOutput, specialChars);
+    }
 
-        testRunner.assertAllFlowFilesTransferred(EncodeContent.REL_FAILURE, 1);
+    @ParameterizedTest
+    @MethodSource("encodeBase32Args")
+    void testBasicDecodeBase32(final String input, final String 
expectedOutput) {
+        // use the same args from `encodeBase32Args`, only flip around input 
and output
+        executeTestSuccessHelper(EncodingMode.DECODE, EncodingType.BASE32, 
expectedOutput, input);
     }
 
-    @Test
-    public void testBase32RoundTrip() throws IOException {
-        final TestRunner testRunner = TestRunners.newTestRunner(new 
EncodeContent());
+    @ParameterizedTest
+    @MethodSource("encodeBase64Args")
+    void testBasicDecodeBase64(final String input, final String 
expectedOutput) {
+        // use the same args from `encodeBase64Args`, only flip around input 
and output
+        executeTestSuccessHelper(EncodingMode.DECODE, EncodingType.BASE64, 
expectedOutput, input);
+    }
 
-        testRunner.setProperty(EncodeContent.MODE, EncodeContent.ENCODE_MODE);
-        testRunner.setProperty(EncodeContent.ENCODING, 
EncodeContent.BASE32_ENCODING);
+    @ParameterizedTest
+    @MethodSource("encodeHexArgs")
+    void testBasicDecodeHex(final String input, final String expectedOutput) {
+        // use the same args from `encodeHexArgs`, only flip around input and 
output
+        executeTestSuccessHelper(EncodingMode.DECODE, 
EncodingType.HEXADECIMAL, expectedOutput, input);
+    }
 
-        testRunner.enqueue(FILE_PATH);
-        testRunner.clearTransferState();
-        testRunner.run();
+    @ParameterizedTest
+    @MethodSource("encodeHexArgs")
+    void testBasicEncodeHex(final String input, final String expectedOutput) {
+        executeTestSuccessHelper(EncodingMode.ENCODE, 
EncodingType.HEXADECIMAL, input, expectedOutput);
+    }
 
-        testRunner.assertAllFlowFilesTransferred(EncodeContent.REL_SUCCESS, 1);
+    private static Stream<Arguments> encodeHexArgs() {
+       return Stream.of(
+               Arguments.of("hello", "68656C6C6F"),
+               Arguments.of("foo", "666F6F"),
+               Arguments.of("你好", "E4BDA0E5A5BD"),
+               Arguments.of("Здравствуйте", 
"D097D0B4D180D0B0D0B2D181D182D0B2D183D0B9D182D0B5")
+       );
+   }
+
+    @ParameterizedTest
+    @MethodSource("encodeBase32Args")
+    void testBasicEncodeBase32(final String input, final String 
expectedOutput) {
+        executeTestSuccessHelper(EncodingMode.ENCODE, EncodingType.BASE32, 
input, expectedOutput);
+    }
 
-        MockFlowFile flowFile = 
testRunner.getFlowFilesForRelationship(EncodeContent.REL_SUCCESS).get(0);
-        testRunner.assertQueueEmpty();
+    private static Stream<Arguments> encodeBase32Args() {
+       return Stream.of(
+               Arguments.of("hello", "NBSWY3DP\n"),
+               Arguments.of("foo", "MZXW6===\n"),
+               Arguments.of("你好", "4S62BZNFXU======\n"),
+               Arguments.of("Здравствуйте", 
"2CL5BNGRQDILBUFS2GA5DAWQWLIYHUFZ2GBNBNI=\n")
+       );
+   }
+
+    @ParameterizedTest
+    @MethodSource("encodeBase64Args")
+    void testBasicEncodeBase64(final String input, final String 
expectedOutput) {
+        executeTestSuccessHelper(EncodingMode.ENCODE, EncodingType.BASE64, 
input, expectedOutput);
+    }
 
-        testRunner.setProperty(EncodeContent.MODE, EncodeContent.DECODE_MODE);
-        testRunner.enqueue(flowFile);
-        testRunner.clearTransferState();
-        testRunner.run();
-        testRunner.assertAllFlowFilesTransferred(EncodeContent.REL_SUCCESS, 1);
+    private static Stream<Arguments> encodeBase64Args() {
+       return Stream.of(
+               Arguments.of("hello", "aGVsbG8=\n"),
+               Arguments.of("foo", "Zm9v\n"),
+               Arguments.of("你好", "5L2g5aW9\n"),
+               Arguments.of("Здравствуйте", 
"0JfQtNGA0LDQstGB0YLQstGD0LnRgtC1\n")
+       );
+   }
 
-        flowFile = 
testRunner.getFlowFilesForRelationship(EncodeContent.REL_SUCCESS).get(0);
-        flowFile.assertContentEquals(FILE_PATH);
+    @Test
+    void testBlankValueShouldNotFail() {
+        executeTestSuccessHelper(EncodingMode.ENCODE,
+            EncodingType.BASE64,
+            StringUtils.EMPTY,
+            StringUtils.EMPTY);
     }
 
     @Test
-    public void testFailDecodeNotBase32() throws IOException {
-        final TestRunner testRunner = TestRunners.newTestRunner(new 
EncodeContent());
+    void testEncodeContentMultipleLinesBase64() {
+        // this input is greater than 57 bytes, sure to generate multiple 
lines in base64
+        final String expectedOutput = 
"TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdCwg\n"
+            + 
"c2VkIGRvIGVpdXNtb2QgdGVtcG9yIGluY2lkaWR1bnQgdXQgbGFib3JlIGV0IGRvbG9yZSBtYWdu\n"
+            + "YSBhbGlxdWEu\n";
+
+        // Execute the test using the helper method
+        executeTestHelper(EncodingMode.ENCODE,
+            EncodingType.BASE64,
+            LOREM_IPSUM,
+            LineOutputMode.MULTIPLE_LINES,
+            expectedOutput,
+            EncodeContent.REL_SUCCESS);
+    }
 
-        testRunner.setProperty(EncodeContent.MODE, EncodeContent.DECODE_MODE);
-        testRunner.setProperty(EncodeContent.ENCODING, 
EncodeContent.BASE32_ENCODING);
+    @Test
+    void testEncodeContentSingleLineBase64() {
+        // this input is greater than 57 bytes, sure to generate multiple 
lines in base64
+        final String expectedOutput = 
"TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdCwg"
+            + 
"c2VkIGRvIGVpdXNtb2QgdGVtcG9yIGluY2lkaWR1bnQgdXQgbGFib3JlIGV0IGRvbG9yZSBtYWdu"
+            + "YSBhbGlxdWEu";
+
+        // Execute the test using the helper method
+        executeTestHelper(EncodingMode.ENCODE,
+            EncodingType.BASE64,
+            LOREM_IPSUM,
+            LineOutputMode.SINGLE_LINE,
+            expectedOutput,
+            EncodeContent.REL_SUCCESS);
+    }
 
-        testRunner.enqueue(FILE_PATH);
-        testRunner.clearTransferState();
-        testRunner.run();
+    @Test
+    void testEncodeContentSingleLineBase32() {
+        // this input is greater than 57 bytes, sure to generate multiple 
lines in base64
+        final String expectedOutput = 
"JRXXEZLNEBUXA43VNUQGI33MN5ZCA43JOQQGC3LFOQWCAY3PNZZWKY3UMV2HK4RAMFSGS4DJONRWS3THEBSWY2LUF"
+            + 
"QQHGZLEEBSG6IDFNF2XG3LPMQQHIZLNOBXXEIDJNZRWSZDJMR2W45BAOV2CA3DBMJXXEZJAMV2CAZDPNRXXEZJANVQWO3TBEBQWY2LROVQS4===";
+
+        // Execute the test using the helper method
+        executeTestHelper(EncodingMode.ENCODE,
+            EncodingType.BASE32,
+            LOREM_IPSUM,
+            LineOutputMode.SINGLE_LINE,
+            expectedOutput,
+            EncodeContent.REL_SUCCESS);
+    }
 
-        testRunner.assertAllFlowFilesTransferred(EncodeContent.REL_FAILURE, 1);
+    @Test
+    void testEncodeContentMultipleLinesBase32() {
+        // this input is greater than 57 bytes, sure to generate multiple 
lines in base64
+        final String expectedOutput = 
"JRXXEZLNEBUXA43VNUQGI33MN5ZCA43JOQQGC3LFOQWCAY3PNZZWKY3UMV2HK4RAMFSGS4DJ\n"
+            + 
"ONRWS3THEBSWY2LUFQQHGZLEEBSG6IDFNF2XG3LPMQQHIZLNOBXXEIDJNZRWSZDJMR2W45BA\n"
+            + "OV2CA3DBMJXXEZJAMV2CAZDPNRXXEZJANVQWO3TBEBQWY2LROVQS4===\n";
+
+        // Execute the test using the helper method
+        executeTestHelper(EncodingMode.ENCODE,
+            EncodingType.BASE32,
+            LOREM_IPSUM,
+            LineOutputMode.MULTIPLE_LINES, // set false to output multiple 
lines
+            expectedOutput,
+            EncodeContent.REL_SUCCESS);
     }
 
     @Test
-    public void testHexRoundTrip() throws IOException {
-        final TestRunner testRunner = TestRunners.newTestRunner(new 
EncodeContent());
+    void testEncodeContentMultipleLinesNonStandardLengthBase32() {
+        // this input is greater than 57 bytes, sure to generate multiple 
lines in base64
+        final String expectedOutput = 
"JRXXEZLNEBUXA43VNUQGI33MN5ZCA43JOQQGC3LFOQWCAY3PNZZWKY3UMV2HK4RAMFSGS4DJONRWS3TH\n"
+            + 
"EBSWY2LUFQQHGZLEEBSG6IDFNF2XG3LPMQQHIZLNOBXXEIDJNZRWSZDJMR2W45BAOV2CA3DBMJXXEZJA\n"
+            + "MV2CAZDPNRXXEZJANVQWO3TBEBQWY2LROVQS4===\n";
+
+        // Execute the test using the helper method
+        executeTestHelper(EncodingMode.ENCODE,
+            EncodingType.BASE32,
+            LOREM_IPSUM,
+            LineOutputMode.MULTIPLE_LINES,
+            80,
+            expectedOutput,
+            EncodeContent.REL_SUCCESS);
+    }
 
-        testRunner.setProperty(EncodeContent.MODE, EncodeContent.ENCODE_MODE);
-        testRunner.setProperty(EncodeContent.ENCODING, 
EncodeContent.HEX_ENCODING);
+    @Test
+    void testThatLineLengthIsIgnoredIfSingleLineOutputTrueBase32() {
+        // this input is greater than 57 bytes, sure to generate multiple 
lines in base64
+        final String expectedOutput = 
"JRXXEZLNEBUXA43VNUQGI33MN5ZCA43JOQQGC3LFOQWCAY3PNZZWKY3UMV2HK4RAMFSGS4DJONRWS3THEBSWY2LUFQQHGZLEEB"
+            + 
"SG6IDFNF2XG3LPMQQHIZLNOBXXEIDJNZRWSZDJMR2W45BAOV2CA3DBMJXXEZJAMV2CAZDPNRXXEZJANVQWO3TBEBQWY2LROVQS4===";
+
+        // Setting a low value for `lineLength` but single line true ensures 
that `lineLength` is ignored
+        executeTestHelper(EncodingMode.ENCODE,
+            EncodingType.BASE32,
+            LOREM_IPSUM,
+            LineOutputMode.SINGLE_LINE,
+            2, // set a low value >= 0
+            expectedOutput,
+            EncodeContent.REL_SUCCESS);
+    }
 
-        testRunner.enqueue(FILE_PATH);
-        testRunner.clearTransferState();
-        testRunner.run();
+    @Test
+    void testEncodeContentMultipleLinesNonStandardLengthBase64() {
+        // this input is greater than 57 bytes, sure to generate multiple 
lines in base64
+        final String expectedOutput = 
"TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdCwgc2Vk\n"
+            + 
"IGRvIGVpdXNtb2QgdGVtcG9yIGluY2lkaWR1bnQgdXQgbGFib3JlIGV0IGRvbG9yZSBtYWduYSBhbGlx\n"
+            + "dWEu\n";
+
+        // Execute the test using the helper method
+        executeTestHelper(EncodingMode.ENCODE,
+            EncodingType.BASE64,
+            LOREM_IPSUM,
+            LineOutputMode.MULTIPLE_LINES, // set false to output multiple 
lines
+            80,
+            expectedOutput,
+            EncodeContent.REL_SUCCESS);
+    }
 
-        testRunner.assertAllFlowFilesTransferred(EncodeContent.REL_SUCCESS, 1);
+    @Test
+    void testThatLineLengthIsIgnoredIfSingleLineOutputTrueBase64() {
+        // this input is greater than 57 bytes, sure to generate multiple 
lines in base64
+        final String expectedOutput = 
"TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdCwg"
+            + 
"c2VkIGRvIGVpdXNtb2QgdGVtcG9yIGluY2lkaWR1bnQgdXQgbGFib3JlIGV0IGRvbG9yZSBtYWdu"
+            + "YSBhbGlxdWEu";
+
+        // Setting a low value for `lineLength` but single line true ensures 
that `lineLength` is ignored
+        executeTestHelper(EncodingMode.ENCODE,
+            EncodingType.BASE64,
+            LOREM_IPSUM,
+            LineOutputMode.SINGLE_LINE, // set true to output single line
+            2,                                      // set a low value >= 0
+            expectedOutput,
+            EncodeContent.REL_SUCCESS);
+    }
 
-        MockFlowFile flowFile = 
testRunner.getFlowFilesForRelationship(EncodeContent.REL_SUCCESS).get(0);
-        testRunner.assertQueueEmpty();
+    private void executeTestSuccessHelper(final DescribedValue mode,
+        final DescribedValue encodingType,
+        final String input,
+        final String expectedOutput) {
+        executeTestSuccessHelper(mode, encodingType, input, 
LineOutputMode.MULTIPLE_LINES, expectedOutput);
+    }
 
-        testRunner.setProperty(EncodeContent.MODE, EncodeContent.DECODE_MODE);
-        testRunner.enqueue(flowFile);
-        testRunner.clearTransferState();
-        testRunner.run();
-        testRunner.assertAllFlowFilesTransferred(EncodeContent.REL_SUCCESS, 1);
+    private void executeTestSuccessHelper(final DescribedValue mode,
+        final DescribedValue encodingType,
+        final String input,
+        final DescribedValue outputToSingleLine,
+        final String expectedOutput) {
+        executeTestHelper(mode, encodingType, input, outputToSingleLine, 
expectedOutput, EncodeContent.REL_SUCCESS);
+    }
 
-        flowFile = 
testRunner.getFlowFilesForRelationship(EncodeContent.REL_SUCCESS).get(0);
-        flowFile.assertContentEquals(FILE_PATH);
+    private void executeTestHelper(final DescribedValue mode,
+        final DescribedValue encodingType,
+        final String input,
+        final DescribedValue outputToSingleLine,
+        final String expectedOutput,
+        final Relationship routedTo) {
+        executeTestHelper(mode,
+            encodingType,
+            input,
+            outputToSingleLine,
+            76,
+            expectedOutput,
+            routedTo);
     }
 
-    @Test
-    public void testFailDecodeNotHex() throws IOException {
-        final TestRunner testRunner = TestRunners.newTestRunner(new 
EncodeContent());
+    private void executeTestHelper(final DescribedValue mode,
+        final DescribedValue encodingType,
+        final String input,
+        final DescribedValue outputToSingleLine,
+        final Integer lineLength,
+        final String expectedOutput,
+        final Relationship routedTo) {
 
-        testRunner.setProperty(EncodeContent.MODE, EncodeContent.DECODE_MODE);
-        testRunner.setProperty(EncodeContent.ENCODING, 
EncodeContent.HEX_ENCODING);
+        testRunner.setProperty(EncodeContent.MODE, mode);
+        testRunner.setProperty(EncodeContent.ENCODING, encodingType);
+        testRunner.setProperty(EncodeContent.LINE_OUTPUT_MODE, 
outputToSingleLine);
+        testRunner.setProperty(EncodeContent.ENCODED_LINE_LENGTH, 
Integer.toString(lineLength));
 
-        testRunner.enqueue(FILE_PATH);
-        testRunner.clearTransferState();
+        testRunner.enqueue(input);
         testRunner.run();
 
-        testRunner.assertAllFlowFilesTransferred(EncodeContent.REL_FAILURE, 1);
+        final MockFlowFile result = 
testRunner.getFlowFilesForRelationship(routedTo).get(0);
+        assertEquals(expectedOutput, result.getContent());
+        testRunner.assertAllFlowFilesTransferred(routedTo, 1);
     }
 }


Reply via email to