@@ -20,62 +20,108 @@ package com.navercorp.fixturemonkey.kotest
2020
2121import com.navercorp.fixturemonkey.api.arbitrary.CharacterCombinableArbitrary
2222import io.kotest.property.Arb
23- import io.kotest.property.arbitrary.char
23+ import io.kotest.property.arbitrary.choice
2424import io.kotest.property.arbitrary.filter
25+ import io.kotest.property.arbitrary.int
26+ import io.kotest.property.arbitrary.map
27+ import io.kotest.property.arbitrary.of
2528import io.kotest.property.arbitrary.single
2629import org.apiguardian.api.API
2730import org.apiguardian.api.API.Status
2831import java.util.function.Predicate
2932
3033@API(since = " 1.1.16" , status = Status .EXPERIMENTAL )
31- class KotestCharacterCombinableArbitrary (private val arb : Arb <Char > = Arb .char()) : CharacterCombinableArbitrary {
34+ class KotestCharacterCombinableArbitrary (
35+ private val arb : Arb <Char > = DEFAULT_CHAR_ARB
36+ ) : CharacterCombinableArbitrary {
3237 override fun combined (): Char = arb.single()
3338
3439 override fun rawValue (): Char = this .combined()
3540
3641 override fun withRange (min : Char , max : Char ): CharacterCombinableArbitrary =
37- KotestCharacterCombinableArbitrary (Arb .char().filter { it in min.. max } )
42+ KotestCharacterCombinableArbitrary (charRange( min, max) )
3843
3944 override fun alphabetic (): CharacterCombinableArbitrary =
40- KotestCharacterCombinableArbitrary (Arb .char().filter { it.isLetter() } )
45+ KotestCharacterCombinableArbitrary (Arb .choice( UPPERCASE_RANGE_ARB , LOWERCASE_RANGE_ARB ) )
4146
4247 override fun numeric (): CharacterCombinableArbitrary =
43- KotestCharacterCombinableArbitrary (Arb .char().filter { it.isDigit() } )
48+ KotestCharacterCombinableArbitrary (NUMERIC_RANGE_ARB )
4449
4550 override fun alphaNumeric (): CharacterCombinableArbitrary =
46- KotestCharacterCombinableArbitrary (Arb .char().filter { it.isLetterOrDigit() } )
51+ KotestCharacterCombinableArbitrary (Arb .choice( UPPERCASE_RANGE_ARB , LOWERCASE_RANGE_ARB , NUMERIC_RANGE_ARB ) )
4752
4853 override fun ascii (): CharacterCombinableArbitrary =
49- KotestCharacterCombinableArbitrary (Arb .char().filter { it.code <= 127 } )
54+ KotestCharacterCombinableArbitrary (charRange( ' \u0000 ' , ' \u007F ' ) )
5055
5156 override fun uppercase (): CharacterCombinableArbitrary =
52- KotestCharacterCombinableArbitrary (Arb .char().filter { it.isUpperCase() } )
57+ KotestCharacterCombinableArbitrary (UPPERCASE_RANGE_ARB )
5358
5459 override fun lowercase (): CharacterCombinableArbitrary =
55- KotestCharacterCombinableArbitrary (Arb .char().filter { it.isLowerCase() } )
60+ KotestCharacterCombinableArbitrary (LOWERCASE_RANGE_ARB )
5661
5762 override fun korean (): CharacterCombinableArbitrary =
58- KotestCharacterCombinableArbitrary (Arb .char().filter { it in ' 가' .. ' 힣' })
59-
60- private fun isEmojiCodePoint (codePoint : Int ): Boolean {
61- return codePoint in 0x1F600 .. 0x1F64F || // Emoticons
62- codePoint in 0x1F300 .. 0x1F5FF || // Misc Symbols and Pictographs
63- codePoint in 0x1F680 .. 0x1F6FF || // Transport and Map
64- codePoint in 0x2600 .. 0x26FF || // Misc symbols
65- codePoint in 0x2700 .. 0x27BF // Dingbats
66- }
63+ KotestCharacterCombinableArbitrary (charRange(' 가' , ' 힣' ))
6764
6865 override fun emoji (): CharacterCombinableArbitrary =
69- KotestCharacterCombinableArbitrary (Arb .char().filter { isEmojiCodePoint(it.code) } )
66+ KotestCharacterCombinableArbitrary (Arb .of( EMOJI_CHAR_CANDIDATES ) )
7067
7168 override fun whitespace (): CharacterCombinableArbitrary =
72- KotestCharacterCombinableArbitrary (Arb .char().filter { it.isWhitespace() } )
69+ KotestCharacterCombinableArbitrary (Arb .of( WHITESPACE_CHAR_CANDIDATES ) )
7370
7471 override fun filter (tries : Int , predicate : Predicate <Char >): CharacterCombinableArbitrary =
75- KotestCharacterCombinableArbitrary (Arb .char() .filter { predicate.test(it) })
72+ KotestCharacterCombinableArbitrary (arb .filter { predicate.test(it) })
7673
7774 override fun clear () {
7875 }
7976
8077 override fun fixed (): Boolean = false
78+
79+ companion object {
80+ private val DEFAULT_CHAR_ARB : Arb <Char > = charRange(Char .MIN_VALUE , Char .MAX_VALUE )
81+ private val UPPERCASE_RANGE_ARB : Arb <Char > = charRange(' A' , ' Z' )
82+ private val LOWERCASE_RANGE_ARB : Arb <Char > = charRange(' a' , ' z' )
83+ private val NUMERIC_RANGE_ARB : Arb <Char > = charRange(' 0' , ' 9' )
84+ private val EMOJI_CHAR_CANDIDATES : List <Char > = listOf (
85+ ' \u263A ' , // ☺
86+ ' \u263B ' , // ☻
87+ ' \u2661 ' , // ♡
88+ ' \u2665 ' , // ♥
89+ ' \u2660 ' , // ♠
90+ ' \u2663 ' , // ♣
91+ ' \u2666 ' , // ♦
92+ ' \u2600 ' , // ☀
93+ ' \u2601 ' , // ☁
94+ ' \u2602 ' , // ☂
95+ ' \u2603 ' , // ☃
96+ ' \u2604 ' , // ☄
97+ ' \u2614 ' , // ☔
98+ ' \u2615 ' , // ☕
99+ ' \u260E ' , // ☎
100+ ' \u2618 ' , // ☘
101+ ' \u2728 ' , // ✨
102+ ' \u2764 ' , // ❤
103+ ' \u2708 ' , // ✈
104+ ' \u270C ' // ✌
105+ )
106+ private val WHITESPACE_CHAR_CANDIDATES : List <Char > = listOf (
107+ ' ' ,
108+ ' \t ' ,
109+ ' \n ' ,
110+ ' \r ' ,
111+ ' \u000B ' , // vertical tab
112+ ' \u000C ' // form feed
113+ )
114+
115+ private fun charRange (startInclusive : Char , endInclusive : Char ): Arb <Char > {
116+ if (startInclusive == endInclusive) {
117+ return Arb .of(startInclusive)
118+ }
119+ val (min, max) = if (startInclusive <= endInclusive) {
120+ startInclusive to endInclusive
121+ } else {
122+ endInclusive to startInclusive
123+ }
124+ return Arb .int(min.code.. max.code).map(Int ::toChar)
125+ }
126+ }
81127}
0 commit comments