Skip to content

Commit 09b42ee

Browse files
Fix argument guards: ThrowIfGreaterThan not ThrowIfGreaterThanOrEqual when equal is allowed; add XML docs to all public API
Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent e850b06 commit 09b42ee

File tree

1 file changed

+86
-5
lines changed

1 file changed

+86
-5
lines changed

src/Exceptionless.RandomData/RandomData.cs

Lines changed: 86 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,30 @@
33

44
namespace Exceptionless;
55

6+
/// <summary>Generates random data for use in unit tests and data seeding.</summary>
67
public 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>&lt;p&gt;</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>
302380
public 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

Comments
 (0)