Skip to content

Commit 2d5b1b4

Browse files
committed
#1659 fix method faker.text().text(1, 64, true, false, true)
... to return a valid string of length 2..64 instead of empty string.
1 parent f4f8bfc commit 2d5b1b4

4 files changed

Lines changed: 140 additions & 28 deletions

File tree

src/main/java/net/datafaker/providers/base/Lorem.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,12 @@ public String characters(int fixedNumberOfCharacters) {
4848
}
4949

5050
public String characters(int fixedNumberOfCharacters, boolean includeUppercase) {
51-
return faker.credentials().password(fixedNumberOfCharacters, fixedNumberOfCharacters, includeUppercase);
51+
return faker.text().text(fixedNumberOfCharacters, fixedNumberOfCharacters, includeUppercase);
5252
}
5353

5454
public String characters(int minimumLength, int maximumLength,
5555
boolean includeUppercase, boolean includeSpecial, boolean includeDigit) {
56-
return faker.credentials().password(minimumLength, maximumLength, includeUppercase, includeSpecial, includeDigit);
56+
return faker.text().text(minimumLength, maximumLength, includeUppercase, includeSpecial, includeDigit);
5757
}
5858

5959
public String characters(int fixedNumberOfCharacters, boolean includeUppercase, boolean includeDigit) {
@@ -62,7 +62,7 @@ public String characters(int fixedNumberOfCharacters, boolean includeUppercase,
6262

6363
public String characters(int fixedNumberOfCharacters,
6464
boolean includeUppercase, boolean includeSpecial, boolean includeDigit) {
65-
return faker.credentials().password(fixedNumberOfCharacters, fixedNumberOfCharacters, includeUppercase, includeSpecial, includeDigit);
65+
return faker.text().text(fixedNumberOfCharacters, fixedNumberOfCharacters, includeUppercase, includeSpecial, includeDigit);
6666
}
6767

6868
public List<String> words(int num) {

src/main/java/net/datafaker/providers/base/Text.java

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -66,25 +66,52 @@ public String text(int minimumLength, int maximumLength, boolean includeUppercas
6666
return text(minimumLength, maximumLength, includeUppercase, includeSpecial, false);
6767
}
6868

69+
/**
70+
* For example, expression {@code text(5, 15, true, false, true} generates a random string of length 5 to 15
71+
* containing at least one upper case letter and at least one digit.
72+
*
73+
* @param minimumLength The generated text will not be shorter than this length
74+
* @param maximumLength The generated text will not be longer than this length
75+
* @param includeUppercase is at least one uppercase letter required
76+
* @param includeSpecial is at least one special symbol required
77+
* @param includeDigit is at least one digit required
78+
* @return a random string withing given length interval
79+
* @see Text#DEFAULT_SPECIAL
80+
* @throws IllegalArgumentException if {@code minimumLength > maximumLength}
81+
* @throws IllegalArgumentException if {@code maximumLength} is not enough to include the required symbols (upper case letter, special char, digit)
82+
*/
6983
public String text(int minimumLength, int maximumLength, boolean includeUppercase, boolean includeSpecial, boolean includeDigit) {
70-
final int len = faker.number().numberBetween(minimumLength, maximumLength + 1);
84+
if (minimumLength > maximumLength) {
85+
throw new IllegalArgumentException("Min length (%s) should not be greater than max length (%s)".formatted(
86+
minimumLength, maximumLength));
87+
}
88+
89+
final int minLength = Math.max(minimumLength, min(includeUppercase) + min(includeSpecial) + min(includeDigit));
90+
if (minLength > maximumLength) {
91+
throw new IllegalArgumentException("Minimum number of required characters (%s) should not be greater than max length (%s)".formatted(
92+
minLength, maximumLength));
93+
}
94+
95+
final int len = faker.number().numberBetween(minLength, maximumLength + 1);
7196
TextConfigPojo pojo = new TextConfigPojo(len, includeUppercase, includeSpecial, includeDigit);
72-
Text.TextRuleConfig config = configMap.get(pojo);
73-
if (config == null) {
97+
Text.TextRuleConfig config = configMap.computeIfAbsent(pojo, (x) -> {
7498
TextSymbolsBuilder builder =
7599
TextSymbolsBuilder.builder()
76100
.with(Text.EN_LOWERCASE);
77101
if (includeUppercase) builder = builder.with(Text.EN_UPPERCASE, 1);
78102
if (includeSpecial) builder = builder.with(Text.DEFAULT_SPECIAL, 1);
79103
if (includeDigit) builder = builder.with(Text.DIGITS, 1);
80104

81-
config = builder.len(len).build();
82-
configMap.putIfAbsent(pojo, config);
83-
}
105+
return builder.len(len).throwIfLengthSmall(true).build();
106+
});
84107

85108
return text(config);
86109
}
87110

111+
private static int min(boolean requireSomeKindOfSymbols) {
112+
return requireSomeKindOfSymbols ? 1 : 0;
113+
}
114+
88115
public static final String EN_LOWERCASE = "abcdefghijklmnopqrstuvwxyz";
89116
public static final String EN_UPPERCASE = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
90117
public static final String DIGITS = "0123456789";
@@ -102,6 +129,9 @@ public static class TextRuleConfig {
102129
private final int numberOfRequiredSymbols;
103130

104131
private TextRuleConfig(int fixedNumberOfCharacters, Map<String, Integer> map, int numberOfRequiredSymbols) {
132+
assert numberOfRequiredSymbols >= 0;
133+
assert fixedNumberOfCharacters >= numberOfRequiredSymbols;
134+
105135
this.fixedNumberOfCharacters = fixedNumberOfCharacters;
106136
this.numberOfRequiredSymbols = numberOfRequiredSymbols;
107137
this.textKeys = new char[map.size()][];
@@ -200,10 +230,10 @@ public TextRuleConfig build() {
200230
* {@code final String customSpecialSymbols = "!@#$%^*;'][{}";}.
201231
*/
202232
public String text(TextRuleConfig textRuleConfig) {
203-
final int fixedNumberOfCharacters = textRuleConfig.getFixedNumberOfCharacters();
233+
int fixedNumberOfCharacters = textRuleConfig.getFixedNumberOfCharacters();
204234
final int numberOfRequiredSymbols = textRuleConfig.getNumberOfRequiredSymbols();
205235
if (fixedNumberOfCharacters < numberOfRequiredSymbols) {
206-
return "";
236+
fixedNumberOfCharacters = numberOfRequiredSymbols;
207237
}
208238
char[] buffer = new char[fixedNumberOfCharacters];
209239
int idx = 0;

src/test/java/net/datafaker/providers/base/LoremTest.java

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import java.util.regex.Pattern;
1313

1414
import static org.assertj.core.api.Assertions.assertThat;
15+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
1516

1617
class LoremTest extends BaseFakerTest {
1718

@@ -74,7 +75,9 @@ void testCharactersWithLength() {
7475
assertThat(lorem.characters(2)).matches("[a-z\\d]{2}");
7576
assertThat(lorem.characters(500)).matches("[a-z\\d]{500}");
7677
assertThat(lorem.characters(0)).isEmpty();
77-
assertThat(lorem.characters(-1)).isEmpty();
78+
assertThatThrownBy(() -> lorem.characters(-1))
79+
.isInstanceOf(IllegalArgumentException.class)
80+
.hasMessage("Minimum number of required characters (0) should not be greater than max length (-1)");
7881
}
7982

8083
@Test
@@ -84,7 +87,14 @@ void testCharactersWithLengthIncludeUppercase() {
8487
assertThat(lorem.characters(2, true)).matches("[a-zA-Z\\d]{2}");
8588
assertThat(lorem.characters(500, true)).matches("[a-zA-Z\\d]{500}");
8689
assertThat(lorem.characters(0, false)).isEmpty();
87-
assertThat(lorem.characters(-1, true)).isEmpty();
90+
assertThat(lorem.characters(1, true)).matches("[A-Z]");
91+
92+
assertThatThrownBy(() -> lorem.characters(-1, false))
93+
.isInstanceOf(IllegalArgumentException.class)
94+
.hasMessage("Minimum number of required characters (0) should not be greater than max length (-1)");
95+
assertThatThrownBy(() -> lorem.characters(0, true))
96+
.isInstanceOf(IllegalArgumentException.class)
97+
.hasMessage("Minimum number of required characters (1) should not be greater than max length (0)");
8898
}
8999

90100
@Test
@@ -109,11 +119,16 @@ void testCharactersFixedLengthIncludingUppercaseAndIncludingDigit() {
109119

110120
@Test
111121
void testFixedNumberOfCharactersEmpty() {
112-
assertThat(lorem.characters(-1)).isEmpty();
113122
assertThat(lorem.characters(0)).isEmpty();
114-
115-
assertThat(lorem.characters(-1, true, true, true)).isEmpty();
116123
assertThat(lorem.characters(0, false, false, false)).isEmpty();
124+
125+
assertThatThrownBy(() -> lorem.characters(-1, true, true, true))
126+
.isInstanceOf(IllegalArgumentException.class)
127+
.hasMessage("Minimum number of required characters (3) should not be greater than max length (-1)");
128+
129+
assertThatThrownBy(() -> lorem.characters(-1))
130+
.isInstanceOf(IllegalArgumentException.class)
131+
.hasMessage("Minimum number of required characters (0) should not be greater than max length (-1)");
117132
}
118133

119134

src/test/java/net/datafaker/providers/base/TextTest.java

Lines changed: 79 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@
77

88
import java.util.regex.Pattern;
99

10+
import static net.datafaker.providers.base.Text.DEFAULT_SPECIAL;
1011
import static net.datafaker.providers.base.Text.DIGITS;
1112
import static net.datafaker.providers.base.Text.EN_LOWERCASE;
1213
import static net.datafaker.providers.base.Text.EN_UPPERCASE;
1314
import static org.assertj.core.api.Assertions.assertThat;
1415
import static org.assertj.core.api.Assertions.assertThatThrownBy;
1516

1617
class TextTest {
18+
private static final Pattern characterPattern = Pattern.compile("[A-Za-z]");
1719
private final Faker faker = new Faker();
1820

1921
@Test
@@ -57,7 +59,8 @@ void exceptionIfLengthIsShorterThanNumberOfRequiredSymbols() {
5759
.with(DIGITS, 1)
5860
.throwIfLengthSmall(true)
5961
.build()))
60-
.isInstanceOf(IllegalArgumentException.class);
62+
.isInstanceOf(IllegalArgumentException.class)
63+
.hasMessage("Min length (1) should be not smaller than number of required characters (3)");
6164
}
6265

6366
@Test
@@ -99,11 +102,8 @@ void everyTextShouldContainLowerCaseUpperCaseAndDigit() {
99102

100103
@Test
101104
void testCharacter() {
102-
final Pattern characterPattern = Pattern.compile("[A-Za-z]");
103-
for (int i = 0; i < 100; i++) {
104-
Character character = faker.text().character();
105-
assertThat(character.toString()).matches(characterPattern);
106-
}
105+
Character character = faker.text().character();
106+
assertThat(character.toString()).matches(characterPattern);
107107
}
108108

109109
@RepeatedTest((100))
@@ -122,16 +122,83 @@ void testLowercaseCharacter() {
122122
void testFixedLengthText() {
123123
for (int i = 0; i < 100; i++) {
124124
String text = faker.text().text(i);
125-
assertThat(text).hasSize(i);
125+
assertThat(text).hasSize(i).matches("[a-z]*");
126126
}
127127
}
128128

129-
@Test
129+
@RepeatedTest(10)
130130
void testDefaultLengthText() {
131-
for (int i = 0; i < 100; i++) {
132-
String text = faker.text().text();
133-
assertThat(text).hasSizeBetween(20, 80);
134-
}
131+
String text = faker.text().text();
132+
assertThat(text).hasSizeBetween(20, 80).matches("[a-z]{20,80}");
133+
}
134+
135+
@RepeatedTest(10)
136+
void upTo64LowerCase() {
137+
assertThat(faker.text().text(1, 64, false, false, false)).matches("[a-z]{1,64}");
138+
assertThat(faker.text().text(2, 64, false, false, false)).matches("[a-z]{2,64}");
139+
assertThat(faker.text().text(64, 64, false, false, false)).matches("[a-z]{64}");
140+
}
141+
142+
@Test
143+
void zeroLength() {
144+
assertThat(faker.text().text(0, 0, false, false, false)).isEqualTo("");
145+
}
146+
147+
@Test
148+
void oneLowerCase() {
149+
assertThat(faker.text().text(1, 1, false, false, false)).matches("[a-z]");
150+
assertThat(faker.text().text(0, 1, false, false, false)).matches("[a-z]?");
151+
}
152+
153+
@RepeatedTest(10)
154+
void oneWithUpperCase() {
155+
assertThat(faker.text().text(1, 1, true, false, false)).matches("[A-Z]");
135156
}
136157

158+
@RepeatedTest(10)
159+
void oneWithDigit() {
160+
assertThat(faker.text().text(1, 1, false, false, true)).matches("[0-9]");
161+
}
162+
163+
@RepeatedTest(10)
164+
void oneWithSpecialSymbol() {
165+
assertThat(faker.text().text(1, 1, false, true, false)).matches("[" + DEFAULT_SPECIAL + "]");
166+
}
167+
168+
@RepeatedTest(10)
169+
void twoWithUpperCaseAndDigit() {
170+
assertThat(faker.text().text(2, 2, true, false, true)).matches("[A-Z0-9]{2}");
171+
}
172+
173+
@RepeatedTest(10)
174+
void twoWithLowerAndUpperCaseAndDigit() {
175+
assertThat(faker.text().text(2, 2, true, false, true)).matches("[a-zA-Z0-9]{2}");
176+
assertThat(faker.text().text(3, 3, true, true, true)).matches("[a-zA-Z0-9" + DEFAULT_SPECIAL + "]{3}");
177+
}
178+
179+
@Test
180+
void minLengthCannotBeGreaterThanMaxLength() {
181+
assertThatThrownBy(() -> faker.text().text(22, 21, false, false, false))
182+
.isInstanceOf(IllegalArgumentException.class)
183+
.hasMessage("Min length (22) should not be greater than max length (21)");
184+
185+
assertThatThrownBy(() -> faker.text().text(3, 2, true, true, true))
186+
.isInstanceOf(IllegalArgumentException.class)
187+
.hasMessage("Min length (3) should not be greater than max length (2)");
188+
}
189+
190+
@Test
191+
void isNotEnoughLengthToContainAllRequiredSymbols() {
192+
assertThatThrownBy(() -> faker.text().text(0, 0, true, false, false))
193+
.isInstanceOf(IllegalArgumentException.class)
194+
.hasMessage("Minimum number of required characters (1) should not be greater than max length (0)");
195+
assertThatThrownBy(() -> faker.text().text(1, 2, true, true, true))
196+
.isInstanceOf(IllegalArgumentException.class)
197+
.hasMessage("Minimum number of required characters (3) should not be greater than max length (2)");
198+
}
199+
200+
@RepeatedTest(10)
201+
void minimumLengthIsNotEnoughToContainAllRequiredSymbols() {
202+
assertThat(faker.text().text(1, 4, true, false, true)).matches("[a-zA-Z0-9]{2,4}");
203+
}
137204
}

0 commit comments

Comments
 (0)