Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add limits overriding with system properties #112

Merged
merged 5 commits into from
Apr 28, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 34 additions & 2 deletions lib/src/main/java/de/siegmar/fastcsv/util/Limits.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@

/**
* The {@code Limits} class defines the maximum limits for various fields and records in a CSV file.
* <p>
* Example use:
* <pre>{@code
* System.setProperty("fastcsv.max.field.size", "1024");
* }</pre>
* <p>
* Or using VM options:
* <pre>{@code
* -Dfastcsv.max.field.count=1024
* }</pre>
*/
public final class Limits {

Expand All @@ -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.
Expand All @@ -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);
}
}
}
67 changes: 67 additions & 0 deletions lib/src/test/java/de/siegmar/fastcsv/util/LimitsTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package de.siegmar.fastcsv.util;

import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertEquals;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FastCSV uses AssertJ-Assertions exclusively.


import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

class LimitsTest {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The two properties (fastcsv.max.field.size and fastcsv.max.field.count) should be declared as constants in order to not repeat them over and over again...


@BeforeEach
void setup() {
System.clearProperty("fastcsv.max.field.size");
System.clearProperty("fastcsv.max.field.count");
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand why this is required. Isn't AfterEach sufficient?


@AfterEach
void cleanup() {
System.clearProperty("fastcsv.max.field.size");
System.clearProperty("fastcsv.max.field.count");
}

@Test
void defaultMaxFieldSize() {
assertEquals(16 * 1024 * 1024, Limits.MAX_FIELD_SIZE, "Default max field size should be correct");
}

@Test
void customMaxFieldSize() {
System.setProperty("fastcsv.max.field.size", "100000");

assertEquals(100000, Limits.getIntProperty("fastcsv.max.field.size", 16 * 1024 * 1024),
"Custom max field size should be respected");
}

@Test
void defaultMaxFieldCount() {
assertEquals(16 * 1024, Limits.MAX_FIELD_COUNT, "Default max field count should be correct");
}

@Test
void customMaxFieldCount() {
System.setProperty("fastcsv.max.field.count", "200");

assertEquals(200, Limits.getIntProperty("fastcsv.max.field.count", 16 * 1024),
"Custom max field count should be respected");
}

@Test
void invalidMaxFieldSizeThrowsException() {
System.setProperty("fastcsv.max.field.size", "invalid");

assertThrows(IllegalArgumentException.class,
() -> Limits.getIntProperty("fastcsv.max.field.size", 16 * 1024 * 1024),
"Should throw IllegalArgumentException for invalid integer format");
}

@Test
void testMaxRecordSizeBasedOnMaxFieldSize() {
System.setProperty("fastcsv.max.field.size", "4000000");

assertEquals(4 * 4000000,
4 * Limits.getIntProperty("fastcsv.max.field.size", 16 * 1024 * 1024),
"MAX_RECORD_SIZE should be four times MAX_FIELD_SIZE");
}
}
Loading