From 72273ca10aed90a87282a483e0161acfac36db4c Mon Sep 17 00:00:00 2001 From: MSWS Date: Sat, 31 Aug 2024 19:06:05 -0700 Subject: [PATCH] Improve commands structure --- Commands/CommandCollection.cs | 10 +++ Commands/Commands.csproj | 18 ++++++ Commands/GangCommand.cs | 34 +++++++++++ Commands/gang/CreateCommand.cs | 15 +++++ {GangsPlugin => Core}/CS2Gangs.cs | 1 + .../GangsPlugin.csproj => Core/Core.csproj | 5 +- .../GangServiceCollection.cs | 7 ++- Gangs.sln | 12 +++- .../Data/{ => Command}/CommandInfoWrapper.cs | 16 +++-- GangsAPI/Data/Command/CommandResult.cs | 5 ++ GangsAPI/Data/PlayerWrapper.cs | 13 ++-- GangsAPI/Data/Stat/IGangPerk.cs | 6 ++ GangsAPI/Data/Stat/IPerk.cs | 5 ++ GangsAPI/Data/Stat/IPlayerPerk.cs | 6 ++ GangsAPI/Permissions/IPermDictator.cs | 1 + GangsAPI/Services/Commands/ICommand.cs | 18 ++++-- GangsAPI/Services/Commands/ICommandManager.cs | 3 +- .../Mock}/MockBankStat.cs | 2 +- GangsImpl/Mock/MockCommandManager.cs | 22 +++---- GangsTest/API/CommandWrapperTests.cs | 5 ++ GangsTest/API/PlayerWrapperTests.cs | 61 ++++++++++++++++++- GangsTest/Commands/CommandLogic/LogicTests.cs | 7 ++- .../Commands/CommandPerms/PermissionTests.cs | 50 +++++++-------- .../Commands/ManagerTests/ManagerTests.cs | 8 ++- .../ManagerTests/RegistrationTests.cs | 12 ++-- GangsTest/GangBankTests/GangBankTest.cs | 9 +++ GangsTest/GangsTest.csproj | 2 +- GangsTest/StatTests/StatRetainTests.cs | 10 ++- 28 files changed, 288 insertions(+), 75 deletions(-) create mode 100644 Commands/CommandCollection.cs create mode 100644 Commands/Commands.csproj create mode 100644 Commands/GangCommand.cs create mode 100644 Commands/gang/CreateCommand.cs rename {GangsPlugin => Core}/CS2Gangs.cs (96%) rename GangsPlugin/GangsPlugin.csproj => Core/Core.csproj (88%) rename {GangsPlugin => Core}/GangServiceCollection.cs (67%) rename GangsAPI/Data/{ => Command}/CommandInfoWrapper.cs (56%) create mode 100644 GangsAPI/Data/Command/CommandResult.cs create mode 100644 GangsAPI/Data/Stat/IGangPerk.cs create mode 100644 GangsAPI/Data/Stat/IPerk.cs create mode 100644 GangsAPI/Data/Stat/IPlayerPerk.cs rename {GangsTest/GangBankTests => GangsImpl/Mock}/MockBankStat.cs (88%) create mode 100644 GangsTest/API/CommandWrapperTests.cs diff --git a/Commands/CommandCollection.cs b/Commands/CommandCollection.cs new file mode 100644 index 0000000..d5f9360 --- /dev/null +++ b/Commands/CommandCollection.cs @@ -0,0 +1,10 @@ +using Microsoft.Extensions.DependencyInjection; +using GangsAPI.Extensions; + +namespace Commands; + +public static class CommandCollection { + public static void RegisterCommands(this IServiceCollection provider) { + provider.AddPluginBehavior(); + } +} \ No newline at end of file diff --git a/Commands/Commands.csproj b/Commands/Commands.csproj new file mode 100644 index 0000000..b13cf6d --- /dev/null +++ b/Commands/Commands.csproj @@ -0,0 +1,18 @@ + + + + net8.0 + enable + enable + + + + + + + + + + + + diff --git a/Commands/GangCommand.cs b/Commands/GangCommand.cs new file mode 100644 index 0000000..558ced3 --- /dev/null +++ b/Commands/GangCommand.cs @@ -0,0 +1,34 @@ +using GangsAPI.Data; +using GangsAPI.Data.Command; +using GangsAPI.Services.Commands; +using Mock; + +namespace Commands; + +public class GangCommand : ICommand { + public string Name => "css_gang"; + public string? Description => "Master command for gangs"; + + private Dictionary sub = new() { + // ["create"] = new CreateGangCommand(), + // ["delete"] = new DeleteGangCommand(), + // ["invite"] = new InviteGangCommand(), + // ["kick"] = new KickGangCommand(), + // ["leave"] = new LeaveGangCommand(), + // ["list"] = new ListGangCommand(), + // ["promote"] = new PromoteGangCommand(), + // ["demote"] = new DemoteGangCommand(), + // ["info"] = new InfoGangCommand() + }; + + public CommandResult + Execute(PlayerWrapper? executor, CommandInfoWrapper info) { + if (info.ArgCount == 0) return CommandResult.FAILURE; + if (!sub.TryGetValue(info[0], out var command)) { + // print usage + return CommandResult.INVALID_ARGS; + } + + return CommandResult.SUCCESS; + } +} \ No newline at end of file diff --git a/Commands/gang/CreateCommand.cs b/Commands/gang/CreateCommand.cs new file mode 100644 index 0000000..583a587 --- /dev/null +++ b/Commands/gang/CreateCommand.cs @@ -0,0 +1,15 @@ +using GangsAPI.Data; +using GangsAPI.Data.Command; +using GangsAPI.Services.Commands; + +namespace Commands.gang; + +public class CreateCommand : ICommand { + public string Name => "create"; + public string? Description => "Creates a new gang"; + + public CommandResult + Execute(PlayerWrapper? executor, CommandInfoWrapper info) { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/GangsPlugin/CS2Gangs.cs b/Core/CS2Gangs.cs similarity index 96% rename from GangsPlugin/CS2Gangs.cs rename to Core/CS2Gangs.cs index c2e7ebf..008ee65 100644 --- a/GangsPlugin/CS2Gangs.cs +++ b/Core/CS2Gangs.cs @@ -1,6 +1,7 @@ using System.Collections.Immutable; using CounterStrikeSharp.API.Core; using GangsAPI; +using GangsAPI.Services.Commands; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; diff --git a/GangsPlugin/GangsPlugin.csproj b/Core/Core.csproj similarity index 88% rename from GangsPlugin/GangsPlugin.csproj rename to Core/Core.csproj index 360596b..8ec66c5 100644 --- a/GangsPlugin/GangsPlugin.csproj +++ b/Core/Core.csproj @@ -8,6 +8,7 @@ + @@ -16,8 +17,4 @@ - - - - diff --git a/GangsPlugin/GangServiceCollection.cs b/Core/GangServiceCollection.cs similarity index 67% rename from GangsPlugin/GangServiceCollection.cs rename to Core/GangServiceCollection.cs index 1770727..2165bf5 100644 --- a/GangsPlugin/GangServiceCollection.cs +++ b/Core/GangServiceCollection.cs @@ -1,9 +1,12 @@ -using CounterStrikeSharp.API.Core; +using Commands; +using CounterStrikeSharp.API.Core; using GangsAPI; using Microsoft.Extensions.DependencyInjection; namespace GangsImpl; public class GangServiceCollection : IPluginServiceCollection { - public void ConfigureServices(IServiceCollection serviceCollection) { } + public void ConfigureServices(IServiceCollection serviceCollection) { + serviceCollection.RegisterCommands(); + } } \ No newline at end of file diff --git a/Gangs.sln b/Gangs.sln index f0fe52f..4dae373 100644 --- a/Gangs.sln +++ b/Gangs.sln @@ -2,7 +2,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GangsAPI", "GangsAPI\GangsAPI.csproj", "{787D12D8-1310-4042-ADCE-102E517F269E}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GangsPlugin", "GangsPlugin\GangsPlugin.csproj", "{3EA38296-9022-4874-8309-872388D884DE}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core", "Core\Core.csproj", "{3EA38296-9022-4874-8309-872388D884DE}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GangsTest", "GangsTest\GangsTest.csproj", "{B1D1E7C7-BDF3-4238-9025-4FEB2B7DAB89}" EndProject @@ -16,6 +16,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GenericDB", "GangsImpl\Gene EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SQLite", "GangsImpl\SQLite\SQLite.csproj", "{5186EA9C-D2A4-4D70-8F52-0D6C7B6A61B6}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CS2", "CS2", "{AC07CD29-5C9D-4AD1-99C7-01DABAB8D0EC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Commands", "Commands\Commands.csproj", "{C7DF1D47-8D2B-4651-98AB-AEEBE5860ECA}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -50,11 +54,17 @@ Global {5186EA9C-D2A4-4D70-8F52-0D6C7B6A61B6}.Debug|Any CPU.Build.0 = Debug|Any CPU {5186EA9C-D2A4-4D70-8F52-0D6C7B6A61B6}.Release|Any CPU.ActiveCfg = Release|Any CPU {5186EA9C-D2A4-4D70-8F52-0D6C7B6A61B6}.Release|Any CPU.Build.0 = Release|Any CPU + {C7DF1D47-8D2B-4651-98AB-AEEBE5860ECA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C7DF1D47-8D2B-4651-98AB-AEEBE5860ECA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C7DF1D47-8D2B-4651-98AB-AEEBE5860ECA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C7DF1D47-8D2B-4651-98AB-AEEBE5860ECA}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {1899055E-62B8-4907-85A2-DFE22531729E} = {3AB7703F-880F-4A41-96EE-B891FA888C65} {74B15261-4B12-4EF6-859A-E46B315E7DD3} = {3AB7703F-880F-4A41-96EE-B891FA888C65} {5186EA9C-D2A4-4D70-8F52-0D6C7B6A61B6} = {3AB7703F-880F-4A41-96EE-B891FA888C65} {140E1706-30E8-4440-AAA0-56E8DD32F054} = {3AB7703F-880F-4A41-96EE-B891FA888C65} + {3EA38296-9022-4874-8309-872388D884DE} = {AC07CD29-5C9D-4AD1-99C7-01DABAB8D0EC} + {C7DF1D47-8D2B-4651-98AB-AEEBE5860ECA} = {AC07CD29-5C9D-4AD1-99C7-01DABAB8D0EC} EndGlobalSection EndGlobal diff --git a/GangsAPI/Data/CommandInfoWrapper.cs b/GangsAPI/Data/Command/CommandInfoWrapper.cs similarity index 56% rename from GangsAPI/Data/CommandInfoWrapper.cs rename to GangsAPI/Data/Command/CommandInfoWrapper.cs index 15b49de..3792644 100644 --- a/GangsAPI/Data/CommandInfoWrapper.cs +++ b/GangsAPI/Data/Command/CommandInfoWrapper.cs @@ -3,21 +3,25 @@ namespace GangsAPI.Data; -public class CommandInfoWrapper(CCSPlayerController? executor, +public class CommandInfoWrapper(CCSPlayerController? executor, int offset = 0, params string[] args) { public readonly CCSPlayerController? CallingPlayer = executor; public readonly CommandCallingContext CallingContext = CommandCallingContext.Console; - public CommandInfoWrapper(CommandInfo info) : this(info.CallingPlayer, - info.ArgString.Split(" ")) { + public CommandInfoWrapper(CommandInfo info, int offset = 0) : this( + info.CallingPlayer, offset, info.ArgString.Split(" ")) { CallingContext = info.CallingContext; } - public int ArgCount => args.Length; - public string this[int index] => args[index]; - public string ArgString => string.Join(' ', args); + public int ArgCount => args.Length - offset; + public string this[int index] => args[index + offset]; + + public string ArgString + => string.Join(' ', GetCommandString.Split(' ').Skip(offset)); + + public string GetCommandString => string.Join(' ', args.Skip(offset)); public void ReplyToCommand(string message) { if (CallingPlayer == null) { diff --git a/GangsAPI/Data/Command/CommandResult.cs b/GangsAPI/Data/Command/CommandResult.cs new file mode 100644 index 0000000..2bb4c3d --- /dev/null +++ b/GangsAPI/Data/Command/CommandResult.cs @@ -0,0 +1,5 @@ +namespace GangsAPI.Data.Command; + +public enum CommandResult { + SUCCESS, FAILURE, UNKNOWN_COMMAND, INVALID_ARGS, NO_PERMISSION +} \ No newline at end of file diff --git a/GangsAPI/Data/PlayerWrapper.cs b/GangsAPI/Data/PlayerWrapper.cs index 580d8dc..7758edb 100644 --- a/GangsAPI/Data/PlayerWrapper.cs +++ b/GangsAPI/Data/PlayerWrapper.cs @@ -40,9 +40,13 @@ public PlayerWrapper WithFlags(params string[] flags) { throw new ArgumentException( $"Expected flag ${flag} to contain a / character"); - var domain = flag[..slashIndex]; + var domain = flag[1..slashIndex]; var permission = flag[(slashIndex + 1)..]; + if (permission.Length == 0) + throw new ArgumentException( + $"Expected flag ${flag} to contain a permission after / character"); + if (!flagMap.TryGetValue(domain, out var map)) flagMap[domain] = map = []; map.Add(permission); @@ -69,11 +73,12 @@ public bool HasFlags(params string[] flags) { throw new ArgumentException( $"Expected flag ${flag} to contain a / character"); - var domain = flag[..slashIndex]; + var domain = flag[1..slashIndex]; var permission = flag[(slashIndex + 1)..]; - if (!Data.Flags.TryGetValue(domain, out var map)) return false; - if (!map.Contains(permission)) return false; + if (!Data.Flags.TryGetValue(domain, out var perms)) return false; + if (perms.Contains("root")) return true; + if (!perms.Any(p => permission.StartsWith(p))) return false; } return true; diff --git a/GangsAPI/Data/Stat/IGangPerk.cs b/GangsAPI/Data/Stat/IGangPerk.cs new file mode 100644 index 0000000..f893160 --- /dev/null +++ b/GangsAPI/Data/Stat/IGangPerk.cs @@ -0,0 +1,6 @@ +namespace GangsAPI.Data.Stat; + +public interface IGangPerk : IPerk { + void ApplyTo(int id); + void RevokedFrom(int id); +} \ No newline at end of file diff --git a/GangsAPI/Data/Stat/IPerk.cs b/GangsAPI/Data/Stat/IPerk.cs new file mode 100644 index 0000000..1a1a231 --- /dev/null +++ b/GangsAPI/Data/Stat/IPerk.cs @@ -0,0 +1,5 @@ +namespace GangsAPI.Data.Stat; + +public interface IPerk : IStat, IPluginBehavior { + +} \ No newline at end of file diff --git a/GangsAPI/Data/Stat/IPlayerPerk.cs b/GangsAPI/Data/Stat/IPlayerPerk.cs new file mode 100644 index 0000000..431d97b --- /dev/null +++ b/GangsAPI/Data/Stat/IPlayerPerk.cs @@ -0,0 +1,6 @@ +namespace GangsAPI.Data.Stat; + +public interface IPlayerPerk : IPerk { + void ApplyTo(ulong steam); + void RevokedFrom(ulong steam); +} \ No newline at end of file diff --git a/GangsAPI/Permissions/IPermDictator.cs b/GangsAPI/Permissions/IPermDictator.cs index 4e033c2..9bb5d68 100644 --- a/GangsAPI/Permissions/IPermDictator.cs +++ b/GangsAPI/Permissions/IPermDictator.cs @@ -5,4 +5,5 @@ /// public interface IPermDictator : IPluginBehavior { bool CanTarget(IGangRank source, IGangRank target); + IGangRank CreateRank(string name, int rank, IGangRank.Permissions perms = 0); } \ No newline at end of file diff --git a/GangsAPI/Services/Commands/ICommand.cs b/GangsAPI/Services/Commands/ICommand.cs index bf1cd19..206a7bb 100644 --- a/GangsAPI/Services/Commands/ICommand.cs +++ b/GangsAPI/Services/Commands/ICommand.cs @@ -1,11 +1,21 @@ using GangsAPI.Data; +using GangsAPI.Data.Command; namespace GangsAPI.Services.Commands; -public interface ICommand { +public interface ICommand : IPluginBehavior { string Name { get; } string? Description { get; } - string[] RequiredFlags { get; } - string[] RequiredGroups { get; } - bool Execute(PlayerWrapper? executor, CommandInfoWrapper info); + string[] RequiredFlags => []; + string[] RequiredGroups => []; + + bool CanExecute(PlayerWrapper? executor) { + if (executor == null) return true; + if (RequiredFlags.Any(flag => !executor.HasFlags(flag))) return false; + if (RequiredGroups.Length == 0) return true; + return executor.Data != null + && RequiredGroups.All(group => executor.Data.Groups.Contains(group)); + } + + CommandResult Execute(PlayerWrapper? executor, CommandInfoWrapper info); } \ No newline at end of file diff --git a/GangsAPI/Services/Commands/ICommandManager.cs b/GangsAPI/Services/Commands/ICommandManager.cs index b890640..3090635 100644 --- a/GangsAPI/Services/Commands/ICommandManager.cs +++ b/GangsAPI/Services/Commands/ICommandManager.cs @@ -1,4 +1,5 @@ using GangsAPI.Data; +using GangsAPI.Data.Command; namespace GangsAPI.Services.Commands; @@ -24,5 +25,5 @@ public interface ICommandManager : IPluginBehavior { /// /// /// True if the command finished processing successfully. - bool ProcessCommand(PlayerWrapper? executor, params string[] args); + CommandResult ProcessCommand(PlayerWrapper? executor, params string[] args); } \ No newline at end of file diff --git a/GangsTest/GangBankTests/MockBankStat.cs b/GangsImpl/Mock/MockBankStat.cs similarity index 88% rename from GangsTest/GangBankTests/MockBankStat.cs rename to GangsImpl/Mock/MockBankStat.cs index bf79ab0..5eaaa5d 100644 --- a/GangsTest/GangBankTests/MockBankStat.cs +++ b/GangsImpl/Mock/MockBankStat.cs @@ -1,6 +1,6 @@ using GangsAPI.Data.Stat; -namespace GangsTest.GangBankTests; +namespace Mock; public class MockBankStat : IGangStat { public string StatId => "gang_bank"; diff --git a/GangsImpl/Mock/MockCommandManager.cs b/GangsImpl/Mock/MockCommandManager.cs index 33d37f7..40f8560 100644 --- a/GangsImpl/Mock/MockCommandManager.cs +++ b/GangsImpl/Mock/MockCommandManager.cs @@ -1,4 +1,5 @@ using GangsAPI.Data; +using GangsAPI.Data.Command; using GangsAPI.Services.Commands; namespace Mock; @@ -14,23 +15,14 @@ public bool UnregisterCommand(ICommand command) { return commands.Remove(command.Name); } - public bool ProcessCommand(PlayerWrapper? executor, string[] args) { - if (args.Length == 0) return false; - if (!commands.TryGetValue(args[0], out var command)) return false; + public CommandResult ProcessCommand(PlayerWrapper? executor, string[] args) { + if (args.Length == 0) return CommandResult.FAILURE; + if (!commands.TryGetValue(args[0], out var command)) + return CommandResult.UNKNOWN_COMMAND; - if (executor == null) - return command.Execute(executor, - new CommandInfoWrapper(executor?.Player, args)); - - if (command.RequiredFlags.Any(flag => !executor.HasFlags(flag))) - return false; - - foreach (var group in command.RequiredGroups) { - if (executor.Data == null) return false; - if (!executor.Data.Groups.Contains(group)) return false; - } + if (!command.CanExecute(executor)) return CommandResult.NO_PERMISSION; return command.Execute(executor, - new CommandInfoWrapper(executor?.Player, args)); + new CommandInfoWrapper(executor?.Player, args: args)); } } \ No newline at end of file diff --git a/GangsTest/API/CommandWrapperTests.cs b/GangsTest/API/CommandWrapperTests.cs new file mode 100644 index 0000000..eea182b --- /dev/null +++ b/GangsTest/API/CommandWrapperTests.cs @@ -0,0 +1,5 @@ +namespace GangsTest.API; + +public class CommandWrapperTests { + +} \ No newline at end of file diff --git a/GangsTest/API/PlayerWrapperTests.cs b/GangsTest/API/PlayerWrapperTests.cs index bd1583d..4947d52 100644 --- a/GangsTest/API/PlayerWrapperTests.cs +++ b/GangsTest/API/PlayerWrapperTests.cs @@ -1,8 +1,13 @@ -using GangsAPI.Data; +using CounterStrikeSharp.API.Modules.Admin; +using FuzzDotNet.Core; +using GangsAPI.Data; namespace GangsTest.API; public class PlayerWrapperTests { + private static char USER_CHAR => PermissionCharacters.UserPermissionChar; + private static char GROUP_CHAR => PermissionCharacters.GroupPermissionChar; + private readonly PlayerWrapper testPlayer = new((ulong)new Random().NextInt64(), "Test Player"); @@ -15,8 +20,58 @@ public void PlayerWrapper_Init() { [Fact] public void PlayerWrapper_Init_Flags() { - var player = testPlayer.WithFlags("@test/flag"); + var player = testPlayer.WithFlags(USER_CHAR + "test/flag"); Assert.NotNull(player.Data); - Assert.True(player.Data.Flags.ContainsKey("@test")); + Assert.Single(player.Data.Flags); + Assert.True(player.Data.Flags.ContainsKey("test")); + } + + [Fact] + public void PlayerWrapper_Init_InvalidFlag() { + Assert.ThrowsAny(() => testPlayer.WithFlags("invalid")); + Assert.ThrowsAny(() + => testPlayer.WithFlags(GROUP_CHAR + "invalid")); + Assert.ThrowsAny(() => testPlayer.WithFlags("_invalid")); + Assert.ThrowsAny(() + => testPlayer.WithFlags(USER_CHAR + "test")); + Assert.ThrowsAny(() + => testPlayer.WithFlags(USER_CHAR + "test/")); + } + + [Fact] + public void PlayerWrapper_Perm_Flag() { + var player = testPlayer.WithFlags(USER_CHAR + "test/flag"); + Assert.True(player.HasFlags(USER_CHAR + "test/flag")); + Assert.False(player.HasFlags(USER_CHAR + "test/other")); + } + + [Fact] + public void PlayerWrapper_Perm_FlagChild() { + var player = testPlayer.WithFlags(USER_CHAR + "test/flag"); + Assert.True(player.HasFlags(USER_CHAR + "test/flag")); + Assert.True(player.HasFlags(USER_CHAR + "test/flag/child")); + } + + [Fact] + public void PlayerWrapper_Perm_FlagParent() { + var player = testPlayer.WithFlags(USER_CHAR + "test/flag/child"); + Assert.False(player.HasFlags(USER_CHAR + "test/flag")); + Assert.True(player.HasFlags(USER_CHAR + "test/flag/child")); + } + + [Fact] + public void PlayerWrapper_Perm_FlagRoot() { + var player = testPlayer.WithFlags(USER_CHAR + "test/root"); + Assert.True(player.HasFlags(USER_CHAR + "test/root")); + Assert.True(player.HasFlags(USER_CHAR + "test/flag")); + Assert.True(player.HasFlags(USER_CHAR + "test/other")); + } + + [Fact] + public void PlayerWrapper_Perm_FlagRootChild() { + var player = testPlayer.WithFlags(USER_CHAR + "test/root"); + Assert.True(player.HasFlags(USER_CHAR + "test/root")); + Assert.True(player.HasFlags(USER_CHAR + "test/flag")); + Assert.True(player.HasFlags(USER_CHAR + "test/other/test")); } } \ No newline at end of file diff --git a/GangsTest/Commands/CommandLogic/LogicTests.cs b/GangsTest/Commands/CommandLogic/LogicTests.cs index 111d8a2..2b21198 100644 --- a/GangsTest/Commands/CommandLogic/LogicTests.cs +++ b/GangsTest/Commands/CommandLogic/LogicTests.cs @@ -1,4 +1,5 @@ using GangsAPI.Data; +using GangsAPI.Data.Command; using GangsAPI.Services.Commands; using GangsTest.Commands.ManagerTests; @@ -9,13 +10,15 @@ public class LogicTests : ManagerTests.ManagerTests { [ClassData(typeof(ManagerData))] public void Command_Logic(ICommandManager mgr) { Assert.True(mgr.RegisterCommand(Dummy)); - Assert.True(mgr.ProcessCommand(TestPlayer, "css_dummy", "foobar")); + Assert.Equal(CommandResult.SUCCESS, + mgr.ProcessCommand(TestPlayer, "css_dummy", "foobar")); } [Theory] [ClassData(typeof(ManagerData))] public void Command_Logic_Fail(ICommandManager mgr) { Assert.True(mgr.RegisterCommand(Dummy)); - Assert.False(mgr.ProcessCommand(TestPlayer, "css_dummy", "barfoo")); + Assert.Equal(CommandResult.FAILURE, + mgr.ProcessCommand(TestPlayer, "css_dummy", "barfoo")); } } \ No newline at end of file diff --git a/GangsTest/Commands/CommandPerms/PermissionTests.cs b/GangsTest/Commands/CommandPerms/PermissionTests.cs index 02216fe..5dcdd6f 100644 --- a/GangsTest/Commands/CommandPerms/PermissionTests.cs +++ b/GangsTest/Commands/CommandPerms/PermissionTests.cs @@ -1,4 +1,6 @@ -using GangsAPI.Data; +using CounterStrikeSharp.API.Modules.Commands; +using GangsAPI.Data; +using GangsAPI.Data.Command; using GangsAPI.Services.Commands; using GangsTest.Commands.ManagerTests; @@ -11,8 +13,9 @@ private class ElevatedCommand(string[] flags, string[] groups) : ICommand { public string[] RequiredFlags { get; } = flags; public string[] RequiredGroups { get; } = groups; - public bool Execute(PlayerWrapper? executor, CommandInfoWrapper info) { - return true; + public CommandResult Execute(PlayerWrapper? executor, + CommandInfoWrapper info) { + return CommandResult.SUCCESS; } } @@ -20,57 +23,56 @@ public bool Execute(PlayerWrapper? executor, CommandInfoWrapper info) { [ClassData(typeof(ManagerData))] public void Permission_Pass(ICommandManager mgr) { mgr.RegisterCommand(Dummy); - Assert.True(mgr.ProcessCommand(TestPlayer, "css_dummy", "foobar")); + Assert.Equal(CommandResult.SUCCESS, + mgr.ProcessCommand(TestPlayer, "css_dummy", "foobar")); } [Theory] [ClassData(typeof(ManagerData))] public void Permission_Pass_Flag_Console(ICommandManager mgr) { mgr.RegisterCommand(new ElevatedCommand(["@test/flag"], [])); - Assert.True(mgr.ProcessCommand(null, "css_elevated"), - "Command manager failed to allow console"); + Assert.Equal(CommandResult.SUCCESS, + mgr.ProcessCommand(null, "css_elevated")); } [Theory] [ClassData(typeof(ManagerData))] public void Permission_Pass_Group_Console(ICommandManager mgr) { mgr.RegisterCommand(new ElevatedCommand([], ["#test/group"])); - Assert.True(mgr.ProcessCommand(null, "css_elevated"), - "Command manager failed to allow console"); + Assert.Equal(CommandResult.SUCCESS, + mgr.ProcessCommand(null, "css_elevated")); } [Theory] [ClassData(typeof(ManagerData))] public void Permission_Fail_Flag(ICommandManager mgr) { mgr.RegisterCommand(new ElevatedCommand(["@test/flag"], [])); - Assert.False(mgr.ProcessCommand(TestPlayer, "css_elevated"), - "Command manager failed to check flags"); + Assert.Equal(CommandResult.NO_PERMISSION, + mgr.ProcessCommand(TestPlayer, "css_elevated")); } [Theory] [ClassData(typeof(ManagerData))] public void Permission_Fail_Group(ICommandManager mgr) { mgr.RegisterCommand(new ElevatedCommand([], ["#test/group"])); - Assert.False(mgr.ProcessCommand(TestPlayer, "css_elevated"), - "Command manager failed to check groups"); + Assert.Equal(CommandResult.NO_PERMISSION, + mgr.ProcessCommand(TestPlayer, "css_elevated")); } [Theory] [ClassData(typeof(ManagerData))] public void Permission_Fail_Both_Flag(ICommandManager mgr) { mgr.RegisterCommand(new ElevatedCommand(["@test/flag"], ["#test/group"])); - Assert.False( - mgr.ProcessCommand(TestPlayer.WithFlags("@test/flag"), "css_elevated"), - "Command manager allowed player with flag but command required group as well"); + Assert.Equal(CommandResult.NO_PERMISSION, + mgr.ProcessCommand(TestPlayer, "css_elevated")); } [Theory] [ClassData(typeof(ManagerData))] public void Permission_Fail_Both_Group(ICommandManager mgr) { mgr.RegisterCommand(new ElevatedCommand(["@test/flag"], ["#test/group"])); - Assert.False( - mgr.ProcessCommand(TestPlayer.WithGroups("@test/flag"), "css_elevated"), - "Command manager allowed player with flag but command required group as well"); + Assert.Equal(CommandResult.NO_PERMISSION, + mgr.ProcessCommand(TestPlayer, "css_elevated")); } [Theory] @@ -78,8 +80,8 @@ public void Permission_Fail_Both_Group(ICommandManager mgr) { public void Permission_Pass_Flag(ICommandManager mgr) { var elevatedPlayer = TestPlayer.WithFlags("@test/flag"); mgr.RegisterCommand(new ElevatedCommand(["@test/flag"], [])); - Assert.True(mgr.ProcessCommand(elevatedPlayer, "css_elevated"), - "Command manager did not allow player with proper flag"); + Assert.Equal(CommandResult.SUCCESS, + mgr.ProcessCommand(elevatedPlayer, "css_elevated")); } [Theory] @@ -87,8 +89,8 @@ public void Permission_Pass_Flag(ICommandManager mgr) { public void Permission_Pass_Group(ICommandManager mgr) { var elevatedPlayer = TestPlayer.WithGroups("#test/group"); mgr.RegisterCommand(new ElevatedCommand([], ["#test/group"])); - Assert.True(mgr.ProcessCommand(elevatedPlayer, "css_elevated"), - "Command manager did not allow player with proper group"); + Assert.Equal(CommandResult.SUCCESS, + mgr.ProcessCommand(elevatedPlayer, "css_elevated")); } [Theory] @@ -97,7 +99,7 @@ public void Permission_Pass_Both(ICommandManager mgr) { var elevatedPlayer = TestPlayer.WithFlags("@test/flag").WithGroups("#test/group"); mgr.RegisterCommand(new ElevatedCommand(["@test/flag"], ["#test/group"])); - Assert.True(mgr.ProcessCommand(elevatedPlayer, "css_elevated"), - "Command manager did not allow player with proper group"); + Assert.Equal(CommandResult.SUCCESS, + mgr.ProcessCommand(elevatedPlayer, "css_elevated")); } } \ No newline at end of file diff --git a/GangsTest/Commands/ManagerTests/ManagerTests.cs b/GangsTest/Commands/ManagerTests/ManagerTests.cs index 03c6f43..55a6ed0 100644 --- a/GangsTest/Commands/ManagerTests/ManagerTests.cs +++ b/GangsTest/Commands/ManagerTests/ManagerTests.cs @@ -1,4 +1,5 @@ using GangsAPI.Data; +using GangsAPI.Data.Command; using GangsAPI.Services.Commands; namespace GangsTest.Commands.ManagerTests; @@ -15,11 +16,14 @@ protected class DummyCommand : ICommand { public string[] RequiredFlags { get; } = []; public string[] RequiredGroups { get; } = []; - public bool Execute(PlayerWrapper? executor, CommandInfoWrapper info) { + public CommandResult Execute(PlayerWrapper? executor, + CommandInfoWrapper info) { if (info[0] != Name) throw new InvalidOperationException("Command name mismatch"); - return info[1] == "foobar"; + return info[1] == "foobar" ? + CommandResult.SUCCESS : + CommandResult.FAILURE; } } } \ No newline at end of file diff --git a/GangsTest/Commands/ManagerTests/RegistrationTests.cs b/GangsTest/Commands/ManagerTests/RegistrationTests.cs index 9a4c2eb..f7bc063 100644 --- a/GangsTest/Commands/ManagerTests/RegistrationTests.cs +++ b/GangsTest/Commands/ManagerTests/RegistrationTests.cs @@ -1,4 +1,5 @@ -using GangsAPI.Services.Commands; +using GangsAPI.Data.Command; +using GangsAPI.Services.Commands; namespace GangsTest.Commands.ManagerTests; @@ -7,13 +8,15 @@ public class RegistrationTests : ManagerTests { [ClassData(typeof(ManagerData))] public void Command_Register(ICommandManager mgr) { Assert.True(mgr.RegisterCommand(Dummy)); - Assert.True(mgr.ProcessCommand(TestPlayer, "css_dummy", "foobar")); + Assert.Equal(CommandResult.SUCCESS, + mgr.ProcessCommand(TestPlayer, "css_dummy", "foobar")); } [Theory] [ClassData(typeof(ManagerData))] public void Command_Unregistered(ICommandManager mgr) { - Assert.False(mgr.ProcessCommand(TestPlayer, "css_dummy")); + Assert.Equal(CommandResult.UNKNOWN_COMMAND, + mgr.ProcessCommand(TestPlayer, "css_dummy")); } [Theory] @@ -21,7 +24,8 @@ public void Command_Unregistered(ICommandManager mgr) { public void Command_Unregister(ICommandManager mgr) { Assert.True(mgr.RegisterCommand(Dummy)); Assert.True(mgr.UnregisterCommand(Dummy)); - Assert.False(mgr.ProcessCommand(TestPlayer, "css_dummy", "foobar")); + Assert.Equal(CommandResult.UNKNOWN_COMMAND, + mgr.ProcessCommand(TestPlayer, "css_dummy")); } [Theory] diff --git a/GangsTest/GangBankTests/GangBankTest.cs b/GangsTest/GangBankTests/GangBankTest.cs index d3016e8..b9bf1e9 100644 --- a/GangsTest/GangBankTests/GangBankTest.cs +++ b/GangsTest/GangBankTests/GangBankTest.cs @@ -1,6 +1,7 @@ using GangsAPI.Data.Stat; using GangsAPI.Services; using GangsTest.GangTests; +using Mock; namespace GangsTest.GangBankTests; @@ -68,6 +69,10 @@ public async Task GangBank_Deposit() { [InlineData(5, 25)] [InlineData(-5, 25)] [InlineData(-5, -25)] + [InlineData(int.MaxValue, int.MinValue)] + [InlineData(int.MinValue, int.MaxValue)] + [InlineData(int.MaxValue, int.MaxValue)] + [InlineData(int.MinValue, int.MinValue)] public async Task GangBank_Withdraw(int initial, int withdraw) { var gang = await GangTestUtil.CreateGang(gangManager); Assert.NotNull(gang); @@ -88,6 +93,10 @@ public async Task GangBank_Withdraw(int initial, int withdraw) { [InlineData(5, 25)] [InlineData(-5, 25)] [InlineData(-5, -25)] + [InlineData(int.MaxValue, int.MinValue)] + [InlineData(int.MinValue, int.MaxValue)] + [InlineData(int.MaxValue, int.MaxValue)] + [InlineData(int.MinValue, int.MinValue)] public async Task GangBank_Withdraw_Indirect_Alias(int initial, int withdraw) { var gang = await GangTestUtil.CreateGang(gangManager); diff --git a/GangsTest/GangsTest.csproj b/GangsTest/GangsTest.csproj index b5772fe..7241a51 100644 --- a/GangsTest/GangsTest.csproj +++ b/GangsTest/GangsTest.csproj @@ -31,7 +31,7 @@ - + \ No newline at end of file diff --git a/GangsTest/StatTests/StatRetainTests.cs b/GangsTest/StatTests/StatRetainTests.cs index 6d1a77e..4a7b5fb 100644 --- a/GangsTest/StatTests/StatRetainTests.cs +++ b/GangsTest/StatTests/StatRetainTests.cs @@ -13,6 +13,15 @@ public async Task Stat_Retain(IStatManager mgr) { Assert.Same(foo1, foo2); } + [Theory] + [ClassData(typeof(StatManagerData))] + public async Task Stat_Retain_Unregsitered(IStatManager mgr) { + var foo1 = await StatTestUtil.CreateStat(mgr); + Assert.NotNull(foo1); + var foo2 = await StatTestUtil.CreateStat(mgr); + Assert.NotSame(foo1, foo2); + } + [Theory] [ClassData(typeof(StatManagerData))] public async Task Stat_Retain_NonTrivial_Name(IStatManager mgr) { @@ -20,7 +29,6 @@ public async Task Stat_Retain_NonTrivial_Name(IStatManager mgr) { Assert.NotNull(foo1); await mgr.RegisterStat(foo1); var foo2 = await StatTestUtil.CreateStat(mgr, "foo", "foobar"); - Assert.NotNull(foo1); Assert.NotNull(foo2); Assert.Same(foo1, foo2); }