dan-s1 commented on code in PR #8417:
URL: https://github.com/apache/nifi/pull/8417#discussion_r1503439274


##########
nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/EncodeContent.java:
##########
@@ -29,55 +37,88 @@
 import org.apache.nifi.annotation.documentation.CapabilityDescription;
 import org.apache.nifi.annotation.documentation.Tags;
 import org.apache.nifi.components.PropertyDescriptor;
+import org.apache.nifi.components.Validator;
+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)
 @Tags({"encode", "decode", "base64", "base32", "hex"})
 @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")
             .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")
             .required(true)
-            .allowableValues(BASE64_ENCODING, BASE32_ENCODING, HEX_ENCODING)
-            .defaultValue(BASE64_ENCODING)
+            .allowableValues(EncodingType.class)
+            .defaultValue(EncodingType.BASE64_ENCODING)
+            .build();
+
+    static final PropertyDescriptor LINE_OUTPUT_MODE = new 
PropertyDescriptor.Builder()
+            .name("line-output-mode")
+            .displayName("Line Output Mode")
+            .description("If set to 'single-line', the encoded FlowFile 
content will output as a single line. If set to 'multiple-lines', "
+                + "it will output as multiple lines. This property is only 
applicable when Base64 or Base32 encoding is selected.")
+            .required(false)
+            .defaultValue(LineOutputMode.SINGLE_LINE)
+            .allowableValues(LineOutputMode.class)
+            .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
+            .dependsOn(MODE, EncodingMode.ENCODE)
+            .dependsOn(ENCODING, EncodingType.BASE64_ENCODING, 
EncodingType.BASE32_ENCODING)
             .build();
 
+    static final PropertyDescriptor ENCODED_LINE_SEPARATOR = new 
PropertyDescriptor.Builder()
+        .name("line-separator")

Review Comment:
   ```suggestion
           .name("Encoded Content Line Separator")
   ```



##########
nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/EncodeContent.java:
##########
@@ -112,9 +153,14 @@ public void onTrigger(final ProcessContext context, final 
ProcessSession session
             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 = 
EncodingType.valueOf(context.getProperty(ENCODING).getValue());
+
+        final Boolean singleLineOutput = 
context.getProperty(LINE_OUTPUT_MODE).getValue().equals(LineOutputMode.SINGLE_LINE.getValue());

Review Comment:
   ```suggestion
           final boolean singleLineOutput = 
context.getProperty(LINE_OUTPUT_MODE).getValue().equals(LineOutputMode.SINGLE_LINE.getValue());
   ```



##########
nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/EncodeContent.java:
##########
@@ -29,55 +37,88 @@
 import org.apache.nifi.annotation.documentation.CapabilityDescription;
 import org.apache.nifi.annotation.documentation.Tags;
 import org.apache.nifi.components.PropertyDescriptor;
+import org.apache.nifi.components.Validator;
+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)
 @Tags({"encode", "decode", "base64", "base32", "hex"})
 @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")
             .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")
             .required(true)
-            .allowableValues(BASE64_ENCODING, BASE32_ENCODING, HEX_ENCODING)
-            .defaultValue(BASE64_ENCODING)
+            .allowableValues(EncodingType.class)
+            .defaultValue(EncodingType.BASE64_ENCODING)
+            .build();
+
+    static final PropertyDescriptor LINE_OUTPUT_MODE = new 
PropertyDescriptor.Builder()
+            .name("line-output-mode")

Review Comment:
   ```suggestion
               .name("Line Output Mode")
   ```



##########
nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestEncodeContent.java:
##########
@@ -70,96 +102,310 @@ public void testFailDecodeNotBase64() throws IOException {
     }
 
     @Test
-    public void testFailDecodeNotBase64ButIsAMultipleOfFourBytes() {
-        final TestRunner testRunner = TestRunners.newTestRunner(new 
EncodeContent());
+    void testEncodeDecodeSpecialCharsBase64() {
+        final String specialChars = "!@#$%^&*()_+{}:\"<>?[];',./~`-=";
+        final String expectedOutput = 
"IUAjJCVeJiooKV8re306Ijw+P1tdOycsLi9+YC09" + System.lineSeparator();
 
-        testRunner.setProperty(EncodeContent.MODE, EncodeContent.DECODE_MODE);
-        testRunner.setProperty(EncodeContent.ENCODING, 
EncodeContent.BASE64_ENCODING);
-
-        testRunner.enqueue("four@@@@multiple".getBytes());
-        testRunner.clearTransferState();
-        testRunner.run();
+        executeTestSuccessHelper(EncodingMode.ENCODE, 
EncodingType.BASE64_ENCODING, specialChars, expectedOutput);
+        testRunner.clearTransferState(); // clear the state for the next test
+        executeTestSuccessHelper(EncodingMode.DECODE, 
EncodingType.BASE64_ENCODING, expectedOutput, specialChars);
+    }
 
-        testRunner.assertAllFlowFilesTransferred(EncodeContent.REL_FAILURE, 1);
+    @ParameterizedTest
+    @MethodSource("encodeBase32Args")
+    void testBasicDecodeBase32(final String input, final String 
expectedOutput) {
+        // we'll use the same args from `encodeBase32Args`, only flip around 
input and output
+        executeTestSuccessHelper(EncodingMode.DECODE, 
EncodingType.BASE32_ENCODING, 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) {
+        // we'll use the same args from `encodeBase64Args`, only flip around 
input and output
+        executeTestSuccessHelper(EncodingMode.DECODE, 
EncodingType.BASE64_ENCODING, 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) {
+        // we'll use the same args from `encodeHexArgs`, only flip around 
input and output
+        executeTestSuccessHelper(EncodingMode.DECODE, 
EncodingType.HEX_ENCODING, 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.HEX_ENCODING, 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_ENCODING, 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" + System.lineSeparator()),
+               Arguments.of("foo", "MZXW6===" + System.lineSeparator()),
+               Arguments.of("你好", "4S62BZNFXU======" + System.lineSeparator()),
+               Arguments.of("Здравствуйте", 
"2CL5BNGRQDILBUFS2GA5DAWQWLIYHUFZ2GBNBNI=" + System.lineSeparator())
+       );
+   }
+
+    @ParameterizedTest
+    @MethodSource("encodeBase64Args")
+    void testBasicEncodeBase64(final String input, final String 
expectedOutput) {
+        executeTestSuccessHelper(EncodingMode.ENCODE, 
EncodingType.BASE64_ENCODING, 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=" + System.lineSeparator()),
+               Arguments.of("foo", "Zm9v" + System.lineSeparator()),
+               Arguments.of("你好", "5L2g5aW9" + System.lineSeparator()),
+               Arguments.of("Здравствуйте", "0JfQtNGA0LDQstGB0YLQstGD0LnRgtC1" 
+ System.lineSeparator())
+       );
+   }
 
-        flowFile = 
testRunner.getFlowFilesForRelationship(EncodeContent.REL_SUCCESS).get(0);
-        flowFile.assertContentEquals(FILE_PATH);
+    @Test
+    void testBlankValueShouldNotFail() {
+        executeTestSuccessHelper(EncodingMode.ENCODE,
+            EncodingType.BASE64_ENCODING,
+            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" 
+ System.lineSeparator()
+            + 
"c2VkIGRvIGVpdXNtb2QgdGVtcG9yIGluY2lkaWR1bnQgdXQgbGFib3JlIGV0IGRvbG9yZSBtYWdu" 
+ System.lineSeparator()
+            + "YSBhbGlxdWEu" + System.lineSeparator();
+
+        // Execute the test using the helper method
+        executeTestHelper(EncodingMode.ENCODE,
+            EncodingType.BASE64_ENCODING,
+            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_ENCODING,
+            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_ENCODING,
+            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" + 
System.lineSeparator()
+            + 
"ONRWS3THEBSWY2LUFQQHGZLEEBSG6IDFNF2XG3LPMQQHIZLNOBXXEIDJNZRWSZDJMR2W45BA" + 
System.lineSeparator()
+            + "OV2CA3DBMJXXEZJAMV2CAZDPNRXXEZJANVQWO3TBEBQWY2LROVQS4===" + 
System.lineSeparator();
+
+        // Execute the test using the helper method
+        executeTestHelper(EncodingMode.ENCODE,
+            EncodingType.BASE32_ENCODING,
+            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"
 + System.lineSeparator()
+            + 
"EBSWY2LUFQQHGZLEEBSG6IDFNF2XG3LPMQQHIZLNOBXXEIDJNZRWSZDJMR2W45BAOV2CA3DBMJXXEZJA"
 + System.lineSeparator()
+            + "MV2CAZDPNRXXEZJANVQWO3TBEBQWY2LROVQS4===" + 
System.lineSeparator();
+
+        // Execute the test using the helper method
+        executeTestHelper(EncodingMode.ENCODE,
+            EncodingType.BASE32_ENCODING,
+            LOREM_IPSUM,
+            LineOutputMode.MULTIPLE_LINES,
+            80,
+            System.lineSeparator(),
+            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_ENCODING,
+            LOREM_IPSUM,
+            LineOutputMode.SINGLE_LINE,
+            2,                          // set a low value >= 0
+            System.lineSeparator(),
+            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"
 + System.lineSeparator()
+            + 
"IGRvIGVpdXNtb2QgdGVtcG9yIGluY2lkaWR1bnQgdXQgbGFib3JlIGV0IGRvbG9yZSBtYWduYSBhbGlx"
 + System.lineSeparator()
+            + "dWEu" + System.lineSeparator();
+
+        // Execute the test using the helper method
+        executeTestHelper(EncodingMode.ENCODE,
+            EncodingType.BASE64_ENCODING,
+            LOREM_IPSUM,
+            LineOutputMode.MULTIPLE_LINES, // set false to output multiple 
lines
+            80,
+            System.lineSeparator(),
+            expectedOutput,
+            EncodeContent.REL_SUCCESS);
+    }
 
-        testRunner.assertAllFlowFilesTransferred(EncodeContent.REL_SUCCESS, 1);
+    @Test
+    void testOverrideLineSeparatorBase64() {
+        // this input is greater than 57 bytes, sure to generate multiple 
lines in base64
+        final String expectedOutput = 
"TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdCwgc2Vk"
 + "|"
+            + 
"IGRvIGVpdXNtb2QgdGVtcG9yIGluY2lkaWR1bnQgdXQgbGFib3JlIGV0IGRvbG9yZSBtYWduYSBhbGlx"
 + "|"
+            + "dWEu" + "|";
+
+        // Execute the test using the helper method
+        executeTestHelper(EncodingMode.ENCODE,
+            EncodingType.BASE64_ENCODING,
+            LOREM_IPSUM,
+            LineOutputMode.MULTIPLE_LINES, // set false to output multiple 
lines
+            80,
+            "|",
+            expectedOutput,
+            EncodeContent.REL_SUCCESS);
+    }
 
-        MockFlowFile flowFile = 
testRunner.getFlowFilesForRelationship(EncodeContent.REL_SUCCESS).get(0);
-        testRunner.assertQueueEmpty();
+    @Test
+    void testOverrideLineSeparatorBase32() {
+        // this input is greater than 57 bytes, sure to generate multiple 
lines in base64
+        final String expectedOutput = 
"JRXXEZLNEBUXA43VNUQGI33MN5ZCA43JOQQGC3LFOQWCAY3PNZZWKY3UMV2HK4RAMFSGS4DJONRWS3TH"
 + "|"
+            + 
"EBSWY2LUFQQHGZLEEBSG6IDFNF2XG3LPMQQHIZLNOBXXEIDJNZRWSZDJMR2W45BAOV2CA3DBMJXXEZJA"
 + "|"
+            + "MV2CAZDPNRXXEZJANVQWO3TBEBQWY2LROVQS4===" + "|";
+
+        // Execute the test using the helper method
+        executeTestHelper(EncodingMode.ENCODE,
+            EncodingType.BASE32_ENCODING,
+            LOREM_IPSUM,
+            LineOutputMode.MULTIPLE_LINES, // set false to output multiple 
lines
+            80,
+            "|",
+            expectedOutput,
+            EncodeContent.REL_SUCCESS);
+    }
 
-        testRunner.setProperty(EncodeContent.MODE, EncodeContent.DECODE_MODE);
-        testRunner.enqueue(flowFile);
-        testRunner.clearTransferState();
-        testRunner.run();
-        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_ENCODING,
+            LOREM_IPSUM,
+            LineOutputMode.SINGLE_LINE, // set true to output single line
+            2,                                      // set a low value >= 0
+            System.lineSeparator(),
+            expectedOutput,
+            EncodeContent.REL_SUCCESS);
+    }
 
-        flowFile = 
testRunner.getFlowFilesForRelationship(EncodeContent.REL_SUCCESS).get(0);
-        flowFile.assertContentEquals(FILE_PATH);
+    private void executeTestSuccessHelper(final DescribedValue mode,
+        final DescribedValue encodingType,
+        final String input,
+        final String expectedOutput) {
+        executeTestSuccessHelper(mode, encodingType, input, 
LineOutputMode.MULTIPLE_LINES, expectedOutput);
     }
 
-    @Test
-    public void testFailDecodeNotHex() throws IOException {
-        final TestRunner testRunner = TestRunners.newTestRunner(new 
EncodeContent());
+    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);
+    }
 
-        testRunner.setProperty(EncodeContent.MODE, EncodeContent.DECODE_MODE);
-        testRunner.setProperty(EncodeContent.ENCODING, 
EncodeContent.HEX_ENCODING);
+    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,
+            System.lineSeparator(),
+            expectedOutput,
+            routedTo);
+    }
 
-        testRunner.enqueue(FILE_PATH);
-        testRunner.clearTransferState();
+    private void executeTestHelper(final DescribedValue mode,
+        final DescribedValue encodingType,
+        final String input,
+        final DescribedValue outputToSingleLine,
+        final Integer lineLength,
+        final String lineSeparator,
+        final String expectedOutput,
+        final Relationship routedTo) {
+
+        testRunner.setProperty(EncodeContent.MODE, mode.getValue());
+        testRunner.setProperty(EncodeContent.ENCODING, 
encodingType.getValue());
+        testRunner.setProperty(EncodeContent.LINE_OUTPUT_MODE, 
outputToSingleLine.getValue());

Review Comment:
   ```suggestion
           testRunner.setProperty(EncodeContent.MODE, mode);
           testRunner.setProperty(EncodeContent.ENCODING, encodingType);
           testRunner.setProperty(EncodeContent.LINE_OUTPUT_MODE, 
outputToSingleLine);
   ```



##########
nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestEncodeContent.java:
##########
@@ -45,7 +78,7 @@ public void testBase64RoundTrip() throws IOException {
         MockFlowFile flowFile = 
testRunner.getFlowFilesForRelationship(EncodeContent.REL_SUCCESS).get(0);
         testRunner.assertQueueEmpty();
 
-        testRunner.setProperty(EncodeContent.MODE, EncodeContent.DECODE_MODE);
+        testRunner.setProperty(EncodeContent.MODE, 
EncodingMode.DECODE.getValue());

Review Comment:
   ```suggestion
           testRunner.setProperty(EncodeContent.MODE, EncodingMode.DECODE);
   ```



##########
nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/EncodeContent.java:
##########
@@ -29,55 +37,88 @@
 import org.apache.nifi.annotation.documentation.CapabilityDescription;
 import org.apache.nifi.annotation.documentation.Tags;
 import org.apache.nifi.components.PropertyDescriptor;
+import org.apache.nifi.components.Validator;
+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)
 @Tags({"encode", "decode", "base64", "base32", "hex"})
 @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")
             .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")
             .required(true)
-            .allowableValues(BASE64_ENCODING, BASE32_ENCODING, HEX_ENCODING)
-            .defaultValue(BASE64_ENCODING)
+            .allowableValues(EncodingType.class)
+            .defaultValue(EncodingType.BASE64_ENCODING)
+            .build();
+
+    static final PropertyDescriptor LINE_OUTPUT_MODE = new 
PropertyDescriptor.Builder()
+            .name("line-output-mode")
+            .displayName("Line Output Mode")
+            .description("If set to 'single-line', the encoded FlowFile 
content will output as a single line. If set to 'multiple-lines', "
+                + "it will output as multiple lines. This property is only 
applicable when Base64 or Base32 encoding is selected.")
+            .required(false)
+            .defaultValue(LineOutputMode.SINGLE_LINE)
+            .allowableValues(LineOutputMode.class)
+            .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
+            .dependsOn(MODE, EncodingMode.ENCODE)
+            .dependsOn(ENCODING, EncodingType.BASE64_ENCODING, 
EncodingType.BASE32_ENCODING)
             .build();
 
+    static final PropertyDescriptor ENCODED_LINE_SEPARATOR = new 
PropertyDescriptor.Builder()
+        .name("line-separator")
+        .displayName("Encoded Content Line Separator")
+        .description("Each line of encoded data will be terminated with this 
byte sequence (e.g. \\r\\n"
+                + "). This property defaults to the system-dependent line 
separator string.  If `line-length` <= 0, "
+                + "the `line-separator` property is not used. This property is 
not used for `hex` encoding.")
+        .required(false)
+        
.expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES)
+        .defaultValue(System.lineSeparator())
+        .addValidator(Validator.VALID)
+        .dependsOn(MODE, EncodingMode.ENCODE)
+        .dependsOn(ENCODING, EncodingType.BASE64_ENCODING, 
EncodingType.BASE32_ENCODING)
+        .build();
+
+    static final PropertyDescriptor ENCODED_LINE_LENGTH = new 
PropertyDescriptor.Builder()
+        .name("encoded-line-length")

Review Comment:
   ```suggestion
           .name("Encoded Content Line Length")
   ```



##########
nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestEncodeContent.java:
##########
@@ -55,12 +88,11 @@ public void testBase64RoundTrip() throws IOException {
         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.getValue());

Review Comment:
   ```suggestion
           testRunner.setProperty(EncodeContent.MODE, EncodingMode.DECODE);
   ```



##########
nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestEncodeContent.java:
##########
@@ -55,12 +88,11 @@ public void testBase64RoundTrip() throws IOException {
         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.getValue());
+        testRunner.setProperty(EncodeContent.ENCODING, encoding.getValue());

Review Comment:
   ```suggestion
           testRunner.setProperty(EncodeContent.ENCODING, encoding);
   ```



##########
nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/EncodeContent.java:
##########
@@ -112,9 +153,14 @@ public void onTrigger(final ProcessContext context, final 
ProcessSession session
             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 = 
EncodingType.valueOf(context.getProperty(ENCODING).getValue());
+

Review Comment:
   ```suggestion
   ```



##########
nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestEncodeContent.java:
##########
@@ -16,25 +16,58 @@
  */
 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.getValue());
+        testRunner.setProperty(EncodeContent.ENCODING, 
EncodingType.BASE64_ENCODING.getValue());

Review Comment:
   ```suggestion
           testRunner.setProperty(EncodeContent.MODE, EncodingMode.DECODE);
           testRunner.setProperty(EncodeContent.ENCODING, 
EncodingType.BASE64_ENCODING);
   ```



##########
nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestEncodeContent.java:
##########
@@ -16,25 +16,58 @@
  */
 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.getValue());
+        testRunner.setProperty(EncodeContent.ENCODING, 
EncodingType.BASE64_ENCODING.getValue());
+
+        testRunner.enqueue("four@@@@multiple".getBytes());
+        testRunner.clearTransferState();
+        testRunner.run();
+
+        testRunner.assertAllFlowFilesTransferred(EncodeContent.REL_FAILURE, 1);
+    }
 
-        testRunner.setProperty(EncodeContent.MODE, EncodeContent.ENCODE_MODE);
-        testRunner.setProperty(EncodeContent.ENCODING, 
EncodeContent.BASE64_ENCODING);
+    @ParameterizedTest
+    @EnumSource(value = EncodingType.class)
+    void testRoundTrip(final EncodingType encoding) throws IOException {
+        testRunner.setProperty(EncodeContent.MODE, 
EncodingMode.ENCODE.getValue());
+        testRunner.setProperty(EncodeContent.ENCODING, encoding.getValue());

Review Comment:
   ```suggestion
           testRunner.setProperty(EncodeContent.MODE, EncodingMode.ENCODE);
           testRunner.setProperty(EncodeContent.ENCODING, encoding);
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


Reply via email to