diff --git a/README.md b/README.md index 08ed3ba..c9a1523 100644 --- a/README.md +++ b/README.md @@ -107,6 +107,6 @@ Just add this to your **pom.xml** com.hijackermax utils - 0.0.8 + 0.0.9 ``` \ No newline at end of file diff --git a/pom.xml b/pom.xml index d4def85..cd2ad9a 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.hijackermax utils - 0.0.8 + 0.0.9 utils A set of utils that can help in app development diff --git a/src/main/java/com/hijackermax/utils/lang/CollectionUtils.java b/src/main/java/com/hijackermax/utils/lang/CollectionUtils.java index ad02f2a..e2f2886 100644 --- a/src/main/java/com/hijackermax/utils/lang/CollectionUtils.java +++ b/src/main/java/com/hijackermax/utils/lang/CollectionUtils.java @@ -789,4 +789,43 @@ public static boolean isEmpty(Enumeration value) { public static Stream safeStreamOf(Enumeration input) { return isEmpty(input) ? Stream.empty() : EnumerationSpliterator.ofOrdered(input).stream(); } + + /** + * Checks if any of input {@link Collection} elements satisfies provided {@link Predicate} + * + * @param values collection that should be checked + * @param valuesPredicate the predicate that should be applied to source elements collection + * @param collection elements type + * @return true if collection contains at least one element that satisfies provided predicate + * @since 0.0.9 + */ + public static boolean safeAnyMatch(Collection values, Predicate valuesPredicate) { + return safeStreamOf(values).anyMatch(valuesPredicate); + } + + /** + * Checks if all of input {@link Collection} elements satisfy provided {@link Predicate} + * + * @param values collection that should be checked + * @param valuesPredicate the predicate that should be applied to source elements collection + * @param collection elements type + * @return true if collection contains all elements that satisfy provided predicate + * @since 0.0.9 + */ + public static boolean safeAllMatch(Collection values, Predicate valuesPredicate) { + return isNotEmpty(values) && values.stream().allMatch(valuesPredicate); + } + + /** + * Checks if none of input {@link Collection} elements satisfy provided {@link Predicate} + * + * @param values collection that should be checked + * @param valuesPredicate the predicate that should be applied to source elements collection + * @param collection elements type + * @return true if collection contains no elements that satisfy provided predicate + * @since 0.0.9 + */ + public static boolean safeNoneMatch(Collection values, Predicate valuesPredicate) { + return isEmpty(values) || values.stream().noneMatch(valuesPredicate); + } } diff --git a/src/main/java/com/hijackermax/utils/lang/DateUtils.java b/src/main/java/com/hijackermax/utils/lang/DateUtils.java index d891937..c58eb21 100644 --- a/src/main/java/com/hijackermax/utils/lang/DateUtils.java +++ b/src/main/java/com/hijackermax/utils/lang/DateUtils.java @@ -1,9 +1,11 @@ package com.hijackermax.utils.lang; import java.time.Instant; +import java.time.LocalDate; import java.time.ZoneId; import java.time.ZoneOffset; import java.time.ZonedDateTime; +import java.time.chrono.ChronoLocalDate; import java.time.temporal.ChronoUnit; import java.util.Date; import java.util.Objects; @@ -186,6 +188,106 @@ public static boolean inRange(Date value, Date target, long offsetMs) { return between(value, shiftDateByMs(target, -offsetMs), shiftDateByMs(target, offsetMs)); } + /** + * Checks if provided {@link ChronoLocalDate} value is before {@link ChronoLocalDate} point in time + * + * @param value the value that should be checked + * @param pointInTime some date that value should be compared to + * @return true if both dates are not null and provided value is before provided point of time, otherwise false + * @since 0.0.9 + */ + public static boolean safeBefore(ChronoLocalDate value, ChronoLocalDate pointInTime) { + return Objects.nonNull(value) && Objects.nonNull(pointInTime) && value.isBefore(pointInTime); + } + + /** + * Checks if provided {@link ChronoLocalDate} value is after {@link ChronoLocalDate} point in time + * + * @param value the value that should be checked + * @param pointInTime some date that value should be compared to + * @return true if both dates are not null and provided value is after provided point of time, otherwise false + * @since 0.0.9 + */ + public static boolean safeAfter(ChronoLocalDate value, ChronoLocalDate pointInTime) { + return Objects.nonNull(value) && Objects.nonNull(pointInTime) && value.isAfter(pointInTime); + } + + /** + * Checks if provided {@link ChronoLocalDate} value is after or the same as {@link ChronoLocalDate} point in time + * + * @param value the value that should be checked + * @param pointInTime some date that value should be compared to + * @return true if both dates are not null and provided value is after or equal to provided point of time, otherwise false + * @since 0.0.9 + */ + public static boolean safeAfterOrSame(ChronoLocalDate value, ChronoLocalDate pointInTime) { + return Objects.nonNull(value) && Objects.nonNull(pointInTime) && !value.isBefore(pointInTime); + } + + /** + * Checks if provided {@link ChronoLocalDate} value is before or the same as {@link ChronoLocalDate} point in time + * + * @param value the value that should be checked + * @param pointInTime some date that value should be compared to + * @return true if both dates are not null and provided value is before or equal to provided point of time, otherwise false + * @since 0.0.9 + */ + public static boolean safeBeforeOrSame(ChronoLocalDate value, ChronoLocalDate pointInTime) { + return Objects.nonNull(value) && Objects.nonNull(pointInTime) && !value.isAfter(pointInTime); + } + + /** + * Provides null-safe check if provided value {@link ChronoLocalDate} between two provided boundary {@link ChronoLocalDate} or equal to one of them + * + * @param value date that should be checked + * @param leftBound start boundary date + * @param rightBound end boundary date + * @return true if date between provided boundaries, false if not or one of the provided dates is null + * @since 0.0.9 + */ + public static boolean between(ChronoLocalDate value, ChronoLocalDate leftBound, ChronoLocalDate rightBound) { + if (Objects.isNull(value) || Objects.isNull(leftBound) || Objects.isNull(rightBound)) { + return false; + } + return !leftBound.isAfter(value) && !rightBound.isBefore(value); + } + + /** + * Shifts provided {@link LocalDate} with provided amount of days + * + * @param source source date + * @param shiftValue amount of days that should be used to shift source date + * @return shifted date, or null if source is null + * @since 0.0.9 + */ + public static LocalDate shiftDateByDays(LocalDate source, long shiftValue) { + return Objects.isNull(source) ? null : source.plusDays(shiftValue); + } + + /** + * Shifts provided {@link LocalDate} with provided amount of months + * + * @param source source date + * @param shiftValue amount of months that should be used to shift source date + * @return shifted date, or null if source is null + * @since 0.0.9 + */ + public static LocalDate shiftDateByMonths(LocalDate source, long shiftValue) { + return Objects.isNull(source) ? null : source.plusMonths(shiftValue); + } + + /** + * Shifts provided {@link LocalDate} with provided amount of years + * + * @param source source date + * @param shiftValue amount of years that should be used to shift source date + * @return shifted date, or null if source is null + * @since 0.0.9 + */ + public static LocalDate shiftDateByYears(LocalDate source, long shiftValue) { + return Objects.isNull(source) ? null : source.plusYears(shiftValue); + } + private static ZonedDateTime getZonedDateTime(Date source) { return ZonedDateTime.ofInstant(source.toInstant(), ZoneOffset.UTC); } diff --git a/src/main/java/com/hijackermax/utils/lang/FunctionalUtils.java b/src/main/java/com/hijackermax/utils/lang/FunctionalUtils.java index b5ecdb6..c215503 100644 --- a/src/main/java/com/hijackermax/utils/lang/FunctionalUtils.java +++ b/src/main/java/com/hijackermax/utils/lang/FunctionalUtils.java @@ -89,4 +89,16 @@ public static Predicate mappedPredicate(Function transformer, Pr return source -> Objects.nonNull(source) && Objects.requireNonNull(transformer).andThen(Objects.requireNonNull(extractedPredicate)::test).apply(source); } + + /** + * Provides empty value {@link Consumer} + * + * @param supplied value type + * @return empty value consumer + * @since 0.0.9 + */ + public static Consumer emptyConsumer() { + return v -> { + }; + } } diff --git a/src/main/java/com/hijackermax/utils/lang/OptionalUtils.java b/src/main/java/com/hijackermax/utils/lang/OptionalUtils.java index f3a9f30..65de605 100644 --- a/src/main/java/com/hijackermax/utils/lang/OptionalUtils.java +++ b/src/main/java/com/hijackermax/utils/lang/OptionalUtils.java @@ -4,8 +4,11 @@ import java.util.Objects; import java.util.Optional; import java.util.function.Function; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import static java.util.Optional.empty; +import static java.util.Optional.ofNullable; /** * Useful optional providers @@ -99,4 +102,19 @@ public static Optional ofBlank(String value) { public static > Optional ofEmptyCollection(C value) { return CollectionUtils.isEmpty(value) ? Optional.empty() : Optional.of(value); } + + /** + * Returns an {@link Optional} describing the given pattern matcher against provided {@link CharSequence} + * + * @param pattern a compiled representation of a regular expression + * @param value a character sequence to be matched + * @return an {@link Optional} with a matcher as value if a subsequence of the input sequence matches the input pattern, + * otherwise an empty {@link Optional} + * @since 0.0.9 + */ + public static Optional ofFind(Pattern pattern, CharSequence value) { + return Objects.isNull(value) ? Optional.empty() : ofNullable(pattern) + .map(p -> p.matcher(value)) + .filter(Matcher::find); + } } diff --git a/src/main/java/com/hijackermax/utils/lang/StringUtils.java b/src/main/java/com/hijackermax/utils/lang/StringUtils.java index 7ed579e..f8cf353 100644 --- a/src/main/java/com/hijackermax/utils/lang/StringUtils.java +++ b/src/main/java/com/hijackermax/utils/lang/StringUtils.java @@ -9,13 +9,18 @@ import java.util.Collection; import java.util.Map; import java.util.Objects; +import java.util.Set; +import java.util.function.BiConsumer; +import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; import java.util.function.UnaryOperator; import java.util.regex.Pattern; import java.util.stream.Collectors; +import java.util.stream.IntStream; +import static com.hijackermax.utils.lang.CollectionUtils.safeStreamOf; import static com.hijackermax.utils.lang.NumberUtils.requireGreaterThanZero; /** @@ -205,7 +210,7 @@ public static Function, String> join(String delimiter, Functio public static String join(Collection collection, String delimiter, Function toStringConverter) { - return CollectionUtils.safeStreamOf(collection) + return safeStreamOf(collection) .filter(Objects::nonNull) .map(toStringConverter) .map(StringUtils::trimToEmpty) @@ -488,4 +493,128 @@ public static Predicate contains(String fragment) { public static Predicate hasLength(ComparisonOperators operator, int reference) { return source -> isNotEmpty(source) && NumberUtils.compare(source.length(), requireGreaterThanZero(reference), operator); } + + /** + * Passes provided {@link String} if not empty to the provided string {@link Consumer} + * + * @param value the value to check + * @param valueConsumer non-empty value consumer + * @since 0.0.9 + */ + public static void ifNotEmpty(String value, Consumer valueConsumer) { + if (isNotEmpty(value)) { + valueConsumer.accept(value); + } + } + + /** + * Passes provided {@link String} if not blank to the provided string {@link Consumer} + * + * @param value the value to check + * @param valueConsumer non-blank value consumer + * @since 0.0.9 + */ + public static void ifNotBlank(String value, Consumer valueConsumer) { + if (isNotBlank(value)) { + valueConsumer.accept(value); + } + } + + /** + * Returns capitalized variant of provided {@link String} with space as default word delimiter + * + * @param source the value to capitalize + * @return capitalized string or empty string if null or blank string is provided + * @since 0.0.9 + */ + public static String capitalize(String source) { + return capitalize(source, ' '); + } + + /** + * Returns capitalized variant of provided {@link String} with provided words delimiters + * + * @param source the value to capitalize + * @param delimiters the words delimiters + * @return capitalized string or empty string if null or blank string is provided or source string if no delimiters provided + * @since 0.0.9 + */ + public static String capitalize(String source, char... delimiters) { + if (isBlank(source)) { + return EMPTY; + } + if (Objects.isNull(delimiters) || 0 == delimiters.length) { + return source; + } + + Set delimiterValues = IntStream.range(0, delimiters.length) + .mapToObj(idx -> Character.codePointAt(delimiters, idx)) + .collect(Collectors.toSet()); + + String lowerCaseSource = source.trim().toLowerCase(); + int sourceLength = lowerCaseSource.length(); + int[] resultValues = new int[sourceLength]; + int resultEndIdx = 0; + boolean capitalizeNext = false; + for (int idx = 0; idx < sourceLength; ) { + int charAt = lowerCaseSource.codePointAt(idx); + if (delimiterValues.contains(charAt)) { + capitalizeNext = true; + idx += Character.charCount(charAt); + resultValues[resultEndIdx++] = charAt; + continue; + } + if (capitalizeNext || 0 == idx) { + int newValue = Character.toTitleCase(charAt); + idx += Character.charCount(newValue); + resultValues[resultEndIdx++] = newValue; + capitalizeNext = false; + continue; + } + idx += Character.charCount(charAt); + resultValues[resultEndIdx++] = charAt; + } + return new String(resultValues, 0, resultEndIdx); + } + + /** + * Joins provided {@link Collection} of {@link CharSequence} with provided delimiter + * + * @param elements collection of charSequences to join + * @param delimiter the delimiter + * @return joint {@link String} or empty string if provided collection is empty or null + * @since 0.0.9 + */ + public static String safeJoin(Collection elements, CharSequence delimiter) { + return CollectionUtils.safeStreamOf(elements) + .collect(Collectors.joining(delimiter)); + } + + /** + * Passes provided {@link String} pair if both of them not empty to the provided string {@link BiConsumer} + * + * @param left the first value to check + * @param right the second value to check + * @param valuesConsumer non-empty values consumer + * @since 0.0.9 + */ + public static void ifBothNotEmpty(String left, String right, BiConsumer valuesConsumer) { + if (isNotEmpty(left) && isNotEmpty(right)) { + valuesConsumer.accept(left, right); + } + } + + /** + * Passes provided {@link String} pair if both of them not blank to the provided string {@link BiConsumer} + * + * @param left the first value to check + * @param right the second value to check + * @param valuesConsumer non-blank values consumer + * @since 0.0.9 + */ + public static void ifBothNotBlank(String left, String right, BiConsumer valuesConsumer) { + if (isNotBlank(left) && isNotBlank(right)) { + valuesConsumer.accept(left, right); + } + } } diff --git a/src/test/java/com/hijackermax/utils/lang/CollectionUtilsTest.java b/src/test/java/com/hijackermax/utils/lang/CollectionUtilsTest.java index 341e202..15ecd7a 100644 --- a/src/test/java/com/hijackermax/utils/lang/CollectionUtilsTest.java +++ b/src/test/java/com/hijackermax/utils/lang/CollectionUtilsTest.java @@ -543,4 +543,30 @@ void testSafeStreamOfEnumeration() { assertEquals(0L, CollectionUtils.safeStreamOf(new Vector<>().elements()).count()); assertEquals(3L, CollectionUtils.safeStreamOf(new Vector<>(List.of(true, false, true))).count()); } + + @Test + void testSafeAnyMatch() { + assertFalse(CollectionUtils.safeAnyMatch(null, Objects::nonNull)); + assertFalse(CollectionUtils.safeAnyMatch(List.of(), Objects::nonNull)); + assertTrue(CollectionUtils.safeAnyMatch(List.of(1, 2, 3), Objects::nonNull)); + assertTrue(CollectionUtils.safeAnyMatch(List.of(1), Objects::nonNull)); + } + + @Test + void testSafeAllMatch() { + assertFalse(CollectionUtils.safeAllMatch(null, Objects::nonNull)); + assertFalse(CollectionUtils.safeAllMatch(List.of(), Objects::nonNull)); + assertFalse(CollectionUtils.safeAllMatch(List.of(1, 2, 4, 10), v -> v < 5)); + assertTrue(CollectionUtils.safeAllMatch(List.of(1, 2, 3), Objects::nonNull)); + assertTrue(CollectionUtils.safeAllMatch(List.of(1), Objects::nonNull)); + } + + @Test + void testSafeNoneMatch() { + assertFalse(CollectionUtils.safeNoneMatch(List.of(1, 2, 4, 10), v -> v < 5)); + assertTrue(CollectionUtils.safeNoneMatch(List.of(), Objects::nonNull)); + assertTrue(CollectionUtils.safeNoneMatch(null, Objects::nonNull)); + assertTrue(CollectionUtils.safeNoneMatch(List.of(1, 2, 3), v -> v > 5)); + assertTrue(CollectionUtils.safeNoneMatch(List.of(1), v -> v > 5)); + } } diff --git a/src/test/java/com/hijackermax/utils/lang/DateUtilsTest.java b/src/test/java/com/hijackermax/utils/lang/DateUtilsTest.java index 64732c7..c19fcbb 100644 --- a/src/test/java/com/hijackermax/utils/lang/DateUtilsTest.java +++ b/src/test/java/com/hijackermax/utils/lang/DateUtilsTest.java @@ -2,6 +2,7 @@ import org.junit.jupiter.api.Test; +import java.time.LocalDate; import java.util.Calendar; import java.util.Date; import java.util.Objects; @@ -70,7 +71,7 @@ void testShiftDayByHours() { @Test void testShiftDayByDays() { - assertNull(DateUtils.shiftDateByDays(null, 10)); + assertNull(DateUtils.shiftDateByDays((Date) null, 10)); long timeMillis = 1679970309662L; //Tue Mar 28 02:25:09.662 GMT 2023 long plusMillis = 1680056709662L; //Tue Mar 29 02:25:09.662 GMT 2023 long minusMillis = 1679883909662L; //Tue Mar 27 02:25:09.662 GMT 2023 @@ -80,7 +81,7 @@ void testShiftDayByDays() { @Test void testShiftDayByMoths() { - assertNull(DateUtils.shiftDateByDays(null, 10)); + assertNull(DateUtils.shiftDateByMonths((Date) null, 10)); long timeMillis = 1679970309662L; //Tue Mar 28 02:25:09.662 GMT 2023 long plusMillis = 1682648709662L; //Fri Apr 28 29 02:25:09.662 GMT 2023 long minusMillis = 1677551109662L; //Tue Feb 28 02:25:09.662 GMT 2023 @@ -90,7 +91,7 @@ void testShiftDayByMoths() { @Test void testShiftDayByYears() { - assertNull(DateUtils.shiftDateByDays(null, 10)); + assertNull(DateUtils.shiftDateByYears((Date) null, 10)); long timeMillis = 1679970309662L; //Tue Mar 28 02:25:09.662 GMT 2023 long plusMillis = 1711592709662L; //Thu Mar 28 02:25:09.662 GMT 2024 long minusMillis = 1648434309662L; //Mon Mar 28 02:25:09.662 GMT 2022 @@ -121,4 +122,87 @@ void testInRange() { assertTrue(DateUtils.inRange(new Date(timeMillis), new Date(timeMillis), 86400000)); assertFalse(DateUtils.inRange(new Date(timeMillis), new Date(targetMiddle), 86400000)); } + + @Test + void testLocalShiftDayByDays() { + assertNull(DateUtils.shiftDateByDays((LocalDate) null, 10)); + LocalDate source = LocalDate.of(2023, 9, 16); + LocalDate plusDay = LocalDate.of(2023, 9, 17); + LocalDate minusDay = LocalDate.of(2023, 9, 15); + assertEquals(plusDay, DateUtils.shiftDateByDays(source, 1)); + assertEquals(minusDay, DateUtils.shiftDateByDays(source, -1)); + } + + @Test + void testLocalShiftDayByMoths() { + assertNull(DateUtils.shiftDateByMonths((LocalDate) null, 10)); + LocalDate source = LocalDate.of(2023, 9, 16); + LocalDate plusMonth = LocalDate.of(2023, 10, 16); + LocalDate minusMonth = LocalDate.of(2023, 8, 16); + assertEquals(plusMonth, DateUtils.shiftDateByMonths(source, 1)); + assertEquals(minusMonth, DateUtils.shiftDateByMonths(source, -1)); + } + + @Test + void testLocalShiftDayByYears() { + assertNull(DateUtils.shiftDateByYears((LocalDate) null, 10)); + LocalDate source = LocalDate.of(2023, 9, 16); + LocalDate plusYear = LocalDate.of(2024, 9, 16); + LocalDate minusYear = LocalDate.of(2022, 9, 16); + assertEquals(plusYear, DateUtils.shiftDateByYears(source, 1)); + assertEquals(minusYear, DateUtils.shiftDateByYears(source, -1)); + } + + @Test + void testLocalBetween() { + assertFalse(DateUtils.between(null, LocalDate.now(), LocalDate.now())); + assertFalse(DateUtils.between(LocalDate.now(), null, LocalDate.now())); + assertFalse(DateUtils.between(LocalDate.now(), LocalDate.now(), null)); + LocalDate source = LocalDate.of(2023, 9, 16); + LocalDate plusYear = LocalDate.of(2024, 9, 16); + LocalDate minusYear = LocalDate.of(2022, 9, 16); + assertTrue(DateUtils.between(source, minusYear, plusYear)); + assertFalse(DateUtils.between(minusYear, source, plusYear)); + assertFalse(DateUtils.between(source, plusYear, minusYear)); + } + + @Test + void testSafeBefore() { + assertFalse(DateUtils.safeBefore(null, LocalDate.now())); + assertFalse(DateUtils.safeBefore(null, LocalDate.now())); + assertFalse(DateUtils.safeBefore(null, null)); + assertFalse(DateUtils.safeBefore(LocalDate.of(2023, 9, 17), LocalDate.of(2023, 9, 16))); + assertTrue(DateUtils.safeBefore(LocalDate.of(2023, 9, 10), LocalDate.of(2023, 9, 16))); + assertTrue(DateUtils.safeBefore(LocalDate.of(2023, 9, 11), LocalDate.of(2023, 9, 16))); + } + + @Test + void testSafeAfter() { + assertFalse(DateUtils.safeAfter(null, LocalDate.now())); + assertFalse(DateUtils.safeAfter(null, LocalDate.now())); + assertFalse(DateUtils.safeAfter(null, null)); + assertFalse(DateUtils.safeAfter(LocalDate.of(2023, 9, 10), LocalDate.of(2023, 9, 16))); + assertTrue(DateUtils.safeAfter(LocalDate.of(2023, 9, 17), LocalDate.of(2023, 9, 16))); + assertTrue(DateUtils.safeAfter(LocalDate.of(2023, 9, 18), LocalDate.of(2023, 9, 16))); + } + + @Test + void testSafeBeforeOrSame() { + assertFalse(DateUtils.safeBeforeOrSame(null, LocalDate.now())); + assertFalse(DateUtils.safeBeforeOrSame(null, LocalDate.now())); + assertFalse(DateUtils.safeBeforeOrSame(null, null)); + assertFalse(DateUtils.safeBeforeOrSame(LocalDate.of(2023, 9, 17), LocalDate.of(2023, 9, 16))); + assertTrue(DateUtils.safeBeforeOrSame(LocalDate.of(2023, 9, 16), LocalDate.of(2023, 9, 16))); + assertTrue(DateUtils.safeBeforeOrSame(LocalDate.of(2023, 9, 15), LocalDate.of(2023, 9, 16))); + } + + @Test + void testSafeAfterOrSame() { + assertFalse(DateUtils.safeAfterOrSame(null, LocalDate.now())); + assertFalse(DateUtils.safeAfterOrSame(null, LocalDate.now())); + assertFalse(DateUtils.safeAfterOrSame(null, null)); + assertFalse(DateUtils.safeAfterOrSame(LocalDate.of(2023, 9, 10), LocalDate.of(2023, 9, 16))); + assertTrue(DateUtils.safeAfterOrSame(LocalDate.of(2023, 9, 16), LocalDate.of(2023, 9, 16))); + assertTrue(DateUtils.safeAfterOrSame(LocalDate.of(2023, 9, 18), LocalDate.of(2023, 9, 16))); + } } diff --git a/src/test/java/com/hijackermax/utils/lang/OptionalUtilsTest.java b/src/test/java/com/hijackermax/utils/lang/OptionalUtilsTest.java index 685565e..74df4b2 100644 --- a/src/test/java/com/hijackermax/utils/lang/OptionalUtilsTest.java +++ b/src/test/java/com/hijackermax/utils/lang/OptionalUtilsTest.java @@ -5,6 +5,7 @@ import java.util.Collections; import java.util.List; import java.util.Optional; +import java.util.regex.Pattern; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -55,4 +56,13 @@ void testOfBlank() { assertTrue(OptionalUtils.ofBlank(" ").isEmpty()); assertTrue(OptionalUtils.ofBlank("Test").isPresent()); } + + @Test + void ofFind() { + assertTrue(OptionalUtils.ofFind(Pattern.compile("[^\\D.]"), null).isEmpty()); + assertTrue(OptionalUtils.ofFind(null, "12345abc").isEmpty()); + assertTrue(OptionalUtils.ofFind(null, null).isEmpty()); + assertTrue(OptionalUtils.ofFind(Pattern.compile("[^\\D.]"), "12345abc").isPresent()); + assertTrue(OptionalUtils.ofFind(Pattern.compile("[^\\D.]"), "abc").isEmpty()); + } } diff --git a/src/test/java/com/hijackermax/utils/lang/StringUtilsTest.java b/src/test/java/com/hijackermax/utils/lang/StringUtilsTest.java index 8fe3787..e876b05 100644 --- a/src/test/java/com/hijackermax/utils/lang/StringUtilsTest.java +++ b/src/test/java/com/hijackermax/utils/lang/StringUtilsTest.java @@ -1,6 +1,8 @@ package com.hijackermax.utils.lang; import com.hijackermax.utils.encoders.Base122; +import com.hijackermax.utils.entities.Single; +import com.hijackermax.utils.entities.Tuple; import com.hijackermax.utils.enums.ComparisonOperators; import org.junit.jupiter.api.Test; @@ -326,4 +328,91 @@ void testHasLength() { .collect(Collectors.toList()); assertLinesMatch(List.of("Foo", "Bar"), filteredList); } + + @Test + void testIfNotEmpty() { + Single valueHolder = new Single<>("Original"); + StringUtils.ifNotEmpty(null, valueHolder::setValue); + assertEquals("Original", valueHolder.getValue()); + StringUtils.ifNotEmpty(StringUtils.EMPTY, valueHolder::setValue); + assertEquals("Original", valueHolder.getValue()); + StringUtils.ifNotEmpty(StringUtils.BLANK, valueHolder::setValue); + assertEquals(StringUtils.BLANK, valueHolder.getValue()); + StringUtils.ifNotEmpty("Foo", valueHolder::setValue); + assertEquals("Foo", valueHolder.getValue()); + } + + @Test + void testIfNotBlank() { + Single valueHolder = new Single<>("Original"); + StringUtils.ifNotBlank(null, valueHolder::setValue); + assertEquals("Original", valueHolder.getValue()); + StringUtils.ifNotBlank(StringUtils.EMPTY, valueHolder::setValue); + assertEquals("Original", valueHolder.getValue()); + StringUtils.ifNotBlank(StringUtils.BLANK, valueHolder::setValue); + assertEquals("Original", valueHolder.getValue()); + StringUtils.ifNotBlank("Foo", valueHolder::setValue); + assertEquals("Foo", valueHolder.getValue()); + } + + @Test + void testCapitalizeDefault() { + assertEquals(StringUtils.EMPTY, StringUtils.capitalize(null)); + assertEquals("Foo Bar", StringUtils.capitalize("foo bar")); + assertEquals("Foo Bar", StringUtils.capitalize("FOO BAR")); + assertEquals("Foo Bar", StringUtils.capitalize("fOO bAR")); + assertEquals("Foo Bar", StringUtils.capitalize("fOo bAr")); + } + + @Test + void testCapitalize() { + assertEquals(StringUtils.EMPTY, StringUtils.capitalize(null, ' ')); + assertEquals("Foo@Bar", StringUtils.capitalize("foo@bar", ' ', '@')); + assertEquals("Foo Bar-Test", StringUtils.capitalize("FOO BAR-TEST", ' ', '-')); + assertEquals("Foo B$Ar", StringUtils.capitalize("fOO b$AR", ' ', '$')); + assertEquals("Foo Ba$R", StringUtils.capitalize("fOo bA$r", ' ', '$')); + } + + @Test + void testSafeJoin() { + assertEquals(StringUtils.EMPTY, StringUtils.safeJoin(null, ",")); + assertEquals(StringUtils.EMPTY, StringUtils.safeJoin(Collections.emptyList(), ",")); + assertEquals("Foo", StringUtils.safeJoin(List.of("Foo"), ",")); + assertEquals("Foo,Bar", StringUtils.safeJoin(List.of("Foo", "Bar"), ",")); + assertEquals("Foo$Bar$Test", StringUtils.safeJoin(List.of("Foo", "Bar", "Test"), "$")); + } + + @Test + void testIfBothNotEmpty() { + Tuple valueHolder = new Tuple<>("OriginalL", "OriginalR"); + StringUtils.ifBothNotEmpty(null, null, valueHolder::setPair); + assertEquals("OriginalL", valueHolder.getKey()); + assertEquals("OriginalR", valueHolder.getValue()); + StringUtils.ifBothNotEmpty(StringUtils.EMPTY, StringUtils.EMPTY, valueHolder::setPair); + assertEquals("OriginalL", valueHolder.getKey()); + assertEquals("OriginalR", valueHolder.getValue()); + StringUtils.ifBothNotEmpty(StringUtils.BLANK, StringUtils.BLANK, valueHolder::setPair); + assertEquals(StringUtils.BLANK, valueHolder.getKey()); + assertEquals(StringUtils.BLANK, valueHolder.getValue()); + StringUtils.ifBothNotEmpty("Foo", "Bar", valueHolder::setPair); + assertEquals("Foo", valueHolder.getKey()); + assertEquals("Bar", valueHolder.getValue()); + } + + @Test + void testIfBothNotBlank() { + Tuple valueHolder = new Tuple<>("OriginalL", "OriginalR"); + StringUtils.ifBothNotBlank(null, null, valueHolder::setPair); + assertEquals("OriginalL", valueHolder.getKey()); + assertEquals("OriginalR", valueHolder.getValue()); + StringUtils.ifBothNotBlank(StringUtils.EMPTY, StringUtils.EMPTY, valueHolder::setPair); + assertEquals("OriginalL", valueHolder.getKey()); + assertEquals("OriginalR", valueHolder.getValue()); + StringUtils.ifBothNotBlank(StringUtils.BLANK, StringUtils.BLANK, valueHolder::setPair); + assertEquals("OriginalL", valueHolder.getKey()); + assertEquals("OriginalR", valueHolder.getValue()); + StringUtils.ifBothNotBlank("Foo", "Bar", valueHolder::setPair); + assertEquals("Foo", valueHolder.getKey()); + assertEquals("Bar", valueHolder.getValue()); + } }