Improved exception messages of builders (#3092)

* Fixed type reader/converter parsing exception

* Added the provided value to exceptions of some builders and, used more the Preconditions class.

* Removed unused `System.Xml.Linq` usings
This commit is contained in:
Suiram1701
2025-04-14 23:19:03 +02:00
committed by GitHub
parent 649f52b491
commit cce62747c9
11 changed files with 74 additions and 99 deletions

View File

@@ -1,5 +1,4 @@
using System; using System;
using System.Xml.Linq;
namespace Discord; namespace Discord;

View File

@@ -1,5 +1,4 @@
using System; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
@@ -147,29 +146,20 @@ namespace Discord
private static void EnsureValidOptionName(string name) private static void EnsureValidOptionName(string name)
{ {
if (name == null) Preconditions.NotNull(name, nameof(Name));
throw new ArgumentNullException(nameof(name), $"{nameof(Name)} cannot be null."); Preconditions.AtMost(name.Length, 32, nameof(Name));
if (name.Length > 32)
throw new ArgumentOutOfRangeException(nameof(name), "Name length must be less than or equal to 32.");
if (!Regex.IsMatch(name, @"^[-_\p{L}\p{N}\p{IsDevanagari}\p{IsThai}]{1,32}$")) if (!Regex.IsMatch(name, @"^[-_\p{L}\p{N}\p{IsDevanagari}\p{IsThai}]{1,32}$"))
throw new ArgumentException(@"Name must match the regex ^[-_\p{L}\p{N}\p{IsDevanagari}\p{IsThai}]{1,32}$", nameof(name)); throw new ArgumentException(@$"Name must match the regex ^[-_\p{{L}}\p{{N}}\p{{IsDevanagari}}\p{{IsThai}}]{{1,32}}$. Value: ""{name}""", nameof(name));
if (name.Any(char.IsUpper)) if (name.Any(char.IsUpper))
throw new FormatException("Name cannot contain any uppercase characters."); throw new FormatException($"Name cannot contain any uppercase characters. Value: \"{name}\"");
} }
private static void EnsureValidOptionDescription(string description) private static void EnsureValidOptionDescription(string description)
{ {
switch (description.Length) Preconditions.AtLeast(description.Length, 1, nameof(Description));
{ Preconditions.AtMost(description.Length, 100, nameof(Description));
case > 100:
throw new ArgumentOutOfRangeException(nameof(description),
"Description length must be less than or equal to 100.");
case 0:
throw new ArgumentOutOfRangeException(nameof(description), "Description length must at least 1.");
}
} }
} }
} }

View File

@@ -1,7 +1,5 @@
using System; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
namespace Discord namespace Discord
@@ -21,12 +19,12 @@ namespace Discord
public string Name public string Name
{ {
get => _name; get => _name;
set => _name = value?.Length switch set
{ {
> 100 => throw new ArgumentOutOfRangeException(nameof(value), "Name length must be less than or equal to 100."), Preconditions.AtLeast(value.Length, 1, nameof(Name));
0 => throw new ArgumentOutOfRangeException(nameof(value), "Name length must at least 1."), Preconditions.AtMost(value.Length, 100, nameof(Name));
_ => value _name = value;
}; }
} }
/// <summary> /// <summary>
@@ -41,7 +39,7 @@ namespace Discord
set set
{ {
if (value != null && value is not string && !value.IsNumericType()) if (value != null && value is not string && !value.IsNumericType())
throw new ArgumentException("The value of a choice must be a string or a numeric type!"); throw new ArgumentException($"The value of a choice must be a string or a numeric type! Value: \"{value}\"");
_value = value; _value = value;
} }
} }
@@ -60,16 +58,10 @@ namespace Discord
foreach (var (locale, name) in value) foreach (var (locale, name) in value)
{ {
if (!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$")) if (!Regex.IsMatch(locale, @"^\w{2}(?:-\w{2})?$"))
throw new ArgumentException("Key values of the dictionary must be valid language codes."); throw new ArgumentException($"Key values of the dictionary must be valid language codes. Locale: \"{locale}\"");
switch (name.Length) Preconditions.AtLeast(name.Length, 1, nameof(name), msg: $"Name value of locale {locale} cannot be empty.");
{ Preconditions.AtMost(name.Length, 100, nameof(name), msg: $"Name value of locale {locale} have to contains 100 chars at most.");
case > 100:
throw new ArgumentOutOfRangeException(nameof(value),
"Name length must be less than or equal to 100.");
case 0:
throw new ArgumentOutOfRangeException(nameof(value), "Name length must at least 1.");
}
} }
} }

View File

@@ -46,7 +46,7 @@ namespace Discord
Preconditions.AtMost(name.Length, SlashCommandBuilder.MaxNameLength, nameof(name)); Preconditions.AtMost(name.Length, SlashCommandBuilder.MaxNameLength, nameof(name));
if (Type == ApplicationCommandType.Slash && !Regex.IsMatch(name, @"^[-_\p{L}\p{N}\p{IsDevanagari}\p{IsThai}]{1,32}$")) if (Type == ApplicationCommandType.Slash && !Regex.IsMatch(name, @"^[-_\p{L}\p{N}\p{IsDevanagari}\p{IsThai}]{1,32}$"))
throw new ArgumentException(@"Name must match the regex ^[-_\p{L}\p{N}\p{IsDevanagari}\p{IsThai}]{1,32}$", nameof(name)); throw new ArgumentException(@$"Name must match the regex ^[-_\p{{L}}\p{{N}}\p{{IsDevanagari}}\p{{IsThai}}]{{1,32}}$. Value: ""{name}""", nameof(name));
} }
} }

View File

@@ -23,14 +23,10 @@ namespace Discord
get => _name; get => _name;
set set
{ {
if (value == null) Preconditions.NotNull(value, nameof(Name));
throw new ArgumentNullException(nameof(value), $"{nameof(Name)} cannot be null."); Preconditions.AtLeast(value.Length, 1, nameof(Name));
_name = value.Length switch Preconditions.AtMost(value.Length, 100, nameof(Name));
{ _name = value;
> 100 => throw new ArgumentOutOfRangeException(nameof(value), "Name length must be less than or equal to 100."),
0 => throw new ArgumentOutOfRangeException(nameof(value), "Name length must be at least 1."),
_ => value
};
} }
} }
@@ -48,7 +44,7 @@ namespace Discord
set set
{ {
if (value is not string && !value.IsNumericType()) if (value is not string && !value.IsNumericType())
throw new ArgumentException($"{nameof(value)} must be a numeric type or a string!"); throw new ArgumentException($"{nameof(value)} must be a numeric type or a string! Value: \"{value}\"");
_value = value; _value = value;
} }

View File

@@ -22,12 +22,12 @@ public class ButtonBuilder
public string Label public string Label
{ {
get => _label; get => _label;
set => _label = value?.Length switch set
{ {
> MaxButtonLabelLength => throw new ArgumentOutOfRangeException(nameof(value), $"Label length must be less or equal to {MaxButtonLabelLength}."), Preconditions.AtLeast(value.Length, 1, nameof(Label));
0 => throw new ArgumentOutOfRangeException(nameof(value), "Label length must be at least 1."), Preconditions.AtMost(value.Length, MaxButtonLabelLength, nameof(Label));
_ => value _label = value;
}; }
} }
/// <summary> /// <summary>
@@ -38,12 +38,12 @@ public class ButtonBuilder
public string CustomId public string CustomId
{ {
get => _customId; get => _customId;
set => _customId = value?.Length switch set
{ {
> ComponentBuilder.MaxCustomIdLength => throw new ArgumentOutOfRangeException(nameof(value), $"Custom Id length must be less or equal to {ComponentBuilder.MaxCustomIdLength}."), Preconditions.AtLeast(value.Length, 1, nameof(CustomId));
0 => throw new ArgumentOutOfRangeException(nameof(value), "Custom Id length must be at least 1."), Preconditions.AtMost(value.Length, ComponentBuilder.MaxCustomIdLength, nameof(CustomId));
_ => value _customId = value;
}; }
} }
/// <summary> /// <summary>
@@ -294,7 +294,6 @@ public class ButtonBuilder
throw new InvalidOperationException("A button must have an Emote or a label!"); throw new InvalidOperationException("A button must have an Emote or a label!");
if (string.IsNullOrWhiteSpace(CustomId)) if (string.IsNullOrWhiteSpace(CustomId))
throw new InvalidOperationException("Non-link and non-premium buttons must have a custom id associated with them"); throw new InvalidOperationException("Non-link and non-premium buttons must have a custom id associated with them");
} }
break; break;

View File

@@ -33,12 +33,12 @@ public class SelectMenuBuilder
public string CustomId public string CustomId
{ {
get => _customId; get => _customId;
set => _customId = value?.Length switch set
{ {
> ComponentBuilder.MaxCustomIdLength => throw new ArgumentOutOfRangeException(nameof(value), $"Custom Id length must be less or equal to {ComponentBuilder.MaxCustomIdLength}."), Preconditions.AtLeast(value.Length, 1, nameof(CustomId));
0 => throw new ArgumentOutOfRangeException(nameof(value), "Custom Id length must be at least 1."), Preconditions.AtMost(value.Length, ComponentBuilder.MaxCustomIdLength, nameof(CustomId));
_ => value _customId = value;
}; }
} }
/// <summary> /// <summary>
@@ -61,12 +61,12 @@ public class SelectMenuBuilder
public string Placeholder public string Placeholder
{ {
get => _placeholder; get => _placeholder;
set => _placeholder = value?.Length switch set
{ {
> MaxPlaceholderLength => throw new ArgumentOutOfRangeException(nameof(value), $"Placeholder length must be less or equal to {MaxPlaceholderLength}."), Preconditions.AtLeast(value.Length, 1, nameof(Placeholder));
0 => throw new ArgumentOutOfRangeException(nameof(value), "Placeholder length must be at least 1."), Preconditions.AtMost(value.Length, MaxPlaceholderLength, nameof(Placeholder));
_ => value _placeholder = value;
}; }
} }
/// <summary> /// <summary>
@@ -109,7 +109,6 @@ public class SelectMenuBuilder
{ {
if (value != null) if (value != null)
Preconditions.AtMost(value.Count, MaxOptionCount, nameof(Options)); Preconditions.AtMost(value.Count, MaxOptionCount, nameof(Options));
_options = value; _options = value;
} }
} }

View File

@@ -30,12 +30,12 @@ public class SelectMenuOptionBuilder
public string Label public string Label
{ {
get => _label; get => _label;
set => _label = value?.Length switch set
{ {
> MaxSelectLabelLength => throw new ArgumentOutOfRangeException(nameof(value), $"Label length must be less or equal to {MaxSelectLabelLength}."), Preconditions.AtLeast(value.Length, 1, nameof(Label));
0 => throw new ArgumentOutOfRangeException(nameof(value), "Label length must be at least 1."), Preconditions.AtMost(value.Length, MaxSelectLabelLength, nameof(Label));
_ => value _label = value;
}; }
} }
/// <summary> /// <summary>
@@ -46,12 +46,12 @@ public class SelectMenuOptionBuilder
public string Value public string Value
{ {
get => _value; get => _value;
set => _value = value?.Length switch set
{ {
> MaxSelectValueLength => throw new ArgumentOutOfRangeException(nameof(value), $"Value length must be less or equal to {MaxSelectValueLength}."), Preconditions.AtLeast(value.Length, 1, nameof(Value));
0 => throw new ArgumentOutOfRangeException(nameof(value), "Value length must be at least 1."), Preconditions.AtMost(value.Length, MaxSelectValueLength, nameof(Value));
_ => value _value = value;
}; }
} }
/// <summary> /// <summary>
@@ -62,12 +62,12 @@ public class SelectMenuOptionBuilder
public string Description public string Description
{ {
get => _description; get => _description;
set => _description = value?.Length switch set
{ {
> MaxDescriptionLength => throw new ArgumentOutOfRangeException(nameof(value), $"Description length must be less or equal to {MaxDescriptionLength}."), Preconditions.AtLeast(value.Length, 1, nameof(Description));
0 => throw new ArgumentOutOfRangeException(nameof(value), "Description length must be at least 1."), Preconditions.AtMost(value.Length, MaxDescriptionLength, nameof(Description));
_ => value _description = value;
}; }
} }
/// <summary> /// <summary>

View File

@@ -22,12 +22,12 @@ public class TextInputBuilder
public string CustomId public string CustomId
{ {
get => _customId; get => _customId;
set => _customId = value?.Length switch set
{ {
> ComponentBuilder.MaxCustomIdLength => throw new ArgumentOutOfRangeException(nameof(value), $"Custom Id length must be less or equal to {ComponentBuilder.MaxCustomIdLength}."), Preconditions.AtLeast(value.Length, 1, nameof(CustomId));
0 => throw new ArgumentOutOfRangeException(nameof(value), "Custom Id length must be at least 1."), Preconditions.AtMost(value.Length, ComponentBuilder.MaxCustomIdLength, nameof(CustomId));
_ => value _customId = value;
}; }
} }
/// <summary> /// <summary>
@@ -49,7 +49,7 @@ public class TextInputBuilder
get => _placeholder; get => _placeholder;
set => _placeholder = (value?.Length ?? 0) <= MaxPlaceholderLength set => _placeholder = (value?.Length ?? 0) <= MaxPlaceholderLength
? value ? value
: throw new ArgumentException($"Placeholder cannot have more than {MaxPlaceholderLength} characters."); : throw new ArgumentException($"Placeholder cannot have more than {MaxPlaceholderLength} characters. Value: \"{value}\"");
} }
/// <summary> /// <summary>
@@ -115,9 +115,9 @@ public class TextInputBuilder
set set
{ {
if (value?.Length > (MaxLength ?? LargestMaxLength)) if (value?.Length > (MaxLength ?? LargestMaxLength))
throw new ArgumentOutOfRangeException(nameof(value), $"Value must not be longer than {MaxLength ?? LargestMaxLength}."); throw new ArgumentOutOfRangeException(nameof(value), $"Value must not be longer than {MaxLength ?? LargestMaxLength}. Value: \"{value}\"");
if (value?.Length < (MinLength ?? 0)) if (value?.Length < (MinLength ?? 0))
throw new ArgumentOutOfRangeException(nameof(value), $"Value must not be shorter than {MinLength}"); throw new ArgumentOutOfRangeException(nameof(value), $"Value must not be shorter than {MinLength}. Value: \"{value}\"");
_value = value; _value = value;
} }

View File

@@ -38,12 +38,12 @@ namespace Discord
public string CustomId public string CustomId
{ {
get => _customId; get => _customId;
set => _customId = value?.Length switch set
{ {
> ComponentBuilder.MaxCustomIdLength => throw new ArgumentOutOfRangeException(nameof(value), $"Custom ID length must be less or equal to {ComponentBuilder.MaxCustomIdLength}."), Preconditions.AtLeast(value.Length, 1, nameof(CustomId));
0 => throw new ArgumentOutOfRangeException(nameof(value), "Custom ID length must be at least 1."), Preconditions.AtMost(value.Length, ComponentBuilder.MaxCustomIdLength, nameof(CustomId));
_ => value _customId = value;
}; }
} }
/// <summary> /// <summary>

View File

@@ -272,7 +272,7 @@ namespace Discord
// https://discord.com/developers/docs/interactions/application-commands // https://discord.com/developers/docs/interactions/application-commands
if (!Regex.IsMatch(name, @"^[-_\p{L}\p{N}\p{IsDevanagari}\p{IsThai}]{1,32}$")) if (!Regex.IsMatch(name, @"^[-_\p{L}\p{N}\p{IsDevanagari}\p{IsThai}]{1,32}$"))
throw new ArgumentException(@"Name must match the regex ^[-_\p{L}\p{N}\p{IsDevanagari}\p{IsThai}]{1,32}$", nameof(name)); throw new ArgumentException(@$"Name must match the regex ^[-_\p{{L}}\p{{N}}\p{{IsDevanagari}}\p{{IsThai}}]{{1,32}}$. Value: ""{name}""", nameof(name));
// make sure theres only one option with default set to true // make sure theres only one option with default set to true
if (isDefault == true && Options?.Any(x => x.IsDefault == true) == true) if (isDefault == true && Options?.Any(x => x.IsDefault == true) == true)
@@ -440,10 +440,10 @@ namespace Discord
// https://discord.com/developers/docs/interactions/application-commands // https://discord.com/developers/docs/interactions/application-commands
if (!Regex.IsMatch(name, @"^[-_\p{L}\p{N}\p{IsDevanagari}\p{IsThai}]{1,32}$")) if (!Regex.IsMatch(name, @"^[-_\p{L}\p{N}\p{IsDevanagari}\p{IsThai}]{1,32}$"))
throw new ArgumentException(@"Name must match the regex ^[-_\p{L}\p{N}\p{IsDevanagari}\p{IsThai}]{1,32}$", nameof(name)); throw new ArgumentException(@$"Name must match the regex ^[-_\p{{L]}}\p{{N}}\p{{IsDevanagari}}\p{{IsThai}}]{{1,32}}$. Value: ""{name}""", nameof(name));
if (name.Any(char.IsUpper)) if (name.Any(char.IsUpper))
throw new FormatException("Name cannot contain any uppercase characters."); throw new FormatException($"Name cannot contain any uppercase characters. Value: \"{name}\"");
} }
internal static void EnsureValidCommandDescription(string description) internal static void EnsureValidCommandDescription(string description)
@@ -650,7 +650,7 @@ namespace Discord
// https://discord.com/developers/docs/interactions/application-commands // https://discord.com/developers/docs/interactions/application-commands
if (!Regex.IsMatch(name, @"^[-_\p{L}\p{N}\p{IsDevanagari}\p{IsThai}]{1,32}$")) if (!Regex.IsMatch(name, @"^[-_\p{L}\p{N}\p{IsDevanagari}\p{IsThai}]{1,32}$"))
throw new ArgumentException(@"Name must match the regex ^[-_\p{L}\p{N}\p{IsDevanagari}\p{IsThai}]{1,32}$", nameof(name)); throw new ArgumentException(@$"Name must match the regex ^[-_\p{{L}}\p{{N}}\p{{IsDevanagari}}\p{{IsThai}}]{{1,32}}$. Value: ""{name}""", nameof(name));
// make sure theres only one option with default set to true // make sure theres only one option with default set to true
if (isDefault && Options?.Any(x => x.IsDefault == true) == true) if (isDefault && Options?.Any(x => x.IsDefault == true) == true)
@@ -1031,7 +1031,7 @@ namespace Discord
// https://discord.com/developers/docs/interactions/application-commands // https://discord.com/developers/docs/interactions/application-commands
if (!Regex.IsMatch(name, @"^[-_\p{L}\p{N}\p{IsDevanagari}\p{IsThai}]{1,32}$")) if (!Regex.IsMatch(name, @"^[-_\p{L}\p{N}\p{IsDevanagari}\p{IsThai}]{1,32}$"))
throw new ArgumentException(@"Name must match the regex ^[-_\p{L}\p{N}\p{IsDevanagari}\p{IsThai}]{1,32}$", nameof(name)); throw new ArgumentException(@$"Name must match the regex ^[-_\p{{L}}\p{{N}}\p{{IsDevanagari}}\p{{IsThai}}]{{1,32}}$. Value: ""{name}""", nameof(name));
} }
private static void EnsureValidCommandOptionDescription(string description) private static void EnsureValidCommandOptionDescription(string description)