diff --git a/README.md b/README.md index 96e0606..08ed3ba 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,10 @@ Licensed under the Apache 2.0 License #### Geographical utils * Mercator(EPSG:3857) to WSG84 convertor * WSG84 to Mercator(EPSG:3857) convertor -* Distance calculation between two WSG84 points +* Distance calculation between two WSG84 points + +#### Collector utils +* Collectors for Java streams #### Collections utils * Null-safe methods to work with collections @@ -18,6 +21,10 @@ Licensed under the Apache 2.0 License #### Optional utils * Optional providers for different situations +#### Functional utils + +* Functional utility methods + #### String Utils * Null-safe methods to work with Strings @@ -33,6 +40,10 @@ Licensed under the Apache 2.0 License #### Math utils * Methods that can help with computations +#### Number utils + +* Methods that can help with numbers + #### Random utils * Methods that can provide some random values or randomize arrays @@ -50,6 +61,14 @@ Licensed under the Apache 2.0 License * Tuple * Triple +#### Builders + +* List builder +* Set builder +* Map builder +* Transformer +* XBuilder + #### IO ##### TemporaryFile @@ -87,7 +106,7 @@ Just add this to your **pom.xml** com.hijackermax - utils - 0.0.7 + utils + 0.0.8 ``` \ No newline at end of file diff --git a/pom.xml b/pom.xml index 486e352..d4def85 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.hijackermax utils - 0.0.7 + 0.0.8 utils A set of utils that can help in app development @@ -55,7 +55,7 @@ org.junit.jupiter junit-jupiter - 5.9.2 + 5.10.0 test diff --git a/src/main/java/com/hijackermax/utils/builders/CollectionBuilder.java b/src/main/java/com/hijackermax/utils/builders/CollectionBuilder.java new file mode 100644 index 0000000..b3c090b --- /dev/null +++ b/src/main/java/com/hijackermax/utils/builders/CollectionBuilder.java @@ -0,0 +1,79 @@ +package com.hijackermax.utils.builders; + +import java.util.Collection; +import java.util.function.Consumer; +import java.util.function.Supplier; + +/** + * Interface for abstract collection builder + * + * @param collection element type + * @param collection type + * @param builder type + * @since 0.0.8 + */ +public interface CollectionBuilder, B extends CollectionBuilder> { + + /** + * Adds provided value to collection which is being built + * + * @param value value that should be added to collection + * @return builder instance + * @since 0.0.8 + */ + B add(T value); + + /** + * Adds result of invoking of provided value supplier to collection which is being built + * + * @param valueSupplier supplier of value that should be added to collection + * @return builder instance + * @since 0.0.8 + */ + B add(Supplier valueSupplier); + + /** + * Adds values from provided collection to collection which is being built + * + * @param values collection that should be added to collection which is being built + * @return builder instance + * @since 0.0.8 + */ + B addAll(Collection values); + + /** + * Builds collection + * + * @return built collection + * @since 0.0.8 + */ + C build(); + + /** + * Builds unmodifiable representation of built collection + * + * @return unmodifiable representation of built collection + * @since 0.0.8 + */ + C buildUnmodifiable(); + + /** + * Builds collection and provides in to the consumer + * + * @param collectionConsumer resulting collection consumer + * @since 0.0.8 + */ + default void provide(Consumer collectionConsumer) { + collectionConsumer.accept(build()); + } + + /** + * Builds unmodifiable representation of built collection and provides in to the consumer + * + * @param collectionConsumer resulting unmodifiable collection consumer + * @since 0.0.8 + */ + default void provideUnmodifiable(Consumer collectionConsumer) { + collectionConsumer.accept(buildUnmodifiable()); + } +} diff --git a/src/main/java/com/hijackermax/utils/builders/DictionaryBuilder.java b/src/main/java/com/hijackermax/utils/builders/DictionaryBuilder.java new file mode 100644 index 0000000..7e88c84 --- /dev/null +++ b/src/main/java/com/hijackermax/utils/builders/DictionaryBuilder.java @@ -0,0 +1,81 @@ +package com.hijackermax.utils.builders; + +import java.util.Map; +import java.util.function.Consumer; + +/** + * Interface for abstract map builder + * + * @param map keys type + * @param map values type + * @param map type + * @param builder type + * @since 0.0.8 + */ +public interface DictionaryBuilder, B extends DictionaryBuilder> { + + /** + * Puts provided key-value pair to map which is being built + * + * @param key key that should be added to map + * @param value value that should be added to map + * @return builder instance + * @since 0.0.8 + */ + B put(K key, V value); + + /** + * Puts provided key-value pair to map which is being built if some value wasn't added previously with the same key + * + * @param key key that should be added to map + * @param value value that should be added to map + * @return builder instance + * @since 0.0.8 + */ + B putIfAbsent(K key, V value); + + /** + * Puts key-value pairs from provided map to map which is being built + * + * @param values map that should be added to map which is being built + * @return builder instance + * @since 0.0.8 + */ + B putAll(Map values); + + /** + * Builds map + * + * @return built map + * @since 0.0.8 + */ + M build(); + + /** + * Builds unmodifiable representation of built map + * + * @return unmodifiable representation of built map + * @since 0.0.8 + */ + M buildUnmodifiable(); + + /** + * Builds map and provides in to the consumer + * + * @param mapConsumer resulting map consumer + * @since 0.0.8 + */ + default void provide(Consumer mapConsumer) { + mapConsumer.accept(build()); + } + + /** + * Builds unmodifiable representation of built map and provides in to the consumer + * + * @param mapConsumer resulting unmodifiable map consumer + * @since 0.0.8 + */ + default void provideUnmodifiable(Consumer mapConsumer) { + mapConsumer.accept(buildUnmodifiable()); + } +} diff --git a/src/main/java/com/hijackermax/utils/builders/ListBuilder.java b/src/main/java/com/hijackermax/utils/builders/ListBuilder.java new file mode 100644 index 0000000..127b948 --- /dev/null +++ b/src/main/java/com/hijackermax/utils/builders/ListBuilder.java @@ -0,0 +1,142 @@ +package com.hijackermax.utils.builders; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.function.Supplier; + +/** + * List builder, builds {@link ArrayList} if not initialized with custom list constructor via {@link com.hijackermax.utils.builders.ListBuilder#with(Supplier)} + * Does not support null elements + * + * @param list element type + * @since 0.0.8 + */ +public class ListBuilder implements CollectionBuilder, ListBuilder> { + private final List data; + + private ListBuilder() { + this.data = new ArrayList<>(); + } + + private ListBuilder(Collection data) { + this.data = new ArrayList<>(Objects.requireNonNull(data)); + } + + private ListBuilder(T value) { + this(List.of(Objects.requireNonNull(value))); + } + + private ListBuilder(Supplier> listSupplier) { + this.data = Objects.requireNonNull(listSupplier.get()); + } + + /** + * Builds instance of list builder with provided list supplier as base collection + * + * @param listSupplier new base collection instance supplier + * @param collection element type + * @return builder instance with custom base collection + * @since 0.0.8 + */ + public static ListBuilder with(Supplier> listSupplier) { + return new ListBuilder<>(listSupplier); + } + + /** + * Builds instance of list builder with {@link ArrayList} base collection + * + * @param collection element type + * @return builder instance with {@link ArrayList} base collection + * @since 0.0.8 + */ + public static ListBuilder of() { + return new ListBuilder<>(); + } + + /** + * Builds instance of list builder with {@link ArrayList} base collection and inserts provided value + * + * @param value element that should be inserted into list + * @param collection element type + * @return builder instance with {@link ArrayList} base collection + * @since 0.0.8 + */ + public static ListBuilder of(T value) { + return new ListBuilder<>(value); + } + + /** + * Builds instance of list builder with {@link ArrayList} base collection and inserts provided collection values + * + * @param data element collection which values should be inserted into list + * @param collection element type + * @return builder instance with {@link ArrayList} base collection + * @since 0.0.8 + */ + public static ListBuilder of(Collection data) { + return new ListBuilder<>(data); + } + + /** + * Adds provided value to list which is being built + * + * @param value value that should be added to collection + * @return builder instance + * @since 0.0.8 + */ + @Override + public ListBuilder add(T value) { + data.add(Objects.requireNonNull(value)); + return this; + } + + /** + * Adds values from provided collection to list which is being built + * + * @param values collection that should be added to collection which is being built + * @return builder instance + * @since 0.0.8 + */ + @Override + public ListBuilder addAll(Collection values) { + data.addAll(Objects.requireNonNull(values)); + return this; + } + + /** + * Adds result of invoking of provided value supplier to list which is being built + * + * @param valueSupplier supplier of value that should be added to collection + * @return builder instance + * @since 0.0.8 + */ + @Override + public ListBuilder add(Supplier valueSupplier) { + return add(valueSupplier.get()); + } + + /** + * Builds list + * + * @return built list + * @since 0.0.8 + */ + @Override + public List build() { + return data; + } + + /** + * Builds unmodifiable representation of built list + * + * @return unmodifiable representation of built list + * @since 0.0.8 + */ + @Override + public List buildUnmodifiable() { + return Collections.unmodifiableList(data); + } +} diff --git a/src/main/java/com/hijackermax/utils/builders/MapBuilder.java b/src/main/java/com/hijackermax/utils/builders/MapBuilder.java new file mode 100644 index 0000000..769ee7a --- /dev/null +++ b/src/main/java/com/hijackermax/utils/builders/MapBuilder.java @@ -0,0 +1,163 @@ +package com.hijackermax.utils.builders; + +import java.util.Collections; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.function.Supplier; + +/** + * Map builder, builds {@link HashMap} if not initialized with custom map constructor via {@link com.hijackermax.utils.builders.MapBuilder#with(Supplier)} or {@link com.hijackermax.utils.builders.MapBuilder#ofEnum(Class)} + * + * @param key type + * @param value type + * @since 0.0.8 + */ +public class MapBuilder implements DictionaryBuilder, MapBuilder> { + private final Map data; + + private MapBuilder() { + this.data = new HashMap<>(); + } + + private MapBuilder(Map data) { + this.data = new HashMap<>(Objects.requireNonNull(data)); + } + + private MapBuilder(K key, V value) { + this(Map.of(key, value)); + } + + private MapBuilder(Supplier> mapSupplier) { + this.data = Objects.requireNonNull(mapSupplier.get()); + } + + /** + * Builds instance of map builder for {@link EnumMap} with provided {@link Enum} class + * + * @param enumClass class of enum that should be used as a key + * @param key type, should be an enum + * @param value type + * @return builder instance with {@link EnumMap} as base map + * @since 0.0.8 + */ + public static , V> MapBuilder ofEnum(Class enumClass) { + return with(() -> new EnumMap<>(Objects.requireNonNull(enumClass))); + } + + /** + * Builds instance of map builder with provided map supplier as base map + * + * @param mapSupplier new base map instance supplier + * @param key type + * @param value type + * @return builder instance with custom base map + * @since 0.0.8 + */ + public static MapBuilder with(Supplier> mapSupplier) { + return new MapBuilder<>(mapSupplier); + } + + /** + * Builds instance of map builder with {@link HashMap} base map + * + * @param key type + * @param value type + * @return builder instance with {@link HashMap} base map + * @since 0.0.8 + */ + public static MapBuilder of() { + return new MapBuilder<>(); + } + + /** + * Builds instance of map builder with {@link HashMap} base map and puts provided key-value pair + * + * @param key key that should be put into map which is being built + * @param value value that should be put into map + * @param key type + * @param value type + * @return builder instance with {@link HashMap} base map + * @since 0.0.8 + */ + public static MapBuilder of(K key, V value) { + return new MapBuilder<>(key, value); + } + + /** + * Builds instance of map builder with {@link HashMap} base map and puts provided map key-value pairs + * + * @param data map which key-value pairs should be put into map which is being built + * @param key type + * @param value type + * @return builder instance with {@link HashMap} base map + * @since 0.0.8 + */ + public static MapBuilder of(Map data) { + return new MapBuilder<>(data); + } + + /** + * Puts provided key-value pair to map which is being built + * + * @param key key that should be added to map + * @param value value that should be added to map + * @return builder instance + * @since 0.0.8 + */ + @Override + public MapBuilder put(K key, V value) { + data.put(key, value); + return this; + } + + /** + * Puts provided key-value pair to map which is being built if some value wasn't added previously with the same key + * + * @param key key that should be added to map + * @param value value that should be added to map + * @return builder instance + * @since 0.0.8 + */ + @Override + public MapBuilder putIfAbsent(K key, V value) { + data.putIfAbsent(key, value); + return this; + } + + /** + * Puts key-value pairs from provided map to map which is being built + * + * @param values map that should be added to map which is being built + * @return builder instance + * @since 0.0.8 + */ + @Override + public MapBuilder putAll(Map values) { + data.putAll(Objects.requireNonNull(values)); + return this; + } + + /** + * Builds map + * + * @return built map + * @since 0.0.8 + */ + @Override + public Map build() { + return data; + } + + /** + * Builds unmodifiable representation of built map + * + * @return unmodifiable representation of built map + * @since 0.0.8 + */ + @Override + public Map buildUnmodifiable() { + return Collections.unmodifiableMap(data); + } +} diff --git a/src/main/java/com/hijackermax/utils/builders/SetBuilder.java b/src/main/java/com/hijackermax/utils/builders/SetBuilder.java new file mode 100644 index 0000000..2ddfd06 --- /dev/null +++ b/src/main/java/com/hijackermax/utils/builders/SetBuilder.java @@ -0,0 +1,142 @@ +package com.hijackermax.utils.builders; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; +import java.util.function.Supplier; + +/** + * Set builder, builds {@link HashSet} if not initialized with custom set constructor via {@link com.hijackermax.utils.builders.SetBuilder#with(Supplier)} + * Does not support null elements + * + * @param set element type + * @since 0.0.8 + */ +public class SetBuilder implements CollectionBuilder, SetBuilder> { + private final Set data; + + private SetBuilder() { + this.data = new HashSet<>(); + } + + private SetBuilder(Collection data) { + this.data = new HashSet<>(Objects.requireNonNull(data)); + } + + private SetBuilder(T value) { + this(Set.of(Objects.requireNonNull(value))); + } + + private SetBuilder(Supplier> setSupplier) { + this.data = Objects.requireNonNull(setSupplier.get()); + } + + /** + * Builds instance of set builder with provided set supplier as base collection + * + * @param setSupplier new base collection instance supplier + * @param collection element type + * @return builder instance with custom base collection + * @since 0.0.8 + */ + public static SetBuilder with(Supplier> setSupplier) { + return new SetBuilder<>(setSupplier); + } + + /** + * Builds instance of set builder with {@link HashSet} base collection + * + * @param collection element type + * @return builder instance with {@link HashSet} base collection + * @since 0.0.8 + */ + public static SetBuilder of() { + return new SetBuilder<>(); + } + + /** + * Builds instance of set builder with {@link HashSet} base collection and inserts provided value + * + * @param value element that should be inserted into set + * @param collection element type + * @return builder instance with {@link HashSet} base collection + * @since 0.0.8 + */ + public static SetBuilder of(T value) { + return new SetBuilder<>(value); + } + + /** + * Builds instance of set builder with {@link HashSet} base collection and inserts provided collection values + * + * @param data element collection which values should be inserted into set + * @param collection element type + * @return builder instance with {@link HashSet} base collection + * @since 0.0.8 + */ + public static SetBuilder of(Collection data) { + return new SetBuilder<>(data); + } + + /** + * Adds provided value to set which is being built + * + * @param value value that should be added to collection + * @return builder instance + * @since 0.0.8 + */ + @Override + public SetBuilder add(T value) { + data.add(Objects.requireNonNull(value)); + return this; + } + + /** + * Adds values from provided collection to set which is being built + * + * @param values collection that should be added to collection which is being built + * @return builder instance + * @since 0.0.8 + */ + @Override + public SetBuilder addAll(Collection values) { + data.addAll(Objects.requireNonNull(values)); + return this; + } + + /** + * Adds result of invoking of provided value supplier to set which is being built + * + * @param valueSupplier supplier of value that should be added to collection + * @return builder instance + * @since 0.0.8 + */ + @Override + public SetBuilder add(Supplier valueSupplier) { + return add(valueSupplier.get()); + } + + /** + * Builds set + * + * @return built set + * @since 0.0.8 + */ + @Override + public Set build() { + return data; + } + + /** + * Builds unmodifiable representation of built set + * + * @return unmodifiable representation of built set + * @since 0.0.8 + */ + @Override + public Set buildUnmodifiable() { + return Collections.unmodifiableSet(data); + } +} diff --git a/src/main/java/com/hijackermax/utils/builders/Transformer.java b/src/main/java/com/hijackermax/utils/builders/Transformer.java new file mode 100644 index 0000000..7f5ca19 --- /dev/null +++ b/src/main/java/com/hijackermax/utils/builders/Transformer.java @@ -0,0 +1,79 @@ +package com.hijackermax.utils.builders; + +import java.util.Objects; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.UnaryOperator; + +/** + * Helper class, provides ability to perform transformation of immutable classes like {@link String} or {@link Integer} + * + * @param type of value for transformation + * @since 0.0.8 + */ +public class Transformer { + private T value; + + @SuppressWarnings("unused") + private Transformer() { + throw new UnsupportedOperationException(); + } + + private Transformer(T value) { + this.value = Objects.requireNonNull(value, "Input argument cannot be null"); + } + + /** + * Provides instance of {@link Transformer} with given value + * + * @param value immutable value to transform + * @param type of value for transformation + * @return instance of {@link Transformer} + * @throws NullPointerException if provided value is null + */ + public static Transformer of(T value) { + return new Transformer<>(value); + } + + /** + * Conducts transformation of value with provided {@link UnaryOperator} processor + * + * @param valueProcessor {@link UnaryOperator} which does transformation over a value + * @return instance of {@link Transformer} + * @throws NullPointerException if valueProcessor result is null + */ + public Transformer run(UnaryOperator valueProcessor) { + this.value = Objects.requireNonNull(valueProcessor.apply(value), "Transformation result cannot be null"); + return this; + } + + /** + * Returns result of all transformations conducted before + * + * @return resulting value, cannot be null + */ + public T result() { + return value; + } + + /** + * Provides result of all transformations conducted before + * + * @param valueConsumer resulting value {@link Consumer} + */ + public void provide(Consumer valueConsumer) { + valueConsumer.accept(value); + } + + /** + * Provides new instance of {@link Transformer} which is built with result of converting + * current {@link Transformer} value with provided mapper {@link Function} + * + * @param mapper converting {@link Function} + * @param type of mapping result + * @return new instance of {@link Transformer} for mapping result + */ + public Transformer evolve(Function mapper) { + return new Transformer<>(mapper.apply(value)); + } +} diff --git a/src/main/java/com/hijackermax/utils/entities/XBuilder.java b/src/main/java/com/hijackermax/utils/builders/XBuilder.java similarity index 97% rename from src/main/java/com/hijackermax/utils/entities/XBuilder.java rename to src/main/java/com/hijackermax/utils/builders/XBuilder.java index 9e13aed..71973d8 100644 --- a/src/main/java/com/hijackermax/utils/entities/XBuilder.java +++ b/src/main/java/com/hijackermax/utils/builders/XBuilder.java @@ -1,4 +1,4 @@ -package com.hijackermax.utils.entities; +package com.hijackermax.utils.builders; import java.util.function.BiConsumer; import java.util.function.Function; diff --git a/src/main/java/com/hijackermax/utils/entities/Single.java b/src/main/java/com/hijackermax/utils/entities/Single.java index bcc180a..cb1ca87 100644 --- a/src/main/java/com/hijackermax/utils/entities/Single.java +++ b/src/main/java/com/hijackermax/utils/entities/Single.java @@ -2,6 +2,7 @@ import java.util.Objects; import java.util.function.Consumer; +import java.util.function.Predicate; import java.util.function.UnaryOperator; import static java.util.Optional.ofNullable; @@ -30,6 +31,17 @@ public Single(V value) { this.value = value; } + /** + * Creates instance of {@link Single} with provided value + * + * @param value that should be wrapped + * @param value type + * @return instance of {@link Single} with provided value + */ + public static Single of(V value) { + return new Single<>(value); + } + /** * Compares value of this instance of {@link Single} with null * @@ -66,6 +78,18 @@ public void modifyValue(UnaryOperator processor) { this.value = processor.apply(value); } + /** + * Provides ability to modify existing value if it satisfies provided predicate + * + * @param processor {@link UnaryOperator} which will be applied to existing value + * @param valuePredicate {@link Predicate} which will be used to check compatibility of existing value + */ + public void modifyValueIfSatisfies(UnaryOperator processor, Predicate valuePredicate) { + if (valuePredicate.test(value)) { + this.value = processor.apply(value); + } + } + /** * Provides non-null value to the provided {@link Consumer} * diff --git a/src/main/java/com/hijackermax/utils/entities/Triple.java b/src/main/java/com/hijackermax/utils/entities/Triple.java index ba4315f..aa5787d 100644 --- a/src/main/java/com/hijackermax/utils/entities/Triple.java +++ b/src/main/java/com/hijackermax/utils/entities/Triple.java @@ -4,6 +4,7 @@ import java.util.Objects; import java.util.function.Consumer; +import java.util.function.Predicate; import java.util.function.UnaryOperator; import static java.util.Optional.ofNullable; @@ -20,7 +21,7 @@ public class Triple extends Tuple { private M middle; /** - * Creates new instance of {@link Triple} with provided key, middle and value + * Creates instance of {@link Triple} with provided key, middle and value * * @param key that should be wrapped * @param middle that should be wrapped @@ -31,6 +32,21 @@ public Triple(K key, M middle, V value) { this.middle = middle; } + /** + * Creates instance of {@link Triple} with provided key, middle and value + * + * @param key that should be wrapped + * @param middle that should be wrapped + * @param value that should be wrapped + * @param key type + * @param middle type + * @param value type + * @return instance of {@link Triple} with provided key, middle and value + */ + public static Triple of(K key, M middle, V value) { + return new Triple<>(key, middle, value); + } + /** * Creates new instance of {@link Triple} with null key, middle and value */ @@ -64,6 +80,18 @@ public void modifyMiddle(UnaryOperator processor) { this.middle = processor.apply(middle); } + /** + * Provides ability to modify existing middle if it satisfies provided predicate + * + * @param processor {@link UnaryOperator} which will be applied to existing middle + * @param middlePredicate {@link Predicate} which will be used to check compatibility of existing middle + */ + public void modifyMiddleIfSatisfies(UnaryOperator processor, Predicate middlePredicate) { + if (middlePredicate.test(middle)) { + this.middle = processor.apply(middle); + } + } + /** * Compares middle of this instance of {@link Triple} with null * diff --git a/src/main/java/com/hijackermax/utils/entities/Tuple.java b/src/main/java/com/hijackermax/utils/entities/Tuple.java index c8530cf..0810876 100644 --- a/src/main/java/com/hijackermax/utils/entities/Tuple.java +++ b/src/main/java/com/hijackermax/utils/entities/Tuple.java @@ -3,6 +3,7 @@ import java.util.Objects; import java.util.function.BiConsumer; import java.util.function.Consumer; +import java.util.function.Predicate; import java.util.function.UnaryOperator; import static java.util.Optional.ofNullable; @@ -18,7 +19,7 @@ public class Tuple extends Single { private K key; /** - * Creates new instance of {@link Tuple} with provided key and value + * Creates instance of {@link Tuple} with provided key and value * * @param key that should be wrapped * @param value that should be wrapped @@ -28,6 +29,19 @@ public Tuple(K key, V value) { this.key = key; } + /** + * Creates instance of {@link Tuple} with provided key and value + * + * @param key that should be wrapped + * @param value that should be wrapped + * @param key type + * @param value type + * @return instance of {@link Tuple} with provided key and value + */ + public static Tuple of(K key, V value) { + return new Tuple<>(key, value); + } + /** * Creates new instance of {@link Tuple} with null key and value */ @@ -61,6 +75,18 @@ public void modifyKey(UnaryOperator processor) { this.key = processor.apply(key); } + /** + * Provides ability to modify existing key if it satisfies provided predicate + * + * @param processor {@link UnaryOperator} which will be applied to existing key + * @param keyPredicate {@link Predicate} which will be used to check compatibility of existing key + */ + public void modifyKeyIfSatisfies(UnaryOperator processor, Predicate keyPredicate) { + if (keyPredicate.test(key)) { + this.key = processor.apply(key); + } + } + /** * Compares key of this instance of {@link Tuple} with null * diff --git a/src/main/java/com/hijackermax/utils/enums/ComparisonOperators.java b/src/main/java/com/hijackermax/utils/enums/ComparisonOperators.java new file mode 100644 index 0000000..1f2639c --- /dev/null +++ b/src/main/java/com/hijackermax/utils/enums/ComparisonOperators.java @@ -0,0 +1,46 @@ +package com.hijackermax.utils.enums; + +/** + * Comparison operators + */ +public enum ComparisonOperators { + /** + * Equal value operator + */ + EQ("=="), + /** + * Non-equal value operator + */ + NEQ("!="), + /** + * Less than value operator + */ + LT("<"), + /** + * Greater than value operator + */ + GT(">"), + /** + * Less than or equal value operator + */ + LTE("<="), + /** + * Greater than or equal value operator + */ + GTE(">="); + + private final String value; + + ComparisonOperators(String value) { + this.value = value; + } + + /** + * Provides symbolic string value of operator + * + * @return symbolic string value of operator + */ + public String getValue() { + return value; + } +} diff --git a/src/main/java/com/hijackermax/utils/lang/CollectionUtils.java b/src/main/java/com/hijackermax/utils/lang/CollectionUtils.java index 3fd9434..ad02f2a 100644 --- a/src/main/java/com/hijackermax/utils/lang/CollectionUtils.java +++ b/src/main/java/com/hijackermax/utils/lang/CollectionUtils.java @@ -1,11 +1,29 @@ package com.hijackermax.utils.lang; -import java.util.*; -import java.util.function.*; -import java.util.stream.Collector; +import com.hijackermax.utils.misc.EnumerationSpliterator; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.Enumeration; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.BiPredicate; +import java.util.function.BinaryOperator; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; +import static java.util.Optional.ofNullable; + /** * Set of utility methods that can help to work with Java collections */ @@ -439,43 +457,6 @@ public static void getDifferences(Collection left, differenceConsumer.accept(subtract(left, right), subtract(right, left)); } - /** - * Provides grouping collector which allows null key - * - * @param keyExtractor {@link Function} for key extraction - * @param input collection elements type - * @param key type - * @return Grouping collector with supported null key - * @since 0.0.1 - */ - public static Collector>> groupingByWithNull(Function keyExtractor) { - return groupingByWithNull(keyExtractor, Function.identity()); - } - - /** - * Provides grouping collector which allows null key - * - * @param keyExtractor {@link Function} for key extraction - * @param valueExtractor {@link Function} for values extraction - * @param input collection elements type - * @param key type - * @param value type - * @return Grouping collector with supported null key - * @since 0.0.1 - */ - public static Collector>> groupingByWithNull(Function keyExtractor, - Function valueExtractor) { - return Collectors.toMap( - keyExtractor, - v -> Collections.singletonList(valueExtractor.apply(v)), - (prev, curr) -> { - List result = new ArrayList<>(prev.size() + curr.size()); - result.addAll(prev); - result.addAll(curr); - return result; - }); - } - /** * Conducts null-safe conversion of input {@link Collection} to {@link Map} using provided key extractor {@link Function} * @@ -648,21 +629,6 @@ public static Predicate> valuePredicate(Predicate predicate.test(entry.getValue()); } - /** - * Provides toString {@link Collector} for stream of {@link Character} - * - * @return {@link Collector} which concatenates {@link Character} elements in encounter order - * @since 0.0.4 - */ - public static Collector toStringCollector() { - return Collector.of( - StringBuffer::new, - StringBuffer::append, - StringBuffer::append, - StringBuffer::toString - ); - } - /** * Checks if input {@link Collection} contains provided value * @@ -756,4 +722,71 @@ public static boolean safeContainsAny(Collection source, Collecti return Objects.nonNull(source) && Objects.nonNull(target) && target.stream() .anyMatch(source::contains); } + + /** + * Safely provides value from source {@link Map} that can be null or doesn't contain provided key or value is null + * + * @param source {@link Map} + * @param key for required value + * @param valueConsumer {@link Consumer} of existing non-null value + * @param type of the map key + * @param type of the map value + * @since 0.0.8 + */ + public static void safeProvide(Map source, K key, Consumer valueConsumer) { + ofNullable(source) + .map(m -> m.get(key)) + .ifPresent(valueConsumer); + } + + /** + * Provides value {@link Consumer} which puts consumed value in provided map by provided key + * + * @param source {@link Map} + * @param key for provided value to put into the source {@link Map} + * @param type of the map key + * @param type of the map value + * @return value {@link Consumer} which puts consumed value in provided map by provided key + * @since 0.0.8 + */ + public static Consumer putWithValue(Map source, K key) { + return value -> source.put(key, value); + } + + /** + * Provides key {@link Consumer} which puts provided value in provided map by consumed key + * + * @param source {@link Map} + * @param value to put into the source {@link Map} + * @param type of the map key + * @param type of the map value + * @return key {@link Consumer} which puts provided value in provided map by consumed key + * @since 0.0.8 + */ + public static Consumer putWithKey(Map source, V value) { + return key -> source.put(key, value); + } + + /** + * Checks if {@link Enumeration} is empty or null + * + * @param value {@link Enumeration} that should be checked + * @return true if {@link Enumeration} is empty or null + * @since 0.0.8 + */ + public static boolean isEmpty(Enumeration value) { + return Objects.isNull(value) || !value.hasMoreElements(); + } + + /** + * Returns stream from input {@link Enumeration} if it is not null or empty, or empty stream + * + * @param input source enumeration + * @param {@link Enumeration} items type + * @return stream consisting of elements from input {@link Enumeration} or empty stream + * @since 0.0.8 + */ + public static Stream safeStreamOf(Enumeration input) { + return isEmpty(input) ? Stream.empty() : EnumerationSpliterator.ofOrdered(input).stream(); + } } diff --git a/src/main/java/com/hijackermax/utils/lang/CollectorUtils.java b/src/main/java/com/hijackermax/utils/lang/CollectorUtils.java new file mode 100644 index 0000000..ab0d9ab --- /dev/null +++ b/src/main/java/com/hijackermax/utils/lang/CollectorUtils.java @@ -0,0 +1,122 @@ +package com.hijackermax.utils.lang; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumMap; +import java.util.List; +import java.util.Map; +import java.util.function.BinaryOperator; +import java.util.function.Function; +import java.util.stream.Collector; +import java.util.stream.Collectors; + +/** + * Set of stream collectors + */ +public final class CollectorUtils { + private CollectorUtils() { + } + + /** + * Provides grouping collector which allows null key + * + * @param keyExtractor {@link Function} for key extraction + * @param input stream elements type + * @param key type + * @return Grouping collector with supported null key + * @since 0.0.1 + */ + public static Collector>> groupingByWithNull(Function keyExtractor) { + return groupingByWithNull(keyExtractor, Function.identity()); + } + + /** + * Provides grouping collector which allows null key + * + * @param keyExtractor {@link Function} for key extraction + * @param valueExtractor {@link Function} for values extraction + * @param input stream elements type + * @param key type + * @param value type + * @return Grouping collector with supported null key + * @since 0.0.1 + */ + public static Collector>> groupingByWithNull(Function keyExtractor, + Function valueExtractor) { + return Collectors.toMap( + keyExtractor, + v -> Collections.singletonList(valueExtractor.apply(v)), + (prev, curr) -> { + List result = new ArrayList<>(prev.size() + curr.size()); + result.addAll(prev); + result.addAll(curr); + return result; + }); + } + + /** + * Provides to {@link String} {@link Collector} for stream of {@link Character} + * + * @return {@link Collector} which concatenates {@link Character} elements in encounter order + * @since 0.0.4 + */ + public static Collector toStringCollector() { + return Collector.of( + StringBuffer::new, + StringBuffer::append, + StringBuffer::append, + StringBuffer::toString + ); + } + + /** + * Provides to {@link EnumMap} {@link Collector} + * + * @param keyExtractor {@link Function} for key extraction + * @param valueExtractor {@link Function} for values extraction + * @param mergeFunction {@link BinaryOperator}, used to resolve collisions between values associated with the same key + * @param enumClass class of {@link Enum} which represents key of resulting {@link EnumMap} + * @param input stream elements type + * @param key type + * @param value type + * @return {@link Collector} which collects provided elements to {@link EnumMap} + * @since 0.0.8 + */ + public static , V> Collector> toEnumMap(Function keyExtractor, + Function valueExtractor, + BinaryOperator mergeFunction, + Class enumClass) { + return Collectors.toMap( + keyExtractor, + valueExtractor, + mergeFunction, + () -> new EnumMap<>(enumClass) + ); + } + + /** + * Provides to {@link EnumMap} {@link Collector} + * + * @param keyExtractor {@link Function} for key extraction + * @param valueExtractor {@link Function} for values extraction + * @param enumClass class of {@link Enum} which represents key of resulting {@link EnumMap} + * @param input stream elements type + * @param key type + * @param value type + * @return {@link Collector} which collects provided elements to {@link EnumMap} + * @throws IllegalStateException if collisions between values associated with the same key encountered + * @since 0.0.8 + */ + public static , V> Collector> toEnumMap(Function keyExtractor, + Function valueExtractor, + Class enumClass) { + return toEnumMap( + keyExtractor, + valueExtractor, + (left, right) -> { + throw new IllegalStateException(String.format("Duplicate keys for values %s and %s", left, right)); + }, + enumClass + ); + } +} diff --git a/src/main/java/com/hijackermax/utils/lang/FunctionalUtils.java b/src/main/java/com/hijackermax/utils/lang/FunctionalUtils.java index 35a7127..b5ecdb6 100644 --- a/src/main/java/com/hijackermax/utils/lang/FunctionalUtils.java +++ b/src/main/java/com/hijackermax/utils/lang/FunctionalUtils.java @@ -1,8 +1,11 @@ package com.hijackermax.utils.lang; +import java.util.Objects; import java.util.concurrent.Callable; 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; /** @@ -70,4 +73,20 @@ public static T failSafeStrategy(Callable callable, } return fallback.get(); } + + /** + * Provides {@link Predicate} which allows to do value transformation and validation of new value with provided {@link Predicate} + * + * @param transformer {@link Function} which transforms provided value to different + * @param extractedPredicate {@link Predicate} for transformed value + * @param source value type + * @param transformed value type + * @return {@link Predicate} which allows to do value transformation and validation of new value with provided {@link Predicate}, + * if source value is null result will be false + * @since 0.0.8 + */ + public static Predicate mappedPredicate(Function transformer, Predicate extractedPredicate) { + return source -> Objects.nonNull(source) && + Objects.requireNonNull(transformer).andThen(Objects.requireNonNull(extractedPredicate)::test).apply(source); + } } diff --git a/src/main/java/com/hijackermax/utils/lang/MathUtils.java b/src/main/java/com/hijackermax/utils/lang/MathUtils.java index c3d1c7d..0a2fc71 100644 --- a/src/main/java/com/hijackermax/utils/lang/MathUtils.java +++ b/src/main/java/com/hijackermax/utils/lang/MathUtils.java @@ -324,4 +324,48 @@ public static UnaryOperator add(float b) { public static UnaryOperator add(double b) { return a -> Double.sum(a, b); } + + /** + * Provides {@link UnaryOperator} which multiplies provided value by {@link Function} argument as per the * operator + * + * @param b multiplicand + * @return {@link UnaryOperator} which multiplies provided value to {@link Function} argument + * @since 0.0.8 + */ + public static UnaryOperator multiply(int b) { + return a -> a * b; + } + + /** + * Provides {@link UnaryOperator} which multiplies provided value by {@link Function} argument as per the * operator + * + * @param b multiplicand + * @return {@link UnaryOperator} which multiplies provided value to {@link Function} argument + * @since 0.0.8 + */ + public static UnaryOperator multiply(long b) { + return a -> a * b; + } + + /** + * Provides {@link UnaryOperator} which multiplies provided value by {@link Function} argument as per the * operator + * + * @param b multiplicand + * @return {@link UnaryOperator} which multiplies provided value to {@link Function} argument + * @since 0.0.8 + */ + public static UnaryOperator multiply(float b) { + return a -> a * b; + } + + /** + * Provides {@link UnaryOperator} which multiplies provided value by {@link Function} argument as per the * operator + * + * @param b multiplicand + * @return {@link UnaryOperator} which multiplies provided value to {@link Function} argument + * @since 0.0.8 + */ + public static UnaryOperator multiply(double b) { + return a -> a * b; + } } diff --git a/src/main/java/com/hijackermax/utils/lang/NumberUtils.java b/src/main/java/com/hijackermax/utils/lang/NumberUtils.java new file mode 100644 index 0000000..338b2f5 --- /dev/null +++ b/src/main/java/com/hijackermax/utils/lang/NumberUtils.java @@ -0,0 +1,56 @@ +package com.hijackermax.utils.lang; + +import com.hijackermax.utils.enums.ComparisonOperators; + +import java.util.Objects; + +/** + * Set of utility methods that can help with number operations + */ +public final class NumberUtils { + private NumberUtils() { + } + + /** + * Provides comparison of two ints with provided {@link ComparisonOperators} + * + * @param left the left value in expression + * @param right the right value in expression + * @param operator the operator + * @return comparison result + * @since 0.0.8 + */ + public static boolean compare(int left, int right, ComparisonOperators operator) { + switch (Objects.requireNonNull(operator)) { + case EQ: + return right == left; + case NEQ: + return right != left; + case LT: + return right > left; + case GT: + return right < left; + case GTE: + return right <= left; + case LTE: + return right >= left; + default: + return false; + } + } + + /** + * Conducts validation if provided value is greater than zero + * + * @param value the value to check + * @return provided value if greater than zero + * @throws IllegalArgumentException if provided value is equal to zero or negative + * @since 0.0.8 + */ + public static int requireGreaterThanZero(int value) { + if (value > 0) { + return value; + } + throw new IllegalArgumentException("Value should be greater than zero"); + } +} diff --git a/src/main/java/com/hijackermax/utils/lang/ObjectUtils.java b/src/main/java/com/hijackermax/utils/lang/ObjectUtils.java index efe410b..821a0a3 100644 --- a/src/main/java/com/hijackermax/utils/lang/ObjectUtils.java +++ b/src/main/java/com/hijackermax/utils/lang/ObjectUtils.java @@ -6,6 +6,7 @@ import java.util.Base64; import java.util.Objects; import java.util.function.Function; +import java.util.function.Supplier; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; @@ -112,4 +113,17 @@ public static byte[] decompress(String source, Function decoder) return inputStream.readAllBytes(); } } + + /** + * Returs provided value or invokes default value {@link Supplier} if value is null + * + * @param value that can be null + * @param defaultValueSupplier fallback value {@link Supplier} + * @param value type + * @return value if it is not null or default value {@link Supplier} invoke result + * @since 0.0.8 + */ + public static T valueOrGetDefault(T value, Supplier defaultValueSupplier) { + return Objects.isNull(value) ? defaultValueSupplier.get() : value; + } } diff --git a/src/main/java/com/hijackermax/utils/lang/RandomUtils.java b/src/main/java/com/hijackermax/utils/lang/RandomUtils.java index 5d8ac1a..1e19f77 100644 --- a/src/main/java/com/hijackermax/utils/lang/RandomUtils.java +++ b/src/main/java/com/hijackermax/utils/lang/RandomUtils.java @@ -7,7 +7,7 @@ /** * Set of utility methods that can provide some random values */ -public class RandomUtils { +public final class RandomUtils { private static final char[] ALPHA_NUMERIC = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz".toCharArray(); private static final char[] NUMERIC = "1234567890".toCharArray(); private static final SecureRandom SECURE_RANDOM = new SecureRandom(); @@ -232,6 +232,6 @@ private static void shuffleToArray(Object source, Object result) { private static String randomStringSequence(char[] charSequence, int length) { return SECURE_RANDOM.ints(length, 0, charSequence.length) .mapToObj(idx -> charSequence[idx]) - .collect(CollectionUtils.toStringCollector()); + .collect(CollectorUtils.toStringCollector()); } } diff --git a/src/main/java/com/hijackermax/utils/lang/StringUtils.java b/src/main/java/com/hijackermax/utils/lang/StringUtils.java index 87f1a1d..7ed579e 100644 --- a/src/main/java/com/hijackermax/utils/lang/StringUtils.java +++ b/src/main/java/com/hijackermax/utils/lang/StringUtils.java @@ -1,14 +1,23 @@ package com.hijackermax.utils.lang; +import com.hijackermax.utils.entities.Single; +import com.hijackermax.utils.enums.ComparisonOperators; + import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.Base64; import java.util.Collection; +import java.util.Map; import java.util.Objects; 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 static com.hijackermax.utils.lang.NumberUtils.requireGreaterThanZero; + /** * Set of utility methods that can help to work with Strings */ @@ -58,6 +67,7 @@ public final class StringUtils { private static final Pattern WHITESPACES_PATTERN = Pattern.compile("\\s+"); private static final Pattern NON_DIGITS_PATTERN = Pattern.compile("[^\\d.]"); + private static final Pattern DIGITS_PATTERN = Pattern.compile("[^\\D.]"); private StringUtils() { } @@ -350,4 +360,132 @@ public static String notBlankOrElse(String value, String defaultValue) { public static String removeWhitespaces(String source) { return isBlank(source) ? EMPTY : WHITESPACES_PATTERN.matcher(source).replaceAll(EMPTY); } + + /** + * Returs provided value {@link String} or {@link String} provided by default + * value {@link Supplier} if value is null, empty or blank + * + * @param value that can be null, blank or empty + * @param defaultValueSupplier fallback value {@link Supplier} + * @return value if it is not null, blank or empty, otherwise default value {@link Supplier} invoke result + * @since 0.0.8 + */ + public static String notBlankOrElseGet(String value, Supplier defaultValueSupplier) { + return isBlank(value) ? defaultValueSupplier.get() : value; + } + + /** + * Removes all digit chars if non-null {@link String} is provided, otherwise returns empty string + * + * @param source {@link String} that should be processed + * @return {@link String} with non-numeric chars only or empty string if input string is blank or null + * @since 0.0.8 + */ + public static String removeDigits(String source) { + return isBlank(source) ? EMPTY : DIGITS_PATTERN.matcher(source).replaceAll(EMPTY); + } + + /** + * Replaces provided {@link CharSequence} values in provided {@link String} with corresponding replacement sequences + * + * @param source {@link String} that should be processed + * @param replacements {@link Map} which contains {@link CharSequence} that should be replaced as key, + * and {@link CharSequence} that should be used as replacement as value + * @return original string if replacement map is empty or null, + * processed {@link String} or empty string if input string is blank or null + * @since 0.0.8 + */ + public static String replace(String source, Map replacements) { + if (isEmpty(source)) { + return EMPTY; + } + Single result = new Single<>(source); + CollectionUtils.safeForEach( + replacements, + (from, to) -> result.modifyValueIfSatisfies(s -> s.replace(from, to), v -> v.contains(from)) + ); + return result.getValue(); + } + + /** + * Provides {@link UnaryOperator} which replaces provided {@link CharSequence} values in provided {@link String} + * with corresponding replacement sequences + * + * @param replacements {@link Map} which contains {@link CharSequence} that should be replaced as key, + * and {@link CharSequence} that should be used as replacement as value + * @return {@link UnaryOperator} which replaces provided {@link CharSequence} values + * in provided {@link String} with corresponding replacement sequences, + * see {@link com.hijackermax.utils.lang.StringUtils#replace(String, Map)} for additional details + * @since 0.0.8 + */ + public static UnaryOperator replace(Map replacements) { + return source -> replace(source, replacements); + } + + /** + * Replaces provided substring value in source {@link String} with provided replacement {@link String} + * + * @param source {@link String} that should be processed + * @param from substring that should be replaced + * @param to replacement substring + * @return original string if from or to substrings are empty or null, + * processed {@link String} or empty string if input string is blank or null + * @since 0.0.8 + */ + public static String replaceIgnoreCase(String source, String from, String to) { + if (isEmpty(from) || isEmpty(to)) { + return source; + } + return isBlank(source) ? EMPTY : source.replaceAll(String.format("(?i)%s", from), to); + } + + /** + * Provides {@link Predicate} which checks if evaluated string starts with provided prefix + * + * @param prefix the prefix + * @return {@link Predicate} which checks if evaluated string starts with provided prefix, + * if source or prefix are empty or null result will be false + * @since 0.0.8 + */ + public static Predicate startsWith(String prefix) { + return source -> isNotEmpty(source) && isNotEmpty(prefix) && source.startsWith(prefix); + } + + /** + * Provides {@link Predicate} which checks if evaluated string ends with provided suffix + * + * @param suffix the suffix + * @return {@link Predicate} which checks if evaluated string ends with provided suffix, + * if source or suffix are empty or null result will be false + * @since 0.0.8 + */ + public static Predicate endsWith(String suffix) { + return source -> isNotEmpty(source) && isNotEmpty(suffix) && source.endsWith(suffix); + } + + /** + * Provides {@link Predicate} which checks if evaluated string contains provided fragment + * + * @param fragment to search for + * @return {@link Predicate} which checks if evaluated string contains provided fragment, + * if source or fragment are empty or null result will be false + * @since 0.0.8 + */ + public static Predicate contains(String fragment) { + return source -> isNotEmpty(source) && isNotEmpty(fragment) && source.contains(fragment); + } + + /** + * Provides {@link Predicate} which checks if evaluated string satisfies length comparison + * + * @param operator the length comparison operator + * @param reference thr reference value that should be compared to string length + * @return {@link Predicate} which checks if evaluated string satisfies length comparison, + * if source is empty or null result will be false + * @throws IllegalArgumentException if reference value is equal to zero or negative + * @since 0.0.8 + */ + public static Predicate hasLength(ComparisonOperators operator, int reference) { + return source -> isNotEmpty(source) && NumberUtils.compare(source.length(), requireGreaterThanZero(reference), operator); + } } diff --git a/src/main/java/com/hijackermax/utils/misc/EnumerationSpliterator.java b/src/main/java/com/hijackermax/utils/misc/EnumerationSpliterator.java new file mode 100644 index 0000000..17fd914 --- /dev/null +++ b/src/main/java/com/hijackermax/utils/misc/EnumerationSpliterator.java @@ -0,0 +1,94 @@ +package com.hijackermax.utils.misc; + +import java.util.Enumeration; +import java.util.Objects; +import java.util.Spliterator; +import java.util.Spliterators; +import java.util.function.Consumer; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +/** + * Spliterator for Enumerations + * + * @param type of enumeration elements + * @since 0.0.8 + */ +public class EnumerationSpliterator extends Spliterators.AbstractSpliterator { + private final Enumeration enumeration; + + private EnumerationSpliterator(long est, int additionalCharacteristics, Enumeration enumeration) { + super(est, additionalCharacteristics); + this.enumeration = enumeration; + } + + /** + * Creates instance of {@link EnumerationSpliterator} with provided size, characteristics and enumeration + * + * @param est the estimated size of spliterator + * @param additionalCharacteristics properties of the enumeration elements + * @param enumeration the enumeration that should be splited + * @param type of enumeration elements + * @return instance of {@link EnumerationSpliterator} with provided size, characteristics and enumeration + */ + public static EnumerationSpliterator of(long est, int additionalCharacteristics, Enumeration enumeration) { + return new EnumerationSpliterator<>(est, additionalCharacteristics, Objects.requireNonNull(enumeration)); + } + + /** + * Creates instance of {@link EnumerationSpliterator} with unknown size ordered enumeration + * + * @param enumeration the enumeration that should be splited + * @param type of enumeration elements + * @return instance of {@link EnumerationSpliterator} with unknown size ordered enumeration + */ + public static EnumerationSpliterator ofOrdered(Enumeration enumeration) { + return of(Long.MAX_VALUE, Spliterator.ORDERED, Objects.requireNonNull(enumeration)); + } + + /** + * Creates a sequential {@link Stream} from current instance of {@link EnumerationSpliterator} + * + * @return a sequential {@link Stream} + */ + public Stream stream() { + return StreamSupport.stream(this, false); + } + + /** + * Creates a parallel {@link Stream} from current instance of {@link EnumerationSpliterator} + * + * @return a parallel {@link Stream} + */ + public Stream parallelStream() { + return StreamSupport.stream(this, true); + } + + /** + * If a remaining element exists, performs provided action on it returning true, if not returns false + * + * @param action The action + * @return false if no remaining elements existed upon entry to this method, else true + */ + @Override + public boolean tryAdvance(Consumer action) { + if (!enumeration.hasMoreElements()) { + return false; + } + action.accept(enumeration.nextElement()); + return true; + } + + /** + * Performs the provided action for each remaining element, sequentially in the current thread, + * until all elements have been processed or the action throws an exception + * + * @param action The action + */ + @Override + public void forEachRemaining(Consumer action) { + while (enumeration.hasMoreElements()) { + action.accept(enumeration.nextElement()); + } + } +} diff --git a/src/test/java/com/hijackermax/utils/aux/Colors.java b/src/test/java/com/hijackermax/utils/aux/Colors.java new file mode 100644 index 0000000..a4b4e08 --- /dev/null +++ b/src/test/java/com/hijackermax/utils/aux/Colors.java @@ -0,0 +1,5 @@ +package com.hijackermax.utils.aux; + +public enum Colors { + RED, GREEN, BLUE +} diff --git a/src/test/java/com/hijackermax/utils/builders/ListBuilderTest.java b/src/test/java/com/hijackermax/utils/builders/ListBuilderTest.java new file mode 100644 index 0000000..7884b83 --- /dev/null +++ b/src/test/java/com/hijackermax/utils/builders/ListBuilderTest.java @@ -0,0 +1,111 @@ +package com.hijackermax.utils.builders; + +import com.hijackermax.utils.entities.Single; +import com.hijackermax.utils.lang.CollectionUtils; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertLinesMatch; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class ListBuilderTest { + @Test + void testAdd() { + List list = ListBuilder.of() + .add("Foo") + .add("Bar") + .build(); + assertFalse(CollectionUtils.isEmpty(list)); + assertLinesMatch(List.of("Foo", "Bar"), list); + } + + @Test + void testAddAll() { + List list = ListBuilder.of("Foo") + .addAll(List.of("Bar", "Test")) + .build(); + assertFalse(CollectionUtils.isEmpty(list)); + assertLinesMatch(List.of("Foo", "Bar", "Test"), list); + } + + @Test + void testAddFromSupplier() { + List list = ListBuilder.of(List.of("Foo", "Bar")) + .add(() -> "Test") + .build(); + assertFalse(CollectionUtils.isEmpty(list)); + assertLinesMatch(List.of("Foo", "Bar", "Test"), list); + } + + @Test + void testUnmodifiable() { + List unmodifiableList = ListBuilder.of() + .add("Foo") + .add("Bar") + .buildUnmodifiable(); + assertFalse(CollectionUtils.isEmpty(unmodifiableList)); + assertThrows(UnsupportedOperationException.class, () -> unmodifiableList.add("Test")); + } + + @Test + void testModifiable() { + List modifiableList = ListBuilder.of() + .add("Foo") + .add("Bar") + .build(); + assertFalse(CollectionUtils.isEmpty(modifiableList)); + assertDoesNotThrow(() -> modifiableList.add("Test Add")); + } + + @Test + void testCustomConstructorSupplier() { + List list = ListBuilder.with(LinkedList::new) + .add("Foo") + .add("Bar") + .build(); + assertFalse(CollectionUtils.isEmpty(list)); + assertTrue(list instanceof LinkedList); + } + + @Test + void testDefaultConstructorSupplier() { + List list = ListBuilder.of() + .add("Foo") + .add("Bar") + .build(); + assertFalse(CollectionUtils.isEmpty(list)); + assertTrue(list instanceof ArrayList); + } + + @Test + void testProvideUnmodifiable() { + Single> wrapper = new Single<>(); + ListBuilder.of() + .add("Foo") + .add("Bar") + .provideUnmodifiable(wrapper::setValue); + assertTrue(wrapper.containsValue()); + List unmodifiableList = wrapper.getValue(); + assertFalse(CollectionUtils.isEmpty(unmodifiableList)); + assertThrows(UnsupportedOperationException.class, () -> unmodifiableList.add("Test")); + } + + @Test + void testProvideModifiable() { + Single> wrapper = new Single<>(); + ListBuilder.of() + .add("Foo") + .add("Bar") + .provide(wrapper::setValue); + assertTrue(wrapper.containsValue()); + List modifiableList = wrapper.getValue(); + assertFalse(CollectionUtils.isEmpty(modifiableList)); + assertDoesNotThrow(() -> modifiableList.add("Test Add")); + } +} diff --git a/src/test/java/com/hijackermax/utils/builders/MapBuilderTest.java b/src/test/java/com/hijackermax/utils/builders/MapBuilderTest.java new file mode 100644 index 0000000..803161a --- /dev/null +++ b/src/test/java/com/hijackermax/utils/builders/MapBuilderTest.java @@ -0,0 +1,168 @@ +package com.hijackermax.utils.builders; + +import com.hijackermax.utils.aux.Colors; +import com.hijackermax.utils.entities.Single; +import com.hijackermax.utils.lang.CollectionUtils; +import org.junit.jupiter.api.Test; + +import java.util.EnumMap; +import java.util.HashMap; +import java.util.Map; +import java.util.TreeMap; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class MapBuilderTest { + @Test + void testPut() { + Map map = MapBuilder.of() + .put("One", 1) + .put("Two", 2) + .put("Three", 3) + .build(); + assertFalse(CollectionUtils.isEmpty(map)); + assertEquals(3, map.size()); + assertEquals(map.get("One"), 1); + assertEquals(map.get("Two"), 2); + assertEquals(map.get("Three"), 3); + } + + @Test + void testPutAll() { + Map map = MapBuilder.of("One", 1) + .putAll(Map.of("Two", 2, "Three", 3)) + .build(); + assertFalse(CollectionUtils.isEmpty(map)); + assertEquals(3, map.size()); + assertEquals(map.get("One"), 1); + assertEquals(map.get("Two"), 2); + assertEquals(map.get("Three"), 3); + } + + @Test + void testPutIfAbsent() { + Map map = MapBuilder.of(Map.of("One", 10)) + .putIfAbsent("One", 1) + .putIfAbsent("Two", 2) + .putIfAbsent("Two", 20) + .putIfAbsent("Three", 3) + .build(); + assertFalse(CollectionUtils.isEmpty(map)); + assertEquals(3, map.size()); + assertEquals(map.get("One"), 10); + assertEquals(map.get("Two"), 2); + assertEquals(map.get("Three"), 3); + } + + @Test + void testUnmodifiable() { + Map unmodifiableMap = MapBuilder.of() + .put("One", 1) + .put("Two", 2) + .put("Three", 3) + .buildUnmodifiable(); + assertFalse(CollectionUtils.isEmpty(unmodifiableMap)); + assertFalse(CollectionUtils.isEmpty(unmodifiableMap)); + assertEquals(3, unmodifiableMap.size()); + assertEquals(unmodifiableMap.get("One"), 1); + assertEquals(unmodifiableMap.get("Two"), 2); + assertEquals(unmodifiableMap.get("Three"), 3); + assertThrows(UnsupportedOperationException.class, () -> unmodifiableMap.put("Four", 4)); + } + + @Test + void testModifiable() { + Map unmodifiableMap = MapBuilder.of() + .put("One", 1) + .put("Two", 2) + .put("Three", 3) + .build(); + assertFalse(CollectionUtils.isEmpty(unmodifiableMap)); + assertDoesNotThrow(() -> unmodifiableMap.put("Four", 4)); + } + + @Test + void testCustomConstructorSupplier() { + Map map = MapBuilder.with(TreeMap::new) + .put("One", 1) + .put("Two", 2) + .put("Three", 3) + .build(); + assertFalse(CollectionUtils.isEmpty(map)); + assertEquals(3, map.size()); + assertEquals(map.get("One"), 1); + assertEquals(map.get("Two"), 2); + assertEquals(map.get("Three"), 3); + assertTrue(map instanceof TreeMap); + } + + @Test + void testEnumMapConstructorSupplier() { + Map map = MapBuilder.ofEnum(Colors.class) + .put(Colors.RED, "FF0000") + .put(Colors.GREEN, "00FF00") + .put(Colors.BLUE, "0000FF") + .build(); + assertFalse(CollectionUtils.isEmpty(map)); + assertEquals(3, map.size()); + assertEquals(map.get(Colors.RED), "FF0000"); + assertEquals(map.get(Colors.GREEN), "00FF00"); + assertEquals(map.get(Colors.BLUE), "0000FF"); + assertTrue(map instanceof EnumMap); + } + + @Test + void testDefaultConstructorSupplier() { + Map map = MapBuilder.of() + .put("One", 1) + .put("Two", 2) + .put("Three", 3) + .build(); + assertFalse(CollectionUtils.isEmpty(map)); + assertEquals(3, map.size()); + assertEquals(map.get("One"), 1); + assertEquals(map.get("Two"), 2); + assertEquals(map.get("Three"), 3); + assertTrue(map instanceof HashMap); + } + + @Test + void testProvideUnmodifiable() { + Single> wrapper = new Single<>(); + MapBuilder.of() + .put("One", 1) + .put("Two", 2) + .put("Three", 3) + .provideUnmodifiable(wrapper::setValue); + assertTrue(wrapper.containsValue()); + Map unmodifiableMap = wrapper.getValue(); + assertFalse(CollectionUtils.isEmpty(unmodifiableMap)); + assertEquals(3, unmodifiableMap.size()); + assertEquals(unmodifiableMap.get("One"), 1); + assertEquals(unmodifiableMap.get("Two"), 2); + assertEquals(unmodifiableMap.get("Three"), 3); + assertThrows(UnsupportedOperationException.class, () -> unmodifiableMap.put("Four", 4)); + } + + @Test + void testProvideModifiable() { + Single> wrapper = new Single<>(); + MapBuilder.of() + .put("One", 1) + .put("Two", 2) + .put("Three", 3) + .provide(wrapper::setValue); + assertTrue(wrapper.containsValue()); + Map modifiableMap = wrapper.getValue(); + assertFalse(CollectionUtils.isEmpty(modifiableMap)); + assertEquals(3, modifiableMap.size()); + assertEquals(modifiableMap.get("One"), 1); + assertEquals(modifiableMap.get("Two"), 2); + assertEquals(modifiableMap.get("Three"), 3); + assertDoesNotThrow(() -> modifiableMap.put("Four", 4)); + } +} diff --git a/src/test/java/com/hijackermax/utils/builders/SetBuilderTest.java b/src/test/java/com/hijackermax/utils/builders/SetBuilderTest.java new file mode 100644 index 0000000..54a287d --- /dev/null +++ b/src/test/java/com/hijackermax/utils/builders/SetBuilderTest.java @@ -0,0 +1,110 @@ +package com.hijackermax.utils.builders; + +import com.hijackermax.utils.entities.Single; +import com.hijackermax.utils.lang.CollectionUtils; +import org.junit.jupiter.api.Test; + +import java.util.HashSet; +import java.util.Set; +import java.util.TreeSet; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class SetBuilderTest { + @Test + void testAdd() { + Set set = SetBuilder.of() + .add("Foo") + .add("Bar") + .build(); + assertFalse(CollectionUtils.isEmpty(set)); + assertTrue(CollectionUtils.safeContainsAll(Set.of("Foo", "Bar"), set)); + } + + @Test + void testAddAll() { + Set set = SetBuilder.of("Foo") + .addAll(Set.of("Bar", "Test")) + .build(); + assertFalse(CollectionUtils.isEmpty(set)); + assertTrue(CollectionUtils.safeContainsAll(Set.of("Foo", "Bar", "Test"), set)); + } + + @Test + void testAddFromSupplier() { + Set set = SetBuilder.of(Set.of("Foo", "Bar")) + .add(() -> "Test") + .build(); + assertFalse(CollectionUtils.isEmpty(set)); + assertTrue(CollectionUtils.safeContainsAll(Set.of("Foo", "Bar", "Test"), set)); + } + + @Test + void testUnmodifiable() { + Set unmodifiableset = SetBuilder.of() + .add("Foo") + .add("Bar") + .buildUnmodifiable(); + assertFalse(CollectionUtils.isEmpty(unmodifiableset)); + assertThrows(UnsupportedOperationException.class, () -> unmodifiableset.add("Test")); + } + + @Test + void testModifiable() { + Set modifiableSet = SetBuilder.of() + .add("Foo") + .add("Bar") + .build(); + assertFalse(CollectionUtils.isEmpty(modifiableSet)); + assertDoesNotThrow(() -> modifiableSet.add("Test Add")); + } + + @Test + void testCustomConstructorSupplier() { + Set set = SetBuilder.with(TreeSet::new) + .add("Foo") + .add("Bar") + .build(); + assertFalse(CollectionUtils.isEmpty(set)); + assertTrue(set instanceof TreeSet); + } + + @Test + void testDefaultConstructorSupplier() { + Set set = SetBuilder.of() + .add("Foo") + .add("Bar") + .build(); + assertFalse(CollectionUtils.isEmpty(set)); + assertTrue(set instanceof HashSet); + } + + @Test + void testProvideUnmodifiable() { + Single> wrapper = new Single<>(); + SetBuilder.of() + .add("Foo") + .add("Bar") + .provideUnmodifiable(wrapper::setValue); + assertTrue(wrapper.containsValue()); + Set unmodifiableSet = wrapper.getValue(); + assertFalse(CollectionUtils.isEmpty(unmodifiableSet)); + assertThrows(UnsupportedOperationException.class, () -> unmodifiableSet.add("Test")); + } + + @Test + void testProvideModifiable() { + Single> wrapper = new Single<>(); + SetBuilder.of() + .add("Foo") + .add("Bar") + .provide(wrapper::setValue); + assertTrue(wrapper.containsValue()); + Set modifiableSet = wrapper.getValue(); + assertFalse(CollectionUtils.isEmpty(modifiableSet)); + assertDoesNotThrow(() -> modifiableSet.add("Test Add")); + } +} diff --git a/src/test/java/com/hijackermax/utils/builders/TransformerTest.java b/src/test/java/com/hijackermax/utils/builders/TransformerTest.java new file mode 100644 index 0000000..17fd3f8 --- /dev/null +++ b/src/test/java/com/hijackermax/utils/builders/TransformerTest.java @@ -0,0 +1,68 @@ +package com.hijackermax.utils.builders; + +import com.hijackermax.utils.entities.Single; +import com.hijackermax.utils.lang.MathUtils; +import com.hijackermax.utils.lang.StringUtils; +import org.junit.jupiter.api.Test; + +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class TransformerTest { + @Test + void testStringTransformation() { + String result = Transformer.of(" Hello World Foo Bar 123456 ") + .run(StringUtils::trimToEmpty) + .run(StringUtils::removeWhitespaces) + .run(StringUtils::removeDigits) + .run(StringUtils.replace(Map.of("o", "0", "l", "1"))) + .result(); + assertFalse(StringUtils.isEmpty(result)); + assertEquals("He110W0r1dF00Bar", result); + } + + @Test + void testNumberTransformation() { + Integer result = Transformer.of(256) + .run(MathUtils.subtract(206)) + .run(MathUtils.multiply(2)) + .run(MathUtils.subtract(99)) + .result(); + assertEquals(1, result); + } + + @Test + void testProvideTransformationResult() { + Single resultWrapper = new Single<>(); + Transformer.of(" Hello World Foo Bar 123456 ") + .run(StringUtils::trimToEmpty) + .run(StringUtils::removeWhitespaces) + .run(StringUtils::removeDigits) + .provide(resultWrapper::setValue); + assertTrue(resultWrapper.containsValue()); + String result = resultWrapper.getValue(); + assertFalse(StringUtils.isEmpty(result)); + assertEquals("HelloWorldFooBar", result); + } + + @Test + void testNullChecks() { + assertThrows(NullPointerException.class, () -> Transformer.of(null)); + assertThrows(NullPointerException.class, () -> Transformer.of("Test").run(s -> null)); + } + + @Test + void testTransformationEvolve() { + Integer result = Transformer.of(" Hello World Foo Bar 123456 ") + .run(StringUtils::trimToEmpty) + .run(StringUtils::removeWhitespaces) + .run(StringUtils::removeDigits) + .evolve(String::length) + .result(); + assertEquals(16, result); + } +} diff --git a/src/test/java/com/hijackermax/encoders/AbstractEncoderTest.java b/src/test/java/com/hijackermax/utils/encoders/AbstractEncoderTest.java similarity index 88% rename from src/test/java/com/hijackermax/encoders/AbstractEncoderTest.java rename to src/test/java/com/hijackermax/utils/encoders/AbstractEncoderTest.java index 0f3e2e8..177ec7a 100644 --- a/src/test/java/com/hijackermax/encoders/AbstractEncoderTest.java +++ b/src/test/java/com/hijackermax/utils/encoders/AbstractEncoderTest.java @@ -1,4 +1,4 @@ -package com.hijackermax.encoders; +package com.hijackermax.utils.encoders; import com.hijackermax.utils.lang.RandomUtils; import com.hijackermax.utils.lang.StringUtils; @@ -8,7 +8,10 @@ import java.util.function.Function; import java.util.stream.IntStream; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; abstract class AbstractEncoderTest { @Test diff --git a/src/test/java/com/hijackermax/encoders/Base122Test.java b/src/test/java/com/hijackermax/utils/encoders/Base122Test.java similarity index 88% rename from src/test/java/com/hijackermax/encoders/Base122Test.java rename to src/test/java/com/hijackermax/utils/encoders/Base122Test.java index 432407d..337b11b 100644 --- a/src/test/java/com/hijackermax/encoders/Base122Test.java +++ b/src/test/java/com/hijackermax/utils/encoders/Base122Test.java @@ -1,6 +1,4 @@ -package com.hijackermax.encoders; - -import com.hijackermax.utils.encoders.Base122; +package com.hijackermax.utils.encoders; import java.nio.charset.StandardCharsets; import java.util.function.Function; diff --git a/src/test/java/com/hijackermax/encoders/Base32Test.java b/src/test/java/com/hijackermax/utils/encoders/Base32Test.java similarity index 88% rename from src/test/java/com/hijackermax/encoders/Base32Test.java rename to src/test/java/com/hijackermax/utils/encoders/Base32Test.java index 5ee6e1f..d8ea175 100644 --- a/src/test/java/com/hijackermax/encoders/Base32Test.java +++ b/src/test/java/com/hijackermax/utils/encoders/Base32Test.java @@ -1,6 +1,4 @@ -package com.hijackermax.encoders; - -import com.hijackermax.utils.encoders.Base32; +package com.hijackermax.utils.encoders; import java.nio.charset.StandardCharsets; import java.util.function.Function; diff --git a/src/test/java/com/hijackermax/encoders/Base58Test.java b/src/test/java/com/hijackermax/utils/encoders/Base58Test.java similarity index 87% rename from src/test/java/com/hijackermax/encoders/Base58Test.java rename to src/test/java/com/hijackermax/utils/encoders/Base58Test.java index 2a6c5fd..62a80ae 100644 --- a/src/test/java/com/hijackermax/encoders/Base58Test.java +++ b/src/test/java/com/hijackermax/utils/encoders/Base58Test.java @@ -1,6 +1,4 @@ -package com.hijackermax.encoders; - -import com.hijackermax.utils.encoders.Base58; +package com.hijackermax.utils.encoders; import java.nio.charset.StandardCharsets; import java.util.function.Function; diff --git a/src/test/java/com/hijackermax/encoders/Base85Test.java b/src/test/java/com/hijackermax/utils/encoders/Base85Test.java similarity index 87% rename from src/test/java/com/hijackermax/encoders/Base85Test.java rename to src/test/java/com/hijackermax/utils/encoders/Base85Test.java index 483c407..e90ac55 100644 --- a/src/test/java/com/hijackermax/encoders/Base85Test.java +++ b/src/test/java/com/hijackermax/utils/encoders/Base85Test.java @@ -1,6 +1,4 @@ -package com.hijackermax.encoders; - -import com.hijackermax.utils.encoders.Base85; +package com.hijackermax.utils.encoders; import java.nio.charset.StandardCharsets; import java.util.function.Function; diff --git a/src/test/java/com/hijackermax/io/TemporaryFileTest.java b/src/test/java/com/hijackermax/utils/io/TemporaryFileTest.java similarity index 86% rename from src/test/java/com/hijackermax/io/TemporaryFileTest.java rename to src/test/java/com/hijackermax/utils/io/TemporaryFileTest.java index 5740d37..7734eff 100644 --- a/src/test/java/com/hijackermax/io/TemporaryFileTest.java +++ b/src/test/java/com/hijackermax/utils/io/TemporaryFileTest.java @@ -1,7 +1,6 @@ -package com.hijackermax.io; +package com.hijackermax.utils.io; import com.hijackermax.utils.entities.Single; -import com.hijackermax.utils.io.TemporaryFile; import org.junit.jupiter.api.Test; import java.io.BufferedReader; @@ -9,7 +8,9 @@ import java.io.FileReader; import java.io.IOException; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; class TemporaryFileTest { @Test diff --git a/src/test/java/com/hijackermax/utils/BooleanUtilsTest.java b/src/test/java/com/hijackermax/utils/lang/BooleanUtilsTest.java similarity index 94% rename from src/test/java/com/hijackermax/utils/BooleanUtilsTest.java rename to src/test/java/com/hijackermax/utils/lang/BooleanUtilsTest.java index 870db26..2d7ad5a 100644 --- a/src/test/java/com/hijackermax/utils/BooleanUtilsTest.java +++ b/src/test/java/com/hijackermax/utils/lang/BooleanUtilsTest.java @@ -1,10 +1,11 @@ -package com.hijackermax.utils; +package com.hijackermax.utils.lang; -import com.hijackermax.utils.lang.BooleanUtils; -import com.hijackermax.utils.lang.StringUtils; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; class BooleanUtilsTest { diff --git a/src/test/java/com/hijackermax/utils/CollectionUtilsTest.java b/src/test/java/com/hijackermax/utils/lang/CollectionUtilsTest.java similarity index 89% rename from src/test/java/com/hijackermax/utils/CollectionUtilsTest.java rename to src/test/java/com/hijackermax/utils/lang/CollectionUtilsTest.java index 703f3dd..341e202 100644 --- a/src/test/java/com/hijackermax/utils/CollectionUtilsTest.java +++ b/src/test/java/com/hijackermax/utils/lang/CollectionUtilsTest.java @@ -1,17 +1,29 @@ -package com.hijackermax.utils; +package com.hijackermax.utils.lang; import com.hijackermax.utils.entities.Single; import com.hijackermax.utils.entities.Tuple; -import com.hijackermax.utils.lang.CollectionUtils; import org.junit.jupiter.api.Test; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.Vector; import java.util.function.BiPredicate; import java.util.function.Function; import java.util.stream.Collectors; -import java.util.stream.IntStream; -import static org.junit.jupiter.api.Assertions.*; +import static com.hijackermax.utils.lang.OptionalUtils.ofEmpty; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; class CollectionUtilsTest { @Test @@ -337,39 +349,6 @@ void testGetDifferences() { }); } - @Test - void testGroupingByWithNull() { - List> input = List.of( - new Tuple<>("Foo", "Bar"), - new Tuple<>(null, "Test"), - new Tuple<>("Hello", "World") - ); - Map>> nullKeyMap = input.stream() - .collect(CollectionUtils.groupingByWithNull(Tuple::getKey)); - - assertEquals(3, nullKeyMap.size()); - assertTrue(nullKeyMap.containsKey("Foo")); - assertTrue(nullKeyMap.containsKey("Hello")); - assertTrue(nullKeyMap.containsKey(null)); - } - - @Test - void testGroupingByWithNullValuesExtraction() { - List> input = List.of( - new Tuple<>("Foo", "Bar"), - new Tuple<>(null, "Test"), - new Tuple<>("Hello", "World") - ); - Map> nullKeyMap = input.stream() - .collect(CollectionUtils.groupingByWithNull(Tuple::getKey, Tuple::getValue)); - - assertEquals(3, nullKeyMap.size()); - assertTrue(nullKeyMap.containsKey("Foo")); - assertTrue(nullKeyMap.containsKey("Hello")); - assertTrue(nullKeyMap.containsKey(null)); - assertEquals(List.of("Test"), nullKeyMap.get(null)); - } - @Test void testSafeRemoveIf() { assertFalse(CollectionUtils.safeRemoveIf(null, Objects::nonNull)); @@ -464,16 +443,6 @@ void testValuePredicate() { assertEquals(24, result.get(1)); } - @Test - void testToStringCollector() { - char[] chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray(); - - String result = IntStream.range(0, chars.length) - .mapToObj(idx -> chars[idx]) - .collect(CollectionUtils.toStringCollector()); - assertEquals(chars.length, result.length()); - } - @Test void testSafeContains() { assertFalse(CollectionUtils.safeContains(null, null)); @@ -532,4 +501,46 @@ void testSafeContainsAny() { assertFalse(CollectionUtils.safeContainsAny(List.of(1, 2, 3, 4, 5), List.of(0, 10))); assertTrue(CollectionUtils.safeContainsAny(List.of(1, 2, 3, 4, 5), List.of(2, 10))); } + + @Test + void testSafeProvide() { + Single valueHolder = new Single<>(); + CollectionUtils.safeProvide(null, "Test", valueHolder::setValue); + assertFalse(valueHolder.containsValue()); + CollectionUtils.safeProvide(Map.of("Foo", "Bar"), "Test", valueHolder::setValue); + assertFalse(valueHolder.containsValue()); + CollectionUtils.safeProvide(Map.of("Foo", "Bar"), "Foo", valueHolder::setValue); + assertTrue(valueHolder.containsValue()); + assertEquals("Bar", valueHolder.getValue()); + } + + @Test + void testPutWithValue() { + Map targetMap = new HashMap<>(); + ofEmpty("Bar").ifPresent(CollectionUtils.putWithValue(targetMap, "Foo")); + assertTrue(targetMap.containsKey("Foo")); + assertEquals("Bar", targetMap.get("Foo")); + } + + @Test + void testPutWithKey() { + Map targetMap = new HashMap<>(); + ofEmpty("Foo").ifPresent(CollectionUtils.putWithKey(targetMap, "Bar")); + assertTrue(targetMap.containsKey("Foo")); + assertEquals("Bar", targetMap.get("Foo")); + } + + @Test + void testIsEmptyEnumeration() { + assertTrue(CollectionUtils.isEmpty((Enumeration) null)); + assertTrue(CollectionUtils.isEmpty(new Vector<>().elements())); + assertFalse(CollectionUtils.isEmpty(new Vector<>(List.of(true)).elements())); + } + + @Test + void testSafeStreamOfEnumeration() { + assertEquals(0L, CollectionUtils.safeStreamOf((Enumeration) null).count()); + assertEquals(0L, CollectionUtils.safeStreamOf(new Vector<>().elements()).count()); + assertEquals(3L, CollectionUtils.safeStreamOf(new Vector<>(List.of(true, false, true))).count()); + } } diff --git a/src/test/java/com/hijackermax/utils/lang/CollectorUtilsTest.java b/src/test/java/com/hijackermax/utils/lang/CollectorUtilsTest.java new file mode 100644 index 0000000..5be1c82 --- /dev/null +++ b/src/test/java/com/hijackermax/utils/lang/CollectorUtilsTest.java @@ -0,0 +1,116 @@ +package com.hijackermax.utils.lang; + +import com.hijackermax.utils.aux.Colors; +import com.hijackermax.utils.entities.Tuple; +import org.junit.jupiter.api.Test; + +import java.util.Comparator; +import java.util.EnumMap; +import java.util.List; +import java.util.Map; +import java.util.stream.IntStream; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class CollectorUtilsTest { + @Test + void testGroupingByWithNull() { + List> input = List.of( + new Tuple<>("Foo", "Bar"), + new Tuple<>(null, "Test"), + new Tuple<>("Hello", "World") + ); + Map>> nullKeyMap = input.stream() + .collect(CollectorUtils.groupingByWithNull(Tuple::getKey)); + + assertEquals(3, nullKeyMap.size()); + assertTrue(nullKeyMap.containsKey("Foo")); + assertTrue(nullKeyMap.containsKey("Hello")); + assertTrue(nullKeyMap.containsKey(null)); + } + + @Test + void testGroupingByWithNullValuesExtraction() { + List> input = List.of( + new Tuple<>("Foo", "Bar"), + new Tuple<>(null, "Test"), + new Tuple<>("Hello", "World") + ); + Map> nullKeyMap = input.stream() + .collect(CollectorUtils.groupingByWithNull(Tuple::getKey, Tuple::getValue)); + + assertEquals(3, nullKeyMap.size()); + assertTrue(nullKeyMap.containsKey("Foo")); + assertTrue(nullKeyMap.containsKey("Hello")); + assertTrue(nullKeyMap.containsKey(null)); + assertEquals(List.of("Test"), nullKeyMap.get(null)); + } + + @Test + void testToStringCollector() { + char[] chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray(); + + String result = IntStream.range(0, chars.length) + .mapToObj(idx -> chars[idx]) + .collect(CollectorUtils.toStringCollector()); + assertEquals(chars.length, result.length()); + } + + @Test + void testToEnumMapCollectorWithDefaultMergeFunction() { + List> colorsWithDuplicates = List.of( + new Tuple<>(Colors.GREEN, "00FF00"), + new Tuple<>(Colors.GREEN, "00FA00"), + new Tuple<>(Colors.RED, "FF0000"), + new Tuple<>(Colors.BLUE, "0000FF") + ); + + assertThrows( + IllegalStateException.class, + () -> colorsWithDuplicates.stream().collect(CollectorUtils.toEnumMap(Tuple::getKey, Tuple::getValue, Colors.class)) + ); + + List> uniqueColors = List.of( + new Tuple<>(Colors.GREEN, "00FF00"), + new Tuple<>(Colors.RED, "FF0000"), + new Tuple<>(Colors.BLUE, "0000FF") + ); + + assertDoesNotThrow( + () -> uniqueColors.stream().collect(CollectorUtils.toEnumMap(Tuple::getKey, Tuple::getValue, Colors.class)) + ); + Map colorsStringMap = uniqueColors.stream() + .collect(CollectorUtils.toEnumMap(Tuple::getKey, Tuple::getValue, Colors.class)); + assertTrue(colorsStringMap instanceof EnumMap); + assertEquals(3, colorsStringMap.size()); + assertEquals("00FF00", colorsStringMap.get(Colors.GREEN)); + assertEquals("FF0000", colorsStringMap.get(Colors.RED)); + assertEquals("0000FF", colorsStringMap.get(Colors.BLUE)); + } + + @Test + void testToEnumMapCollectorWithCustomMergeFunction() { + List> colorsWithDuplicates = List.of( + new Tuple<>(Colors.GREEN, "00FF00"), + new Tuple<>(Colors.GREEN, "00FA00"), + new Tuple<>(Colors.GREEN, "001100"), + new Tuple<>(Colors.RED, "FF0000"), + new Tuple<>(Colors.BLUE, "0000FF") + ); + + assertDoesNotThrow( + () -> colorsWithDuplicates.stream().collect(CollectorUtils.toEnumMap(Tuple::getKey, Tuple::getValue, (l, r) -> r, Colors.class)) + ); + Map colorsStringMap = colorsWithDuplicates.stream() + .sorted(Comparator.comparing(Tuple::getValue)) + .collect(CollectorUtils.toEnumMap(Tuple::getKey, Tuple::getValue, (l, r) -> r, Colors.class)); + assertTrue(colorsStringMap instanceof EnumMap); + assertEquals(3, colorsStringMap.size()); + assertEquals("00FF00", colorsStringMap.get(Colors.GREEN)); + assertEquals("FF0000", colorsStringMap.get(Colors.RED)); + assertEquals("0000FF", colorsStringMap.get(Colors.BLUE)); + } +} diff --git a/src/test/java/com/hijackermax/utils/DateUtilsTest.java b/src/test/java/com/hijackermax/utils/lang/DateUtilsTest.java similarity index 94% rename from src/test/java/com/hijackermax/utils/DateUtilsTest.java rename to src/test/java/com/hijackermax/utils/lang/DateUtilsTest.java index 3f4faeb..64732c7 100644 --- a/src/test/java/com/hijackermax/utils/DateUtilsTest.java +++ b/src/test/java/com/hijackermax/utils/lang/DateUtilsTest.java @@ -1,13 +1,16 @@ -package com.hijackermax.utils; +package com.hijackermax.utils.lang; -import com.hijackermax.utils.lang.DateUtils; import org.junit.jupiter.api.Test; import java.util.Calendar; import java.util.Date; import java.util.Objects; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; class DateUtilsTest { @Test diff --git a/src/test/java/com/hijackermax/utils/FunctionalUtilsTest.java b/src/test/java/com/hijackermax/utils/lang/FunctionalUtilsTest.java similarity index 78% rename from src/test/java/com/hijackermax/utils/FunctionalUtilsTest.java rename to src/test/java/com/hijackermax/utils/lang/FunctionalUtilsTest.java index 8083cbd..84a4095 100644 --- a/src/test/java/com/hijackermax/utils/FunctionalUtilsTest.java +++ b/src/test/java/com/hijackermax/utils/lang/FunctionalUtilsTest.java @@ -1,15 +1,19 @@ -package com.hijackermax.utils; +package com.hijackermax.utils.lang; import com.hijackermax.utils.entities.Single; import com.hijackermax.utils.entities.Tuple; -import com.hijackermax.utils.lang.FunctionalUtils; import org.junit.jupiter.api.Test; +import java.util.List; import java.util.concurrent.Callable; import java.util.function.Consumer; import java.util.function.Supplier; +import java.util.stream.Collectors; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; class FunctionalUtilsTest { @Test @@ -75,4 +79,21 @@ void testFailSafeStrategyConsumer() { assertFalse(exceptionHolder.containsValue()); assertFalse(exceptionHolder.containsKey()); } + + @Test + void testMappedPredicate() { + List> singlesList = List.of( + Single.of("Foo@"), + Single.of("Bar@"), + Single.of("Test$") + ); + + List filteredList = singlesList.stream() + .filter(FunctionalUtils.mappedPredicate(Single::getValue, StringUtils.endsWith("@"))) + .map(Single::getValue) + .collect(Collectors.toList()); + assertEquals(2, filteredList.size()); + assertEquals("Foo@", filteredList.get(0)); + assertEquals("Bar@", filteredList.get(1)); + } } diff --git a/src/test/java/com/hijackermax/utils/GeographicalUtilsTest.java b/src/test/java/com/hijackermax/utils/lang/GeographicalUtilsTest.java similarity index 97% rename from src/test/java/com/hijackermax/utils/GeographicalUtilsTest.java rename to src/test/java/com/hijackermax/utils/lang/GeographicalUtilsTest.java index 8a8f27c..a35cea9 100644 --- a/src/test/java/com/hijackermax/utils/GeographicalUtilsTest.java +++ b/src/test/java/com/hijackermax/utils/lang/GeographicalUtilsTest.java @@ -1,4 +1,4 @@ -package com.hijackermax.utils; +package com.hijackermax.utils.lang; import com.hijackermax.utils.geography.GeographicalUtils; import com.hijackermax.utils.models.MercatorCoordinates; diff --git a/src/test/java/com/hijackermax/utils/MathUtilsTest.java b/src/test/java/com/hijackermax/utils/lang/MathUtilsTest.java similarity index 85% rename from src/test/java/com/hijackermax/utils/MathUtilsTest.java rename to src/test/java/com/hijackermax/utils/lang/MathUtilsTest.java index 8798447..9ab547d 100644 --- a/src/test/java/com/hijackermax/utils/MathUtilsTest.java +++ b/src/test/java/com/hijackermax/utils/lang/MathUtilsTest.java @@ -1,6 +1,5 @@ -package com.hijackermax.utils; +package com.hijackermax.utils.lang; -import com.hijackermax.utils.lang.MathUtils; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -164,7 +163,6 @@ void testSubtractDoubleUnaryOperator() { assertEquals(20D, MathUtils.subtract(-10D).apply(10D)); } - @Test void testAddLongUnaryOperator() { assertEquals(30L, MathUtils.add(20L).apply(10L)); @@ -192,4 +190,32 @@ void testAddDoubleUnaryOperator() { assertEquals(0D, MathUtils.add(0D).apply(0D)); assertEquals(0D, MathUtils.add(-10D).apply(10D)); } + + @Test + void testMultiplyLongUnaryOperator() { + assertEquals(600L, MathUtils.multiply(20L).apply(30L)); + assertEquals(0L, MathUtils.multiply(0L).apply(0L)); + assertEquals(0L, MathUtils.multiply(-10L).apply(0L)); + } + + @Test + void testMultiplyIntUnaryOperator() { + assertEquals(600, MathUtils.multiply(20).apply(30)); + assertEquals(0, MathUtils.multiply(0).apply(0)); + assertEquals(0, MathUtils.multiply(-10).apply(0)); + } + + @Test + void testMultiplyFloatUnaryOperator() { + assertEquals(600F, MathUtils.multiply(20F).apply(30F)); + assertEquals(0F, MathUtils.multiply(0F).apply(0F)); + assertEquals(-0F, MathUtils.multiply(-10F).apply(0F)); + } + + @Test + void testMultiplyDoubleUnaryOperator() { + assertEquals(600D, MathUtils.multiply(20D).apply(30D)); + assertEquals(0D, MathUtils.multiply(0D).apply(0D)); + assertEquals(-0D, MathUtils.multiply(-10D).apply(0D)); + } } diff --git a/src/test/java/com/hijackermax/utils/lang/NumberUtilsTest.java b/src/test/java/com/hijackermax/utils/lang/NumberUtilsTest.java new file mode 100644 index 0000000..2fe783e --- /dev/null +++ b/src/test/java/com/hijackermax/utils/lang/NumberUtilsTest.java @@ -0,0 +1,44 @@ +package com.hijackermax.utils.lang; + +import com.hijackermax.utils.enums.ComparisonOperators; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class NumberUtilsTest { + @Test + void testCompare() { + assertTrue(NumberUtils.compare(10, 20, ComparisonOperators.LT)); + assertFalse(NumberUtils.compare(100, 20, ComparisonOperators.LT)); + assertFalse(NumberUtils.compare(20, 20, ComparisonOperators.LT)); + assertTrue(NumberUtils.compare(100, 20, ComparisonOperators.GT)); + assertFalse(NumberUtils.compare(10, 20, ComparisonOperators.GT)); + assertFalse(NumberUtils.compare(20, 20, ComparisonOperators.GT)); + assertTrue(NumberUtils.compare(10, 20, ComparisonOperators.LTE)); + assertFalse(NumberUtils.compare(100, 20, ComparisonOperators.LTE)); + assertTrue(NumberUtils.compare(20, 20, ComparisonOperators.LTE)); + assertTrue(NumberUtils.compare(100, 20, ComparisonOperators.GTE)); + assertFalse(NumberUtils.compare(10, 20, ComparisonOperators.GTE)); + assertTrue(NumberUtils.compare(20, 20, ComparisonOperators.GTE)); + assertFalse(NumberUtils.compare(100, 20, ComparisonOperators.EQ)); + assertFalse(NumberUtils.compare(10, 20, ComparisonOperators.EQ)); + assertTrue(NumberUtils.compare(20, 20, ComparisonOperators.EQ)); + assertTrue(NumberUtils.compare(100, 20, ComparisonOperators.NEQ)); + assertTrue(NumberUtils.compare(10, 20, ComparisonOperators.NEQ)); + assertFalse(NumberUtils.compare(20, 20, ComparisonOperators.NEQ)); + assertTrue(NumberUtils.compare(100, -20, ComparisonOperators.GT)); + assertTrue(NumberUtils.compare(10, 0, ComparisonOperators.GT)); + } + + @Test + void testRequireGreaterThanZero() { + assertThrows(IllegalArgumentException.class, () -> NumberUtils.requireGreaterThanZero(0)); + assertThrows(IllegalArgumentException.class, () -> NumberUtils.requireGreaterThanZero(-1)); + assertThrows(IllegalArgumentException.class, () -> NumberUtils.requireGreaterThanZero(Integer.MIN_VALUE)); + assertDoesNotThrow(() -> NumberUtils.requireGreaterThanZero(1)); + assertDoesNotThrow(() -> NumberUtils.requireGreaterThanZero(Integer.MAX_VALUE)); + } +} diff --git a/src/test/java/com/hijackermax/utils/ObjectUtilsTest.java b/src/test/java/com/hijackermax/utils/lang/ObjectUtilsTest.java similarity index 78% rename from src/test/java/com/hijackermax/utils/ObjectUtilsTest.java rename to src/test/java/com/hijackermax/utils/lang/ObjectUtilsTest.java index bf313c8..5e37c74 100644 --- a/src/test/java/com/hijackermax/utils/ObjectUtilsTest.java +++ b/src/test/java/com/hijackermax/utils/lang/ObjectUtilsTest.java @@ -1,14 +1,15 @@ -package com.hijackermax.utils; +package com.hijackermax.utils.lang; import com.hijackermax.utils.encoders.Base122; -import com.hijackermax.utils.lang.ObjectUtils; -import com.hijackermax.utils.lang.RandomUtils; import org.junit.jupiter.api.Test; import java.io.IOException; import java.nio.charset.StandardCharsets; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; class ObjectUtilsTest { @Test @@ -49,4 +50,12 @@ void testCompressDecompressCustom() throws IOException { byte[] decompressedBytes = ObjectUtils.decompress(compressedBytes, Base122::decode); assertArrayEquals(sourceBytes, decompressedBytes); } + + @Test + void testValueOrGetDefault() { + assertEquals(5, ObjectUtils.valueOrGetDefault(null, () -> 5)); + assertEquals(2, ObjectUtils.valueOrGetDefault(2, () -> 5)); + assertEquals(7, ObjectUtils.valueOrGetDefault(7, () -> null)); + assertNull(ObjectUtils.valueOrGetDefault(null, () -> null)); + } } diff --git a/src/test/java/com/hijackermax/utils/OptionalUtilsTest.java b/src/test/java/com/hijackermax/utils/lang/OptionalUtilsTest.java similarity index 90% rename from src/test/java/com/hijackermax/utils/OptionalUtilsTest.java rename to src/test/java/com/hijackermax/utils/lang/OptionalUtilsTest.java index 176f2ce..685565e 100644 --- a/src/test/java/com/hijackermax/utils/OptionalUtilsTest.java +++ b/src/test/java/com/hijackermax/utils/lang/OptionalUtilsTest.java @@ -1,13 +1,14 @@ -package com.hijackermax.utils; +package com.hijackermax.utils.lang; -import com.hijackermax.utils.lang.OptionalUtils; import org.junit.jupiter.api.Test; import java.util.Collections; import java.util.List; import java.util.Optional; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; class OptionalUtilsTest { @Test diff --git a/src/test/java/com/hijackermax/utils/RandomUtilsTest.java b/src/test/java/com/hijackermax/utils/lang/RandomUtilsTest.java similarity index 95% rename from src/test/java/com/hijackermax/utils/RandomUtilsTest.java rename to src/test/java/com/hijackermax/utils/lang/RandomUtilsTest.java index bee0ae6..17a350d 100644 --- a/src/test/java/com/hijackermax/utils/RandomUtilsTest.java +++ b/src/test/java/com/hijackermax/utils/lang/RandomUtilsTest.java @@ -1,6 +1,5 @@ -package com.hijackermax.utils; +package com.hijackermax.utils.lang; -import com.hijackermax.utils.lang.RandomUtils; import org.junit.jupiter.api.Test; import java.util.Arrays; @@ -8,7 +7,10 @@ import java.util.stream.Collectors; import java.util.stream.IntStream; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; class RandomUtilsTest { @Test diff --git a/src/test/java/com/hijackermax/utils/StringUtilsTest.java b/src/test/java/com/hijackermax/utils/lang/StringUtilsTest.java similarity index 67% rename from src/test/java/com/hijackermax/utils/StringUtilsTest.java rename to src/test/java/com/hijackermax/utils/lang/StringUtilsTest.java index e793be5..8fe3787 100644 --- a/src/test/java/com/hijackermax/utils/StringUtilsTest.java +++ b/src/test/java/com/hijackermax/utils/lang/StringUtilsTest.java @@ -1,7 +1,7 @@ -package com.hijackermax.utils; +package com.hijackermax.utils.lang; import com.hijackermax.utils.encoders.Base122; -import com.hijackermax.utils.lang.StringUtils; +import com.hijackermax.utils.enums.ComparisonOperators; import org.junit.jupiter.api.Test; import java.io.IOException; @@ -9,11 +9,16 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; import java.util.stream.IntStream; import static java.util.Optional.of; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertLinesMatch; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; class StringUtilsTest { @@ -233,4 +238,92 @@ void testRemoveWhitespaces() { assertEquals("Foo", StringUtils.removeWhitespaces("F o o")); assertEquals("Foo", StringUtils.removeWhitespaces(" F o o ")); } + + @Test + void testNotBlankOrElseGet() { + assertEquals("Hello", StringUtils.notBlankOrElseGet("Hello", () -> "Foo")); + assertEquals("Hello", StringUtils.notBlankOrElseGet("Hello", () -> null)); + assertEquals("Foo", StringUtils.notBlankOrElseGet(null, () -> "Foo")); + assertEquals("Foo", StringUtils.notBlankOrElseGet("", () -> "Foo")); + assertEquals("Foo", StringUtils.notBlankOrElseGet(" ", () -> "Foo")); + assertNull(StringUtils.notBlankOrElseGet(" ", () -> null)); + } + + @Test + void testRemoveDigits() { + assertEquals(StringUtils.EMPTY, StringUtils.removeDigits(null)); + assertEquals("xcvbnm,", StringUtils.removeDigits("x1c2v3b4n5m6,7")); + assertEquals(" xc v b n m , ", StringUtils.removeDigits(" 0 x1c 2v3 b4 n5 m6 ,7 ")); + } + + @Test + void testReplace() { + Map replacements = Map.of("Hello", "Foo", "World", "Bar", "Red", "Green"); + assertEquals(StringUtils.EMPTY, StringUtils.replace(null, replacements)); + assertEquals("Foo Bar Test Value", StringUtils.replace("Hello World Test Value", replacements)); + assertEquals("Green Apple", StringUtils.replace("Red Apple", replacements)); + } + + @Test + void testReplaceUnaryOperator() { + Map replacements = Map.of("Hello", "Foo", "World", "Bar", "Red", "Green"); + assertEquals(StringUtils.EMPTY, StringUtils.replace(replacements).apply(null)); + assertEquals("Foo Bar Test Value", StringUtils.replace(replacements).apply("Hello World Test Value")); + assertEquals("Green Apple", StringUtils.replace(replacements).apply("Red Apple")); + } + + @Test + void testReplaceIgnoreCase() { + assertEquals(StringUtils.EMPTY, StringUtils.replaceIgnoreCase(null, "Hello", "Foo")); + assertEquals("Red Apple", StringUtils.replaceIgnoreCase("Red Apple", null, null)); + assertEquals("Foo TEST Value", StringUtils.replaceIgnoreCase("heLLo TEST Value", "Hello", "Foo")); + assertEquals("Green Apple", StringUtils.replaceIgnoreCase("RED Apple", "Red", "Green")); + } + + @Test + void testStartsWith() { + List stringList = List.of("", "1Foo", "1Bar"); + assertEquals(2L, stringList.stream().filter(StringUtils.startsWith("1")).count()); + assertEquals(0L, stringList.stream().filter(StringUtils.startsWith("")).count()); + List filteredList = stringList.stream() + .filter(StringUtils.startsWith("1")) + .collect(Collectors.toList()); + assertLinesMatch(List.of("1Foo", "1Bar"), filteredList); + } + + @Test + void testEndsWith() { + List stringList = List.of("", "Foo1", "Bar1"); + assertEquals(2L, stringList.stream().filter(StringUtils.endsWith("1")).count()); + assertEquals(0L, stringList.stream().filter(StringUtils.endsWith("")).count()); + List filteredList = stringList.stream() + .filter(StringUtils.endsWith("1")) + .collect(Collectors.toList()); + assertLinesMatch(List.of("Foo1", "Bar1"), filteredList); + } + + @Test + void testContains() { + List stringList = List.of("", "Fo1o", "Ba1r"); + assertEquals(2L, stringList.stream().filter(StringUtils.contains("1")).count()); + assertEquals(0L, stringList.stream().filter(StringUtils.contains("")).count()); + List filteredList = stringList.stream() + .filter(StringUtils.contains("1")) + .collect(Collectors.toList()); + assertLinesMatch(List.of("Fo1o", "Ba1r"), filteredList); + } + + @Test + void testHasLength() { + List stringList = List.of("Foo", "Bar", "Test", "Hello", "Hi"); + assertEquals(2L, stringList.stream().filter(StringUtils.hasLength(ComparisonOperators.GT, 3)).count()); + assertEquals(1L, stringList.stream().filter(StringUtils.hasLength(ComparisonOperators.GT, 4)).count()); + assertEquals(4L, stringList.stream().filter(StringUtils.hasLength(ComparisonOperators.LT, 5)).count()); + assertEquals(4L, stringList.stream().filter(StringUtils.hasLength(ComparisonOperators.NEQ, 5)).count()); + assertEquals(3L, stringList.stream().filter(StringUtils.hasLength(ComparisonOperators.LTE, 3)).count()); + List filteredList = stringList.stream() + .filter(StringUtils.hasLength(ComparisonOperators.EQ, 3)) + .collect(Collectors.toList()); + assertLinesMatch(List.of("Foo", "Bar"), filteredList); + } } diff --git a/src/test/java/com/hijackermax/utils/misc/EnumerationSpliteratorTest.java b/src/test/java/com/hijackermax/utils/misc/EnumerationSpliteratorTest.java new file mode 100644 index 0000000..e63df2a --- /dev/null +++ b/src/test/java/com/hijackermax/utils/misc/EnumerationSpliteratorTest.java @@ -0,0 +1,46 @@ +package com.hijackermax.utils.misc; + +import com.hijackermax.utils.lang.CollectionUtils; +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.Spliterator; +import java.util.Vector; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import static com.hijackermax.utils.misc.EnumerationSpliterator.of; +import static com.hijackermax.utils.misc.EnumerationSpliterator.ofOrdered; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class EnumerationSpliteratorTest { + @Test + void testStream() { + Vector numberVector = IntStream.range(0, 100) + .boxed() + .collect(Collectors.toCollection(Vector::new)); + boolean isParallel = of(numberVector.size(), Spliterator.ORDERED, numberVector.elements()).stream() + .isParallel(); + assertFalse(isParallel); + List collectedNumbers = of(numberVector.size(), Spliterator.ORDERED, numberVector.elements()).stream() + .collect(Collectors.toList()); + assertEquals(49, collectedNumbers.get(49)); + assertTrue(CollectionUtils.safeContainsAll(numberVector, collectedNumbers)); + } + + @Test + void testParallelStream() { + Vector numberVector = IntStream.range(0, 100) + .boxed() + .collect(Collectors.toCollection(Vector::new)); + boolean isParallel = ofOrdered(numberVector.elements()).parallelStream() + .isParallel(); + assertTrue(isParallel); + List collectedNumbers = ofOrdered(numberVector.elements()).parallelStream() + .collect(Collectors.toList()); + assertEquals(49, collectedNumbers.get(49)); + assertTrue(CollectionUtils.safeContainsAll(numberVector, collectedNumbers)); + } +} diff --git a/src/test/java/com/hijackermax/switches/ActionsDynamicSwitchTest.java b/src/test/java/com/hijackermax/utils/switches/ActionsDynamicSwitchTest.java similarity index 93% rename from src/test/java/com/hijackermax/switches/ActionsDynamicSwitchTest.java rename to src/test/java/com/hijackermax/utils/switches/ActionsDynamicSwitchTest.java index a645e55..9bb2d39 100644 --- a/src/test/java/com/hijackermax/switches/ActionsDynamicSwitchTest.java +++ b/src/test/java/com/hijackermax/utils/switches/ActionsDynamicSwitchTest.java @@ -1,7 +1,6 @@ -package com.hijackermax.switches; +package com.hijackermax.utils.switches; import com.hijackermax.utils.entities.Single; -import com.hijackermax.utils.switches.ActionsDynamicSwitch; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/src/test/java/com/hijackermax/switches/ClassDynamicSwitchTest.java b/src/test/java/com/hijackermax/utils/switches/ClassDynamicSwitchTest.java similarity index 97% rename from src/test/java/com/hijackermax/switches/ClassDynamicSwitchTest.java rename to src/test/java/com/hijackermax/utils/switches/ClassDynamicSwitchTest.java index fd9cfe9..9591eb2 100644 --- a/src/test/java/com/hijackermax/switches/ClassDynamicSwitchTest.java +++ b/src/test/java/com/hijackermax/utils/switches/ClassDynamicSwitchTest.java @@ -1,8 +1,7 @@ -package com.hijackermax.switches; +package com.hijackermax.utils.switches; import com.hijackermax.utils.entities.Single; import com.hijackermax.utils.entities.Tuple; -import com.hijackermax.utils.switches.ClassDynamicSwitch; import org.junit.jupiter.api.Test; import java.util.Collections; diff --git a/src/test/java/com/hijackermax/switches/ValuesDynamicSwitchTest.java b/src/test/java/com/hijackermax/utils/switches/ValuesDynamicSwitchTest.java similarity index 93% rename from src/test/java/com/hijackermax/switches/ValuesDynamicSwitchTest.java rename to src/test/java/com/hijackermax/utils/switches/ValuesDynamicSwitchTest.java index 78c3791..8617ec3 100644 --- a/src/test/java/com/hijackermax/switches/ValuesDynamicSwitchTest.java +++ b/src/test/java/com/hijackermax/utils/switches/ValuesDynamicSwitchTest.java @@ -1,6 +1,5 @@ -package com.hijackermax.switches; +package com.hijackermax.utils.switches; -import com.hijackermax.utils.switches.ValuesDynamicSwitch; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals;