diff --git a/src/main/java/net/andreinc/mockneat/abstraction/MockUnitChar.java b/src/main/java/net/andreinc/mockneat/abstraction/MockUnitChar.java new file mode 100644 index 0000000..1949e70 --- /dev/null +++ b/src/main/java/net/andreinc/mockneat/abstraction/MockUnitChar.java @@ -0,0 +1,45 @@ +package net.andreinc.mockneat.abstraction; + +import java.util.function.Supplier; + +import static net.andreinc.mockneat.utils.ValidationUtils.*; + +public interface MockUnitChar extends MockUnit { + + /** + *

Transforms an existing {@code MockUnitChar} into a {@code MockUnitString}.

+ * + *

The chars in the string will be generated using the {@code MockUnitChar} supplier + * and length of string will be generated using the {@code MockUnitInt}.

+ * + * @param lengthUnit The length of the String + * @return A new {@code MockUnitString} + */ + default MockUnitString string(MockUnitInt lengthUnit) { + notNull(lengthUnit, "lengthUnit"); + Supplier supp = () -> { + int length = lengthUnit.get(); + isTrue(length >= 0, SIZE_BIGGER_THAN_ZERO); + return stream().get() + .limit(length) + .reduce(new StringBuilder(length), StringBuilder::append, StringBuilder::append) + .toString(); + }; + return () -> supp; + } + + /** + *

Transforms an existing {@code MockUnitChar} into a {@code MockUnitString}.

+ * + *

The chars in the string will be generated using the {@code MockUnitChar} supplier + * and length of string will be generated using the {@code MockUnitInt}.

+ * + * @param length The length of the String + * @return A new {@code MockUnitString} + */ + default MockUnitString string(int length) { + isTrue(length >= 0, SIZE_BIGGER_THAN_ZERO); + return string(() -> () -> length); + } + +} diff --git a/src/main/java/net/andreinc/mockneat/unit/financial/CVVS.java b/src/main/java/net/andreinc/mockneat/unit/financial/CVVS.java index 006acb2..46db69c 100644 --- a/src/main/java/net/andreinc/mockneat/unit/financial/CVVS.java +++ b/src/main/java/net/andreinc/mockneat/unit/financial/CVVS.java @@ -4,7 +4,6 @@ import net.andreinc.mockneat.abstraction.MockUnitBase; import net.andreinc.mockneat.abstraction.MockUnitString; import net.andreinc.mockneat.types.enums.CVVType; -import net.andreinc.mockneat.utils.LoopsUtils; import java.util.function.Supplier; @@ -61,13 +60,7 @@ public MockUnitString cvv4() { */ public MockUnitString type(CVVType type) { notNull(type, "type"); - Supplier supplier = () -> { - final StringBuilder builder = new StringBuilder(); - LoopsUtils.loop(type.getLength(), () -> - builder.append(mockNeat.chars().digits().val())); - return builder.toString(); - }; - return () -> supplier; + return mockNeat.chars().digits().string(type.getLength()); } /** diff --git a/src/main/java/net/andreinc/mockneat/unit/types/Chars.java b/src/main/java/net/andreinc/mockneat/unit/types/Chars.java index 9fa6060..b31dc10 100644 --- a/src/main/java/net/andreinc/mockneat/unit/types/Chars.java +++ b/src/main/java/net/andreinc/mockneat/unit/types/Chars.java @@ -2,7 +2,7 @@ import net.andreinc.mockneat.MockNeat; import net.andreinc.mockneat.abstraction.MockUnitBase; -import net.andreinc.mockneat.abstraction.MockUnit; +import net.andreinc.mockneat.abstraction.MockUnitChar; import net.andreinc.mockneat.types.enums.CharsType; import java.util.function.Supplier; @@ -10,14 +10,14 @@ import static net.andreinc.mockneat.alphabets.Alphabets.*; import static net.andreinc.mockneat.utils.ValidationUtils.*; -public class Chars extends MockUnitBase implements MockUnit { +public class Chars extends MockUnitBase implements MockUnitChar { /** *

Returns a {@code Chars} object that can be used to generate arbitrary {@code Character} values.

* *

Note: Without any additional constraint, the {@code Chars} object will generate alphanumeric characters.

* - * @return A re-usable {@code Chars} instance. The class implements {@code MockUnit}. + * @return A re-usable {@code Chars} instance. The class implements {@code MockUnitChar}. */ public static Chars chars() { return MockNeat.threadLocal().chars(); @@ -41,66 +41,66 @@ public Supplier supplier() { /** - *

Returns a new {@code MockUnit} that is used to generate arbitrary {@code Character} values. The generated characters are digits.

+ *

Returns a new {@code MockUnitChar} that is used to generate arbitrary {@code Character} values. The generated characters are digits.

* - * @return A new {@code MockUnit} that generates digits characters (Eg.: '0', '1', etc.) + * @return A new {@code MockUnitChar} that generates digits characters (Eg.: '0', '1', etc.) */ - public MockUnit digits() { - return mockNeat.from(DIGITS); + public MockUnitChar digits() { + return mockNeat.from(DIGITS)::supplier; } /** - *

Returns a new {@code MockUnit} that is used to generate arbitrary {@code Character} values. The generated characters are lower-case letters.

+ *

Returns a new {@code MockUnitChar} that is used to generate arbitrary {@code Character} values. The generated characters are lower-case letters.

* - * @return A new {@code MockUnit} that generates lower-letter characters (Eg.: 'a', 'z', etc.) + * @return A new {@code MockUnitChar} that generates lower-letter characters (Eg.: 'a', 'z', etc.) */ - public MockUnit lowerLetters() { - return mockNeat.from(LETTERS_LOWERCASE); + public MockUnitChar lowerLetters() { + return mockNeat.from(LETTERS_LOWERCASE)::supplier; } /** - *

Returns a new {@code MockUnit} that is used to generate arbitrary {@code Character} values. The generated characters are upper-case letters.

+ *

Returns a new {@code MockUnitChar} that is used to generate arbitrary {@code Character} values. The generated characters are upper-case letters.

* - * @return A new {@code MockUnit} that generate lower-letters characters (Eg.: 'A', 'J', etc.) + * @return A new {@code MockUnitChar} that generate lower-letters characters (Eg.: 'A', 'J', etc.) */ - public MockUnit upperLetters() { - return mockNeat.from(LETTERS_UPPERCASE); + public MockUnitChar upperLetters() { + return mockNeat.from(LETTERS_UPPERCASE)::supplier; } /** - *

Returns a new {@code MockUnit} that is used to generate arbitrary {@code Character} values. The generated values are letters.

+ *

Returns a new {@code MockUnitChar} that is used to generate arbitrary {@code Character} values. The generated values are letters.

* *

Note: The generated values are both lower-case and uppercase.

* - * @return A new {@code MockUnit} that generate letters characters (Eg.: 'a', 'X', etc.) + * @return A new {@code MockUnitChar} that generate letters characters (Eg.: 'a', 'X', etc.) */ - public MockUnit letters() { - return mockNeat.from(LETTERS); + public MockUnitChar letters() { + return mockNeat.from(LETTERS)::supplier; } /** - *

Returns a new {@code MockUnit} that is used to generate arbitrary {@code Character} values. The generated values are HEXA-characters.

+ *

Returns a new {@code MockUnitChar} that is used to generate arbitrary {@code Character} values. The generated values are HEXA-characters.

* *

Note: By HEXA-characters we mean: {@code {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9","a", "b", "c", "d", "e", "f"}}

* - * @return A new {@code MockUnit} that generated HEXA-characters. + * @return A new {@code MockUnitChar} that generated HEXA-characters. */ - public MockUnit hex() { return mockNeat.from(HEXA); } + public MockUnitChar hex() { return mockNeat.from(HEXA)::supplier; } /** - *

Returns a new {@code MockUnit} that is used to generate arbitrary {@code Character} values. The generated values are alphanumeric. The ' ' (space) character is not included.

+ *

Returns a new {@code MockUnitChar} that is used to generate arbitrary {@code Character} values. The generated values are alphanumeric. The ' ' (space) character is not included.

* - * @return A new {@code MockUnit} that generate alpha-numeric characters. + * @return A new {@code MockUnitChar} that generate alpha-numeric characters. */ - public MockUnit alphaNumeric() { return mockNeat.from(ALPHA_NUMERIC); } + public MockUnitChar alphaNumeric() { return mockNeat.from(ALPHA_NUMERIC)::supplier; } /** - *

Returns a new {@code MockUnit} that is used to generate arbitrary {@code Character} values. The generated characters match the supplied type: {@link CharsType}

+ *

Returns a new {@code MockUnitChar} that is used to generate arbitrary {@code Character} values. The generated characters match the supplied type: {@link CharsType}

* * @param type The type of the characters. - * @return A new {@code MockUnit} that generates {@code Character} values of the given {@code type}. + * @return A new {@code MockUnitChar} that generates {@code Character} values of the given {@code type}. */ - public MockUnit type(CharsType type) { + public MockUnitChar type(CharsType type) { notNull(type, "type"); switch (type) { case DIGITS: return digits(); @@ -114,12 +114,12 @@ public MockUnit type(CharsType type) { } /** - *

Returns a new {@code MockUnit} that is used to generate arbitrary {@code Character} values. The generated characters match one of the supplied types: {@link CharsType}

+ *

Returns a new {@code MockUnitChar} that is used to generate arbitrary {@code Character} values. The generated characters match one of the supplied types: {@link CharsType}

* * @param types A var-arg array of types. Everything you call {@code val()} on the {@code MockUnit} a new character is generated matching one of the types. - * @return A new {@code MockUnit} that generates {@code Character} values of the given type(s). + * @return A new {@code MockUnitChar} that generates {@code Character} values of the given type(s). */ - public MockUnit types(CharsType... types) { + public MockUnitChar types(CharsType... types) { notEmptyOrNullValues(types, "types"); Supplier supplier = () -> { CharsType type = mockNeat.from(types).val(); @@ -129,27 +129,23 @@ public MockUnit types(CharsType... types) { } /** - *

Creates a new {@code MockUnit} that is used to generate arbitrary characters contained in the {@code alphabet}.

+ *

Creates a new {@code MockUnitChar} that is used to generate arbitrary characters contained in the {@code alphabet}.

* * @param alphabet The {@code alphabet} from where the characters are randomly picked. - * @return A new {@code MockUnit} that generates {@code Character} values from the given {@code alphabet}. + * @return A new {@code MockUnitChar} that generates {@code Character} values from the given {@code alphabet}. */ - public MockUnit from(String alphabet) { + public MockUnitChar from(String alphabet) { notEmpty(alphabet, "alphabet"); - Supplier supp = () -> { - int idx = mockNeat.getRandom().nextInt(alphabet.length()); - return alphabet.charAt(idx); - }; - return () -> supp; + return from(alphabet.toCharArray()); } /** - *

Creates a new {@code MockUnit} that is used to generate arbitrary characters contained in the {@code alphabet}.

+ *

Creates a new {@code MockUnitChar} that is used to generate arbitrary characters contained in the {@code alphabet}.

* * @param alphabet The {@code alphabet} from where the characters are randomly picked. - * @return A new {@code MockUnit} that generates {@code Character} values from the given {@code alphabet}. + * @return A new {@code MockUnitChar} that generates {@code Character} values from the given {@code alphabet}. */ - public MockUnit from(char[] alphabet) { + public MockUnitChar from(char[] alphabet) { notEmpty(alphabet, "alphabet"); Supplier supp = () -> { int idx = mockNeat.getRandom().nextInt(alphabet.length); diff --git a/src/test/java/net/andreinc/mockneat/unit/types/CharsTest.java b/src/test/java/net/andreinc/mockneat/unit/types/CharsTest.java index f211863..5454cb5 100644 --- a/src/test/java/net/andreinc/mockneat/unit/types/CharsTest.java +++ b/src/test/java/net/andreinc/mockneat/unit/types/CharsTest.java @@ -1,7 +1,5 @@ package net.andreinc.mockneat.unit.types; -import net.andreinc.mockneat.Constants; -import org.junit.Assert; import org.junit.Test; import java.util.HashSet; @@ -10,74 +8,134 @@ import java.util.function.Supplier; import static java.util.Arrays.stream; +import static net.andreinc.mockneat.Constants.*; import static net.andreinc.mockneat.alphabets.Alphabets.*; import static net.andreinc.mockneat.utils.LoopsUtils.loop; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; public class CharsTest { protected void inAlpabet(List alphabet, Supplier charSuppl) { Set possibleDigits = new HashSet<>(alphabet); - loop(Constants.CHARS_CYCLES, () -> { + loop(CHARS_CYCLES, () -> { char c = charSuppl.get(); - Assert.assertTrue(possibleDigits.contains(c)); + assertTrue(possibleDigits.contains(c)); }); } @Test public void testAlphaNumeric() { - stream(Constants.MOCKS).forEach(rand -> + stream(MOCKS).forEach(rand -> inAlpabet(ALPHA_NUMERIC, rand.chars()::val)); } @Test public void testDigits() { - stream(Constants.MOCKS).forEach(rand -> + stream(MOCKS).forEach(rand -> inAlpabet(DIGITS, rand.chars().digits()::val)); } @Test public void testLowerLetters() { - stream(Constants.MOCKS).forEach(rand -> + stream(MOCKS).forEach(rand -> inAlpabet(LETTERS_LOWERCASE, rand.chars().lowerLetters()::val)); } @Test public void testUpperLetters() { - stream(Constants.MOCKS).forEach(rand -> + stream(MOCKS).forEach(rand -> inAlpabet(LETTERS_UPPERCASE, rand.chars().upperLetters()::val)); } @Test public void testLetters() { - stream(Constants.MOCKS).forEach(rand -> + stream(MOCKS).forEach(rand -> inAlpabet(LETTERS, rand.chars().letters()::val)); } @Test public void testHexa() { - stream(Constants.MOCKS).forEach(rand -> + stream(MOCKS).forEach(rand -> inAlpabet(HEXA, rand.chars().hex()::val)); } @Test(expected = IllegalArgumentException.class) public void testFromStringEmptyAlphabet() { String alphabet = ""; - Constants.M.chars().from(alphabet).val(); + M.chars().from(alphabet).val(); } @Test(expected = NullPointerException.class) public void testFromStringNullAlphabet() { - Constants.M.chars().from((String) null).val(); + M.chars().from((String) null).val(); } @Test(expected = IllegalArgumentException.class) public void testFromArrayEmpty() { char[] alphabet = {}; - Constants.M.chars().from(alphabet).val(); + M.chars().from(alphabet).val(); } @Test(expected = NullPointerException.class) public void testFromArrayNull() { - Constants.M.chars().from((char[]) null).val(); + M.chars().from((char[]) null).val(); } + + private static final char[] ALPHABET = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'a', 'b', 'c', 'd', 'e', 'f', '*'}; + + @Test(expected = NullPointerException.class) + public void testStringNullLength() { + M.chars().from(ALPHABET) + .string(null); + } + + @Test(expected = IllegalArgumentException.class) + public void testStringNegativeLength1() { + int length = -1; + M.chars().from(ALPHABET) + .string(length); + } + + @Test(expected = IllegalArgumentException.class) + public void testStringNegativeLength2() { + int length = -1; + M.chars().from(ALPHABET) + .string(M.fromInts(new int[]{length})) + .val(); + } + + @Test + public void testStringZeroLength1() { + int length = 0; + loop(1, + MOCKS, + m -> m.chars().from(ALPHABET) + .string(length) + .val(), + v -> assertEquals(length, v.length())); + } + + @Test + public void testStringZeroLength2() { + int length = 0; + loop(1, + MOCKS, + m -> m.chars().from(ALPHABET) + .string(M.fromInts(new int[]{length})) + .val(), + v -> assertEquals(length, v.length())); + } + + @Test + public void testString() { + loop(MOCK_CYCLES, + MOCKS, + m -> m.chars().from(ALPHABET) + .string(m.ints().range(1, 10)) + .val(), + v -> assertTrue(1 <= v.length() && v.length() < 10) + ); + } + }