Skip to content

Commit

Permalink
fix bs
Browse files Browse the repository at this point in the history
  • Loading branch information
Lulalaby committed Sep 21, 2023
1 parent cc08ec3 commit fe6bff6
Showing 1 changed file with 76 additions and 49 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using System;
using System.Collections.Generic;
using System.Linq;

Expand All @@ -11,6 +10,9 @@

namespace DisCatSharp.ApplicationCommands.Checks;

/// <summary>
/// The application command equality checks.
/// </summary>
internal static class ApplicationCommandEqualityChecks
{
/// <summary>
Expand All @@ -22,8 +24,7 @@ internal static class ApplicationCommandEqualityChecks
/// <param name="isGuild">Whether the equal check is performed for a guild command.</param>
internal static bool IsEqualTo(
this DiscordApplicationCommand? ac1,
DiscordApplicationCommand? targetApplicationCommand, DiscordClient client,
bool isGuild
DiscordApplicationCommand? targetApplicationCommand, DiscordClient client, bool isGuild
)
{
if (targetApplicationCommand is null || ac1 is null)
Expand All @@ -45,6 +46,10 @@ bool isGuild
{
sourceApplicationCommand.DmPermission = null;
targetApplicationCommand.DmPermission = null;
sourceApplicationCommand.IntegrationTypes = null;
targetApplicationCommand.IntegrationTypes = null;
sourceApplicationCommand.AllowedContexts = null;
targetApplicationCommand.AllowedContexts = null;
}
else
{
Expand All @@ -64,7 +69,7 @@ bool isGuild
JsonConvert.SerializeObject(targetApplicationCommand));

return ac1.Type == targetApplicationCommand.Type && sourceApplicationCommand.SoftEqual(targetApplicationCommand,
ac1.Type, ApplicationCommandsExtension.Configuration?.EnableLocalization ?? false, isGuild);
ac1.Type, client, ApplicationCommandsExtension.Configuration?.EnableLocalization ?? false, isGuild);
}

/// <summary>
Expand All @@ -74,11 +79,12 @@ bool isGuild
/// <param name="source">Source application command.</param>
/// <param name="target">Application command to check against.</param>
/// <param name="type">The application command type.</param>
/// <param name="client">The discord client.</param>
/// <param name="localizationEnabled">Whether localization is enabled.</param>
/// <param name="guild">Whether the equal check is performed for a guild command.</param>
internal static bool SoftEqual(
this DiscordApplicationCommand source, DiscordApplicationCommand target,
ApplicationCommandType type, bool localizationEnabled = false, bool guild = false
ApplicationCommandType type, BaseDiscordClient client, bool localizationEnabled = false, bool guild = false
)
{
bool? sDmPerm = source.DmPermission ?? true;
Expand All @@ -87,17 +93,18 @@ internal static bool SoftEqual(
return localizationEnabled
? type switch
{
ApplicationCommandType.ChatInput => DeepEqual(source, target, true, sDmPerm, tDmPerm),
ApplicationCommandType.ChatInput => DeepEqual(source, target, client, true, sDmPerm, tDmPerm),
_ => source.Name == target.Name
&& source.Type == target.Type && source.NameLocalizations == target.NameLocalizations
&& source.DefaultMemberPermissions == target.DefaultMemberPermissions
&& sDmPerm == tDmPerm && source.IsNsfw == target.IsNsfw
&& source.AllowedContexts.NullableSequenceEqual(target.AllowedContexts) &&
source.IntegrationTypes.NullableSequenceEqual(target.IntegrationTypes)
source.IntegrationTypes.NullableSequenceEqual(target.IntegrationTypes) &&
source.RawNameLocalizations.AreDictionariesEqual(target.RawNameLocalizations)
}
: type switch
{
ApplicationCommandType.ChatInput => DeepEqual(source, target, false, sDmPerm, tDmPerm),
ApplicationCommandType.ChatInput => DeepEqual(source, target, client, false, sDmPerm, tDmPerm),
_ => source.Name == target.Name
&& source.Type == target.Type
&& source.DefaultMemberPermissions == target.DefaultMemberPermissions
Expand All @@ -111,23 +118,20 @@ internal static bool SoftEqual(
return localizationEnabled
? type switch
{
ApplicationCommandType.ChatInput => DeepEqual(source, target, true, sDmPerm, tDmPerm),
ApplicationCommandType.ChatInput => DeepEqual(source, target, client, true, sDmPerm, tDmPerm),
_ => source.Name == target.Name
&& source.Type == target.Type && source.NameLocalizations == target.NameLocalizations
&& source.DefaultMemberPermissions == target.DefaultMemberPermissions
&& sDmPerm == tDmPerm && source.IsNsfw == target.IsNsfw
&& source.AllowedContexts.NullableSequenceEqual(target.AllowedContexts) &&
source.IntegrationTypes.NullableSequenceEqual(target.IntegrationTypes)
&& source.RawNameLocalizations.AreDictionariesEqual(target.RawNameLocalizations)
}
: type switch
{
ApplicationCommandType.ChatInput => DeepEqual(source, target, false, sDmPerm, tDmPerm),
ApplicationCommandType.ChatInput => DeepEqual(source, target, client, false, sDmPerm, tDmPerm),
_ => source.Name == target.Name
&& source.Type == target.Type
&& source.DefaultMemberPermissions == target.DefaultMemberPermissions
&& sDmPerm == tDmPerm && source.IsNsfw == target.IsNsfw
&& source.AllowedContexts.NullableSequenceEqual(target.AllowedContexts) &&
source.IntegrationTypes.NullableSequenceEqual(target.IntegrationTypes)
};
}

Expand All @@ -138,47 +142,72 @@ internal static bool SoftEqual(
/// <param name="source">The source enumerable.</param>
/// <param name="target">The target enumerable.</param>
/// <returns>Whether both nullable enumerable are equal.</returns>
internal static bool NullableSequenceEqual<T>(this IEnumerable<T>? source, IEnumerable<T>? target)
=> source is not null && target is not null
? source.OrderBy(x => x).SequenceEqual(target.OrderBy(x => x))
: (source is null || target is not null) &&
(source is not null || target is null);
internal static bool NullableSequenceEqual<T>(this List<T>? source, List<T>? target)
{
if (source is not null && target is not null)
return source.All(target.Contains) && source.Count == target.Count;

return source is null && target is null;
}

/// <summary>
/// Checks whether two dictionaries are equal.
/// </summary>
/// <param name="sourceDictionary">The source dictionary.</param>
/// <param name="targetDictionary">The target dictionary.</param>
/// <returns>Whether both dictionaries are equal.</returns>
internal static bool AreDictionariesEqual(this Dictionary<string, string> sourceDictionary, Dictionary<string, string> targetDictionary)
{
if (sourceDictionary?.Count != targetDictionary?.Count)
return false;

if (sourceDictionary is null && targetDictionary is null)
return true;

foreach (var kvp in sourceDictionary)
if (!targetDictionary.TryGetValue(kvp.Key, out var value) || value != kvp.Value)
return false;

return true;
}

/// <summary>
/// Checks deeply whether two <see cref="DiscordApplicationCommand"/>s are the same.
/// Excluding id, application id and version here.
/// </summary>
/// <param name="source">Source application command.</param>
/// <param name="target">Application command to check against.</param>
/// <param name="client">The discord client.</param>
/// <param name="localizationEnabled">Whether localization is enabled.</param>
/// <param name="sDmPerm">The source dm permission.</param>
/// <param name="tDmPerm">The target dm permission.</param>
internal static bool DeepEqual(
DiscordApplicationCommand source, DiscordApplicationCommand target,
DiscordApplicationCommand source, DiscordApplicationCommand target, BaseDiscordClient client,
bool localizationEnabled = false, bool? sDmPerm = null, bool? tDmPerm = null
)
{
var name = source.Name;
var rootCheck = source.Name == target.Name &&
source.Description == target.Description &&
source.Type == target.Type &&
source.DefaultMemberPermissions == target.DefaultMemberPermissions &&
sDmPerm == tDmPerm &&
source.IsNsfw == target.IsNsfw
&& source.AllowedContexts.NullableSequenceEqual(target.AllowedContexts) &&
source.IsNsfw == target.IsNsfw &&
source.AllowedContexts.NullableSequenceEqual(target.AllowedContexts) &&
source.IntegrationTypes.NullableSequenceEqual(target.IntegrationTypes);

if (localizationEnabled)
rootCheck = rootCheck &&
source.NameLocalizations.Localizations.NullableSequenceEqual(target.NameLocalizations
.Localizations) &&
source.DescriptionLocalizations.Localizations.NullableSequenceEqual(target
.DescriptionLocalizations
.Localizations);
source.RawNameLocalizations.AreDictionariesEqual(target.RawNameLocalizations) &&
source.RawDescriptionLocalizations.AreDictionariesEqual(target.RawDescriptionLocalizations);

// Compare the Options using recursion
var optionsEqual = DeepEqualOptions(source.Options, target.Options, localizationEnabled);
if (optionsEqual.Reason is not null)
client.Logger.Log(ApplicationCommandsExtension.ApplicationCommandsLogLevel, "Inequality found in options of {name} - {reason}", name, optionsEqual.Reason);
if (!rootCheck)
client.Logger.Log(ApplicationCommandsExtension.ApplicationCommandsLogLevel, "Inequality found in root of {name}", name);

return rootCheck && optionsEqual;
return rootCheck && optionsEqual.Equal;
}

/// <summary>
Expand All @@ -187,20 +216,19 @@ internal static bool DeepEqual(
/// <param name="sourceOptions">Source options.</param>
/// <param name="targetOptions">Options to check against.</param>
/// <param name="localizationEnabled">Whether localization is enabled.</param>
private static bool DeepEqualOptions(
private static (bool Equal, string? Reason) DeepEqualOptions(
IReadOnlyList<DiscordApplicationCommandOption>? sourceOptions,
IReadOnlyList<DiscordApplicationCommandOption>? targetOptions,
bool localizationEnabled
IReadOnlyList<DiscordApplicationCommandOption>? targetOptions, bool localizationEnabled
)
{
if (sourceOptions == null && targetOptions == null)
return true;
return (true, null);

if ((sourceOptions != null && targetOptions == null) || (sourceOptions == null && targetOptions != null))
return false;
return (false, "source or target option null, but not both");

if (sourceOptions!.Count != targetOptions!.Count)
return false;
return (false, "source option count mismatches target option count");

for (var i = 0; i < sourceOptions.Count; i++)
{
Expand All @@ -212,44 +240,43 @@ bool localizationEnabled
sourceOption.Type == targetOption.Type &&
sourceOption.Required == targetOption.Required &&
sourceOption.AutoComplete == targetOption.AutoComplete &&
sourceOption.MinimumValue == targetOption.MinimumValue &&
sourceOption.MaximumValue == targetOption.MaximumValue &&
sourceOption.MinimumValue?.ToString() == targetOption.MinimumValue?.ToString() &&
sourceOption.MaximumValue?.ToString() == targetOption.MaximumValue?.ToString() &&
sourceOption.MinimumLength == targetOption.MinimumLength &&
sourceOption.MaximumLength == targetOption.MaximumLength;

if (localizationEnabled)
optionCheck = optionCheck &&
sourceOption.NameLocalizations.Localizations.NullableSequenceEqual(targetOption
.NameLocalizations
.Localizations) &&
sourceOption.DescriptionLocalizations.Localizations.NullableSequenceEqual(targetOption
.DescriptionLocalizations.Localizations);
sourceOption.RawNameLocalizations.AreDictionariesEqual(targetOption.RawNameLocalizations) &&
sourceOption.RawDescriptionLocalizations.AreDictionariesEqual(targetOption
.RawDescriptionLocalizations);

if ((sourceOption.Choices is null && targetOption.Choices is not null) ||
(sourceOption.Choices is not null && targetOption.Choices is null))
return false;
return (false, "source or target choices null, but not both - " + sourceOption.Name);

if (sourceOption.Choices is not null && targetOption.Choices is not null)
{
var j1 = JsonConvert.SerializeObject(sourceOption.Choices.OrderBy(x => x.Name), Formatting.None);
var j2 = JsonConvert.SerializeObject(targetOption.Choices.OrderBy(x => x.Name), Formatting.None);
if (j1 != j2)
return false;
return (false, "choice mismatch - " + sourceOption.Name);
}

if ((sourceOption.ChannelTypes is null && targetOption.ChannelTypes is not null) ||
(sourceOption.ChannelTypes is not null && targetOption.ChannelTypes is null) ||
(sourceOption.ChannelTypes is not null && targetOption.ChannelTypes is not null &&
!sourceOption.ChannelTypes.OrderBy(x => x).All(targetOption.ChannelTypes.OrderBy(x => x).Contains)))
return false;
return (false, "channel type mismatch - " + sourceOption.Name);

if (!DeepEqualOptions(sourceOption.Options, targetOption.Options, localizationEnabled))
return false;
var rec = DeepEqualOptions(sourceOption.Options, targetOption.Options, localizationEnabled);
if (!rec.Equal)
return (false, "Options Recursive - " + sourceOption.Name + " -- " + rec.Reason);

if (!optionCheck)
return false;
return (false, "OptionCheck - " + sourceOption.Name);
}

return true;
return (true, null);
}
}

0 comments on commit fe6bff6

Please sign in to comment.