diff --git a/Color-Chan.Discord.sln b/Color-Chan.Discord.sln
index 4c8b5cf5..e2699ffa 100644
--- a/Color-Chan.Discord.sln
+++ b/Color-Chan.Discord.sln
@@ -54,6 +54,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ButtonArgs", "samples\Butto
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ComponentsV2", "samples\ComponentsV2\ComponentsV2.csproj", "{3D545B51-0245-43BF-9588-2C299B7DD9A5}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Color-Chan.Discord.Commands.Tests.Valid2", "tests\mockCommandAssemblies\Color-Chan.Discord.Commands.Tests.Valid2\Color-Chan.Discord.Commands.Tests.Valid2.csproj", "{A19857F5-7AC6-4CAE-BAB4-7CE371F96300}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -136,6 +138,10 @@ Global
{3D545B51-0245-43BF-9588-2C299B7DD9A5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3D545B51-0245-43BF-9588-2C299B7DD9A5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3D545B51-0245-43BF-9588-2C299B7DD9A5}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A19857F5-7AC6-4CAE-BAB4-7CE371F96300}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A19857F5-7AC6-4CAE-BAB4-7CE371F96300}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A19857F5-7AC6-4CAE-BAB4-7CE371F96300}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A19857F5-7AC6-4CAE-BAB4-7CE371F96300}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -162,6 +168,7 @@ Global
{4D344610-2AD1-44D1-A3FE-76908972AA9B} = {B2D862F3-8ED1-4D09-8248-8D4B5EB2737A}
{7F0D86B2-209D-4C6A-BB68-489C59756FC2} = {B2D862F3-8ED1-4D09-8248-8D4B5EB2737A}
{3D545B51-0245-43BF-9588-2C299B7DD9A5} = {B2D862F3-8ED1-4D09-8248-8D4B5EB2737A}
+ {A19857F5-7AC6-4CAE-BAB4-7CE371F96300} = {ADBC5773-D0F4-4A9E-BC6F-6EF9220718A4}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {AC84D902-ABC1-47C3-9993-F769F483E5CE}
diff --git a/src/Color-Chan.Discord.Commands/Services/Builders/ISlashCommandBuildService.cs b/src/Color-Chan.Discord.Commands/Services/Builders/ISlashCommandBuildService.cs
index b88365f7..ec554b67 100644
--- a/src/Color-Chan.Discord.Commands/Services/Builders/ISlashCommandBuildService.cs
+++ b/src/Color-Chan.Discord.Commands/Services/Builders/ISlashCommandBuildService.cs
@@ -12,12 +12,12 @@ namespace Color_Chan.Discord.Commands.Services.Builders;
public interface ISlashCommandBuildService
{
///
- /// Builds all commands in a specific and stores them in a
+ /// Builds all commands in specific and stores them in a
/// of of ,
/// .
///
- ///
- /// The where the will search for commands.
+ ///
+ /// The s where the will search for commands.
///
///
/// A of of ,
@@ -25,7 +25,7 @@ public interface ISlashCommandBuildService
/// The key contains the command name.
/// And the value contains the commands information to execute it.
///
- IReadOnlyList> BuildSlashCommandInfos(Assembly assembly);
+ IReadOnlyList> BuildSlashCommandInfos(params Assembly[] assemblies);
///
/// Get all the interaction command modules.
diff --git a/src/Color-Chan.Discord.Commands/Services/ISlashCommandService.cs b/src/Color-Chan.Discord.Commands/Services/ISlashCommandService.cs
index 8fee67f4..54777463 100644
--- a/src/Color-Chan.Discord.Commands/Services/ISlashCommandService.cs
+++ b/src/Color-Chan.Discord.Commands/Services/ISlashCommandService.cs
@@ -16,12 +16,12 @@ namespace Color_Chan.Discord.Commands.Services;
public interface ISlashCommandService
{
///
- /// Add all interaction commands in an to the .
+ /// Add all interaction commands in s to the .
///
- /// The where the commands are located.
+ /// The s where the commands are located.
///
///
- Task AddInteractionCommandsAsync(Assembly assembly);
+ Task AddInteractionCommandsAsync(params Assembly[] assemblies);
///
/// Execute a specific command with their dependencies.
@@ -41,9 +41,14 @@ public interface ISlashCommandService
///
///
///
- Task> ExecuteSlashCommandAsync(MethodInfo commandMethod, IEnumerable? options,
- IEnumerable? requirements, ISlashCommandContext context,
- List? suppliedOptions = null, IServiceProvider? serviceProvider = null);
+ Task> ExecuteSlashCommandAsync(
+ MethodInfo commandMethod,
+ IEnumerable? options,
+ IEnumerable? requirements,
+ ISlashCommandContext context,
+ List? suppliedOptions = null,
+ IServiceProvider? serviceProvider = null
+ );
///
/// Execute a specific command with their dependencies.
@@ -61,8 +66,12 @@ Task> ExecuteSlashCommandAsync(MethodInfo co
///
///
///
- Task> ExecuteSlashCommandAsync(ISlashCommandInfo commandInfo, ISlashCommandContext context, List? suppliedOptions = null,
- IServiceProvider? serviceProvider = null);
+ Task> ExecuteSlashCommandAsync(
+ ISlashCommandInfo commandInfo,
+ ISlashCommandContext context,
+ List? suppliedOptions = null,
+ IServiceProvider? serviceProvider = null
+ );
///
/// Execute a specific command with their dependencies.
@@ -80,8 +89,12 @@ Task> ExecuteSlashCommandAsync(ISlashCommand
///
///
///
- Task> ExecuteSlashCommandAsync(ISlashCommandOptionInfo commandOptionInfo, ISlashCommandContext context,
- List? suppliedOptions = null, IServiceProvider? serviceProvider = null);
+ Task> ExecuteSlashCommandAsync(
+ ISlashCommandOptionInfo commandOptionInfo,
+ ISlashCommandContext context,
+ List? suppliedOptions = null,
+ IServiceProvider? serviceProvider = null
+ );
///
/// Execute a specific command with their dependencies.
@@ -98,8 +111,11 @@ Task> ExecuteSlashCommandAsync(ISlashCommand
///
///
///
- Task> ExecuteSlashCommandAsync(ISlashCommandContext context, IEnumerable? options = null,
- IServiceProvider? serviceProvider = null);
+ Task> ExecuteSlashCommandAsync(
+ ISlashCommandContext context,
+ IEnumerable? options = null,
+ IServiceProvider? serviceProvider = null
+ );
///
/// Search for a command by its .
diff --git a/src/Color-Chan.Discord.Commands/Services/Implementations/Builders/SlashCommandBuildService.cs b/src/Color-Chan.Discord.Commands/Services/Implementations/Builders/SlashCommandBuildService.cs
index 937ebf1c..c1b88213 100644
--- a/src/Color-Chan.Discord.Commands/Services/Implementations/Builders/SlashCommandBuildService.cs
+++ b/src/Color-Chan.Discord.Commands/Services/Implementations/Builders/SlashCommandBuildService.cs
@@ -41,8 +41,11 @@ public class SlashCommandBuildService : ISlashCommandBuildService
/// The that will get and build the
/// s.
///
- public SlashCommandBuildService(ISlashCommandRequirementBuildService requirementBuildService, ISlashCommandGuildBuildService guildBuildService, ILogger logger,
- ISlashCommandOptionBuildService optionBuildService)
+ public SlashCommandBuildService(
+ ISlashCommandRequirementBuildService requirementBuildService,
+ ISlashCommandGuildBuildService guildBuildService,
+ ILogger logger,
+ ISlashCommandOptionBuildService optionBuildService)
{
_requirementBuildService = requirementBuildService;
_guildBuildService = guildBuildService;
@@ -51,40 +54,45 @@ public SlashCommandBuildService(ISlashCommandRequirementBuildService requirement
}
///
- public IReadOnlyList> BuildSlashCommandInfos(Assembly assembly)
+ public IReadOnlyList> BuildSlashCommandInfos(params Assembly[] assemblies)
{
- _logger.LogInformation("Loading interaction commands for assembly {AssemblyName}", assembly.FullName);
var validCommands = new List>();
- foreach (var parentModule in GetSlashCommandModules(assembly))
+ foreach (var assembly in assemblies)
{
- if (IsValidCommandGroupModuleDefinition(parentModule))
+ _logger.LogInformation("Loading interaction commands for assembly {AssemblyName}", assembly.FullName);
+
+ foreach (var parentModule in GetSlashCommandModules(assembly))
{
- var groupAttribute = parentModule.GetCustomAttribute();
- if (groupAttribute is null)
+ if (IsValidCommandGroupModuleDefinition(parentModule))
{
- _logger.LogWarning("Can not load command group {ModuleName} since it doesn't have the SlashCommandGroupAttribute attribute", parentModule.Name);
- continue;
+ var groupAttribute = parentModule.GetCustomAttribute();
+ if (groupAttribute is null)
+ {
+ _logger.LogWarning("Can not load command group {ModuleName} since it doesn't have the SlashCommandGroupAttribute attribute", parentModule.Name);
+ continue;
+ }
+
+ var commandInfoKeyValuePair = BuildCommandGroupInfoKeyValuePair(groupAttribute, parentModule);
+ validCommands.Add(commandInfoKeyValuePair);
+ _logger.LogDebug("Found valid command in command module {TopLevelCommandName}", commandInfoKeyValuePair.Key);
}
- var commandInfoKeyValuePair = BuildCommandGroupInfoKeyValuePair(groupAttribute, parentModule);
- validCommands.Add(commandInfoKeyValuePair);
- _logger.LogDebug("Found valid command in command module {TopLevelCommandName}", commandInfoKeyValuePair.Key);
- }
-
- // The command is not a sub command / group.
+ // The command is not a sub command / group.
- foreach (var validMethod in GetValidSlashCommandsMethods(parentModule))
- {
- var commandInfoKeyValuePair = BuildCommandInfoKeyValuePair(validMethod, parentModule);
+ foreach (var validMethod in GetValidSlashCommandsMethods(parentModule))
+ {
+ var commandInfoKeyValuePair = BuildCommandInfoKeyValuePair(validMethod, parentModule);
- if (!commandInfoKeyValuePair.HasValue) continue;
- validCommands.Add(commandInfoKeyValuePair.Value);
- _logger.LogDebug("Found valid command in command module {TopLevelCommandName}", commandInfoKeyValuePair.Value.Key);
+ if (!commandInfoKeyValuePair.HasValue) continue;
+ validCommands.Add(commandInfoKeyValuePair.Value);
+ _logger.LogDebug("Found valid command in command module {TopLevelCommandName}", commandInfoKeyValuePair.Value.Key);
+ }
}
+
+ _logger.LogDebug("Found {CommandCount} valid commands in assembly {AssemblyName}", validCommands.Count.ToString(), assembly.FullName);
}
- _logger.LogDebug("Found {CommandCount} valid commands in assembly {AssemblyName}", validCommands.Count.ToString(), assembly.FullName);
return validCommands;
}
@@ -183,12 +191,12 @@ private KeyValuePair BuildCommandGroupInfoKeyValuePai
var commandRequirements = _requirementBuildService.GetCommandRequirements(rawValidCommand);
var options = _optionBuildService.GetCommandOptions(rawValidCommand);
var subCommand = new SlashCommandOptionInfo(subCommandAttribute.Name,
- subCommandAttribute.Description,
- subCommandAttribute.Acknowledge,
- rawValidCommand,
- parentModule,
- commandRequirements,
- options.ToList());
+ subCommandAttribute.Description,
+ subCommandAttribute.Acknowledge,
+ rawValidCommand,
+ parentModule,
+ commandRequirements,
+ options.ToList());
// Check if the command doesn't belong to a sub command group.
if (subCommandGroupAttribute is null)
@@ -235,8 +243,8 @@ private IEnumerable GetValidSlashCommandsMethods(Type parentModule)
if (IsValidCommandGroupModuleDefinition(parentModule)) return new List();
return parentModule
- .GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
- .Where(IsValidCommandDefinition);
+ .GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
+ .Where(IsValidCommandDefinition);
}
///
@@ -251,8 +259,8 @@ private IEnumerable GetValidSubSlashCommandsMethods(Type parentModul
if (!IsValidCommandGroupModuleDefinition(parentModule)) return new List();
return parentModule
- .GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
- .Where(IsValidCommandDefinition);
+ .GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
+ .Where(IsValidCommandDefinition);
}
///
diff --git a/src/Color-Chan.Discord.Commands/Services/Implementations/SlashCommandService.cs b/src/Color-Chan.Discord.Commands/Services/Implementations/SlashCommandService.cs
index f1935981..05b0a213 100644
--- a/src/Color-Chan.Discord.Commands/Services/Implementations/SlashCommandService.cs
+++ b/src/Color-Chan.Discord.Commands/Services/Implementations/SlashCommandService.cs
@@ -42,8 +42,11 @@ public class SlashCommandService : ISlashCommandService
/// The that handles all the syncing of
/// the slash commands.
///
- public SlashCommandService(ILogger logger, ISlashCommandBuildService slashCommandBuildService,
- ISlashCommandRequirementService requirementService, ISlashCommandAutoSyncService commandAutoSyncService)
+ public SlashCommandService(
+ ILogger logger,
+ ISlashCommandBuildService slashCommandBuildService,
+ ISlashCommandRequirementService requirementService,
+ ISlashCommandAutoSyncService commandAutoSyncService)
{
_logger = logger;
_slashCommandBuildService = slashCommandBuildService;
@@ -52,12 +55,12 @@ public SlashCommandService(ILogger logger, ISlashCommandBui
}
///
- public async Task AddInteractionCommandsAsync(Assembly assembly)
+ public async Task AddInteractionCommandsAsync(params Assembly[] assemblies)
{
_logger.LogDebug("Registering slash commands...");
// Build all commands in a specific assembly.
- var commandInfos = _slashCommandBuildService.BuildSlashCommandInfos(assembly);
+ var commandInfos = _slashCommandBuildService.BuildSlashCommandInfos(assemblies);
foreach (var (key, commandInfo) in commandInfos)
{
if (_slashCommands.TryAdd(key, commandInfo)) continue;
@@ -70,18 +73,18 @@ public async Task AddInteractionCommandsAsync(Assembly assembly)
_logger.LogInformation("Registered {Count} slash commands to the command registry", _slashCommands.Count.ToString());
- var result = await _commandAutoSyncService.UpdateApplicationCommandsAsync(commandInfos.Select(x => x.Value)).ConfigureAwait(false);
-
+ var result = await _commandAutoSyncService.UpdateApplicationCommandsAsync(_slashCommands.Select(x => x.Value)).ConfigureAwait(false);
if (!result.IsSuccessful) throw new UpdateSlashCommandException(result.ErrorResult?.ErrorMessage ?? "Failed to sync the slash command to discord.");
}
///
- public async Task> ExecuteSlashCommandAsync(MethodInfo commandMethod,
- IEnumerable? options,
- IEnumerable? requirements,
- ISlashCommandContext context,
- List? suppliedOptions = null,
- IServiceProvider? serviceProvider = null)
+ public async Task> ExecuteSlashCommandAsync(
+ MethodInfo commandMethod,
+ IEnumerable? options,
+ IEnumerable? requirements,
+ ISlashCommandContext context,
+ List? suppliedOptions = null,
+ IServiceProvider? serviceProvider = null)
{
serviceProvider ??= DefaultServiceProvider.Instance;
@@ -140,8 +143,11 @@ public async Task> ExecuteSlashCommandAsync(
}
///
- public async Task> ExecuteSlashCommandAsync(ISlashCommandInfo commandInfo, ISlashCommandContext context,
- List? suppliedOptions = null, IServiceProvider? serviceProvider = null)
+ public async Task> ExecuteSlashCommandAsync(
+ ISlashCommandInfo commandInfo,
+ ISlashCommandContext context,
+ List? suppliedOptions = null,
+ IServiceProvider? serviceProvider = null)
{
if (commandInfo.CommandMethod is not null)
{
@@ -153,17 +159,20 @@ public async Task> ExecuteSlashCommandAsync(
}
///
- public async Task> ExecuteSlashCommandAsync(ISlashCommandOptionInfo commandOptionInfo, ISlashCommandContext context,
- List? suppliedOptions = null, IServiceProvider? serviceProvider = null)
+ public async Task> ExecuteSlashCommandAsync(
+ ISlashCommandOptionInfo commandOptionInfo,
+ ISlashCommandContext context,
+ List? suppliedOptions = null,
+ IServiceProvider? serviceProvider = null)
{
if (commandOptionInfo.CommandMethod is not null)
{
return await ExecuteSlashCommandAsync(commandOptionInfo.CommandMethod,
- commandOptionInfo.CommandOptions,
- commandOptionInfo.Requirements,
- context,
- suppliedOptions,
- serviceProvider).ConfigureAwait(false);
+ commandOptionInfo.CommandOptions,
+ commandOptionInfo.Requirements,
+ context,
+ suppliedOptions,
+ serviceProvider).ConfigureAwait(false);
}
_logger.LogWarning("Interaction: {Id} : Failed to executed {Name} since it was a command group or a sub command group", context.InteractionId, commandOptionInfo.Name);
@@ -171,8 +180,10 @@ public async Task> ExecuteSlashCommandAsync(
}
///
- public async Task> ExecuteSlashCommandAsync(ISlashCommandContext context, IEnumerable? options = null,
- IServiceProvider? serviceProvider = null)
+ public async Task> ExecuteSlashCommandAsync(
+ ISlashCommandContext context,
+ IEnumerable? options = null,
+ IServiceProvider? serviceProvider = null)
{
var arr = context.SlashCommandName.ToArray();
var count = arr.Length;
diff --git a/tests/Color-Chan.Discord.Commands.Tests/Color-Chan.Discord.Commands.Tests.csproj b/tests/Color-Chan.Discord.Commands.Tests/Color-Chan.Discord.Commands.Tests.csproj
index bea85111..1285968f 100644
--- a/tests/Color-Chan.Discord.Commands.Tests/Color-Chan.Discord.Commands.Tests.csproj
+++ b/tests/Color-Chan.Discord.Commands.Tests/Color-Chan.Discord.Commands.Tests.csproj
@@ -19,6 +19,7 @@
+
diff --git a/tests/Color-Chan.Discord.Commands.Tests/Services/Implementations/Builders/SlashCommandBuildServiceTests.cs b/tests/Color-Chan.Discord.Commands.Tests/Services/Implementations/Builders/SlashCommandBuildServiceTests.cs
index 0834e110..1b047826 100644
--- a/tests/Color-Chan.Discord.Commands.Tests/Services/Implementations/Builders/SlashCommandBuildServiceTests.cs
+++ b/tests/Color-Chan.Discord.Commands.Tests/Services/Implementations/Builders/SlashCommandBuildServiceTests.cs
@@ -4,6 +4,7 @@
using Color_Chan.Discord.Commands.Services.Implementations.Builders;
using Color_Chan.Discord.Commands.Tests.Invalid;
using Color_Chan.Discord.Commands.Tests.Valid;
+using Color_Chan.Discord.Commands.Tests.Valid2;
using FluentAssertions;
using Microsoft.Extensions.Logging;
using Moq;
@@ -14,7 +15,8 @@ namespace Color_Chan.Discord.Commands.Tests.Services.Implementations.Builders;
[TestFixture]
public class SlashCommandBuildServiceTests
{
- private static readonly Assembly ValidAssembly = typeof(ValidMockCommandModule1).Assembly;
+ private static readonly Assembly ValidAssembly1 = typeof(ValidMockCommandModule1).Assembly;
+ private static readonly Assembly ValidAssembly2 = typeof(ValidMockCommandModule0).Assembly;
private static readonly Assembly InValidAssembly = typeof(InValidMockCommandModule1).Assembly;
[Test]
@@ -28,11 +30,28 @@ public void Should_get_interaction_command_modules()
var buildService = new SlashCommandBuildService(requirementBuilderMock.Object, guildBuilderMock.Object, loggerMock.Object, optionBuilderMock.Object);
// Act
- var types = buildService.GetSlashCommandModules(ValidAssembly);
+ var types = buildService.GetSlashCommandModules(ValidAssembly1);
// Assert
types.Count().Should().Be(8);
}
+
+ [Test]
+ public void Should_get_interaction_commands_with_multiple_assemblies()
+ {
+ // Arrange
+ var loggerMock = new Mock>();
+ var requirementBuilderMock = new Mock();
+ var guildBuilderMock = new Mock();
+ var optionBuilderMock = new Mock();
+ var buildService = new SlashCommandBuildService(requirementBuilderMock.Object, guildBuilderMock.Object, loggerMock.Object, optionBuilderMock.Object);
+
+ // Act
+ var commands = buildService.BuildSlashCommandInfos(ValidAssembly1, ValidAssembly2);
+
+ // Assert
+ commands.Count.Should().Be(21);
+ }
[Test]
public void Should_get_interaction_commands()
@@ -45,7 +64,7 @@ public void Should_get_interaction_commands()
var buildService = new SlashCommandBuildService(requirementBuilderMock.Object, guildBuilderMock.Object, loggerMock.Object, optionBuilderMock.Object);
// Act
- var commands = buildService.BuildSlashCommandInfos(ValidAssembly);
+ var commands = buildService.BuildSlashCommandInfos(ValidAssembly1);
// Assert
commands.Count.Should().Be(20);
diff --git a/tests/mockCommandAssemblies/Color-Chan.Discord.Commands.Tests.Valid2/Color-Chan.Discord.Commands.Tests.Valid2.csproj b/tests/mockCommandAssemblies/Color-Chan.Discord.Commands.Tests.Valid2/Color-Chan.Discord.Commands.Tests.Valid2.csproj
new file mode 100644
index 00000000..928ccbfb
--- /dev/null
+++ b/tests/mockCommandAssemblies/Color-Chan.Discord.Commands.Tests.Valid2/Color-Chan.Discord.Commands.Tests.Valid2.csproj
@@ -0,0 +1,14 @@
+
+
+
+ net10.0
+ Color_Chan.Discord.Commands.Tests.Valid2
+ enable
+ enable
+
+
+
+
+
+
+
diff --git a/tests/mockCommandAssemblies/Color-Chan.Discord.Commands.Tests.Valid2/ValidMockCommandModule0.cs b/tests/mockCommandAssemblies/Color-Chan.Discord.Commands.Tests.Valid2/ValidMockCommandModule0.cs
new file mode 100644
index 00000000..cb344b89
--- /dev/null
+++ b/tests/mockCommandAssemblies/Color-Chan.Discord.Commands.Tests.Valid2/ValidMockCommandModule0.cs
@@ -0,0 +1,15 @@
+using Color_Chan.Discord.Commands.Attributes;
+using Color_Chan.Discord.Commands.Modules;
+using Color_Chan.Discord.Core.Common.Models.Interaction;
+using Color_Chan.Discord.Core.Results;
+
+namespace Color_Chan.Discord.Commands.Tests.Valid2;
+
+public class ValidMockCommandModule0 : SlashCommandModule
+{
+ [SlashCommand("AGoodCommand", "a unit test command.")]
+ public Task> AGoodCommand()
+ {
+ throw new Exception();
+ }
+}
\ No newline at end of file