From 221865397f0cf87c20487b44174c37c02990c344 Mon Sep 17 00:00:00 2001 From: Tom Ansill Date: Wed, 29 Jul 2020 14:56:52 -0600 Subject: [PATCH 1/7] 0.1.1 - Added README.md --- README.md | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..479ad26 --- /dev/null +++ b/README.md @@ -0,0 +1,78 @@ +# Utility + +A collection of helpful utility functions and classes. + +By Tom Ansill + +## Contents + +- `Utility` - Collection of commonly used functions. + - `bytesToHex(byte[])` - Converts a byte array to hexidecimal string. + - `hexToBytes(String)` - Converts a hexidecimal string to byte array. + - `format(String,Object,Object...)` - Formats string, replaces any '{}' with object's `toString()` representation. + - `f(String,Object,Object...)` - Shorthand function for `format(String,Object,Object...)`. + - `simpleToString(Object)` - `toString()` implementation for the lazy. It will create a string with class name and its fields. Example: MyDogClass(name="fido", color="Brown", age=1). In `toString()` of your classes, you just put `Utility.simpleToString(this)`. + - `sensibleToString(Object object)` - Simply adds double quotation marks between a String if input `Object` is a string, otherwise, returns `toString()` of non-`String` object. This function help to solve my minor beef with `String`'s `toString()` implementation where one can easily confuse with `null` or `"null"` when object automatically gets converted to String in like `System.out.println("Hello " + nullableString)`. + - `generateString(long)` - Generates a random sequence of string. The characters in the random string will be alphanumeric `[a-zA-z0-9]`. + +- `ResourceUtility` - Collection of functions related to reading resources within `.jar` files. + - `getAllFilesInResource(Class,String,boolean)` - Scans all resources inside `.jar` file that owns the input `Class` and outputs a `Set` of path of resources. + - `getResourceListing(Class,String)` - Returns a listing of specified path in the `.jar` that owns the input `Class`. **NOTE:** This is not same as `getResource(String)` because directories are not a thing in `.jar` files. All of the files are flattened into a single big root directory. Meaning if you export a `.jar` file and attempt to find a directory in it with just `getResource(String)`, it wouldn't work. + - `getResourceFileContent(Class,String)` - Reads entire file in `.jar` that owns the input `Class` and output it as String. +- `Version` - Class to detect and interpret versions in Jars. Assuming the Jar file will have manifest file that has version on it. Class will attempt to find it and interpret it. First it looks at package's `getImplementationVersion()`, then `getSpecificationVersion()`, finally, as last-resort, it will look for `verison.properties` in the resources. If that fails, then it will just output `X.Y.Z`. +- `ExCollectors` - Extended `Collectors` utility class for more terminal `Stream` functions. + - `toMap()` - Convenience function of `Collectors.toMap(K,V)` if you are already streaming `Map.Entry`. Equivalent to `Collectors.toMap(Map.Entry::getKey,Map.Entry::getValue)`. + - `toConcurrentMap()` - Same as `toMap()` but as `ConcurrentMap`. +- `function/*` - Package of lambda functions + - `ConsumerWithException` - Variant of `Consumer` that throws `Exception`. + - `FunctionWithException` - Variant of `Function` that throws `Exception`. + - `SupplierWithException` - Variant of `Supplier` that throws `Exception`. + - `BiConsumerWithException` - Variant of `BiConsumer` that throws `Exception`. + - `BiFunctionWithException` - Variant of `BiFunction` that throws `Exception`. + - `TriConsumer` - Extension of `Consumer` but with 3 parameters. + - `TriConsumerWithException` - Variant of `TriConsumer` that throws `Exception`. + - `TriFunction` - Extension of `Function` but with 3 parameters. + - `TriFunctionWithException` - Variant of `TriFunction` that throws `Exception`. + - `QuadConsumer` - Extension of `Consumer` but with 4 parameters. + - `QuadConsumerWithException` - Variant of `QuadConsumer` that throws `Exception`. + - `QuadFunction` - Extension of `Function` but with 4 parameters. + - `QuadFunctionWithException` - Variant of `QuadFunction` that throws `Exception`. + +## Prerequisites + +- Java 8 or better +- [Java Validation Library](https://github.com/tomansill/JavaValidation/) + +## Download and Install + +### Package Repository + +The library is availble for download on Sonatype public Maven repository (https://oss.sonatype.org/#nexus):The library is availble for download on Sonatype public Maven repository (https://oss.sonatype.org/#nexus): + +#### Utility (`Utility`, `ResourceUtility`, `ExCollectors`, and `functions/*`) +```xml + + com.ansill.utility + utility + 0.1.1 + +``` + +#### Version +```xml + + com.ansill.utility + version + 0.1.1 + +``` + +### Build and Install + +Maven (or other similar build tools) is needed to build and install JavaUtility + +```sh +$ git clone https://github.com/tomansill/javautility +$ cd javautility +$ mvn install +``` \ No newline at end of file From 5bd1b52c37059c25216c88eef584c5677f72be14 Mon Sep 17 00:00:00 2001 From: Tom Ansill Date: Wed, 29 Jul 2020 14:59:12 -0600 Subject: [PATCH 2/7] 0.1.1 - Added the missing `RunnableWithException` --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 479ad26..44d050a 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ By Tom Ansill - `toMap()` - Convenience function of `Collectors.toMap(K,V)` if you are already streaming `Map.Entry`. Equivalent to `Collectors.toMap(Map.Entry::getKey,Map.Entry::getValue)`. - `toConcurrentMap()` - Same as `toMap()` but as `ConcurrentMap`. - `function/*` - Package of lambda functions + - `RunnableWithException` - Variant of `Runnable` that throws `Exception`. - `ConsumerWithException` - Variant of `Consumer` that throws `Exception`. - `FunctionWithException` - Variant of `Function` that throws `Exception`. - `SupplierWithException` - Variant of `Supplier` that throws `Exception`. From 39368d8cde1a0137cb5c8c14d1b98c9a9c38c4cd Mon Sep 17 00:00:00 2001 From: Tom Ansill Date: Sat, 5 Sep 2020 11:32:15 -0600 Subject: [PATCH 3/7] 0.1.2 - Fixed bug where generateString(int) doesn't actually use '0' character --- pom.xml | 2 +- utility/src/main/java/com/ansill/utility/Utility.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 90a1264..469f1a6 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ com.ansill.utility utility-all pom - 0.1.1 + 0.1.2 ${project.groupId}:${project.artifactId} diff --git a/utility/src/main/java/com/ansill/utility/Utility.java b/utility/src/main/java/com/ansill/utility/Utility.java index 62771d3..3dde04d 100644 --- a/utility/src/main/java/com/ansill/utility/Utility.java +++ b/utility/src/main/java/com/ansill/utility/Utility.java @@ -245,7 +245,7 @@ public static String generateString(@Nonnegative long length){ // Set up characterset String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - String fullAlphabetSet = alphabet + alphabet.toLowerCase() + "123456789"; + String fullAlphabetSet = alphabet + alphabet.toLowerCase() + "0123456789"; // Set up random generator Random random = getRandom(); From e3e7c187fdced2f46f50b7cdc4de8a6ed748cfb3 Mon Sep 17 00:00:00 2001 From: Tom Ansill Date: Sat, 5 Sep 2020 11:32:15 -0600 Subject: [PATCH 4/7] 0.1.2 - Fixed bug where generateString(int) doesn't actually use '0' character --- utility/pom.xml | 2 +- version/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/utility/pom.xml b/utility/pom.xml index e36955e..2864e24 100644 --- a/utility/pom.xml +++ b/utility/pom.xml @@ -5,7 +5,7 @@ utility-all com.ansill.utility - 0.1.1 + 0.1.2 4.0.0 diff --git a/version/pom.xml b/version/pom.xml index 5b0026c..52d47c6 100644 --- a/version/pom.xml +++ b/version/pom.xml @@ -5,7 +5,7 @@ utility-all com.ansill.utility - 0.1.1 + 0.1.2 4.0.0 From be4d29d5a7dbf90ceedf3af5b3ec5ddd7d44eb50 Mon Sep 17 00:00:00 2001 From: Tom Ansill Date: Wed, 16 Sep 2020 12:27:52 -0600 Subject: [PATCH 5/7] 0.1.3 - Added new generateString with random generator --- README.md | 1 + pom.xml | 2 +- utility/pom.xml | 2 +- .../main/java/com/ansill/utility/Utility.java | 18 +++++++++++++----- version/pom.xml | 2 +- 5 files changed, 17 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 44d050a..98d737c 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ By Tom Ansill - `simpleToString(Object)` - `toString()` implementation for the lazy. It will create a string with class name and its fields. Example: MyDogClass(name="fido", color="Brown", age=1). In `toString()` of your classes, you just put `Utility.simpleToString(this)`. - `sensibleToString(Object object)` - Simply adds double quotation marks between a String if input `Object` is a string, otherwise, returns `toString()` of non-`String` object. This function help to solve my minor beef with `String`'s `toString()` implementation where one can easily confuse with `null` or `"null"` when object automatically gets converted to String in like `System.out.println("Hello " + nullableString)`. - `generateString(long)` - Generates a random sequence of string. The characters in the random string will be alphanumeric `[a-zA-z0-9]`. + - `generateString(Random, long)` - Generates a random sequence of string with provided random generator. The characters in the random string will be alphanumeric `[a-zA-z0-9]`. - `ResourceUtility` - Collection of functions related to reading resources within `.jar` files. - `getAllFilesInResource(Class,String,boolean)` - Scans all resources inside `.jar` file that owns the input `Class` and outputs a `Set` of path of resources. diff --git a/pom.xml b/pom.xml index 469f1a6..ddc0c69 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ com.ansill.utility utility-all pom - 0.1.2 + 0.1.3 ${project.groupId}:${project.artifactId} diff --git a/utility/pom.xml b/utility/pom.xml index 2864e24..43d2cf3 100644 --- a/utility/pom.xml +++ b/utility/pom.xml @@ -5,7 +5,7 @@ utility-all com.ansill.utility - 0.1.2 + 0.1.3 4.0.0 diff --git a/utility/src/main/java/com/ansill/utility/Utility.java b/utility/src/main/java/com/ansill/utility/Utility.java index 3dde04d..626af27 100644 --- a/utility/src/main/java/com/ansill/utility/Utility.java +++ b/utility/src/main/java/com/ansill/utility/Utility.java @@ -238,7 +238,7 @@ private static Random getRandom(){ * @return randomized string up to specified length */ @Nonnull - public static String generateString(@Nonnegative long length){ + public static String generateString(@Nonnull Random randomGenerator, @Nonnegative long length){ // Check length Validation.assertNaturalNumber(length, "length"); @@ -247,18 +247,26 @@ public static String generateString(@Nonnegative long length){ String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; String fullAlphabetSet = alphabet + alphabet.toLowerCase() + "0123456789"; - // Set up random generator - Random random = getRandom(); - // Set up string builder StringBuilder sb = new StringBuilder(); // Build random string LongStream.range(0, length) - .forEach(i -> sb.append(fullAlphabetSet.charAt(random.nextInt(fullAlphabetSet.length())))); + .forEach(i -> sb.append(fullAlphabetSet.charAt(randomGenerator.nextInt(fullAlphabetSet.length())))); // Return the string return sb.toString(); } + + /** + * Generates string with random characters of specified length + * + * @param length length of string + * @return randomized string up to specified length + */ + @Nonnull + public static String generateString(@Nonnegative long length){ + return generateString(getRandom(), length); + } } diff --git a/version/pom.xml b/version/pom.xml index 52d47c6..c87036b 100644 --- a/version/pom.xml +++ b/version/pom.xml @@ -5,7 +5,7 @@ utility-all com.ansill.utility - 0.1.2 + 0.1.3 4.0.0 From d8352a1cb261aba7b9cb345af9d5ecccf10fc2c9 Mon Sep 17 00:00:00 2001 From: Tom Ansill Date: Wed, 16 Sep 2020 12:31:34 -0600 Subject: [PATCH 6/7] 0.1.3 - Update documentation - Added validation guard --- utility/src/main/java/com/ansill/utility/Utility.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/utility/src/main/java/com/ansill/utility/Utility.java b/utility/src/main/java/com/ansill/utility/Utility.java index 626af27..41ce035 100644 --- a/utility/src/main/java/com/ansill/utility/Utility.java +++ b/utility/src/main/java/com/ansill/utility/Utility.java @@ -234,13 +234,15 @@ private static Random getRandom(){ /** * Generates string with random characters of specified length * - * @param length length of string + * @param length length of string + * @param randomGenerator random generator used to generate the string * @return randomized string up to specified length */ @Nonnull public static String generateString(@Nonnull Random randomGenerator, @Nonnegative long length){ // Check length + Validation.assertNonnull(randomGenerator, "randomGenerator"); Validation.assertNaturalNumber(length, "length"); // Set up characterset From 094d8ccb99f816b6b385ee970ff1394e7d522402 Mon Sep 17 00:00:00 2001 From: Tom Ansill Date: Fri, 18 Dec 2020 04:23:31 -0700 Subject: [PATCH 7/7] 0.1.4 - Added unmodifiable collections functions --- pom.xml | 2 +- utility/pom.xml | 2 +- .../main/java/com/ansill/utility/Utility.java | 131 ++++++++ .../com/ansill/test/utility/UtilityTest.java | 311 ++++++++++++++++++ version/pom.xml | 2 +- 5 files changed, 445 insertions(+), 3 deletions(-) create mode 100644 utility/src/test/java/com/ansill/test/utility/UtilityTest.java diff --git a/pom.xml b/pom.xml index ddc0c69..2390b1a 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ com.ansill.utility utility-all pom - 0.1.3 + 0.1.4 ${project.groupId}:${project.artifactId} diff --git a/utility/pom.xml b/utility/pom.xml index 43d2cf3..4453b7e 100644 --- a/utility/pom.xml +++ b/utility/pom.xml @@ -5,7 +5,7 @@ utility-all com.ansill.utility - 0.1.3 + 0.1.4 4.0.0 diff --git a/utility/src/main/java/com/ansill/utility/Utility.java b/utility/src/main/java/com/ansill/utility/Utility.java index 41ce035..f0d9c69 100644 --- a/utility/src/main/java/com/ansill/utility/Utility.java +++ b/utility/src/main/java/com/ansill/utility/Utility.java @@ -7,8 +7,16 @@ import javax.annotation.Nullable; import java.lang.reflect.Modifier; import java.security.SecureRandom; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; import java.util.Random; +import java.util.Set; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; import java.util.stream.LongStream; @@ -22,6 +30,29 @@ public final class Utility{ /** Hex array */ private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray(); + /** Class for unmodifiable map class created by Collections.unmodifiableMap(Map) */ + @Nonnull + private static final Class UNMODIFIABLE_MAP_CLASS; + + /** Class for unmodifiable set class created by Collections.unmodifiableSet(Set) */ + @Nonnull + private static final Class UNMODIFIABLE_SET_CLASS; + + /** Class for unmodifiable list class created by Collections.unmodifiableList(List) */ + @Nonnull + private static final Class UNMODIFIABLE_LIST_CLASS; + + /** Class for unmodifiable list class created by Collections.unmodifiableSet(List) that's for special list classes like ArrayList */ + @Nonnull + private static final Class UNMODIFIABLE_RANDOM_ACCESS_LIST_CLASS; + + static{ + UNMODIFIABLE_MAP_CLASS = Collections.unmodifiableMap(new HashMap<>()).getClass(); + UNMODIFIABLE_SET_CLASS = Collections.unmodifiableSet(new HashSet<>()).getClass(); + UNMODIFIABLE_LIST_CLASS = Collections.unmodifiableList(new LinkedList<>()).getClass(); + UNMODIFIABLE_RANDOM_ACCESS_LIST_CLASS = Collections.unmodifiableList(new ArrayList<>()).getClass(); + } + /** * Private constructor *

@@ -271,4 +302,104 @@ public static String generateString(@Nonnull Random randomGenerator, @Nonnegativ public static String generateString(@Nonnegative long length){ return generateString(getRandom(), length); } + + /** + * Behaves same as Collections.unmodifiableMap(Map) but this function will simply return if input map is already an unmodifiable map instead of wrapping it again + * + * @param originalMap original map + * @param key type of map + * @param value type of map + * @return unmodifiable map + */ + @Nonnull + public static Map unmodifiableMap(@Nonnull Map originalMap){ + if(originalMap.getClass().equals(UNMODIFIABLE_MAP_CLASS)) return originalMap; + return Collections.unmodifiableMap(originalMap); + } + + /** + * Behaves same as Collections.unmodifiableSet(Set) but this function will simply return if input set is already an unmodifiable set instead of wrapping it again + * + * @param originalSet original set + * @param value type of set + * @return unmodifiable set + */ + @Nonnull + public static Set unmodifiableSet(@Nonnull Set originalSet){ + if(originalSet.getClass().equals(UNMODIFIABLE_SET_CLASS)) return originalSet; + return Collections.unmodifiableSet(originalSet); + } + + /** + * Behaves same as Collections.unmodifiableList(Set) but this function will simply return if input list is already an unmodifiable list instead of wrapping it again + * + * @param originalList original list + * @param value type of list + * @return unmodifiable list + */ + @Nonnull + public static List unmodifiableList(@Nonnull List originalList){ + if(originalList.getClass().equals(UNMODIFIABLE_LIST_CLASS) || originalList.getClass().equals( + UNMODIFIABLE_RANDOM_ACCESS_LIST_CLASS)) return originalList; + return Collections.unmodifiableList(originalList); + } + + /** + * Unites multiple sets together, will re-use any one of set if all other sets are empty + * + * @param originalSet original set + * @param otherSet other set + * @param moreSet list of additional set + * @param value type of set + * @return united set + */ + @SafeVarargs + @Nonnull + public static Set union(@Nonnull Set originalSet, @Nonnull Set otherSet, @Nonnull Set... moreSet){ + long nonEmptys = Arrays.stream(moreSet).filter(item -> !item.isEmpty()).count(); + if(nonEmptys == 0 && otherSet.isEmpty()) return originalSet; + if(nonEmptys == 0 && originalSet.isEmpty()) return otherSet; + if(nonEmptys == 1 && originalSet.isEmpty() && otherSet.isEmpty()){ + return Arrays.stream(moreSet) + .filter(item -> !item.isEmpty()) + .findAny() + .orElseThrow(() -> new RuntimeException("count failed")); + } + Set newSet = new HashSet<>(originalSet); + newSet.addAll(otherSet); + Arrays.stream(moreSet).forEach(newSet::addAll); + return newSet; + } + + /** + * Unites multiple sets together, will re-use any one of set if all other sets are empty, then returns as unmodifiable set + * + * @param originalSet original set + * @param otherSet other set + * @param moreSet list of additional set + * @param value type of set + * @return unmodifiable united set + */ + @SafeVarargs + @Nonnull + public static Set unmodifiableSet( + @Nonnull Set originalSet, + @Nonnull Set otherSet, + @Nonnull Set... moreSet + ){ + return unmodifiableSet(union(originalSet, otherSet, moreSet)); + } + + /** + * Behaves same as Arrays.asList(V...) but for set + * + * @param items items + * @param value type of set + * @return set + */ + @SafeVarargs + @Nonnull + public static Set asSet(@Nonnull V... items){ + return new HashSet<>(Arrays.asList(items)); + } } diff --git a/utility/src/test/java/com/ansill/test/utility/UtilityTest.java b/utility/src/test/java/com/ansill/test/utility/UtilityTest.java new file mode 100644 index 0000000..1060c8e --- /dev/null +++ b/utility/src/test/java/com/ansill/test/utility/UtilityTest.java @@ -0,0 +1,311 @@ +package com.ansill.test.utility; + +import com.ansill.utility.Utility; +import org.junit.jupiter.api.Test; + +import java.security.SecureRandom; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.Set; + +import static com.ansill.utility.Utility.generateString; +import static org.junit.jupiter.api.Assertions.*; + +class UtilityTest{ + + @Test + void testNegativeLength(){ + assertThrows(IllegalArgumentException.class, () -> generateString(-1)); + assertThrows(IllegalArgumentException.class, () -> generateString(new SecureRandom(), -1)); + } + + @SuppressWarnings("ConstantConditions") // Ignored because of test + @Test + void testNullGenerator(){ + assertThrows(IllegalArgumentException.class, () -> generateString(null, 1)); + } + + @Test + void testRandomNumberGenerator(){ + + // Get random generator + Random randomGenerator = new SecureRandom(); + + // Set length + int length = randomGenerator.nextInt(49) + 1; + + // Generate it + String string = generateString(length); + + // Check length + assertEquals(length, string.length()); + } + + @Test + void testRandomness(){ + + // Get random generator + Random randomGenerator = new SecureRandom("some seed".getBytes()); + + // Set length + int length = 10; + + // Set + Set generated = new HashSet<>(); + + // Repeat a million times + for(int i = 0; i < 1_000_000; i++){ + + // Generate it + String string = generateString(randomGenerator, length); + + // Check length + assertEquals(length, string.length()); + + // Ensure no duplicate + assertTrue( + generated.add(string), + "Found a duplicate string in the set. Either the code is incorrect or maybe you should buy a lottery ticket ;)" + ); + } + } + + @Test + void testUnmodifiableMap(){ + + // Create map + Map map = new HashMap<>(); + map.put(generateString(8), generateString(32)); + map.put(generateString(3), generateString(22)); + + // Create map + Map unmodMap = Utility.unmodifiableMap(map); + assertNotEquals(System.identityHashCode(unmodMap), System.identityHashCode(map)); + assertEquals(map, unmodMap); + + // Manipulate it + map.put(generateString(4), generateString(32)); + assertEquals(map, unmodMap); + + // Try again + Map otherUnmodMap = Utility.unmodifiableMap(unmodMap); + assertEquals(System.identityHashCode(unmodMap), System.identityHashCode(otherUnmodMap)); + assertEquals(unmodMap, otherUnmodMap); + + // Clone map + Map cloned = new HashMap<>(unmodMap); + assertNotEquals(System.identityHashCode(unmodMap), System.identityHashCode(cloned)); + assertEquals(unmodMap, otherUnmodMap); + + // Manipulate it + cloned.put(generateString(4), generateString(32)); + assertNotEquals(map, cloned); + assertNotEquals(unmodMap, cloned); + + // Ensure it's unmodifiable + assertThrows(UnsupportedOperationException.class, () -> unmodMap.put(generateString(2), generateString(22))); + } + + @Test + void testUnmodifiableSet(){ + + // Create set + Set set = new HashSet<>(); + set.add(generateString(32)); + set.add(generateString(22)); + + // Create set + Set unmodSet = Utility.unmodifiableSet(set); + assertNotEquals(System.identityHashCode(unmodSet), System.identityHashCode(set)); + assertEquals(set, unmodSet); + + // Manipulate it + set.add(generateString(32)); + assertEquals(set, unmodSet); + + // Try again + Set otherUnmodSet = Utility.unmodifiableSet(unmodSet); + assertEquals(System.identityHashCode(unmodSet), System.identityHashCode(otherUnmodSet)); + assertEquals(unmodSet, otherUnmodSet); + + // Clone set + Set cloned = new HashSet<>(unmodSet); + assertNotEquals(System.identityHashCode(unmodSet), System.identityHashCode(cloned)); + assertEquals(unmodSet, otherUnmodSet); + + // Manipulate it + cloned.add(generateString(32)); + assertNotEquals(set, cloned); + assertNotEquals(unmodSet, cloned); + + // Ensure it's unmodifiable + assertThrows(UnsupportedOperationException.class, () -> unmodSet.add(generateString(22))); + } + + @Test + void testUnmodifiableList(){ + + // Create list + List list = new LinkedList<>(); + list.add(generateString(32)); + list.add(generateString(22)); + + // Create list + List unmodList = Utility.unmodifiableList(list); + assertNotEquals(System.identityHashCode(unmodList), System.identityHashCode(list)); + assertEquals(list, unmodList); + + // Manipulate it + list.add(generateString(32)); + assertEquals(list, unmodList); + + // Try again + List otherUnmodList = Utility.unmodifiableList(unmodList); + assertEquals(System.identityHashCode(unmodList), System.identityHashCode(otherUnmodList)); + assertEquals(unmodList, otherUnmodList); + + // Clone list + List cloned = new LinkedList<>(unmodList); + assertNotEquals(System.identityHashCode(unmodList), System.identityHashCode(cloned)); + assertEquals(unmodList, otherUnmodList); + + // Manipulate it + cloned.add(generateString(32)); + assertNotEquals(list, cloned); + assertNotEquals(unmodList, cloned); + + // Ensure it's unmodifiable + assertThrows(UnsupportedOperationException.class, () -> unmodList.add(generateString(22))); + } + + @Test + void testUnmodifiableRandomAccessList(){ + + // Create list + List list = new ArrayList<>(); + list.add(generateString(32)); + list.add(generateString(22)); + + // Create list + List unmodList = Utility.unmodifiableList(list); + assertNotEquals(System.identityHashCode(unmodList), System.identityHashCode(list)); + assertEquals(list, unmodList); + + // Manipulate it + list.add(generateString(32)); + assertEquals(list, unmodList); + + // Try again + List otherUnmodList = Utility.unmodifiableList(unmodList); + assertEquals(System.identityHashCode(unmodList), System.identityHashCode(otherUnmodList)); + assertEquals(unmodList, otherUnmodList); + + // Clone list + List cloned = new ArrayList<>(unmodList); + assertNotEquals(System.identityHashCode(unmodList), System.identityHashCode(cloned)); + assertEquals(unmodList, otherUnmodList); + + // Manipulate it + cloned.add(generateString(32)); + assertNotEquals(list, cloned); + assertNotEquals(unmodList, cloned); + + // Ensure it's unmodifiable + assertThrows(UnsupportedOperationException.class, () -> unmodList.add(generateString(22))); + } + + @Test + void testUnion(){ + + // Create Set + Set set = new HashSet<>(); + set.add(generateString(32)); + set.add(generateString(22)); + + // Create set + Set combinedSet = Utility.union(set, Collections.emptySet()); + assertEquals(System.identityHashCode(combinedSet), System.identityHashCode(set)); + assertEquals(set, combinedSet); + + // Again + combinedSet = Utility.union(set, Collections.emptySet(), Collections.emptySet()); + assertEquals(System.identityHashCode(combinedSet), System.identityHashCode(set)); + assertEquals(set, combinedSet); + + // Reverse + combinedSet = Utility.union(Collections.emptySet(), set); + assertEquals(System.identityHashCode(combinedSet), System.identityHashCode(set)); + assertEquals(set, combinedSet); + + // Again + combinedSet = Utility.union(Collections.emptySet(), set, Collections.emptySet()); + assertEquals(System.identityHashCode(combinedSet), System.identityHashCode(set)); + assertEquals(set, combinedSet); + + // In variadic + combinedSet = Utility.union(Collections.emptySet(), Collections.emptySet(), set); + assertEquals(System.identityHashCode(combinedSet), System.identityHashCode(set)); + assertEquals(set, combinedSet); + + // Create Set + Set set1 = new HashSet<>(); + set1.add(generateString(32)); + set1.add(set.iterator().next()); + + // Unite + combinedSet = Utility.union(set, set1); + assertNotEquals(System.identityHashCode(set), System.identityHashCode(combinedSet)); + assertNotEquals(System.identityHashCode(set1), System.identityHashCode(combinedSet)); + Set testSet = new HashSet<>(set); + testSet.addAll(set1); + assertEquals(testSet, combinedSet); + + // Create other Set + Set set2 = new HashSet<>(); + set2.add(generateString(32)); + set2.add(generateString(33)); + set2.add(set1.iterator().next()); + + // Unite + combinedSet = Utility.union(set, set1, set2); + assertNotEquals(System.identityHashCode(set), System.identityHashCode(combinedSet)); + assertNotEquals(System.identityHashCode(set1), System.identityHashCode(combinedSet)); + assertNotEquals(System.identityHashCode(set2), System.identityHashCode(combinedSet)); + testSet = new HashSet<>(set); + testSet.addAll(set1); + testSet.addAll(set2); + assertEquals(testSet, combinedSet); + + // Modify it + combinedSet.add(generateString(3)); + + // Create unmodifiable + Set unmodSet = Utility.unmodifiableSet(set, set1, set2); + + // Ensure it's unmodifiable + assertThrows(UnsupportedOperationException.class, () -> unmodSet.add(generateString(22))); + } + + @Test + void testAsSet(){ + + // Create values + String item1 = generateString(32); + String item2 = generateString(32); + String item3 = generateString(32); + String item4 = generateString(32); + + // Create set + Set items = Utility.asSet(item1, item2, item3, item4, item2); + + // Compare + assertEquals(new HashSet<>(Arrays.asList(item1, item2, item3, item4)), items); + } +} \ No newline at end of file diff --git a/version/pom.xml b/version/pom.xml index c87036b..e2d6957 100644 --- a/version/pom.xml +++ b/version/pom.xml @@ -5,7 +5,7 @@ utility-all com.ansill.utility - 0.1.3 + 0.1.4 4.0.0