diff --git a/.gitignore b/.gitignore index 48267e9..6c9b373 100644 --- a/.gitignore +++ b/.gitignore @@ -71,3 +71,8 @@ hs_err_pid* !gradle/wrapper/gradle-wrapper.jar +/bin/ + +.classpath +.project +.settings diff --git a/README.md b/README.md index 028ec4d..bd9ffd6 100644 --- a/README.md +++ b/README.md @@ -1,566 +1,40 @@ strman-java [![Build Status](https://travis-ci.org/shekhargulati/strman-java.svg?branch=master)](https://travis-ci.org/shekhargulati/strman-java) [![codecov.io](https://codecov.io/github/shekhargulati/strman-java/coverage.svg?branch=master)](https://codecov.io/github/shekhargulati/strman-java?branch=master) [![License](https://img.shields.io/:license-mit-blue.svg)](./LICENSE.txt) ------ -A Java 8 library for working with String. It is inspired by [dleitee/strman](https://github.com/dleitee/strman). +A Java 8 library for working with Strings. +You can learn about all the String utility functions implemented in `strman` library by reading the [documentation](https://github.com/shekhargulati/strman-java/wiki). Getting Started -------- -To use strman in your application, you have to add `strman` in your classpath. strman is available on [Maven Central](http://search.maven.org/) so you just need to add dependency to your favorite build tool as show below. +To use strman in your application, you have to add `strman` to your classpath. +strman is available on [Maven Central](http://search.maven.org/) so you just need to add dependency in your favorite build tool as shown below. -For Apache Maven users, please add following to your pom.xml. +For Apache Maven users, please add following to your `pom.xml`. ```xml com.shekhargulati strman - 0.2.0 - jar + 0.4.0 ``` -Gradle users can add following to their build.gradle file. +Gradle users can add following to their `build.gradle` file. ``` -compile(group: 'com.shekhargulati', name: 'strman', version: '0.2.0', ext: 'jar'){ - transitive=true -} +compile(group: 'com.shekhargulati', name: 'strman', version: '0.4.0') ``` -## Available Functions +To learn what we added in the latest version please refer to `./changelog.md`. -These are the available functions in current version of library: +You can refer to Javadocs online [http://shekhargulati.github.io/strman-java/](http://shekhargulati.github.io/strman-java/). -## append +## Inspiration -Appends Strings to value - -```java -import static strman.Strman.append -append("f", "o", "o", "b", "a", "r") -// result => "foobar" -``` - -## appendArray - -Append an array of String to value - -```java -import static strman.Strman.appendArray -appendArray("f", new String[]{"o", "o", "b", "a", "r"} -// result => "foobar" -``` - -## at - -Get the character at index. This method will take care of negative indexes. - -```java -import static strman.Strman.at -at("foobar", 0) -// result => Optional("f") -``` - -## between - -Returns an array with strings between start and end. - -```java -import static strman.Strman.between -between("[abc][def]", "[", "]") -// result => ["abc","def"] -``` - -## chars - -Returns a String array consisting of the characters in the String. - -```java -import static strman.Strman.chars -chars("title") -// result => ["t", "i", "t", "l", "e"] -``` - -## collapseWhitespace - -Replace consecutive whitespace characters with a single space. - -```java -import static strman.Strman.collapseWhitespace -collapseWhitespace("foo bar") -// result => "foo bar" -``` - -## contains - -Verifies that the needle is contained in the value. - -```java -import static strman.Strman.contains -contains("foo bar","foo") -// result => true - -contains("foo bar","FOO", false) // turning off case sensitivity -// result => true -``` - -## containsAll - -Verifies that all needles are contained in value - -```java -import static strman.Strman.containsAll -containsAll("foo bar", new String[]{"foo", "bar"}) -// result => true - -containsAll("foo bar", new String[]{"FOO", "bar"},false) -// result => true -``` - -## containsAny - -Verifies that one or more of needles are contained in value. - -```java -import static strman.Strman.containsAny -containsAny("bar foo", new String[]{"FOO", "BAR", "Test"}, true) -// result => true -``` - -## countSubstr - -Count the number of times substr appears in value - -```java -import static strman.Strman.countSubstr -countSubstr("aaaAAAaaa", "aaa") -// result => 2 -countSubstr("aaaAAAaaa", "aaa", false, false) -// result => 3 -``` - -## endsWith - -Test if value ends with search. - -```java -import static strman.Strman.endsWith -endsWith("foo bar", "bar") -// result => true -endsWith("foo Bar", "BAR", false) -// result => true -``` - -## ensureLeft - -Ensures that the value begins with prefix. If it doesn't exist, it's prepended. - -```java -import static strman.Strman.ensureLeft -ensureLeft("foobar", "foo") -// result => "foobar" -ensureLeft("bar", "foo") -// result => "foobar" -ensureLeft("foobar", "FOO", false) -// result => "foobar" -``` - -## base64Decode - -Decodes data encoded with MIME base64 - -```java -import static strman.Strman.base64Decode -base64Decode("c3RybWFu") -// result => "strman" -``` - -## base64Encode - -Encodes data with MIME base64. - -```java -import static strman.Strman.base64Encode -base64Encode("strman") -// result => "c3RybWFu" -``` - -## binDecode - -Convert binary unicode (16 digits) string to string chars - -```java -import static strman.Strman.binDecode -binDecode("0000000001000001") -// result => "A" -``` - -## binEncode - -Convert string chars to binary unicode (16 digits) - -```java -import static strman.Strman.binEncode -binEncode("A") -// result => "0000000001000001" -``` - -## decDecode - -Convert decimal unicode (5 digits) string to string chars - -```java -import static strman.Strman.decDecode -decDecode("00065") -// result => "A" -``` - -## decEncode - -Convert string chars to decimal unicode (5 digits) - -```java -import static strman.Strman.decEncode -decEncode("A") -// result => "00065" -``` - -## ensureRight - -Ensures that the value ends with suffix. If it doesn't, it's appended. - -```java -import static strman.Strman.ensureRight -ensureRight("foo", "bar") -// result => "foobar" - -ensureRight("foobar", "bar") -// result => "foobar" - -ensureRight("fooBAR", "bar", false) -// result => "foobar" -``` - -## first - -Returns the first n chars of String - -```java -import static strman.Strman.first -first("foobar", 3) -// result => "foo" -``` - -## head - -Return the first char of String - -```java -import static strman.Strman.head -head("foobar") -// result => "f" -``` - -## hexDecode - -Convert hexadecimal unicode (4 digits) string to string chars - -```java -import static strman.Strman.hexDecode -hexDecode("0041") -// result => "A" -``` - -## hexEncode - -Convert string chars to hexadecimal unicode (4 digits) - -```java -import static strman.Strman.hexEncode -hexEncode("A") -// result => "0041" -``` - -## inequal - -Tests if two Strings are inequal - -```java -import static strman.Strman.inequal -inequal("a", "b") -// result => true -``` - -## insert - -Inserts 'substr' into the 'value' at the 'index' provided. - -```java -import static strman.Strman.insert -insert("fbar", "oo", 1) -// result => "foobar" -``` - -## last - -Return the last n chars of String - -```java -import static strman.Strman.last -last("foobarfoo", 3) -// result => "foo" -``` - -## leftPad - -Returns a new string of a given length such that the beginning of the string is padded. - -```java -import static strman.Strman.leftPad -leftPad("1", "0", 5) -// result => "00001" -``` - -## lastIndexOf - -This method returns the index within the calling String object of the last occurrence of the specified value, searching backwards from the offset. - -```java -import static strman.Strman.lastIndexOf -lastIndexOf("foobarfoobar", "F", false) -// result => 6 -``` - -## leftTrim - -Removes all spaces on left - -```java -import static strman.Strman.leftTrim -leftTrim(" strman") -// result => "strman" -``` - -## prepend - -Return a new String starting with prepends - -```java -prepend("r", "f", "o", "o", "b", "a") -// "foobar" -``` - -## removeEmptyStrings - -Remove empty Strings from string array - -```java -removeEmptyStrings(new String[]{"aa", "", " ", "bb", "cc", null}) -// result => ["aa", "bb", "cc"] -``` - -## removeLeft - -Returns a new String with the prefix removed, if present. - -```java -removeLeft("foofoo", "foo") -// "foo" -``` - -## removeNonWords - -Remove all non word characters. - -```java -removeNonWords("foo&bar-") -// result => "foobar" -``` - -## removeRight - -Returns a new string with the 'suffix' removed, if present. - -```java -removeRight("foobar", "bar") -// result => "foo" -removeRight("foobar", "BAR",false) -// result => "foo" -``` - -## removeSpaces - -Remove all spaces and replace for value. - -```java -removeSpaces("foo bar") -// result => "foobar" -``` - -## repeat - -Returns a repeated string given a multiplier. - -``` -repeat("1", 3) -// result => "111" -``` - -## reverse - -Reverse the input String - -```java -reverse("foo") -// result => "oof" -``` - -## rightPad - -Returns a new string of a given length such that the ending of the string is padded. - -```java -rightPad("1", "0", 5) -// result => "10000" -``` - -## rightTrim - -Remove all spaces on right. - -```java -rightTrim("strman ") -// result => "strman" -``` - -## safeTruncate - -Truncate the string securely, not cutting a word in half. It always returns the last full word. - -```java -safeTruncate("foo bar", 4, ".") -// result => "foo." -safeTruncate("A Javascript string manipulation library.", 16, "...") -// result => "A Javascript..." -``` - -## truncate - -Truncate the unsecured form string, cutting the independent string of required position. - -```java -truncate("A Javascript string manipulation library.", 14, "...") -// result => "A Javascrip..." -``` - -## htmlDecode - -Converts all HTML entities to applicable characters. - -```java -htmlDecode("Ш") -// result => Ш -``` - -## htmlEncode - -Convert all applicable characters to HTML entities. - -```java -htmlEncode("Ш") -// result => "Ш" -``` - -## shuffle - -It returns a string with its characters in random order. - -```java -shuffle("shekhar") -``` - -## slugify - -Convert a String to a slug - -```java -slugify("foo bar") -// result => "foo-bar" -``` - -## transliterate - -Remove all non valid characters. Example: change á => a or ẽ => e. - -```java -transliterate("fóõ bár") -// result => "foo bar" -``` - -## surround - -Surrounds a 'value' with the given 'prefix' and 'suffix'. - -```java -surround("div", "<", ">" -// result => "
s" -``` - -## tail - -```java -tail("foobar") -// result => "oobar" -``` - -## toCamelCase - -Transform to camelCase - -```java -toCamelCase("CamelCase") -// result => "camelCase" -toCamelCase("camel-case") -// result => "camelCase" -``` - -## toStudlyCase - -Transform to StudlyCaps. - -```java -toStudlyCase("hello world") -// result => "HelloWorld" -``` - -## toDecamelize - -Decamelize String - -```java -toDecamelize("helloWorld",null) -// result => "hello world" -``` - -## toKebabCase - -Transform to kebab-case. - -```java -toKebabCase("hello World") -// result => "hello-world" -``` - -## toSnakeCase - -Transform to snake_case. - -```java -toSnakeCase("hello world") -// result => "hello_world" -``` +This library is inspired by [dleitee/strman](https://github.com/dleitee/strman). License ------- diff --git a/build.gradle b/build.gradle index 5baa1f1..7fba771 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,6 @@ plugins { id 'net.researchgate.release' version '2.3.3' + id "net.ltgt.errorprone" version "0.0.10" } group 'com.shekhargulati' @@ -9,6 +10,8 @@ apply plugin: 'maven' apply plugin: 'maven-publish' apply plugin: 'signing' apply plugin: "jacoco" +apply from: rootProject.file('gradle/checkstyle.gradle') +apply plugin: "net.ltgt.errorprone" sourceCompatibility = 1.8 @@ -92,4 +95,4 @@ jacocoTestReport { } } -check.dependsOn jacocoTestReport \ No newline at end of file +check.dependsOn jacocoTestReport diff --git a/changelog.md b/changelog.md new file mode 100644 index 0000000..03f1e28 --- /dev/null +++ b/changelog.md @@ -0,0 +1,63 @@ +# Version 0.3.0 + + +* __Feature required in #73 (#77)__: Added `charsCount` function + + [César Aguilera](mailto:cesar.aguilera.p@gmail.com) - Tue, 9 May 2017 18:16:11 +0530 + + ​ + +* __fixed bug in containsAll (#76)__ + + [wli75](mailto:wli75@illinois.edu) - Tue, 7 Mar 2017 20:09:18 +0530 + + ​ + +* __Resolved #66__: Added `trimEnd` function + + [Shekhar Gulati](mailto:shekhargulati84@gmail.com) - Wed, 24 Aug 2016 15:32:45 +0530 + + ​ + +* __Resolved #65__: Added `trimStart`function + + [Shekhar Gulati](mailto:shekhargulati84@gmail.com) - Wed, 24 Aug 2016 15:02:00 +0530 + + ​ + +* __Resolved #68__: Added `upperFirst` function + + [Shekhar Gulati](mailto:shekhargulati84@gmail.com) - Wed, 24 Aug 2016 14:26:16 +0530 + + ​ + +* __Resolved #69__: Added `words` function + + [Shekhar Gulati](mailto:shekhargulati84@gmail.com) - Wed, 24 Aug 2016 12:56:18 +0530 + + ​ + +* __Resolved#71__: Added `isEnclosedBetween` function + + [Shekhar Gulati](mailto:shekhargulati84@gmail.com) - Wed, 24 Aug 2016 12:11:04 +0530 + + ​ + +* __Resolved #54 and Resolved #59__: Added `capitalize` and `lowerFirst` functions + + [Shekhar Gulati](mailto:shekhargulati84@gmail.com) - Wed, 27 Jul 2016 23:19:41 +0530 + + ​ + +* __Resolved #53__: Added `join` function + + [Shekhar Gulati](mailto:shekhargulati84@gmail.com) - Mon, 25 Jul 2016 15:29:43 +0530 + + ​ + +* __Simplify Maven and Gradle configuration (#70)__ + + [Marcin Zajączkowski](mailto:mszpak@wp.pl) - Tue, 19 Jul 2016 20:58:57 +0530 + + + diff --git a/etc/checkstyle-exclude.xml b/etc/checkstyle-exclude.xml new file mode 100644 index 0000000..533e04f --- /dev/null +++ b/etc/checkstyle-exclude.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/etc/checkstyle.xml b/etc/checkstyle.xml new file mode 100644 index 0000000..d93ff58 --- /dev/null +++ b/etc/checkstyle.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gradle.properties b/gradle.properties index 401ddf4..7890fd8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -version=0.3.0-SNAPSHOT \ No newline at end of file +version= 0.5.0-SNAPSHOT \ No newline at end of file diff --git a/gradle/checkstyle.gradle b/gradle/checkstyle.gradle new file mode 100644 index 0000000..19768d2 --- /dev/null +++ b/gradle/checkstyle.gradle @@ -0,0 +1,10 @@ +apply plugin: 'checkstyle' + +checkstyle { + configFile rootProject.file('etc/checkstyle.xml') + showViolations true +} + +dependencies { + checkstyle 'com.puppycrawl.tools:checkstyle:7.7' +} diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 4e58c1b..1e1ca40 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-3.5-all.zip diff --git a/src/main/java/strman/Strman.java b/src/main/java/strman/Strman.java index fe5fad5..9b1e3c2 100644 --- a/src/main/java/strman/Strman.java +++ b/src/main/java/strman/Strman.java @@ -1,4 +1,3 @@ - /* * * * The MIT License @@ -27,22 +26,26 @@ package strman; +import java.nio.charset.StandardCharsets; import java.util.*; import java.util.function.Predicate; import java.util.function.Supplier; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.IntStream; import java.util.stream.Stream; -import static java.util.stream.Collectors.joining; +import static java.util.function.Function.identity; +import static java.util.stream.Collectors.*; /** * A String manipulation library without any dependencies */ public abstract class Strman { - private static final Predicate NULL_STRING_PREDICATE = str -> str == null; + private static final Predicate NULL_STRING_PREDICATE = Objects::isNull; private static final Supplier NULL_STRING_MSG_SUPPLIER = () -> "'value' should be not null."; + private static final String[] EMPTY_ARRAY = new String[0]; private Strman() { } @@ -87,7 +90,7 @@ public static String appendArray(final String value, final String[] appends) { * @return an Optional String if found else empty */ public static Optional at(final String value, int index) { - if (value == null || value.isEmpty()) { + if (isNullOrEmpty(value)) { return Optional.empty(); } int length = value.length(); @@ -112,7 +115,10 @@ public static String[] between(final String value, final String start, final Str validate(end, NULL_STRING_PREDICATE, () -> "'end' should be not null."); String[] parts = value.split(end); - return Arrays.stream(parts).map(subPart -> subPart.substring(subPart.indexOf(start) + start.length())).toArray(String[]::new); + return Arrays.stream(parts) + .filter(subPart -> subPart.contains(start)) + .map(subPart -> subPart.substring(subPart.indexOf(start) + start.length())) + .toArray(String[]::new); } /** @@ -126,7 +132,6 @@ public static String[] chars(final String value) { return value.split(""); } - /** * Replace consecutive whitespace characters with a single space. * @@ -138,7 +143,6 @@ public static String collapseWhitespace(final String value) { return value.trim().replaceAll("\\s\\s+", " "); } - /** * Verifies that the needle is contained in the value. The search is case insensitive * @@ -175,7 +179,7 @@ public static boolean contains(final String value, final String needle, final bo */ public static boolean containsAll(final String value, final String[] needles) { validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER); - return Arrays.stream(needles).allMatch(needle -> contains(value, needle, true)); + return Arrays.stream(needles).allMatch(needle -> contains(value, needle, false)); } /** @@ -235,9 +239,11 @@ public static long countSubstr(final String value, final String subStr) { * @param allowOverlapping boolean to take into account overlapping * @return count of times substring exists */ - public static long countSubstr(final String value, final String subStr, final boolean caseSensitive, boolean allowOverlapping) { + public static long countSubstr(final String value, final String subStr, final boolean caseSensitive, + boolean allowOverlapping) { validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER); - return countSubstr(caseSensitive ? value : value.toLowerCase(), caseSensitive ? subStr : subStr.toLowerCase(), allowOverlapping, 0L); + return countSubstr(caseSensitive ? value : value.toLowerCase(), caseSensitive ? subStr : subStr.toLowerCase(), + allowOverlapping, 0L); } /** @@ -274,7 +280,8 @@ public static boolean endsWith(final String value, final String search, final bo * @param caseSensitive true or false * @return true or false */ - public static boolean endsWith(final String value, final String search, final int position, final boolean caseSensitive) { + public static boolean endsWith(final String value, final String search, final int position, + final boolean caseSensitive) { validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER); int remainingLength = position - search.length(); if (caseSensitive) { @@ -320,7 +327,7 @@ public static String ensureLeft(final String value, final String prefix, final b */ public static String base64Decode(final String value) { validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER); - return new String(Base64.getDecoder().decode(value)); + return new String(Base64.getDecoder().decode(value), StandardCharsets.UTF_8); } /** @@ -331,7 +338,7 @@ public static String base64Decode(final String value) { */ public static String base64Encode(final String value) { validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER); - return Base64.getEncoder().encodeToString(value.getBytes()); + return Base64.getEncoder().encodeToString(value.getBytes(StandardCharsets.UTF_8)); } /** @@ -405,9 +412,8 @@ public static String ensureRight(final String value, final String suffix, boolea * @param n Number of chars to return * @return The first n chars */ - public static String first(final String value, final int n) { - validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER); - return value.substring(0, n); + public static Optional first(final String value, final int n) { + return Optional.ofNullable(value).filter(v -> !v.isEmpty()).map(v -> v.substring(0, n)); } /** @@ -416,7 +422,7 @@ public static String first(final String value, final int n) { * @param value The input String * @return The first char */ - public static String head(final String value) { + public static Optional head(final String value) { return first(value, 1); } @@ -429,7 +435,7 @@ public static String head(final String value) { */ public static String format(final String value, String... params) { validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER); - Pattern p = Pattern.compile("\\{(\\w+)\\}"); + Pattern p = Pattern.compile("\\{(\\w+)}"); Matcher m = p.matcher(value); String result = value; while (m.find()) { @@ -634,7 +640,8 @@ public static int lastIndexOf(final String value, final String needle, boolean c * @param caseSensitive whether search should be case sensitive * @return Return position of the last occurrence of 'needle'. */ - public static int lastIndexOf(final String value, final String needle, final int offset, final boolean caseSensitive) { + public static int lastIndexOf(final String value, final String needle, final int offset, + final boolean caseSensitive) { validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER); validate(needle, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER); if (caseSensitive) { @@ -769,7 +776,8 @@ public static String removeRight(final String value, final String suffix) { public static String removeRight(final String value, final String suffix, final boolean caseSensitive) { validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER); validate(suffix, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER); - return endsWith(value, suffix, caseSensitive) ? value.substring(0, value.toLowerCase().lastIndexOf(suffix.toLowerCase())) : value; + return endsWith(value, suffix, caseSensitive) ? value + .substring(0, value.toLowerCase().lastIndexOf(suffix.toLowerCase())) : value; } /** @@ -804,13 +812,15 @@ public static String repeat(final String value, final int multiplier) { * @param caseSensitive whether search should be case sensitive or not * @return String replaced with 'newvalue'. */ - public static String replace(final String value, final String search, final String newValue, final boolean caseSensitive) { + public static String replace(final String value, final String search, final String newValue, + final boolean caseSensitive) { validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER); validate(search, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER); if (caseSensitive) { return value.replace(search, newValue); } - return Pattern.compile(search, Pattern.CASE_INSENSITIVE).matcher(value).replaceAll(Matcher.quoteReplacement(newValue)); + return Pattern.compile(search, Pattern.CASE_INSENSITIVE).matcher(value) + .replaceAll(Matcher.quoteReplacement(newValue)); } /** @@ -901,10 +911,22 @@ public static String[] split(final String value, final String regex) { * @return Words Array */ public static String[] words(final String value) { + return words(value, "\\s+"); + } + + /** + * Splits a String to words by delimiter, \s+ by default + * + * @param value The input String + * @param delimiter delimiter for splitting input String + * @return words array + */ + public static String[] words(final String value, final String delimiter) { validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER); - return value.split("\\W+"); + return value.split(delimiter); } + /** * Truncate the unsecured form string, cutting the independent string of required position. * @@ -944,7 +966,8 @@ public static String htmlDecode(final String encodedHtml) { */ public static String htmlEncode(final String html) { validate(html, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER); - return html.chars().mapToObj(c -> "\\u" + String.format("%04x", c).toUpperCase()).map(e -> HtmlEntities.encodedEntities.get(e)).collect(joining()); + return html.chars().mapToObj(c -> "\\u" + String.format("%04x", c).toUpperCase()) + .map(HtmlEntities.encodedEntities::get).collect(joining()); } /** @@ -988,7 +1011,7 @@ public static String slice(final String value, int begin, int end) { public static String slugify(final String value) { validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER); String transliterated = transliterate(collapseWhitespace(value.trim().toLowerCase())); - return Arrays.stream(words(transliterated.replace("&", "-and-"))).collect(joining("-")); + return Arrays.stream(words(transliterated.replace("&", "-and-"), "\\W+")).collect(joining("-")); } /** @@ -1009,7 +1032,6 @@ public static String transliterate(final String value) { return result; } - /** * Surrounds a 'value' with the given 'prefix' and 'suffix'. * @@ -1031,7 +1053,9 @@ public static String surround(final String value, final String prefix, final Str * @return String in camelCase. */ public static String toCamelCase(final String value) { - validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER); + if (value == null || value.length() == 0) { + return ""; + } String str = toStudlyCase(value); return str.substring(0, 1).toLowerCase() + str.substring(1); } @@ -1045,7 +1069,7 @@ public static String toCamelCase(final String value) { public static String toStudlyCase(final String value) { validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER); String[] words = collapseWhitespace(value.trim()).split("\\s*(_|-|\\s)\\s*"); - return Arrays.stream(words).filter(w -> !w.trim().isEmpty()).map(w -> head(w).toUpperCase() + tail(w)).collect(joining()); + return Arrays.stream(words).filter(w -> !w.trim().isEmpty()).map(Strman::upperFirst).collect(joining()); } /** @@ -1054,9 +1078,8 @@ public static String toStudlyCase(final String value) { * @param value The input String * @return String tail */ - public static String tail(final String value) { - validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER); - return last(value, value.length() - 1); + public static Optional tail(final String value) { + return Optional.ofNullable(value).filter(v -> !v.isEmpty()).map(v -> last(v, v.length() - 1)); } /** @@ -1094,8 +1117,7 @@ public static String toSnakeCase(final String value) { public static String decode(final String value, final int digits, final int radix) { validate(value, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER); - return Arrays - .stream(value.split("(?<=\\G.{" + digits + "})")) + return Arrays.stream(value.split("(?<=\\G.{" + digits + "})")) .map(data -> String.valueOf(Character.toChars(Integer.parseInt(data, radix)))) .collect(joining()); } @@ -1105,6 +1127,328 @@ public static String encode(final String value, final int digits, final int radi return value.chars().mapToObj(ch -> leftPad(Integer.toString(ch, radix), "0", digits)).collect(joining()); } + /** + * Join concatenates all the elements of the strings array into a single String. The separator string is placed between elements in the resulting string. + * + * @param strings The input array to concatenate + * @param separator The separator to use + * @return Concatenated String + */ + public static String join(final String[] strings, final String separator) throws IllegalArgumentException { + if (strings == null) { + throw new IllegalArgumentException("Input array 'strings' can't be null"); + } + if (separator == null) { + throw new IllegalArgumentException("separator can't be null"); + } + StringJoiner joiner = new StringJoiner(separator); + for (String el : strings) { + joiner.add(el); + } + return joiner.toString(); + } + + /** + * Converts the first character of string to upper case and the remaining to lower case. + * + * @param input The string to capitalize + * @return The capitalized string + */ + public static String capitalize(final String input) throws IllegalArgumentException { + if (input == null) { + throw new IllegalArgumentException("input can't be null"); + } + if (input.length() == 0) { + return ""; + } + return head(input).map(String::toUpperCase).map(h -> tail(input).map(t -> h + t.toLowerCase()).orElse(h)).get(); + } + + /** + * Converts the first character of string to lower case. + * + * @param input The string to convert + * @return The converted string + */ + public static String lowerFirst(final String input) throws IllegalArgumentException { + if (input == null) { + throw new IllegalArgumentException("input can't be null"); + } + if (input.length() == 0) { + return ""; + } + + return head(input).map(String::toLowerCase).map(h -> tail(input).map(t -> h + t).orElse(h)).get(); + } + + /** + * Verifies whether String is enclosed by encloser + * + * @param input The input String + * @param encloser String which encloses input String + * @return true if enclosed false otherwise + */ + public static boolean isEnclosedBetween(final String input, final String encloser) { + return isEnclosedBetween(input, encloser, encloser); + } + + /** + * Verifies whether String is enclosed by encloser + * + * @param input The input String + * @param leftEncloser String which encloses input String at left start + * @param rightEncloser String which encloses input String at the right end + * @return true if enclosed false otherwise + */ + public static boolean isEnclosedBetween(final String input, final String leftEncloser, String rightEncloser) { + if (input == null) { + throw new IllegalArgumentException("input can't be null"); + } + if (leftEncloser == null) { + throw new IllegalArgumentException("leftEncloser can't be null"); + } + if (rightEncloser == null) { + throw new IllegalArgumentException("rightEncloser can't be null"); + } + return input.startsWith(leftEncloser) && input.endsWith(rightEncloser); + } + + /** + * Converts the first character of string to upper case. + * + * @param input The string to convert. + * @return Returns the converted string. + */ + public static String upperFirst(String input) { + if (input == null) { + throw new IllegalArgumentException("input can't be null"); + } + return head(input).map(String::toUpperCase).map(h -> tail(input).map(t -> h + t).orElse(h)).get(); + } + + /** + * Removes leading whitespace from string. + * + * @param input The string to trim. + * @return Returns the trimmed string. + */ + public static Optional trimStart(final String input) { + return Optional.ofNullable(input).filter(v -> !v.isEmpty()).map(Strman::leftTrim); + } + + /** + * Removes leading characters from string. + * + * @param input The string to trim. + * @param chars The characters to trim. + * @return Returns the trimmed string. + */ + public static Optional trimStart(final String input, String... chars) { + return Optional.ofNullable(input).filter(v -> !v.isEmpty()).map(v -> { + String pattern = String.format("^[%s]+", join(chars, "\\")); + return v.replaceAll(pattern, ""); + }); + } + + /** + * Removes trailing whitespace from string. + * + * @param input The string to trim. + * @return Returns the trimmed string. + */ + public static Optional trimEnd(final String input) { + return Optional.ofNullable(input).filter(v -> !v.isEmpty()).map(Strman::rightTrim); + } + + /** + * Removes trailing characters from string. + * + * @param input The string to trim. + * @param chars The characters to trim. + * @return Returns the trimmed string. + */ + public static Optional trimEnd(final String input, String... chars) { + return Optional.ofNullable(input).filter(v -> !v.isEmpty()).map(v -> { + String pattern = String.format("[%s]+$", join(chars, "\\")); + return v.replaceAll(pattern, ""); + }); + } + + /** + * Counts the number of occurrences of each character in the string + * + * @param input The input string + * @return A map containing the number of occurrences of each character in the string + */ + public static Map charsCount(String input) { + if (isNullOrEmpty(input)) { + return Collections.emptyMap(); + } + + return input.chars().mapToObj(c -> (char) c).collect(groupingBy(identity(), counting())); + } + + /** + * Checks if string is empty. This is a null safe check and will return true when string is null. + * + * @param input The input string + * @return true if input string is null or empty + */ + public static boolean isBlank(String input) { + return input == null || input.isEmpty(); + } + + /** + * Changes passed in string to all lower case and adds underscore between words. + * + * @param input The input string + * @return the input string in all lower case with underscores between words + */ + public static String underscored(final String input) { + if (input == null || input.length() == 0) { + return ""; + } + + return input.trim().replaceAll("([a-z\\d])([A-Z]+)", "$1_$2").replaceAll("[-\\s]+", "_").toLowerCase(); + } + + /** + * Aggregates the contents of n strings into a single list of tuples. + * + * @param inputs A list of strings. + * @return A list of strings if none of the strings in the input is null or empty. + * An empty list otherwise. + */ + public static List zip(String... inputs) { + if (inputs.length == 0) { + return Collections.emptyList(); + } + OptionalInt min = Arrays.stream(inputs).mapToInt(str -> str == null ? 0 : str.length()).min(); + if (!min.isPresent()) { + return Collections.emptyList(); + } + return IntStream.range(0, min.getAsInt()) + .mapToObj(elementIndex -> Arrays.stream(inputs) + .map(input -> String.valueOf(input.charAt(elementIndex))) + .collect(joining())) + .collect(toList()); + } + + /** + * Split lines to an array + * + * @param input The input String + * @return lines in an array + */ + public static String[] lines(String input) { + if (input == null) { + return EMPTY_ARRAY; + } + return input.split("\r\n?|\n"); + } + + /** + * Converts a underscored or camelized string into an dasherized one. + * + * @param input The input String + * @return dasherized String. + */ + public static String dasherize(String input) { + return toKebabCase(input); + } + + /** + * Converts an underscored, camelized, or dasherized string into a humanized one. Also removes beginning and ending whitespace. + * + * @param input The input String + * @return humanized version of String + */ + public static String humanize(final String input) { + if (input == null || input.length() == 0) { + return ""; + } + return upperFirst(underscored(input).replaceAll("_", " ")); + } + + /** + * Returns a copy of the string in which all the case-based characters have had their case swapped. + * + * @param input Input string + * @return String with all the case swapped + */ + public static String swapCase(String input) { + if (input == null || input.length() == 0) { + return ""; + } + StringBuilder resultBuilder = new StringBuilder(); + for (char ch : input.toCharArray()) { + if (Character.isUpperCase(ch)) { + resultBuilder.append(Character.toLowerCase(ch)); + } else { + resultBuilder.append(Character.toUpperCase(ch)); + } + } + return resultBuilder.toString(); + } + + /** + * Returns a string representation of the number passed in where groups of three digits are delimited by comma + * + * @param number Input number + * @return formatted String + */ + public static String formatNumber(long number) { + String stringRepresentation = Long.toString(number); + StringBuilder sb = new StringBuilder(); + int bound = stringRepresentation.length() - 1; + String delimiter = ","; + int counter = 0; + for (int i = bound; i >= 0; i--) { + char c = stringRepresentation.charAt(i); + if (i != bound && counter % 3 == 0) { + sb.append(delimiter); + } + sb.append(c); + counter++; + } + return sb.reverse().toString(); + } + + public static String[] chop(String input, int step) { + if (input == null || input.length() == 0) { + return EMPTY_ARRAY; + } + if (step == 0) { + return new String[]{input}; + } + int strLength = input.length(); + int iterations = strLength % step == 0 ? strLength / step : strLength / step + 1; + return IntStream.iterate(0, i -> i + step) + .limit(iterations) + .mapToObj(i -> input.substring(i, (i + step) < strLength ? i + step : strLength)) + .toArray(String[]::new); + } + + /** + * Converts a String into its Start Case version + * https://en.wikipedia.org/wiki/Letter_case#Stylistic_or_specialised_usage + * + * @param input The input String + * @return Start Case String + */ + public static String startCase(final String input) { + validate(input, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER); + // split into a word when we encounter a space, or an underscore, or a dash, or a switch from lower to upper case + String[] words = words(input, "\\s|_|-|(?<=[a-z])(?=[A-Z])"); + return Arrays.stream(words).filter(w -> !w.trim().isEmpty()) + .map(w -> upperFirst(w.toLowerCase())).collect(joining(" ")); + } + + public static String escapeRegExp(final String input) { + validate(input, NULL_STRING_PREDICATE, NULL_STRING_MSG_SUPPLIER); + return input.replaceAll("[\\\\\\^\\$\\*\\+\\-\\?\\.\\|\\(\\)\\{\\}\\[\\]]", "\\\\$0"); + } + private static void validate(String value, Predicate predicate, final Supplier supplier) { if (predicate.test(value)) { throw new IllegalArgumentException(supplier.get()); @@ -1124,4 +1468,10 @@ private static long countSubstr(String value, String subStr, boolean allowOverla } return countSubstr(value.substring(offset), subStr, allowOverlapping, ++count); } + + private static boolean isNullOrEmpty(String input) { + return input == null || input.isEmpty(); + } + } + diff --git a/src/test/java/strman/StrmanTest.java b/src/test/java/strman/StrmanTests.java similarity index 66% rename from src/test/java/strman/StrmanTest.java rename to src/test/java/strman/StrmanTests.java index be931e4..8ab7ffe 100644 --- a/src/test/java/strman/StrmanTest.java +++ b/src/test/java/strman/StrmanTests.java @@ -26,21 +26,29 @@ package strman; -import org.junit.Test; - import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import java.util.Optional; +import org.junit.Ignore; +import org.junit.Test; + +import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; import static java.util.stream.Collectors.toList; import static org.hamcrest.CoreMatchers.*; +import static org.hamcrest.collection.IsArrayContaining.hasItemInArray; import static org.hamcrest.collection.IsArrayContainingInOrder.arrayContaining; +import static org.hamcrest.collection.IsArrayWithSize.arrayWithSize; import static org.hamcrest.collection.IsArrayWithSize.emptyArray; +import static org.hamcrest.collection.IsEmptyCollection.empty; import static org.junit.Assert.*; import static strman.Strman.*; import static strman.Strman.endsWith; -import static strman.Strman.format; -public class StrmanTest { +public class StrmanTests { @Test public void append_shouldAppendStringsToEndOfValue() throws Exception { @@ -84,9 +92,9 @@ public void between_shouldReturnArrayWithStringsBetweenStartAndEnd() throws Exce } @Test - public void between_shouldReturnFullStringWhenStartAndEndDoesNotExist() throws Exception { - assertThat(between("[abc][def]", "{", "}"), arrayContaining("[abc][def]")); - assertThat(between("", "{", "}"), arrayContaining("")); + public void between_shouldReturnEmptyArrayWhenStartAndEndDoesNotExist() throws Exception { + assertThat(between("[abc][def]", "{", "}").length, equalTo(0)); + assertThat(between("", "{", "}").length, equalTo(0)); } @Test @@ -344,7 +352,7 @@ public void first_shouldReturnFirstThreeCharsOfString() throws Exception { final String[] fixture = { "foo", "foobar" }; - Arrays.stream(fixture).forEach(el -> assertThat(first(el, 3), equalTo("foo"))); + Arrays.stream(fixture).forEach(el -> assertThat(first(el, 3), equalTo(Optional.of("foo")))); } @Test @@ -353,7 +361,7 @@ public void head_shouldReturnFirstCharOfString() throws Exception { "foo", "foobar" }; - Arrays.stream(fixture).forEach(el -> assertThat(head(el), equalTo("f"))); + Arrays.stream(fixture).forEach(el -> assertThat(head(el), equalTo(Optional.of("f")))); } @Test @@ -410,9 +418,9 @@ public void indexOf_shouldBeTrueWhenNeedleExistCaseSensitive() throws Exception @Test public void inequal_shouldTestInequalityOfStrings() throws Exception { - assertThat(inequal("a", "b"), equalTo(true)); - assertThat(inequal("a", "a"), equalTo(false)); - assertThat(inequal("0", "1"), equalTo(true)); + assertThat(unequal("a", "b"), equalTo(true)); + assertThat(unequal("a", "a"), equalTo(false)); + assertThat(unequal("0", "1"), equalTo(true)); } @Test @@ -800,7 +808,8 @@ public void toKebabCase_shouldKebabCaseAString() throws Exception { " de_camelize" }; - Arrays.stream(fixture).forEach(el -> assertThat(String.format("toKebabCase(%s) should be de-camelize", el), toKebabCase(el), equalTo("de-camelize"))); + Arrays.stream(fixture).forEach(el -> + assertThat(String.format("toKebabCase(%s) should be de-camelize", el), toKebabCase(el), equalTo("de-camelize"))); } @Test @@ -820,6 +829,18 @@ public void toSnakeCase_shouldSnakeCaseAString() throws Exception { Arrays.stream(fixture).forEach(el -> assertThat(String.format("toSnakeCase(%s) should be de_camelize", el), toSnakeCase(el), equalTo("de_camelize"))); } + @Test + public void snakeCase_shouldConvertAStringToSnakecase() throws Exception { + String[] input = { + "Foo Bar", + "fooBar" + }; + + Arrays.stream(input).forEach(el -> + assertThat(String.format("%s should be foo_bar", el), toSnakeCase(el), is(equalTo("foo_bar")))); + + } + @Test public void unequal_shouldTestInequalityOfStrings() throws Exception { assertThat(unequal("a", "b"), equalTo(true)); @@ -845,4 +866,376 @@ public void removeRight_shouldNotLowercaseWhenCaseInsensitive() throws Exception String result = removeRight("Remove the END at the end", " END", false); assertThat(result, is("Remove the END at the")); } -} \ No newline at end of file + + @Test + public void transliterate_shouldDeburrTheString() throws Exception { + String result = transliterate("déjà vu"); + assertThat(result, is(equalTo("deja vu"))); + } + + @Ignore + public void htmlEncode_shouldConvertCharactersToTheirHtmlEntities() throws Exception { + String result = htmlEncode("fred, barney, & pebbles"); + assertThat(result, is(equalTo("fred, barney, & pebbles"))); + } + + @Test + public void kebabCase_shouldConvertAStringToKebabCase() throws Exception { + String[] input = { + "Foo Bar", + "fooBar" + }; + + Arrays.stream(input).forEach(el -> + assertThat(String.format("%s should be foo-bar", el), toKebabCase(el), is(equalTo("foo-bar")))); + + } + + @Test + public void join_shouldJoinArrayOfStringIntoASingleString() throws Exception { + String[] strings = { + "hello", + "world", + "123" + }; + assertThat(join(strings, ";"), is(equalTo("hello;world;123"))); + } + + @Test(expected = IllegalArgumentException.class) + public void join_shouldThrowIllegalArgumentExceptionWhenSeparatorIsNull() throws Exception { + String[] strings = { + "hello", + "world", + "123" + }; + + join(strings, null); + } + + @Test + public void join_shouldReturnEmptyStringWhenInputArrayIsEmpty() throws Exception { + String[] emptyArray = {}; + assertThat(join(emptyArray, ","), is(equalTo(""))); + } + + @Test + public void capitalize_shouldCapitalizeFirstCharacterOfString() throws Exception { + String[] strings = { + "FRED", + "fRED", + "fred" + }; + Arrays.stream(strings).forEach(el -> assertThat(String.format("%s should be Fred", el), capitalize(el), equalTo("Fred"))); + } + + @Test + public void lowerFirst_shouldLowercasedFirstCharacterOfString() throws Exception { + assertThat(lowerFirst("FRED"), is(equalTo("fRED"))); + assertThat(lowerFirst("fred"), is(equalTo("fred"))); + assertThat(lowerFirst("Fred"), is(equalTo("fred"))); + } + + @Test + public void isEnclosedBetween_shouldChekcWhetherStringIsEnclosed() throws Exception { + assertThat(isEnclosedBetween("{{shekhar}}", "{{", "}}"), is(true)); + assertThat(isEnclosedBetween("shekhar", "{{", "}}"), is(false)); + assertThat(isEnclosedBetween("*shekhar*", "*"), is(true)); + assertThat(isEnclosedBetween("shekhar", "*"), is(false)); + } + + @Test(expected = IllegalArgumentException.class) + public void isEnclosedBetween_shouldThrowIllegalArgumentExceptionWhenEncloserIsNull() throws Exception { + assertThat(isEnclosedBetween("shekhar", null), is(false)); + } + + @Test + public void words_shouldConvertTextToWords() throws Exception { + final String line = "This is a string, with words!"; + assertThat(words(line), arrayContaining("This", "is", "a", "string,", "with", "words!")); + } + + @Test + public void upperFirst_shouldConvertFirstCharToUpperCase() throws Exception { + assertThat(upperFirst("fred"), is("Fred")); + } + + @Test + public void upperFirst_shouldReturnSameStringIfFirstCharIsUpperCase() throws Exception { + assertThat(upperFirst("FRED"), is("FRED")); + } + + @Test + public void trimStart_shouldRemoveAllWhitespaceAtStart() throws Exception { + assertThat(trimStart(" abc "), is(Optional.of("abc "))); + assertThat(trimStart("abc "), is(Optional.of("abc "))); + assertThat(trimStart("abc"), is(Optional.of("abc"))); + assertThat(trimStart(""), is(Optional.empty())); + assertThat(trimStart(null), is(Optional.empty())); + } + + @Test + public void trimStart_shouldRemoveSpecialCharactersAtStart() throws Exception { + assertThat(trimStart("-_-abc-_-", "_", "-"), is(Optional.of("abc-_-"))); + assertThat(trimStart("-_-!abc-_-", "_", "-", "!"), is(Optional.of("abc-_-"))); + assertThat(trimStart("-_-#abc-_-", "_", "-", "!", "#"), is(Optional.of("abc-_-"))); + } + + @Test + public void trimEnd_shouldRemoveAllTrailingWhitespace() throws Exception { + assertThat(trimEnd(" abc "), is(Optional.of(" abc"))); + assertThat(trimEnd("abc "), is(Optional.of("abc"))); + assertThat(trimEnd("abc"), is(Optional.of("abc"))); + assertThat(trimEnd(""), is(Optional.empty())); + assertThat(trimEnd(null), is(Optional.empty())); + } + + @Test + public void trimEnd_shouldRemoveAllTrailingSpecialCharacters() throws Exception { + assertThat(trimEnd("-_-abc-_-", "_", "-"), is(Optional.of("-_-abc"))); + assertThat(trimEnd("-_-abc!-_-", "_", "-", "!"), is(Optional.of("-_-abc"))); + assertThat(trimEnd("-_-abc#-_-", "_", "-", "!", "#"), is(Optional.of("-_-abc"))); + } + + + @Test + public void charsCount_shouldReturnEmptyWhenInputStringIsNull() { + assertThat(charsCount(null), equalTo(Collections.emptyMap())); + } + + @Test + public void charsCount_shouldReturnEmptyWhenInputStringIsEmpty() { + assertThat(charsCount(""), equalTo(Collections.emptyMap())); + } + + @Test + public void charsCount_shouldReturnCharsCountWhenInputIsASimpleString() { + Map expectedOutput = new HashMap() {{ + put('a', 1L); + put('b', 1L); + put('c', 1L); + }}; + + assertThat(charsCount("abc"), equalTo(expectedOutput)); + } + + @Test + public void charsCount_shouldReturnCharsCountWhenInputIsAComplexString() { + Map expectedOutput = new HashMap() {{ + put('a', 1L); + put('b', 2L); + put('c', 3L); + + put('A', 1L); + put('B', 2L); + put('C', 3L); + put('-', 10L); + }}; + + assertThat(charsCount("-----abbcccCCCBBA-----"), equalTo(expectedOutput)); + } + + @Test + public void isBlank_shouldReturnTrueIfNull() { + assertTrue(isBlank(null)); + } + + @Test + public void isBlank_shouldReturnTrueIfEmpty() { + assertTrue(isBlank("")); + } + + @Test + public void isBlank_shouldReturnFalseIfNotEmpty() { + assertFalse(isBlank("ac")); + } + + @Test + public void underscored_shouldReturnUnderscoredString() { + assertThat(underscored("MozTransform"), equalTo("moz_transform")); + } + + @Test + public void underscored_shouldReturnEmptyStringIfEmptyStringPassedIn() { + assertThat(underscored(""), equalTo("")); + } + + @Test + public void underscored_shouldReturnNullIfNullPassedIn() { + assertThat(underscored(null), equalTo("")); + } + + @Test + public void underscored_shouldUnderscoreInputString() throws Exception { +// assertThat(underscored("foo-bar-baz"), equalTo("foo_bar_baz")); + assertThat(underscored("fooBarBaz"), equalTo("foo_bar_baz")); +// assertThat(underscored("FooBarBaz"), equalTo("foo_bar_baz")); +// assertThat(underscored(" foo bar baz "), equalTo("foo_bar_baz")); + } + + @Test + public void zip_shouldReturnEmptyList_whenNullOrEmptyIsPassedIn() { + assertThat(zip("a", null), is(empty())); + assertThat(zip("", "a"), is(empty())); + } + + @Test + public void zip_shouldReturnListOfOneElement_forSimplestValidInput() { + assertThat(zip("a", "b"), equalTo(asList("ab"))); + } + + @Test + public void zip_shouldReturnExpectedListOfPairs_whenBothInputsHaveSameSize() { + assertThat(zip("abc", "def"), equalTo(asList("ad", "be", "cf"))); + assertThat(zip("ABC", "DEF"), equalTo(asList("AD", "BE", "CF"))); + } + + @Test + public void zip_shouldReturnExpectedListOfPairs_whenFirstInputIsBiggerThanSecond() { + assertThat(zip("abc", "d"), equalTo(asList("ad"))); + assertThat(zip("ABCDE", "FGH"), equalTo(asList("AF", "BG", "CH"))); + } + + @Test + public void zip_shouldReturnExpectedListOfPairs_whenSecondInputIsBiggerThanFirst() { + assertThat(zip("d", "abc"), equalTo(asList("da"))); + assertThat(zip("FGH", "ABCDE"), equalTo(asList("FA", "GB", "HC"))); + } + + @Test + public void zip_shouldReturnExpectedListOfTriplets_whenThreeInputs() { + assertThat(zip("abc", "def", "ghi"), equalTo(asList("adg", "beh", "cfi"))); + } + + @Test + public void zip_shouldReturnExpectedListOfTuples_whenMoreThanThreeInputs() { + assertThat(zip("abc", "def", "ghi", "123"), equalTo(asList("adg1", "beh2", "cfi3"))); + } + + @Test + public void zip_shouldReturnEmptyList_whenNotEnoughInputs() { + assertThat(zip(), is(empty())); + } + + @Test + public void zip_shouldReturnInputInListForm_whenOnlyOneInput() { + assertThat(zip("zip"), is(equalTo(asList("z", "i", "p")))); + assertThat(zip("z"), is(equalTo(singletonList("z")))); + } + + @Test + public void lines_shouldReturnEmptyArrayWhenInputIsNull() throws Exception { + assertThat(lines(null), emptyArray()); + } + + @Test + public void lines_shouldReturnArrayWithOneEmptyElementWhenInputIsEmptyString() throws Exception { + assertThat(lines(""), arrayWithSize(1)); + assertThat(lines(""), hasItemInArray("")); + } + + @Test + public void lines_shouldSplitToLines() throws Exception { + assertThat(lines("Hello\r\nWorld").length, equalTo(2)); + assertThat(lines("Hello\rWorld").length, equalTo(2)); + assertThat(lines("Hello World").length, equalTo(1)); + assertThat(lines("\r\n\n\r ").length, equalTo(4)); + assertThat(lines("Hello\r\r\nWorld").length, equalTo(3)); + assertThat(lines("Hello\r\rWorld").length, equalTo(3)); + } + + @Test + public void humanize_shouldHumanizeStrings() throws Exception { + assertThat(humanize("the_humanize_method"), equalTo("The humanize method")); + assertThat(humanize("ThehumanizeMethod"), equalTo("Thehumanize method")); + assertThat(humanize("ThehumanizeMethod"), equalTo("Thehumanize method")); + assertThat(humanize("the humanize method"), equalTo("The humanize method")); + assertThat(humanize("the humanize_id method_id"), equalTo("The humanize id method id")); + assertThat(humanize("the humanize method "), equalTo("The humanize method")); + assertThat(humanize(" capitalize dash-CamelCase_underscore trim "), equalTo("Capitalize dash camel case underscore trim")); + assertThat(humanize(""), equalTo("")); + assertThat(humanize(null), equalTo("")); + } + + @Test + public void dasherize_shouldDasherizeInputString() throws Exception { + assertThat(dasherize("the_dasherize_string_method"), equalTo("the-dasherize-string-method")); + assertThat(dasherize("TheDasherizeStringMethod"), equalTo("the-dasherize-string-method")); + assertThat(dasherize("thisIsATest"), equalTo("this-is-a-test")); + assertThat(dasherize("this Is A Test"), equalTo("this-is-a-test")); + assertThat(dasherize("thisIsATest123"), equalTo("this-is-a-test123")); + assertThat(dasherize("123thisIsATest"), equalTo("123this-is-a-test")); + assertThat(dasherize("the dasherize string method"), equalTo("the-dasherize-string-method")); + assertThat(dasherize("the dasherize string method "), equalTo("the-dasherize-string-method")); + assertThat(dasherize("input with a-dash"), equalTo("input-with-a-dash")); + assertThat(dasherize(""), equalTo("")); + assertThat(dasherize(null), equalTo("")); + } + + @Test + public void swapCase_shouldSwapCaseOfCharacters() throws Exception { + assertThat(swapCase("AaBbCcDdEe"), equalTo("aAbBcCdDeE")); + assertThat(swapCase("Hello World"), equalTo("hELLO wORLD")); + assertThat(swapCase(""), equalTo("")); + assertThat(swapCase(null), equalTo("")); + } + + @Test + public void chop_shouldChopStringByStep() throws Exception { + assertThat(chop(null, 2).length, equalTo(0)); + assertThat(chop("whitespace", 2).length, equalTo(5)); + assertThat(chop("whitespace", 3).length, equalTo(4)); + assertThat(chop("whitespace", 0)[0].length(), equalTo(10)); + } + + @Test + public void formatNumber_shouldFormatNumberWithCommaDelimiter() throws Exception { + assertThat(formatNumber(1000), equalTo("1,000")); + assertThat(formatNumber(100000), equalTo("100,000")); + assertThat(formatNumber(10000000), equalTo("10,000,000")); + assertThat(formatNumber(100000000), equalTo("100,000,000")); + } + + @Test(expected = IllegalArgumentException.class) + public void startCase_shouldThrowException() throws Exception { + startCase(null); + } + + @Test + public void startCase_shouldStartCaseInputString() throws Exception { + assertThat(startCase(""), equalTo("")); + assertThat(startCase("ALL CAPS"), equalTo("All Caps")); + assertThat(startCase("camelCase"), equalTo("Camel Case")); + assertThat(startCase("kebab-case"), equalTo("Kebab Case")); + assertThat(startCase("Snake_case"), equalTo("Snake Case")); + assertThat(startCase(" spaces "), equalTo("Spaces")); + assertThat(startCase("spaces between words"), equalTo("Spaces Between Words")); + assertThat(startCase("--dashes--"), equalTo("Dashes")); + assertThat(startCase("dashes----between----words"), equalTo("Dashes Between Words")); + } + + @Test(expected = IllegalArgumentException.class) + public void escapeRegExp_shouldThrowException() throws Exception { + escapeRegExp(null); + } + + @Test + public void escapeRegExp_shouldEscapeRegExp() throws Exception { + assertThat(escapeRegExp("\\"), equalTo("\\\\")); + assertThat(escapeRegExp("^"), equalTo("\\^")); + assertThat(escapeRegExp("$"), equalTo("\\$")); + assertThat(escapeRegExp("*"), equalTo("\\*")); + assertThat(escapeRegExp("+"), equalTo("\\+")); + assertThat(escapeRegExp("-"), equalTo("\\-")); + assertThat(escapeRegExp("?"), equalTo("\\?")); + assertThat(escapeRegExp("."), equalTo("\\.")); + assertThat(escapeRegExp("|"), equalTo("\\|")); + assertThat(escapeRegExp("("), equalTo("\\(")); + assertThat(escapeRegExp(")"), equalTo("\\)")); + assertThat(escapeRegExp("{"), equalTo("\\{")); + assertThat(escapeRegExp("}"), equalTo("\\}")); + assertThat(escapeRegExp("["), equalTo("\\[")); + assertThat(escapeRegExp("]"), equalTo("\\]")); + assertThat(escapeRegExp("How much is (2+3)? 5"), equalTo("How much is \\(2\\+3\\)\\? 5")); + assertThat(escapeRegExp("\\s|_|-|(?<=[a-z])(?=[A-Z])"), equalTo("\\\\s\\|_\\|\\-\\|\\(\\?<=\\[a\\-z\\]\\)\\(\\?=\\[A\\-Z\\]\\)")); + } +}