Skip to content

Commit 9667086

Browse files
authored
Add CharacterCombinableArbitrary (#1239)
1 parent e70b0c0 commit 9667086

File tree

11 files changed

+967
-3
lines changed

11 files changed

+967
-3
lines changed
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
/*
2+
* Fixture Monkey
3+
*
4+
* Copyright (c) 2021-present NAVER Corp.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
package com.navercorp.fixturemonkey.api.arbitrary;
20+
21+
import java.util.function.Predicate;
22+
23+
import org.apiguardian.api.API;
24+
import org.apiguardian.api.API.Status;
25+
26+
/**
27+
* A combinable arbitrary for generating single characters with various character sets and constraints.
28+
* This interface provides Character-specific generation methods that are not available in StringCombinableArbitrary.
29+
*/
30+
@API(since = "1.1.16", status = Status.EXPERIMENTAL)
31+
public interface CharacterCombinableArbitrary extends CombinableArbitrary<Character> {
32+
@Override
33+
Character rawValue();
34+
35+
/**
36+
* Generates a CharacterCombinableArbitrary which produces characters within the specified range.
37+
*
38+
* @param min the minimum character value (inclusive)
39+
* @param max the maximum character value (inclusive)
40+
* @return the CharacterCombinableArbitrary producing characters between {@code min} and {@code max}
41+
*/
42+
CharacterCombinableArbitrary withRange(char min, char max);
43+
44+
/**
45+
* Generates a CharacterCombinableArbitrary which produces only alphabetic characters (a-z, A-Z).
46+
*
47+
* @return the CharacterCombinableArbitrary producing alphabetic characters
48+
*/
49+
CharacterCombinableArbitrary alphabetic();
50+
51+
/**
52+
* Generates a CharacterCombinableArbitrary which produces only numeric characters (0-9).
53+
*
54+
* @return the CharacterCombinableArbitrary producing numeric characters
55+
*/
56+
CharacterCombinableArbitrary numeric();
57+
58+
/**
59+
* Generates a CharacterCombinableArbitrary which produces alphanumeric characters (a-z, A-Z, 0-9).
60+
*
61+
* @return the CharacterCombinableArbitrary producing alphanumeric characters
62+
*/
63+
CharacterCombinableArbitrary alphaNumeric();
64+
65+
/**
66+
* Generates a CharacterCombinableArbitrary which produces only ASCII printable characters.
67+
*
68+
* @return the CharacterCombinableArbitrary producing ASCII printable characters
69+
*/
70+
CharacterCombinableArbitrary ascii();
71+
72+
/**
73+
* Generates a CharacterCombinableArbitrary which produces only uppercase alphabetic characters (A-Z).
74+
*
75+
* @return the CharacterCombinableArbitrary producing uppercase characters
76+
*/
77+
CharacterCombinableArbitrary uppercase();
78+
79+
/**
80+
* Generates a CharacterCombinableArbitrary which produces only lowercase alphabetic characters (a-z).
81+
*
82+
* @return the CharacterCombinableArbitrary producing lowercase characters
83+
*/
84+
CharacterCombinableArbitrary lowercase();
85+
86+
/**
87+
* Generates a CharacterCombinableArbitrary which produces Korean characters (가-힣).
88+
*
89+
* @return the CharacterCombinableArbitrary producing Korean characters
90+
*/
91+
CharacterCombinableArbitrary korean();
92+
93+
/**
94+
* Generates a CharacterCombinableArbitrary which produces emoji characters.
95+
*
96+
* @return the CharacterCombinableArbitrary producing emoji characters
97+
*/
98+
CharacterCombinableArbitrary emoji();
99+
100+
/**
101+
* Generates a CharacterCombinableArbitrary which produces whitespace characters.
102+
*
103+
* @return the CharacterCombinableArbitrary producing whitespace characters
104+
*/
105+
CharacterCombinableArbitrary whitespace();
106+
107+
@Override
108+
default CharacterCombinableArbitrary filter(Predicate<Character> predicate) {
109+
return this.filter(DEFAULT_MAX_TRIES, predicate);
110+
}
111+
112+
@Override
113+
default CharacterCombinableArbitrary filter(int tries, Predicate<Character> predicate) {
114+
return new CharacterCombinableArbitraryDelegator(CombinableArbitrary.super.filter(tries, predicate));
115+
}
116+
117+
@Override
118+
default CharacterCombinableArbitrary injectNull(double nullProbability) {
119+
return new CharacterCombinableArbitraryDelegator(CombinableArbitrary.super.injectNull(nullProbability));
120+
}
121+
122+
@Override
123+
default CharacterCombinableArbitrary unique() {
124+
return new CharacterCombinableArbitraryDelegator(CombinableArbitrary.super.unique());
125+
}
126+
127+
@Override
128+
void clear();
129+
130+
@Override
131+
boolean fixed();
132+
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
* Fixture Monkey
3+
*
4+
* Copyright (c) 2021-present NAVER Corp.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
package com.navercorp.fixturemonkey.api.arbitrary;
20+
21+
import org.apiguardian.api.API;
22+
import org.apiguardian.api.API.Status;
23+
24+
@API(since = "1.1.16", status = Status.EXPERIMENTAL)
25+
final class CharacterCombinableArbitraryDelegator implements CharacterCombinableArbitrary {
26+
private final CombinableArbitrary<Character> delegate;
27+
28+
public CharacterCombinableArbitraryDelegator(CombinableArbitrary<Character> delegate) {
29+
this.delegate = delegate;
30+
}
31+
32+
@Override
33+
public Character combined() {
34+
return delegate.combined();
35+
}
36+
37+
@Override
38+
public Character rawValue() {
39+
return delegate.combined();
40+
}
41+
42+
@Override
43+
public CharacterCombinableArbitrary withRange(char min, char max) {
44+
return CombinableArbitrary.chars().withRange(min, max);
45+
}
46+
47+
@Override
48+
public CharacterCombinableArbitrary alphabetic() {
49+
return CombinableArbitrary.chars().alphabetic();
50+
}
51+
52+
@Override
53+
public CharacterCombinableArbitrary numeric() {
54+
return CombinableArbitrary.chars().numeric();
55+
}
56+
57+
@Override
58+
public CharacterCombinableArbitrary alphaNumeric() {
59+
return CombinableArbitrary.chars().alphaNumeric();
60+
}
61+
62+
@Override
63+
public CharacterCombinableArbitrary ascii() {
64+
return CombinableArbitrary.chars().ascii();
65+
}
66+
67+
@Override
68+
public CharacterCombinableArbitrary uppercase() {
69+
return CombinableArbitrary.chars().uppercase();
70+
}
71+
72+
@Override
73+
public CharacterCombinableArbitrary lowercase() {
74+
return CombinableArbitrary.chars().lowercase();
75+
}
76+
77+
@Override
78+
public CharacterCombinableArbitrary korean() {
79+
return CombinableArbitrary.chars().korean();
80+
}
81+
82+
@Override
83+
public CharacterCombinableArbitrary emoji() {
84+
return CombinableArbitrary.chars().emoji();
85+
}
86+
87+
@Override
88+
public CharacterCombinableArbitrary whitespace() {
89+
return CombinableArbitrary.chars().whitespace();
90+
}
91+
92+
@Override
93+
public void clear() {
94+
delegate.clear();
95+
}
96+
97+
@Override
98+
public boolean fixed() {
99+
return delegate.fixed();
100+
}
101+
}

fixture-monkey-api/src/main/java/com/navercorp/fixturemonkey/api/arbitrary/CombinableArbitrary.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ public interface CombinableArbitrary<T> {
5050
ServiceLoader.load(LongCombinableArbitrary.class);
5151
ServiceLoader<ShortCombinableArbitrary> SHORT_COMBINABLE_ARBITRARY_SERVICE_LOADER =
5252
ServiceLoader.load(ShortCombinableArbitrary.class);
53+
ServiceLoader<CharacterCombinableArbitrary> CHARACTER_COMBINABLE_ARBITRARY_SERVICE_LOADER =
54+
ServiceLoader.load(CharacterCombinableArbitrary.class);
5355

5456
/**
5557
* Generates a {@link FixedCombinableArbitrary} which returns always same value.
@@ -254,4 +256,15 @@ static ShortCombinableArbitrary shorts() {
254256
return SHORT_COMBINABLE_ARBITRARY_SERVICE_LOADER.iterator().next();
255257
}
256258

259+
/**
260+
* Generates a {@link CharacterCombinableArbitrary} which returns a randomly generated Character.
261+
* You can customize the generated Character by using {@link CharacterCombinableArbitrary}.
262+
*
263+
* @return a {@link CombinableArbitrary} returns a randomly generated Character
264+
*/
265+
@API(since = "1.1.16", status = Status.EXPERIMENTAL)
266+
static CharacterCombinableArbitrary chars() {
267+
return CHARACTER_COMBINABLE_ARBITRARY_SERVICE_LOADER.iterator().next();
268+
}
269+
257270
}
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
/*
2+
* Fixture Monkey
3+
*
4+
* Copyright (c) 2021-present NAVER Corp.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
package com.navercorp.fixturemonkey.api.jqwik;
20+
21+
import org.apiguardian.api.API;
22+
import org.apiguardian.api.API.Status;
23+
24+
import net.jqwik.api.Arbitraries;
25+
import net.jqwik.api.Arbitrary;
26+
27+
import com.navercorp.fixturemonkey.api.arbitrary.CharacterCombinableArbitrary;
28+
29+
@API(since = "1.1.16", status = Status.EXPERIMENTAL)
30+
public final class JqwikCharacterCombinableArbitrary implements CharacterCombinableArbitrary {
31+
private final Arbitrary<Character> characterArbitrary;
32+
33+
public JqwikCharacterCombinableArbitrary() {
34+
this.characterArbitrary = Arbitraries.chars();
35+
}
36+
37+
private JqwikCharacterCombinableArbitrary(Arbitrary<Character> characterArbitrary) {
38+
this.characterArbitrary = characterArbitrary;
39+
}
40+
41+
@Override
42+
public Character rawValue() {
43+
return this.characterArbitrary.sample();
44+
}
45+
46+
@Override
47+
public CharacterCombinableArbitrary withRange(char minValue, char maxValue) {
48+
return new JqwikCharacterCombinableArbitrary(
49+
Arbitraries.chars().range(minValue, maxValue)
50+
);
51+
}
52+
53+
@Override
54+
public CharacterCombinableArbitrary alphabetic() {
55+
return new JqwikCharacterCombinableArbitrary(
56+
Arbitraries.chars().alpha()
57+
);
58+
}
59+
60+
@Override
61+
public CharacterCombinableArbitrary numeric() {
62+
return new JqwikCharacterCombinableArbitrary(
63+
Arbitraries.chars().numeric()
64+
);
65+
}
66+
67+
@Override
68+
public CharacterCombinableArbitrary alphaNumeric() {
69+
return new JqwikCharacterCombinableArbitrary(
70+
Arbitraries.oneOf(
71+
Arbitraries.chars().alpha(),
72+
Arbitraries.chars().numeric()
73+
)
74+
);
75+
}
76+
77+
@Override
78+
public CharacterCombinableArbitrary ascii() {
79+
return new JqwikCharacterCombinableArbitrary(
80+
Arbitraries.chars().ascii()
81+
);
82+
}
83+
84+
@Override
85+
public CharacterCombinableArbitrary uppercase() {
86+
return new JqwikCharacterCombinableArbitrary(
87+
Arbitraries.chars().range('A', 'Z')
88+
);
89+
}
90+
91+
@Override
92+
public CharacterCombinableArbitrary lowercase() {
93+
return new JqwikCharacterCombinableArbitrary(
94+
Arbitraries.chars().range('a', 'z')
95+
);
96+
}
97+
98+
@Override
99+
public CharacterCombinableArbitrary korean() {
100+
return new JqwikCharacterCombinableArbitrary(
101+
Arbitraries.chars().range('\uAC00', '\uD7A3') // 가-힣
102+
);
103+
}
104+
105+
@Override
106+
public CharacterCombinableArbitrary emoji() {
107+
return new JqwikCharacterCombinableArbitrary(
108+
Arbitraries.chars().range('\u2600', '\u27BF')
109+
);
110+
}
111+
112+
@Override
113+
public CharacterCombinableArbitrary whitespace() {
114+
return new JqwikCharacterCombinableArbitrary(
115+
Arbitraries.of(' ', '\t', '\n', '\r', '\f')
116+
);
117+
}
118+
119+
@Override
120+
public void clear() {
121+
// ignored
122+
}
123+
124+
@Override
125+
public boolean fixed() {
126+
return false;
127+
}
128+
129+
@Override
130+
public Character combined() {
131+
return this.characterArbitrary.sample();
132+
}
133+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
com.navercorp.fixturemonkey.api.jqwik.JqwikCharacterCombinableArbitrary

0 commit comments

Comments
 (0)