diff --git a/core-java-modules/core-java-string-operations-3/src/main/java/com/baeldung/stringfilenamevalidaiton/StringFilenameValidationUtils.java b/core-java-modules/core-java-string-operations-3/src/main/java/com/baeldung/stringfilenamevalidaiton/StringFilenameValidationUtils.java new file mode 100644 index 0000000000..1a86edd45a --- /dev/null +++ b/core-java-modules/core-java-string-operations-3/src/main/java/com/baeldung/stringfilenamevalidaiton/StringFilenameValidationUtils.java @@ -0,0 +1,61 @@ +package com.baeldung.stringfilenamevalidaiton; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Paths; +import java.util.Arrays; + +public class StringFilenameValidationUtils { + + public static final Character[] INVALID_WINDOWS_SPECIFIC_CHARS = {'"', '*', ':', '<', '>', '?', '\\', '|', 0x7F}; + public static final Character[] INVALID_UNIX_SPECIFIC_CHARS = {'\000'}; + + public static final String REGEX_PATTERN = "^[A-za-z0-9.]{1,255}$"; + + private StringFilenameValidationUtils() { + } + + public static boolean validateStringFilenameUsingIO(String filename) throws IOException { + File file = new File(filename); + boolean created = false; + try { + created = file.createNewFile(); + return created; + } finally { + if (created) { + file.delete(); + } + } + } + + public static boolean validateStringFilenameUsingNIO2(String filename) { + Paths.get(filename); + return true; + } + + public static boolean validateStringFilenameUsingContains(String filename) { + if (filename == null || filename.isEmpty() || filename.length() > 255) { + return false; + } + return Arrays.stream(getInvalidCharsByOS()) + .noneMatch(ch -> filename.contains(ch.toString())); + } + + public static boolean validateStringFilenameUsingRegex(String filename) { + if (filename == null) { + return false; + } + return filename.matches(REGEX_PATTERN); + } + + private static Character[] getInvalidCharsByOS() { + String os = System.getProperty("os.name").toLowerCase(); + if (os.contains("win")) { + return INVALID_WINDOWS_SPECIFIC_CHARS; + } else if (os.contains("nix") || os.contains("nux") || os.contains("mac")) { + return INVALID_UNIX_SPECIFIC_CHARS; + } else { + return new Character[]{}; + } + } +} diff --git a/core-java-modules/core-java-string-operations-3/src/test/java/com/baeldung/stringfilenamevalidaiton/StringFilenameValidationUnitTest.java b/core-java-modules/core-java-string-operations-3/src/test/java/com/baeldung/stringfilenamevalidaiton/StringFilenameValidationUnitTest.java new file mode 100644 index 0000000000..3e787f08be --- /dev/null +++ b/core-java-modules/core-java-string-operations-3/src/test/java/com/baeldung/stringfilenamevalidaiton/StringFilenameValidationUnitTest.java @@ -0,0 +1,130 @@ +package com.baeldung.stringfilenamevalidaiton; + +import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.RandomUtils; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledOnOs; +import org.junit.jupiter.api.condition.OS; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EmptySource; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.NullSource; + +import java.io.IOException; +import java.nio.file.InvalidPathException; +import java.util.Arrays; +import java.util.stream.Stream; + +import static com.baeldung.stringfilenamevalidaiton.StringFilenameValidationUtils.validateStringFilenameUsingContains; +import static com.baeldung.stringfilenamevalidaiton.StringFilenameValidationUtils.validateStringFilenameUsingIO; +import static com.baeldung.stringfilenamevalidaiton.StringFilenameValidationUtils.validateStringFilenameUsingNIO2; +import static com.baeldung.stringfilenamevalidaiton.StringFilenameValidationUtils.validateStringFilenameUsingRegex; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +public class StringFilenameValidationUnitTest { + + private static final String CORRECT_FILENAME_PATTERN = "baeldung.txt"; + + @ParameterizedTest + @MethodSource("correctAlphanumericFilenamesProvider") + public void givenCorrectAlphanumericRandomFilenameString_whenValidateUsingIO_thenReturnTrue(String filename) throws IOException { + assertThat(validateStringFilenameUsingIO(filename)).isTrue(); + assertThat(validateStringFilenameUsingNIO2(filename)).isTrue(); + assertThat(validateStringFilenameUsingContains(filename)).isTrue(); + assertThat(validateStringFilenameUsingRegex(filename)).isTrue(); + } + + @Test + public void givenTooLongFileNameString_whenValidate_thenIOAndCustomFailsNIO2Succeed() { + String filename = RandomStringUtils.randomAlphabetic(500); + assertThatThrownBy(() -> validateStringFilenameUsingIO(filename)) + .isInstanceOf(IOException.class) + .hasMessageContaining("File name too long"); + assertThat(validateStringFilenameUsingNIO2(filename)).isTrue(); + assertThat(validateStringFilenameUsingContains(filename)).isFalse(); + assertThat(validateStringFilenameUsingRegex(filename)).isFalse(); + } + + @ParameterizedTest + @NullSource + public void givenNullString_whenValidate_thenFails(String filename) { + assertThatThrownBy(() -> validateStringFilenameUsingIO(filename)) + .isInstanceOf(NullPointerException.class); + assertThatThrownBy(() -> validateStringFilenameUsingNIO2(filename)) + .isInstanceOf(NullPointerException.class); + assertThat(validateStringFilenameUsingContains(filename)).isFalse(); + assertThat(validateStringFilenameUsingRegex(filename)).isFalse(); + } + + @ParameterizedTest + @EmptySource + public void givenEmptyString_whenValidate_thenIOAndCustomFailsNIO2Succeed(String filename) { + assertThatThrownBy(() -> validateStringFilenameUsingIO(filename)) + .isInstanceOf(IOException.class); + assertThat(validateStringFilenameUsingNIO2(filename)).isTrue(); + assertThat(validateStringFilenameUsingContains(filename)).isFalse(); + assertThat(validateStringFilenameUsingRegex(filename)).isFalse(); + } + + @ParameterizedTest + @EnabledOnOs({OS.LINUX, OS.MAC}) + @MethodSource("filenamesWithInvalidWindowsChars") + public void givenFilenameStringWithInvalidWindowsCharAndIsUnix_whenValidateUsingIO_thenReturnTrue(String filename) throws IOException { + assertThat(validateStringFilenameUsingIO(filename)).isTrue(); + assertThat(validateStringFilenameUsingNIO2(filename)).isTrue(); + assertThat(validateStringFilenameUsingContains(filename)).isTrue(); + } + + @ParameterizedTest + @EnabledOnOs(OS.WINDOWS) + @MethodSource("filenamesWithInvalidWindowsChars") + public void givenFilenameStringWithInvalidWindowsCharAndIsWindows_whenValidateUsingIO_thenRaiseException(String filename) { + assertThatThrownBy(() -> validateStringFilenameUsingIO(filename)) + .isInstanceOf(IOException.class) + .hasMessageContaining("Invalid file path"); + + assertThatThrownBy(() -> validateStringFilenameUsingNIO2(filename)) + .isInstanceOf(InvalidPathException.class) + .hasMessage("character not allowed"); + + assertThat(validateStringFilenameUsingContains(filename)).isFalse(); + } + + @ParameterizedTest + @EnabledOnOs({OS.LINUX, OS.MAC}) + @MethodSource("filenamesWithInvalidUnixChars") + public void givenFilenameStringWithInvalidUnixCharAndIsUnix_whenValidate_thenRaiseException(String filename) { + assertThatThrownBy(() -> validateStringFilenameUsingIO(filename)) + .isInstanceOf(IOException.class) + .hasMessageContaining("Invalid file path"); + + assertThatThrownBy(() -> validateStringFilenameUsingNIO2(filename)) + .isInstanceOf(InvalidPathException.class) + .hasMessageContaining("character not allowed"); + + assertThat(validateStringFilenameUsingContains(filename)).isFalse(); + } + + + private static Stream correctAlphanumericFilenamesProvider() { + return Stream.generate(() -> RandomStringUtils.randomAlphanumeric(1, 10) + "." + RandomStringUtils.randomAlphabetic(3, 5)).limit(10); + } + + private static Stream filenamesWithInvalidWindowsChars() { + return Arrays.stream(StringFilenameValidationUtils.INVALID_WINDOWS_SPECIFIC_CHARS) + .map(character -> { + int idx = RandomUtils.nextInt(0, CORRECT_FILENAME_PATTERN.length()); + return CORRECT_FILENAME_PATTERN.substring(0, idx) + character + CORRECT_FILENAME_PATTERN.substring(idx); + }); + } + + private static Stream filenamesWithInvalidUnixChars() { + return Arrays.stream(StringFilenameValidationUtils.INVALID_UNIX_SPECIFIC_CHARS) + .map(character -> { + int idx = RandomUtils.nextInt(0, CORRECT_FILENAME_PATTERN.length()); + return CORRECT_FILENAME_PATTERN.substring(0, idx) + character + CORRECT_FILENAME_PATTERN.substring(idx); + }); + } + +}