@@ -823,86 +823,127 @@ object Gen extends GenArities with GenVersionSpecific {
823
823
824
824
// // Character Generators ////
825
825
826
+ private def charSample (cs : Array [Char ]): Gen [Char ] =
827
+ new Gen [Char ] {
828
+ def doApply (p : P , seed0 : Seed ): Gen .R [Char ] = {
829
+ val seed1 = p.initialSeed.getOrElse(seed0)
830
+ val (x, seed2) = seed1.long
831
+ val i = ((x & Long .MaxValue ) % cs.length).toInt
832
+ r(Some (cs(i)), seed2)
833
+ }
834
+ }
835
+
826
836
/** Generates a numerical character */
827
837
val numChar : Gen [Char ] =
828
- choose( 48 .toChar, 57 .toChar )
838
+ charSample(( '0' to '9' ).toArray )
829
839
830
840
/** Generates an upper-case alpha character */
831
841
val alphaUpperChar : Gen [Char ] =
832
- choose( 65 .toChar, 90 .toChar )
842
+ charSample(( 'A' to 'Z' ).toArray )
833
843
834
844
/** Generates a lower-case alpha character */
835
845
val alphaLowerChar : Gen [Char ] =
836
- choose( 97 .toChar, 122 .toChar )
846
+ charSample(( 'a' to 'z' ).toArray )
837
847
838
848
/** Generates an alpha character */
839
849
val alphaChar : Gen [Char ] =
840
- frequency(( 1 ,alphaUpperChar), ( 9 ,alphaLowerChar) )
850
+ charSample((( 'A' to 'Z' ) ++ ( 'a' to 'z' )).toArray )
841
851
842
852
/** Generates an alphanumerical character */
843
853
val alphaNumChar : Gen [Char ] =
844
- frequency(( 1 ,numChar), ( 9 ,alphaChar) )
854
+ charSample((( '0' to '9' ) ++ ( 'A' to 'Z' ) ++ ( 'a' to 'z' )).toArray )
845
855
846
856
/** Generates a ASCII character, with extra weighting for printable characters */
847
857
val asciiChar : Gen [Char ] =
848
- chooseNum( 0 , 127 , 32 to 126 :_* ).map(_. toChar)
858
+ charSample(( 0 .toChar to 127 . toChar).toArray )
849
859
850
860
/** Generates a ASCII printable character */
851
861
val asciiPrintableChar : Gen [Char ] =
852
- choose( 32 .toChar, 126 .toChar)
862
+ charSample(( 32 .toChar to 126 .toChar).toArray )
853
863
854
864
/** Generates a character that can represent a valid hexadecimal digit. This
855
865
* includes both upper and lower case values.
856
866
*/
857
867
val hexChar : Gen [Char ] =
858
- Gen .oneOf(
859
- Gen .oneOf(" 0123456789abcdef" .toSeq),
860
- Gen .oneOf(" 0123456789ABCDEF" .toSeq)
861
- )
868
+ charSample(" 0123456789abcdef0123456789ABCDEF" .toArray)
862
869
863
870
// // String Generators ////
864
871
872
+ private def mkString (n : Int , sb : StringBuilder , gc : Gen [Char ], p : P , seed0 : Seed ): R [String ] = {
873
+ var seed : Seed = seed0
874
+ val allowedFailures = Gen .collectionRetries(n)
875
+ var failures = 0
876
+ var count = 0
877
+ while (count < n) {
878
+ val res = gc.doApply(p, seed)
879
+ res.retrieve match {
880
+ case Some (c) =>
881
+ sb += c
882
+ count += 1
883
+ case None =>
884
+ failures += 1
885
+ if (failures >= allowedFailures) return r(None , res.seed)
886
+ }
887
+ seed = res.seed
888
+ }
889
+ r(Some (sb.toString), seed)
890
+ }
891
+
892
+ def stringOfN (n : Int , gc : Gen [Char ]): Gen [String ] =
893
+ gen { (p, seed) =>
894
+ mkString(n, new StringBuilder , gc, p, seed)
895
+ }
896
+
897
+ def stringOf (gc : Gen [Char ]): Gen [String ] =
898
+ gen { (p, seed0) =>
899
+ val (n, seed1) = Gen .mkSize(p, seed0)
900
+ mkString(n, new StringBuilder , gc, p, seed1)
901
+ }
902
+
865
903
/** Generates a string that starts with a lower-case alpha character,
866
904
* and only contains alphanumerical characters */
867
905
val identifier : Gen [String ] =
868
- for {
869
- c <- alphaLowerChar
870
- cs <- listOf(alphaNumChar)
871
- } yield (c:: cs).mkString
906
+ gen { (p, seed0) =>
907
+ val (n, seed1) = Gen .mkSize(p, seed0)
908
+ val sb = new StringBuilder
909
+ val res1 = alphaLowerChar.doApply(p, seed1)
910
+ sb += res1.retrieve.get
911
+ mkString(n - 1 , sb, alphaNumChar, p, res1.seed)
912
+ }
872
913
873
914
/** Generates a string of digits */
874
915
val numStr : Gen [String ] =
875
- listOf (numChar).map(_.mkString )
916
+ stringOf (numChar)
876
917
877
918
/** Generates a string of upper-case alpha characters */
878
919
val alphaUpperStr : Gen [String ] =
879
- listOf (alphaUpperChar).map(_.mkString )
920
+ stringOf (alphaUpperChar)
880
921
881
922
/** Generates a string of lower-case alpha characters */
882
923
val alphaLowerStr : Gen [String ] =
883
- listOf (alphaLowerChar).map(_.mkString )
924
+ stringOf (alphaLowerChar)
884
925
885
926
/** Generates a string of alpha characters */
886
927
val alphaStr : Gen [String ] =
887
- listOf (alphaChar).map(_.mkString )
928
+ stringOf (alphaChar)
888
929
889
930
/** Generates a string of alphanumerical characters */
890
931
val alphaNumStr : Gen [String ] =
891
- listOf (alphaNumChar).map(_.mkString )
932
+ stringOf (alphaNumChar)
892
933
893
934
/** Generates a string of ASCII characters, with extra weighting for printable characters */
894
935
val asciiStr : Gen [String ] =
895
- listOf (asciiChar).map(_.mkString )
936
+ stringOf (asciiChar)
896
937
897
938
/** Generates a string of ASCII printable characters */
898
939
val asciiPrintableStr : Gen [String ] =
899
- listOf (asciiPrintableChar).map(_.mkString )
940
+ stringOf (asciiPrintableChar)
900
941
901
942
/** Generates a string that can represent a valid hexadecimal digit. This
902
943
* includes both upper and lower case values.
903
944
*/
904
945
val hexStr : Gen [String ] =
905
- listOf (hexChar).map(_.mkString )
946
+ stringOf (hexChar)
906
947
907
948
// // Number Generators ////
908
949
@@ -1041,6 +1082,13 @@ object Gen extends GenArities with GenVersionSpecific {
1041
1082
1 -> const(Duration .Zero ),
1042
1083
6 -> finiteDuration)
1043
1084
1085
+ // used to compute a uniformly-distributed size
1086
+ private def mkSize (p : Gen .Parameters , seed0 : Seed ): (Int , Seed ) = {
1087
+ val maxSize = Integer .max(p.size + 1 , 1 )
1088
+ val (x, seed1) = seed0.long
1089
+ (((x & Long .MaxValue ) % maxSize).toInt, seed1)
1090
+ }
1091
+
1044
1092
// used to calculate how many per-item retries we should allow.
1045
1093
private def collectionRetries (n : Int ): Int =
1046
1094
Integer .max(10 , n / 10 )
0 commit comments