From 8419a802e739d215312ab660d83ab12b7e10c754 Mon Sep 17 00:00:00 2001 From: Obolrom <65775868+Obolrom@users.noreply.github.com> Date: Sun, 28 Apr 2024 07:42:59 +0300 Subject: [PATCH] Add limits overriding with system properties (#112) --- .../java/de/siegmar/fastcsv/util/Limits.java | 36 +++++++++- .../de/siegmar/fastcsv/util/LimitsTest.java | 69 +++++++++++++++++++ 2 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 lib/src/test/java/de/siegmar/fastcsv/util/LimitsTest.java diff --git a/lib/src/main/java/de/siegmar/fastcsv/util/Limits.java b/lib/src/main/java/de/siegmar/fastcsv/util/Limits.java index e4acfeea..7450b1eb 100644 --- a/lib/src/main/java/de/siegmar/fastcsv/util/Limits.java +++ b/lib/src/main/java/de/siegmar/fastcsv/util/Limits.java @@ -2,6 +2,16 @@ /** * The {@code Limits} class defines the maximum limits for various fields and records in a CSV file. + *

+ * Example use: + *

{@code
+ * System.setProperty("fastcsv.max.field.size", "1024");
+ * }
+ *

+ * Or using VM options: + *

{@code
+ * -Dfastcsv.max.field.count=1024
+ * }
*/ public final class Limits { @@ -10,13 +20,13 @@ public final class Limits { * The value is set to 16,777,216 characters (16 to 64 MiB depending on the circumstance of multibyte character * utilization). */ - public static final int MAX_FIELD_SIZE = 16 * 1024 * 1024; + public static final int MAX_FIELD_SIZE = getIntProperty("fastcsv.max.field.size", 16 * 1024 * 1024); /** * The {@code MAX_FIELDS_SIZE} constant defines the maximum number of fields per record. * The value is set to 16,384. */ - public static final int MAX_FIELD_COUNT = 16 * 1024; + public static final int MAX_FIELD_COUNT = getIntProperty("fastcsv.max.field.count", 16 * 1024); /** * The {@code MAX_RECORD_SIZE} constant defines the maximum size for all fields combined in a CSV record. @@ -27,4 +37,26 @@ public final class Limits { private Limits() { } + /** + * Retrieves the system property value if presented, otherwise default value is returned. + * If the property cannot be parsed as an integer, an {@code IllegalArgumentException} is thrown. + * + * @param key The system property key. + * @param defaultValue The default value to use if the system property is not set or is invalid. + * @return The system property value as an integer or the default value if the property is not set or is invalid. + * @throws IllegalArgumentException If the system property value cannot be parsed as an integer. + */ + static int getIntProperty(final String key, final int defaultValue) { + final String value = System.getProperty(key); + + if (value == null) { + return defaultValue; + } + + try { + return Integer.parseInt(value); + } catch (final NumberFormatException e) { + throw new IllegalArgumentException("Invalid format for system property " + key, e); + } + } } diff --git a/lib/src/test/java/de/siegmar/fastcsv/util/LimitsTest.java b/lib/src/test/java/de/siegmar/fastcsv/util/LimitsTest.java new file mode 100644 index 00000000..f930cec6 --- /dev/null +++ b/lib/src/test/java/de/siegmar/fastcsv/util/LimitsTest.java @@ -0,0 +1,69 @@ +package de.siegmar.fastcsv.util; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; + +class LimitsTest { + + public static final String FASTCSV_MAX_FIELD_SIZE = "fastcsv.max.field.size"; + public static final String FASTCSV_MAX_FIELD_COUNT = "fastcsv.max.field.count"; + + @AfterEach + void cleanup() { + System.clearProperty(FASTCSV_MAX_FIELD_SIZE); + System.clearProperty(FASTCSV_MAX_FIELD_COUNT); + } + + @Test + void defaultMaxFieldSize() { + assertThat(Limits.MAX_FIELD_SIZE) + .as("Default max field size should be correct") + .isEqualTo(16 * 1024 * 1024); + } + + @Test + void customMaxFieldSize() { + System.setProperty(FASTCSV_MAX_FIELD_SIZE, "100000"); + + assertThat(Limits.getIntProperty(FASTCSV_MAX_FIELD_SIZE, 16 * 1024 * 1024)) + .as("Custom max field size should be respected") + .isEqualTo(100000); + } + + @Test + void defaultMaxFieldCount() { + assertThat(Limits.MAX_FIELD_COUNT) + .as("Default max field count should be correct") + .isEqualTo(16 * 1024); + } + + @Test + void customMaxFieldCount() { + System.setProperty(FASTCSV_MAX_FIELD_COUNT, "200"); + + assertThat(Limits.getIntProperty(FASTCSV_MAX_FIELD_COUNT, 16 * 1024)) + .as("Custom max field count should be respected") + .isEqualTo(200); + } + + @Test + void invalidMaxFieldSizeThrowsException() { + System.setProperty(FASTCSV_MAX_FIELD_SIZE, "invalid"); + + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(() -> Limits.getIntProperty(FASTCSV_MAX_FIELD_SIZE, 16 * 1024 * 1024)) + .withMessageContaining("Invalid format for system property " + FASTCSV_MAX_FIELD_SIZE); + } + + @Test + void maxRecordSizeBasedOnMaxFieldSize() { + System.setProperty(FASTCSV_MAX_FIELD_SIZE, "4000000"); + + assertThat(4 * Limits.getIntProperty(FASTCSV_MAX_FIELD_SIZE, 16 * 1024 * 1024)) + .as("MAX_RECORD_SIZE should be four times MAX_FIELD_SIZE") + .isEqualTo(4 * 4000000); + } +}