33
44namespace Exceptionless ;
55
6+ /// <summary>Generates random data for use in unit tests and data seeding.</summary>
67public static class RandomData {
8+ /// <summary>Gets the shared <see cref="Random"/> instance. Thread-safe.</summary>
79 public static Random Instance => Random . Shared ;
810
11+ /// <summary>Returns a random integer in the inclusive range [<paramref name="min"/>, <paramref name="max"/>].</summary>
12+ /// <remarks>Returns <paramref name="min"/> immediately when both values are equal.</remarks>
13+ /// <exception cref="ArgumentOutOfRangeException"><paramref name="min"/> is greater than <paramref name="max"/>.</exception>
914 public static int GetInt ( int min , int max ) {
1015 if ( min == max )
1116 return min ;
1217
13- ArgumentOutOfRangeException . ThrowIfGreaterThanOrEqual ( min , max ) ;
18+ ArgumentOutOfRangeException . ThrowIfGreaterThan ( min , max ) ;
1419
1520 return Random . Shared . Next ( min , max + 1 ) ;
1621 }
1722
23+ /// <summary>Returns a random integer across the full <see cref="Int32"/> range.</summary>
1824 public static int GetInt ( ) => GetInt ( Int32 . MinValue , Int32 . MaxValue ) ;
1925
26+ /// <summary>
27+ /// Returns a random version string between <paramref name="min"/> and <paramref name="max"/>.
28+ /// Defaults to a range of "0.0.0.0" – "25.100.9999.9999" when either bound is null or empty.
29+ /// </summary>
2030 public static string GetVersion ( string ? min , string ? max ) {
2131 if ( String . IsNullOrEmpty ( min ) )
2232 min = "0.0.0.0" ;
@@ -48,11 +58,14 @@ public static string GetVersion(string? min, string? max) {
4858 return new Version ( major , minor , build , revision ) . ToString ( ) ;
4959 }
5060
61+ /// <summary>Returns a random <see cref="long"/> in the inclusive range [<paramref name="min"/>, <paramref name="max"/>].</summary>
62+ /// <remarks>Returns <paramref name="min"/> immediately when both values are equal.</remarks>
63+ /// <exception cref="ArgumentOutOfRangeException"><paramref name="min"/> is greater than <paramref name="max"/>.</exception>
5164 public static long GetLong ( long min , long max ) {
5265 if ( min == max )
5366 return min ;
5467
55- ArgumentOutOfRangeException . ThrowIfGreaterThanOrEqual ( min , max ) ;
68+ ArgumentOutOfRangeException . ThrowIfGreaterThan ( min , max ) ;
5669
5770 var buf = new byte [ 8 ] ;
5871 Random . Shared . NextBytes ( buf ) ;
@@ -61,16 +74,24 @@ public static long GetLong(long min, long max) {
6174 return ( Math . Abs ( longRand % ( max - min ) ) + min ) ;
6275 }
6376
77+ /// <summary>Returns a random <see cref="long"/> across the full <see cref="Int64"/> range.</summary>
6478 public static long GetLong ( ) => GetLong ( Int64 . MinValue , Int64 . MaxValue ) ;
6579
80+ /// <summary>Returns a random latitude/longitude coordinate string in the form <c>"lat,lng"</c>.</summary>
6681 public static string GetCoordinate ( ) => $ "{ GetDouble ( - 90.0 , 90.0 ) } ,{ GetDouble ( - 180.0 , 180.0 ) } ";
6782
83+ /// <summary>
84+ /// Returns a random <see cref="DateTime"/> between <paramref name="start"/> and <paramref name="end"/>.
85+ /// Defaults to <see cref="DateTime.MinValue"/> and <see cref="DateTime.MaxValue"/> when not specified.
86+ /// </summary>
87+ /// <remarks>Returns <paramref name="start"/> immediately when both values are equal.</remarks>
88+ /// <exception cref="ArgumentOutOfRangeException"><paramref name="start"/> is greater than <paramref name="end"/>.</exception>
6889 public static DateTime GetDateTime ( DateTime ? start = null , DateTime ? end = null ) {
6990 if ( start . HasValue && end . HasValue && start . Value == end . Value )
7091 return start . Value ;
7192
7293 if ( start . HasValue && end . HasValue )
73- ArgumentOutOfRangeException . ThrowIfGreaterThanOrEqual ( start . Value , end . Value , nameof ( start ) ) ;
94+ ArgumentOutOfRangeException . ThrowIfGreaterThan ( start . Value , end . Value , nameof ( start ) ) ;
7495
7596 start ??= DateTime . MinValue ;
7697 end ??= DateTime . MaxValue ;
@@ -81,6 +102,11 @@ public static DateTime GetDateTime(DateTime? start = null, DateTime? end = null)
81102 return start . Value + newSpan ;
82103 }
83104
105+ /// <summary>
106+ /// Returns a random <see cref="DateTimeOffset"/> between <paramref name="start"/> and <paramref name="end"/>.
107+ /// Defaults to <see cref="DateTimeOffset.MinValue"/> and <see cref="DateTimeOffset.MaxValue"/> when not specified.
108+ /// </summary>
109+ /// <exception cref="ArgumentOutOfRangeException"><paramref name="start"/> is greater than or equal to <paramref name="end"/>.</exception>
84110 public static DateTimeOffset GetDateTimeOffset ( DateTimeOffset ? start = null , DateTimeOffset ? end = null ) {
85111 if ( start . HasValue && end . HasValue )
86112 ArgumentOutOfRangeException . ThrowIfGreaterThanOrEqual ( start . Value , end . Value , nameof ( start ) ) ;
@@ -94,50 +120,77 @@ public static DateTimeOffset GetDateTimeOffset(DateTimeOffset? start = null, Dat
94120 return start . Value + newSpan ;
95121 }
96122
123+ /// <summary>
124+ /// Returns a random <see cref="TimeSpan"/> between <paramref name="min"/> and <paramref name="max"/>.
125+ /// Defaults to <see cref="TimeSpan.Zero"/> and <see cref="TimeSpan.MaxValue"/> when not specified.
126+ /// </summary>
127+ /// <remarks>Returns <paramref name="min"/> immediately when both values are equal.</remarks>
128+ /// <exception cref="ArgumentOutOfRangeException"><paramref name="min"/> is greater than <paramref name="max"/>.</exception>
97129 public static TimeSpan GetTimeSpan ( TimeSpan ? min = null , TimeSpan ? max = null ) {
98130 if ( min . HasValue && max . HasValue && min . Value == max . Value )
99131 return min . Value ;
100132
101133 if ( min . HasValue && max . HasValue )
102- ArgumentOutOfRangeException . ThrowIfGreaterThanOrEqual ( min . Value , max . Value , nameof ( min ) ) ;
134+ ArgumentOutOfRangeException . ThrowIfGreaterThan ( min . Value , max . Value , nameof ( min ) ) ;
103135
104136 min ??= TimeSpan . Zero ;
105137 max ??= TimeSpan . MaxValue ;
106138
107139 return min . Value + new TimeSpan ( ( long ) ( new TimeSpan ( max . Value . Ticks - min . Value . Ticks ) . Ticks * Random . Shared . NextDouble ( ) ) ) ;
108140 }
109141
142+ /// <summary>Returns <c>true</c> with the given probability percentage.</summary>
143+ /// <param name="chance">Probability of returning <c>true</c>, from 0 (never) to 100 (always). Clamped to [0, 100].</param>
110144 public static bool GetBool ( int chance = 50 ) {
111145 chance = Math . Clamp ( chance , 0 , 100 ) ;
112146 double c = 1 - ( chance / 100.0 ) ;
113147 return Random . Shared . NextDouble ( ) > c ;
114148 }
115149
150+ /// <summary>
151+ /// Returns a random <see cref="double"/> in the inclusive range [<paramref name="min"/>, <paramref name="max"/>].
152+ /// Defaults to <see cref="Double.MinValue"/> and <see cref="Double.MaxValue"/> when not specified.
153+ /// </summary>
154+ /// <remarks>Returns <paramref name="min"/> immediately when both values are equal.</remarks>
155+ /// <exception cref="ArgumentOutOfRangeException"><paramref name="min"/> is greater than <paramref name="max"/>.</exception>
116156 public static double GetDouble ( double ? min = null , double ? max = null ) {
117157 if ( min . HasValue && max . HasValue && min . Value == max . Value )
118158 return min . Value ;
119159
120160 if ( min . HasValue && max . HasValue )
121- ArgumentOutOfRangeException . ThrowIfGreaterThanOrEqual ( min . Value , max . Value , nameof ( min ) ) ;
161+ ArgumentOutOfRangeException . ThrowIfGreaterThan ( min . Value , max . Value , nameof ( min ) ) ;
122162
123163 min ??= Double . MinValue ;
124164 max ??= Double . MaxValue ;
125165
126166 return Random . Shared . NextDouble ( ) * ( max . Value - min . Value ) + min . Value ;
127167 }
128168
169+ /// <summary>Returns a random <see cref="decimal"/> using two random integers as bounds.</summary>
129170 public static decimal GetDecimal ( ) => GetDecimal ( GetInt ( ) , GetInt ( ) ) ;
130171
172+ /// <summary>Returns a random <see cref="decimal"/> in the range [<paramref name="min"/>, <paramref name="max"/>].</summary>
131173 public static decimal GetDecimal ( int min , int max ) => ( decimal ) GetDouble ( min , max ) ;
132174
175+ /// <summary>Returns a random value from the enum type <typeparamref name="T"/>.</summary>
133176 public static T GetEnum < T > ( ) where T : struct , Enum {
134177 Array values = Enum . GetValues ( typeof ( T ) ) ;
135178 return ( T ) values . GetValue ( GetInt ( 0 , values . Length - 1 ) ) ! ;
136179 }
137180
181+ /// <summary>Returns a random IPv4 address string in the form <c>"a.b.c.d"</c>.</summary>
138182 public static string GetIp4Address ( ) => $ "{ GetInt ( 0 , 255 ) } .{ GetInt ( 0 , 255 ) } .{ GetInt ( 0 , 255 ) } .{ GetInt ( 0 , 255 ) } ";
139183
140184 private const string DEFAULT_RANDOM_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" ;
185+
186+ /// <summary>
187+ /// Returns a random string of the specified length using <paramref name="allowedChars"/> as the character pool.
188+ /// Uses a cryptographically secure source to eliminate modulo bias.
189+ /// </summary>
190+ /// <param name="minLength">Minimum length of the generated string.</param>
191+ /// <param name="maxLength">Maximum length of the generated string.</param>
192+ /// <param name="allowedChars">Pool of characters to pick from. Must contain 256 or fewer distinct characters.</param>
193+ /// <exception cref="ArgumentOutOfRangeException"><paramref name="allowedChars"/> contains more than 256 distinct characters.</exception>
141194 public static string GetString ( int minLength = 5 , int maxLength = 20 , string allowedChars = DEFAULT_RANDOM_CHARS ) {
142195 int length = minLength != maxLength ? GetInt ( minLength , maxLength ) : minLength ;
143196
@@ -163,19 +216,31 @@ public static string GetString(int minLength = 5, int maxLength = 20, string all
163216
164217 // Some characters are left out because they are hard to tell apart.
165218 private const string DEFAULT_ALPHA_CHARS = "abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ" ;
219+
220+ /// <summary>Returns a random alpha string (no ambiguous characters such as l/1 or O/0).</summary>
166221 public static string GetAlphaString ( int minLength = 5 , int maxLength = 20 ) => GetString ( minLength , maxLength , DEFAULT_ALPHA_CHARS ) ;
167222
168223 // Some characters are left out because they are hard to tell apart.
169224 private const string DEFAULT_ALPHANUMERIC_CHARS = "abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789" ;
225+
226+ /// <summary>Returns a random alphanumeric string (no ambiguous characters such as l/1 or O/0).</summary>
170227 public static string GetAlphaNumericString ( int minLength = 5 , int maxLength = 20 ) => GetString ( minLength , maxLength , DEFAULT_ALPHANUMERIC_CHARS ) ;
171228
229+ /// <summary>Returns a title-cased phrase of random lorem ipsum words.</summary>
172230 public static string GetTitleWords ( int minWords = 2 , int maxWords = 10 ) => GetWords ( minWords , maxWords , titleCaseAllWords : true ) ;
173231
232+ /// <summary>Returns a single random lorem ipsum word, optionally title-cased.</summary>
174233 public static string GetWord ( bool titleCase = true ) {
175234 var word = _words [ GetInt ( 0 , _words . Length - 1 ) ] ;
176235 return titleCase ? UpperCaseFirstCharacter ( word ) : word ;
177236 }
178237
238+ /// <summary>Returns a space-separated phrase of random lorem ipsum words.</summary>
239+ /// <param name="minWords">Minimum number of words. Must be 2 or more.</param>
240+ /// <param name="maxWords">Maximum number of words. Must be 2 or more.</param>
241+ /// <param name="titleCaseFirstWord">Whether to title-case the first word.</param>
242+ /// <param name="titleCaseAllWords">Whether to title-case every word.</param>
243+ /// <exception cref="ArgumentOutOfRangeException"><paramref name="minWords"/> or <paramref name="maxWords"/> is less than 2.</exception>
179244 public static string GetWords ( int minWords = 2 , int maxWords = 10 , bool titleCaseFirstWord = true , bool titleCaseAllWords = true ) {
180245 ArgumentOutOfRangeException . ThrowIfLessThan ( minWords , 2 ) ;
181246 ArgumentOutOfRangeException . ThrowIfLessThan ( maxWords , 2 ) ;
@@ -188,6 +253,10 @@ public static string GetWords(int minWords = 2, int maxWords = 10, bool titleCas
188253 return builder . ToString ( ) . Trim ( ) ;
189254 }
190255
256+ /// <summary>Returns a random lorem ipsum sentence ending with a period.</summary>
257+ /// <param name="minWords">Minimum number of words. Must be 3 or more.</param>
258+ /// <param name="maxWords">Maximum number of words. Must be 3 or more.</param>
259+ /// <exception cref="ArgumentOutOfRangeException"><paramref name="minWords"/> or <paramref name="maxWords"/> is less than 3.</exception>
191260 public static string GetSentence ( int minWords = 5 , int maxWords = 25 ) {
192261 ArgumentOutOfRangeException . ThrowIfLessThan ( minWords , 3 ) ;
193262 ArgumentOutOfRangeException . ThrowIfLessThan ( maxWords , 3 ) ;
@@ -218,6 +287,14 @@ private static string UpperCaseFirstCharacter(string input) {
218287 return new String ( chars ) ;
219288 }
220289
290+ /// <summary>Returns one or more paragraphs of random lorem ipsum text.</summary>
291+ /// <param name="count">Number of paragraphs. Must be 1 or more.</param>
292+ /// <param name="minSentences">Minimum sentences per paragraph. Must be 1 or more.</param>
293+ /// <param name="maxSentences">Maximum sentences per paragraph.</param>
294+ /// <param name="minSentenceWords">Minimum words per sentence.</param>
295+ /// <param name="maxSentenceWords">Maximum words per sentence.</param>
296+ /// <param name="html">When <c>true</c>, wraps each paragraph in <c><p></c> tags.</param>
297+ /// <exception cref="ArgumentOutOfRangeException"><paramref name="count"/> or <paramref name="minSentences"/> is less than 1.</exception>
221298 public static string GetParagraphs ( int count = 3 , int minSentences = 3 , int maxSentences = 25 , int minSentenceWords = 5 , int maxSentenceWords = 25 , bool html = false ) {
222299 ArgumentOutOfRangeException . ThrowIfLessThan ( count , 1 ) ;
223300 ArgumentOutOfRangeException . ThrowIfLessThan ( minSentences , 1 ) ;
@@ -299,7 +376,11 @@ public static string GetParagraphs(int count = 3, int minSentences = 3, int maxS
299376 ] ;
300377}
301378
379+ /// <summary>Extension methods for <see cref="IEnumerable{T}"/> providing random element selection.</summary>
302380public static class EnumerableExtensions {
381+ /// <summary>
382+ /// Returns a random element from <paramref name="items"/>, or <paramref name="defaultValue"/> if the sequence is null or empty.
383+ /// </summary>
303384 public static T ? Random < T > ( this IEnumerable < T > ? items , T ? defaultValue = default ) {
304385 if ( items is null )
305386 return defaultValue ;
0 commit comments