From def99cbc9434bfbad7b287b086edb13813485b57 Mon Sep 17 00:00:00 2001 From: MSWS Date: Mon, 2 Sep 2024 22:46:48 -0700 Subject: [PATCH] Add SQL Gang Manager --- Commands/CommandCollection.cs | 5 +- Commands/CommandManager.cs | 1 - Commands/Commands.csproj | 6 +- Commands/GangCommand.cs | 10 +- Commands/gang/CreateCommand.cs | 6 +- Commands/gang/HelpCommand.cs | 3 +- Gangs.sln | 2 +- Gangs/CS2Gangs.cs | 1 - Gangs/GangServiceCollection.cs | 6 +- Gangs/Gangs.csproj | 9 +- GangsAPI/Data/Command/CommandInfoWrapper.cs | 8 +- GangsAPI/Data/Command/CommandResult.cs | 20 ++-- GangsAPI/Data/PlayerWrapper.cs | 10 +- GangsAPI/Data/Stat/IPerk.cs | 4 +- GangsAPI/Services/Commands/ICommandManager.cs | 2 +- .../AbstractDB.csproj} | 2 + GangsImpl/AbstractDB/AbstractDBGangManager.cs | 79 ++++++++++++ GangsImpl/AbstractDB/AbstractDBStatManager.cs | 84 +++++++++++++ GangsImpl/AbstractDB/DBGang.cs | 29 +++++ GangsImpl/{GenericDB => AbstractDB}/DBStat.cs | 0 GangsImpl/GenericDB/GenericDBStatManager.cs | 112 ------------------ GangsImpl/Mock/Mock.csproj | 2 +- GangsImpl/Mock/MockGang.cs | 10 +- GangsImpl/Mock/MockGangManager.cs | 18 +-- GangsImpl/Mock/MockStatManager.cs | 16 ++- GangsImpl/SQL/SQL.csproj | 2 +- GangsImpl/SQL/SQLGangManager.cs | 13 ++ ...qlStatStatManager.cs => SQLStatManager.cs} | 8 +- GangsImpl/SQLite/SQLite.csproj | 2 +- GangsImpl/SQLite/SQLiteStatManager.cs | 6 +- GangsTest/API/CommandWrapperTests.cs | 4 +- GangsTest/API/PlayerWrapperTests.cs | 7 +- GangsTest/Commands/CommandTests.cs | 2 +- GangsTest/Commands/CreateTests.cs | 4 +- GangsTest/Commands/GangCommandTests.cs | 2 +- GangsTest/Commands/LogicTests.cs | 8 +- .../{ManagerData.cs => CommandTestData.cs} | 4 +- .../Commands/ManagerTests/ManagerHandling.cs | 20 ++-- .../ManagerTests/RegistrationTests.cs | 8 +- GangsTest/Commands/PermissionTests.cs | 48 ++++---- GangsTest/GangTests/GangFetchTests.cs | 1 - GangsTest/GangTests/GangManagerData.cs | 8 +- GangsTest/GangsTest.csproj | 22 ++-- GangsTest/Permissions/GangRankTests.cs | 6 +- GangsTest/Startup.cs | 6 +- GangsTest/StatTests/StatManagerData.cs | 5 +- 46 files changed, 353 insertions(+), 278 deletions(-) rename GangsImpl/{GenericDB/GenericDB.csproj => AbstractDB/AbstractDB.csproj} (82%) create mode 100644 GangsImpl/AbstractDB/AbstractDBGangManager.cs create mode 100644 GangsImpl/AbstractDB/AbstractDBStatManager.cs create mode 100644 GangsImpl/AbstractDB/DBGang.cs rename GangsImpl/{GenericDB => AbstractDB}/DBStat.cs (100%) delete mode 100644 GangsImpl/GenericDB/GenericDBStatManager.cs create mode 100644 GangsImpl/SQL/SQLGangManager.cs rename GangsImpl/SQL/{SqlStatStatManager.cs => SQLStatManager.cs} (53%) rename GangsTest/Commands/ManagerTests/{ManagerData.cs => CommandTestData.cs} (85%) diff --git a/Commands/CommandCollection.cs b/Commands/CommandCollection.cs index d3e6642..8ace032 100644 --- a/Commands/CommandCollection.cs +++ b/Commands/CommandCollection.cs @@ -1,7 +1,6 @@ -using Microsoft.Extensions.DependencyInjection; -using GangsAPI.Extensions; -using GangsAPI.Services; +using GangsAPI.Extensions; using GangsAPI.Services.Commands; +using Microsoft.Extensions.DependencyInjection; namespace Commands; diff --git a/Commands/CommandManager.cs b/Commands/CommandManager.cs index 3029dc8..38bd1fa 100644 --- a/Commands/CommandManager.cs +++ b/Commands/CommandManager.cs @@ -2,7 +2,6 @@ using CounterStrikeSharp.API.Core; using GangsAPI; using GangsAPI.Data; -using GangsAPI.Data.Command; using GangsAPI.Services; using GangsAPI.Services.Commands; using Mock; diff --git a/Commands/Commands.csproj b/Commands/Commands.csproj index b13cf6d..17a820a 100644 --- a/Commands/Commands.csproj +++ b/Commands/Commands.csproj @@ -7,12 +7,12 @@ - + - - + + diff --git a/Commands/GangCommand.cs b/Commands/GangCommand.cs index 727a434..cda5b9b 100644 --- a/Commands/GangCommand.cs +++ b/Commands/GangCommand.cs @@ -3,14 +3,10 @@ using GangsAPI.Data.Command; using GangsAPI.Services; using GangsAPI.Services.Commands; -using Mock; namespace Commands; public class GangCommand(IGangManager gangMgr) : ICommand { - public string Name => "css_gang"; - public string? Description => "Master command for gangs"; - private readonly Dictionary sub = new() { // ["delete"] = new DeleteGangCommand(), // ["invite"] = new InviteGangCommand(), @@ -23,6 +19,9 @@ public class GangCommand(IGangManager gangMgr) : ICommand { ["create"] = new CreateCommand(gangMgr), ["help"] = new HelpCommand() }; + public string Name => "css_gang"; + public string? Description => "Master command for gangs"; + public async Task Execute(PlayerWrapper? executor, CommandInfoWrapper info) { if (info.ArgCount == 0) @@ -35,11 +34,10 @@ public async Task Execute(PlayerWrapper? executor, if (info.ArgCount == 1) return CommandResult.INVALID_ARGS; - if (!sub.TryGetValue(info[1], out var command)) { + if (!sub.TryGetValue(info[1], out var command)) // print usage // info.ReplySync("Usage: /css_gang [create|help]"); return CommandResult.UNKNOWN_COMMAND; - } var newInfo = new CommandInfoWrapper(info, 1); return await command.Execute(executor, newInfo); diff --git a/Commands/gang/CreateCommand.cs b/Commands/gang/CreateCommand.cs index b9e7db2..080232f 100644 --- a/Commands/gang/CreateCommand.cs +++ b/Commands/gang/CreateCommand.cs @@ -1,9 +1,7 @@ -using CounterStrikeSharp.API; -using GangsAPI.Data; +using GangsAPI.Data; using GangsAPI.Data.Command; using GangsAPI.Services; using GangsAPI.Services.Commands; -using Microsoft.VisualBasic; namespace Commands.gang; @@ -15,7 +13,7 @@ public class CreateCommand(IGangManager gang) : ICommand { public async Task Execute(PlayerWrapper? executor, CommandInfoWrapper info) { - if (executor == null) { return CommandResult.PLAYER_ONLY; } + if (executor == null) return CommandResult.PLAYER_ONLY; if (info.ArgCount < 2) { info.ReplySync("Please provide a name for the gang"); diff --git a/Commands/gang/HelpCommand.cs b/Commands/gang/HelpCommand.cs index e31792d..6929996 100644 --- a/Commands/gang/HelpCommand.cs +++ b/Commands/gang/HelpCommand.cs @@ -1,5 +1,4 @@ -using CounterStrikeSharp.API.Core.Commands; -using GangsAPI.Data; +using GangsAPI.Data; using GangsAPI.Data.Command; using GangsAPI.Services.Commands; diff --git a/Gangs.sln b/Gangs.sln index 916ab7e..4c8d781 100644 --- a/Gangs.sln +++ b/Gangs.sln @@ -12,7 +12,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "GangsImpl", "GangsImpl", "{ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SQL", "GangsImpl\SQL\SQL.csproj", "{1899055E-62B8-4907-85A2-DFE22531729E}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GenericDB", "GangsImpl\GenericDB\GenericDB.csproj", "{74B15261-4B12-4EF6-859A-E46B315E7DD3}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AbstractDB", "GangsImpl\AbstractDB\AbstractDB.csproj", "{74B15261-4B12-4EF6-859A-E46B315E7DD3}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SQLite", "GangsImpl\SQLite\SQLite.csproj", "{5186EA9C-D2A4-4D70-8F52-0D6C7B6A61B6}" EndProject diff --git a/Gangs/CS2Gangs.cs b/Gangs/CS2Gangs.cs index 34f70ae..c07ac45 100644 --- a/Gangs/CS2Gangs.cs +++ b/Gangs/CS2Gangs.cs @@ -1,7 +1,6 @@ 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/Gangs/GangServiceCollection.cs b/Gangs/GangServiceCollection.cs index f774cbf..3756f91 100644 --- a/Gangs/GangServiceCollection.cs +++ b/Gangs/GangServiceCollection.cs @@ -1,18 +1,20 @@ using Commands; using CounterStrikeSharp.API.Core; -using GangsAPI; using GangsAPI.Extensions; using GangsAPI.Services; using Microsoft.Extensions.DependencyInjection; using Mock; +using SQLImpl; namespace GangsImpl; public class GangServiceCollection : IPluginServiceCollection { public void ConfigureServices(IServiceCollection serviceCollection) { serviceCollection.AddPluginBehavior(); + // serviceCollection.AddPluginBehavior(); + serviceCollection.AddPluginBehavior(); serviceCollection.AddPluginBehavior(); - serviceCollection.AddPluginBehavior(); + serviceCollection.AddPluginBehavior(); serviceCollection .AddPluginBehavior(); serviceCollection diff --git a/Gangs/Gangs.csproj b/Gangs/Gangs.csproj index 2c57d5d..51a32bf 100644 --- a/Gangs/Gangs.csproj +++ b/Gangs/Gangs.csproj @@ -10,6 +10,7 @@ + @@ -18,16 +19,16 @@ - + - + - - + + diff --git a/GangsAPI/Data/Command/CommandInfoWrapper.cs b/GangsAPI/Data/Command/CommandInfoWrapper.cs index c777f90..8cdd8d4 100644 --- a/GangsAPI/Data/Command/CommandInfoWrapper.cs +++ b/GangsAPI/Data/Command/CommandInfoWrapper.cs @@ -1,16 +1,14 @@ -using CounterStrikeSharp.API; -using CounterStrikeSharp.API.Core; -using CounterStrikeSharp.API.Modules.Commands; +using CounterStrikeSharp.API.Modules.Commands; namespace GangsAPI.Data.Command; public class CommandInfoWrapper(PlayerWrapper? executor, int offset = 0, params string[] args) { - public readonly PlayerWrapper? CallingPlayer = executor; - public readonly CommandCallingContext CallingContext = CommandCallingContext.Console; + public readonly PlayerWrapper? CallingPlayer = executor; + public CommandInfoWrapper(CommandInfo info, int offset = 0) : this( info.CallingPlayer == null ? null : new PlayerWrapper(info.CallingPlayer), offset, info.ArgString.Split(" ")) { diff --git a/GangsAPI/Data/Command/CommandResult.cs b/GangsAPI/Data/Command/CommandResult.cs index 08c8c13..f4ff678 100644 --- a/GangsAPI/Data/Command/CommandResult.cs +++ b/GangsAPI/Data/Command/CommandResult.cs @@ -2,37 +2,37 @@ public enum CommandResult { /// - /// The command completed successfully + /// The command completed successfully /// SUCCESS, /// - /// The command encountered an error or other - /// scenario that prevented success + /// The command encountered an error or other + /// scenario that prevented success /// FAILURE, /// - /// The command was improperly formatted + /// The command was improperly formatted /// UNKNOWN_COMMAND, /// - /// The command has improper arguments, or - /// no sufficient arguments + /// The command has improper arguments, or + /// no sufficient arguments /// INVALID_ARGS, /// - /// The executor of the command did not have - /// the required permissions + /// The executor of the command did not have + /// the required permissions /// NO_PERMISSION, /// - /// This command can only be executed by a player - /// (i.e. not from the console) + /// This command can only be executed by a player + /// (i.e. not from the console) /// PLAYER_ONLY } \ No newline at end of file diff --git a/GangsAPI/Data/PlayerWrapper.cs b/GangsAPI/Data/PlayerWrapper.cs index 58f65f2..93e1492 100644 --- a/GangsAPI/Data/PlayerWrapper.cs +++ b/GangsAPI/Data/PlayerWrapper.cs @@ -1,5 +1,4 @@ -using System.Collections.Immutable; -using System.Diagnostics; +using System.Diagnostics; using System.Diagnostics.Contracts; using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Modules.Admin; @@ -7,13 +6,11 @@ namespace GangsAPI.Data; public class PlayerWrapper { + private readonly List chatOutput = [], consoleOutput = []; public readonly string? Name; public readonly CCSPlayerController? Player; public readonly ulong Steam; public AdminData? Data; - private readonly List chatOutput = [], consoleOutput = []; - public IReadOnlyList ChatOutput => chatOutput; - public IReadOnlyList ConsoleOutput => consoleOutput; public PlayerWrapper(CCSPlayerController player) { Player = player; @@ -30,6 +27,9 @@ public PlayerWrapper(ulong steam, string? name) { Data = new AdminData { Identity = Steam.ToString() }; } + public IReadOnlyList ChatOutput => chatOutput; + public IReadOnlyList ConsoleOutput => consoleOutput; + public bool IsValid => Player == null || Player.IsValid; private static char USER_CHAR => PermissionCharacters.UserPermissionChar; diff --git a/GangsAPI/Data/Stat/IPerk.cs b/GangsAPI/Data/Stat/IPerk.cs index 1a1a231..93c0ad6 100644 --- a/GangsAPI/Data/Stat/IPerk.cs +++ b/GangsAPI/Data/Stat/IPerk.cs @@ -1,5 +1,3 @@ namespace GangsAPI.Data.Stat; -public interface IPerk : IStat, IPluginBehavior { - -} \ No newline at end of file +public interface IPerk : IStat, IPluginBehavior { } \ No newline at end of file diff --git a/GangsAPI/Services/Commands/ICommandManager.cs b/GangsAPI/Services/Commands/ICommandManager.cs index 8cd8f42..ab19077 100644 --- a/GangsAPI/Services/Commands/ICommandManager.cs +++ b/GangsAPI/Services/Commands/ICommandManager.cs @@ -14,7 +14,7 @@ public interface ICommandManager : IPluginBehavior { bool RegisterCommand(ICommand command); /// - /// Unregisters a command from the manager. + /// Unregisters a command from the manager. /// /// True if the command was successfully unregistered. bool UnregisterCommand(ICommand command); diff --git a/GangsImpl/GenericDB/GenericDB.csproj b/GangsImpl/AbstractDB/AbstractDB.csproj similarity index 82% rename from GangsImpl/GenericDB/GenericDB.csproj rename to GangsImpl/AbstractDB/AbstractDB.csproj index 4176159..806d8f5 100644 --- a/GangsImpl/GenericDB/GenericDB.csproj +++ b/GangsImpl/AbstractDB/AbstractDB.csproj @@ -4,10 +4,12 @@ net8.0 enable enable + GenericDB + diff --git a/GangsImpl/AbstractDB/AbstractDBGangManager.cs b/GangsImpl/AbstractDB/AbstractDBGangManager.cs new file mode 100644 index 0000000..6361ece --- /dev/null +++ b/GangsImpl/AbstractDB/AbstractDBGangManager.cs @@ -0,0 +1,79 @@ +using System.Data.Common; +using CounterStrikeSharp.API.Core; +using Dapper; +using GangsAPI.Data.Gang; +using Mock; +using Xunit; + +namespace GenericDB; + +public abstract class AbstractDBGangManager(string connectionString, + string table = "gang_gangs", bool testing = false) : MockGangManager { + private DbConnection connection = null!; + private DbTransaction? transaction; + public override void ClearCache() { cachedGangs.Clear(); } + + public override void Start(BasePlugin? plugin, bool hotReload) { + Assert.NotNull(table); + connection = CreateDbConnection(connectionString); + + connection.Open(); + + if (testing) transaction = connection.BeginTransaction(); + + try { + var command = connection.CreateCommand(); + + command.Transaction = transaction; + command.CommandText = testing ? + $"CREATE TEMPORARY TABLE IF NOT EXISTS {table} (GangId INT NOT NULL AUTO_INCREMENT PRIMARY KEY, Name VARCHAR(255) NOT NULL)" : + $"CREATE TABLE IF NOT EXISTS {table} (GangId INT NOT NULL PRIMARY KEY, Name VARCHAR(255) NOT NULL)"; + + command.ExecuteNonQuery(); + } catch (Exception e) { + transaction?.Rollback(); + throw new InvalidOperationException("Failed initializing the database", + e); + } + } + + abstract protected DbConnection CreateDbConnection(string connectionString); + + public override async Task Load() { + var query = $"SELECT * FROM {table}"; + var gangs = await connection.QueryAsync(query); + foreach (var gang in gangs) cachedGangs.Add(gang); + } + + public override async Task UpdateGang(IGang gang) { + await base.UpdateGang(gang); + var query = $"UPDATE {table} SET Name = @Name WHERE GangId = @GangId"; + return await connection.ExecuteAsync(query, new { gang.Name, gang.GangId }, + transaction) > 0; + } + + public override async Task DeleteGang(int id) { + await base.DeleteGang(id); + var query = $"DELETE FROM {table} WHERE GangId = @id"; + return await connection.ExecuteAsync(query, new { id }, transaction) > 0; + } + + public override async Task CreateGang(string name, ulong owner) { + Assert.NotNull(table); + if (cachedGangs.Any(g => g.Name == name)) return null; + var query = $"INSERT INTO {table} (Name) VALUES (@name)"; + var result = + await connection.ExecuteAsync(query, new { name }, transaction); + if (result == 0) return null; + var id = await connection.ExecuteScalarAsync("SELECT LAST_INSERT_ID()", + transaction: transaction); + var gang = new DBGang(id, name, owner); + cachedGangs.Add(gang); + return gang.Clone() as IGang; + } + + public override void Dispose() { + transaction?.Dispose(); + connection.Dispose(); + } +} \ No newline at end of file diff --git a/GangsImpl/AbstractDB/AbstractDBStatManager.cs b/GangsImpl/AbstractDB/AbstractDBStatManager.cs new file mode 100644 index 0000000..74040ad --- /dev/null +++ b/GangsImpl/AbstractDB/AbstractDBStatManager.cs @@ -0,0 +1,84 @@ +using System.Data.Common; +using CounterStrikeSharp.API.Core; +using Dapper; +using GangsAPI.Data.Stat; +using Mock; + +namespace GenericDB; + +public abstract class AbstractDBStatManager(string connectionString, + string table = "gang_stats", bool testing = false) : MockStatManager { + private DbConnection connection = null!; + private DbTransaction? transaction; + + public override void Start(BasePlugin? plugin, bool hotReload) { + connection = CreateDbConnection(connectionString); + + connection.Open(); + + if (testing) transaction = connection.BeginTransaction(); + + try { + var command = connection.CreateCommand(); + + command.Transaction = transaction; + command.CommandText = testing ? + $"CREATE TEMPORARY TABLE IF NOT EXISTS {table} (StatId VARCHAR(255) NOT NULL PRIMARY KEY, Name VARCHAR(255) NOT NULL, Description TEXT)" : + $"CREATE TABLE IF NOT EXISTS {table} (StatId VARCHAR(255) NOT NULL PRIMARY KEY, Name VARCHAR(255) NOT NULL, Description TEXT)"; + + command.ExecuteNonQuery(); + + // TODO: For some reason GitHub CI fails here + // LoadStats().GetAwaiter().GetResult(); + } catch (Exception e) { + transaction?.Rollback(); + throw new InvalidOperationException("Failed initializing the database", + e); + } + } + + public void Dispose() { + transaction?.Commit(); + connection.Close(); + connection.Dispose(); + } + + public override async Task CreateStat(string id, string name, + string? description = null) { + var stat = await GetStat(id); + if (stat != null) return stat; + stat = new DBStat(id, name, description); + return stat; + } + + public override async Task RegisterStat(IStat stat) { + if (cachedStats.Contains(stat)) return false; + var sqlStat = (DBStat)stat; + // var command = connection.CreateCommand(); + await connection.ExecuteAsync( + $"INSERT INTO {table} (StatId, Name, Description) VALUES (@StatId, @Name, @Description)", + new { sqlStat.StatId, sqlStat.Name, sqlStat.Description }, transaction); + return cachedStats.Add(stat); + } + + public override async Task UnregisterStat(string id) { + var matches = cachedStats.Where(stat => stat.StatId == id).ToList(); + foreach (var stat in matches) cachedStats.Remove(stat); + + await connection.ExecuteAsync($"DELETE FROM {table} WHERE StatId = @StatId", + new { StatId = id }, transaction); + + return await Task.FromResult(matches.Count > 0); + } + + public override async Task Load() { + var query = $"SELECT * FROM {table}"; + var result = await connection.QueryAsync(query, + transaction: transaction); + foreach (var stat in result) cachedStats.Add(stat); + } + + public abstract DbConnection CreateDbConnection(string connectionString); + + // public abstract DbParameter CreateDbParameter(string key, object value); +} \ No newline at end of file diff --git a/GangsImpl/AbstractDB/DBGang.cs b/GangsImpl/AbstractDB/DBGang.cs new file mode 100644 index 0000000..a50c316 --- /dev/null +++ b/GangsImpl/AbstractDB/DBGang.cs @@ -0,0 +1,29 @@ +using GangsAPI.Data.Gang; +using GangsAPI.Data.Stat; +using GangsAPI.Permissions; +using Mock; + +namespace GenericDB; + +/// +/// Dapper-compatible representation of a gang. +/// +public class DBGang : MockGang { + public DBGang(int id, string name, ulong owner, + IDictionary members, ISet ranks, + ISet perks, ISet stats) : base(id, name, owner) { + Members = members; + Ranks = ranks; + Perks = perks; + Stats = stats; + } + + public DBGang(IGang gang) : base(gang.GangId, gang.Name, gang.Owner) { + Members = gang.Members; + Ranks = gang.Ranks; + Perks = gang.Perks; + Stats = gang.Stats; + } + + public DBGang(int id, string name, ulong owner) : base(id, name, owner) { } +} \ No newline at end of file diff --git a/GangsImpl/GenericDB/DBStat.cs b/GangsImpl/AbstractDB/DBStat.cs similarity index 100% rename from GangsImpl/GenericDB/DBStat.cs rename to GangsImpl/AbstractDB/DBStat.cs diff --git a/GangsImpl/GenericDB/GenericDBStatManager.cs b/GangsImpl/GenericDB/GenericDBStatManager.cs deleted file mode 100644 index 3ed6465..0000000 --- a/GangsImpl/GenericDB/GenericDBStatManager.cs +++ /dev/null @@ -1,112 +0,0 @@ -using System.Data.Common; -using CounterStrikeSharp.API.Core; -using Dapper; -using GangsAPI.Data.Stat; -using GangsAPI.Services; - -namespace GenericDB; - -public abstract class GenericDBStatManager(string connectionString, - string table = "gang_stats", bool testing = false) : IStatManager { - private readonly HashSet stats = []; - private DbConnection connection = null!; - private DbTransaction? transaction; - - public void Start(BasePlugin? plugin, bool hotReload) { - connection = CreateDbConnection(connectionString); - - connection.Open(); - - if (testing) transaction = connection.BeginTransaction(); - - try { - var command = connection.CreateCommand(); - - command.Transaction = transaction; - command.CommandText = testing ? - $"CREATE TEMPORARY TABLE IF NOT EXISTS {table} (StatId VARCHAR(255) NOT NULL PRIMARY KEY, Name VARCHAR(255) NOT NULL, Description TEXT)" : - $"CREATE TABLE IF NOT EXISTS {table} (StatId VARCHAR(255) NOT NULL PRIMARY KEY, Name VARCHAR(255) NOT NULL, Description TEXT)"; - - command.ExecuteNonQuery(); - - // TODO: For some reason GitHub CI fails here - // LoadStats().GetAwaiter().GetResult(); - } catch (Exception e) { - transaction?.Rollback(); - throw new InvalidOperationException("Failed initializing the database", - e); - } - } - - public void Dispose() { - transaction?.Commit(); - connection.Close(); - connection.Dispose(); - } - - public async Task> GetStats() { - return await Task.FromResult>(stats); - } - - public Task GetStat(string id) { - return Task.FromResult(stats.FirstOrDefault(stat => stat.StatId == id)); - } - - public async Task CreateStat(string id, string name, - string? description = null) { - var stat = await GetStat(id); - if (stat != null) return stat; - // stat = new DBStat { StatId = id, Name = name, Description = description }; - stat = new DBStat(id, name, description); - return stat; - } - - public async Task RegisterStat(IStat stat) { - if (stats.Contains(stat)) return false; - var sqlStat = (DBStat)stat; - var command = connection.CreateCommand(); - command.Transaction = transaction; - command.CommandText = - $"INSERT INTO {table} (StatId, Name, Description) VALUES (@StatId, @Name, @Description)"; - - command.Parameters.Add(CreateDbParameter("@StatId", sqlStat.StatId)); - command.Parameters.Add(CreateDbParameter("@Name", sqlStat.Name)); - - if (sqlStat.Description != null) - command.Parameters.Add(CreateDbParameter("@Description", - sqlStat.Description)); - else - command.Parameters.Add(CreateDbParameter("@Description", DBNull.Value)); - - await command.ExecuteNonQueryAsync(); - return stats.Add(stat); - } - - public async Task UnregisterStat(string id) { - var matches = stats.Where(stat => stat.StatId == id).ToList(); - foreach (var stat in matches) stats.Remove(stat); - - var command = connection.CreateCommand(); - command.Transaction = transaction; - command.CommandText = $"DELETE FROM {table} WHERE StatId = @StatId"; - command.Parameters.Add(CreateDbParameter("@StatId", id)); - await command.ExecuteNonQueryAsync(); - - return await Task.FromResult(matches.Count > 0); - } - - public void ClearCache() { stats.Clear(); } - - public async Task Load() { await LoadStats(); } - - virtual protected async Task LoadStats() { - var query = $"SELECT * FROM {table}"; - var result = await connection.QueryAsync(query, - transaction: transaction); - foreach (var stat in result) stats.Add(stat); - } - - public abstract DbConnection CreateDbConnection(string connectionString); - - public abstract DbParameter CreateDbParameter(string key, object value); -} \ No newline at end of file diff --git a/GangsImpl/Mock/Mock.csproj b/GangsImpl/Mock/Mock.csproj index 37884f1..7fd3d93 100644 --- a/GangsImpl/Mock/Mock.csproj +++ b/GangsImpl/Mock/Mock.csproj @@ -19,7 +19,7 @@ - + diff --git a/GangsImpl/Mock/MockGang.cs b/GangsImpl/Mock/MockGang.cs index 0fa95f9..c5e4cae 100644 --- a/GangsImpl/Mock/MockGang.cs +++ b/GangsImpl/Mock/MockGang.cs @@ -19,12 +19,12 @@ public MockGang(int id, string name, ulong owner) { Ranks.Add(ownerRank); } - public int GangId { get; } + public int GangId { get; protected init; } public string Name { get; set; } - public IDictionary Members { get; } - public ISet Ranks { get; } - public ISet Perks { get; } - public ISet Stats { get; } + public IDictionary Members { get; protected init; } + public ISet Ranks { get; protected init; } + public ISet Perks { get; protected init; } + public ISet Stats { get; protected init; } public object Clone() { var clone = new MockGang(GangId, Name, ((IGang)this).Owner); diff --git a/GangsImpl/Mock/MockGangManager.cs b/GangsImpl/Mock/MockGangManager.cs index aa3a824..ae4462b 100644 --- a/GangsImpl/Mock/MockGangManager.cs +++ b/GangsImpl/Mock/MockGangManager.cs @@ -1,10 +1,11 @@ -using GangsAPI.Data.Gang; +using CounterStrikeSharp.API.Core; +using GangsAPI.Data.Gang; using GangsAPI.Services; namespace Mock; public class MockGangManager : IGangManager { - private readonly HashSet cachedGangs = [], backendGangs = []; + protected readonly HashSet cachedGangs = [], backendGangs = []; public Task> GetGangs() { return Task.FromResult(cachedGangs.AsEnumerable()); @@ -19,7 +20,7 @@ public Task> GetGangs() { cachedGangs.FirstOrDefault(g => g.Members.ContainsKey(steam))); } - public Task UpdateGang(IGang gang) { + public virtual Task UpdateGang(IGang gang) { var g = cachedGangs.FirstOrDefault(g => g.GangId == gang.GangId); if (g == null) return Task.FromResult(false); g.Name = gang.Name; @@ -28,11 +29,11 @@ public Task UpdateGang(IGang gang) { return Task.FromResult(true); } - public Task DeleteGang(int id) { + public virtual Task DeleteGang(int id) { return Task.FromResult(cachedGangs.RemoveWhere(g => g.GangId == id) > 0); } - public Task CreateGang(string name, ulong owner) { + public virtual Task CreateGang(string name, ulong owner) { var id = cachedGangs.Count + 1; var gang = new MockGang(id, name, owner); if (cachedGangs.Any(g => g.GangId == id)) @@ -42,10 +43,13 @@ public Task DeleteGang(int id) { return Task.FromResult(gang.Clone() as IGang); } - public void ClearCache() { cachedGangs.Clear(); } + public virtual void ClearCache() { cachedGangs.Clear(); } - public Task Load() { + public virtual Task Load() { cachedGangs.UnionWith(backendGangs); return Task.CompletedTask; } + + public virtual void Start(BasePlugin? plugin, bool hotReload) { } + public virtual void Dispose() { } } \ No newline at end of file diff --git a/GangsImpl/Mock/MockStatManager.cs b/GangsImpl/Mock/MockStatManager.cs index 7fad9d3..09821af 100644 --- a/GangsImpl/Mock/MockStatManager.cs +++ b/GangsImpl/Mock/MockStatManager.cs @@ -1,10 +1,14 @@ -using GangsAPI.Data.Stat; +using CounterStrikeSharp.API.Core; +using GangsAPI.Data.Stat; using GangsAPI.Services; namespace Mock; public class MockStatManager : IStatManager { - private readonly HashSet cachedStats = [], backendStats = []; + private readonly HashSet backendStats = []; + protected readonly HashSet cachedStats = []; + + public virtual void Start(BasePlugin? plugin, bool hotReload) { } public Task> GetStats() { return Task.FromResult>(cachedStats); @@ -15,7 +19,7 @@ public Task> GetStats() { cachedStats.FirstOrDefault(stat => stat.StatId == id)); } - public async Task CreateStat(string id, string name, + public virtual async Task CreateStat(string id, string name, string? description = null) { var stat = await GetStat(id); if (stat != null) return stat; @@ -23,13 +27,13 @@ public Task> GetStats() { return stat; } - public Task RegisterStat(IStat stat) { + public virtual Task RegisterStat(IStat stat) { if (!cachedStats.Add(stat)) return Task.FromResult(false); backendStats.Add(stat); return Task.FromResult(true); } - public Task UnregisterStat(string id) { + public virtual Task UnregisterStat(string id) { var matches = cachedStats.Where(stat => stat.StatId == id).ToList(); foreach (var stat in matches) { cachedStats.Remove(stat); @@ -41,7 +45,7 @@ public Task UnregisterStat(string id) { public void ClearCache() { cachedStats.Clear(); } - public Task Load() { + public virtual Task Load() { cachedStats.UnionWith(backendStats); return Task.CompletedTask; } diff --git a/GangsImpl/SQL/SQL.csproj b/GangsImpl/SQL/SQL.csproj index e1a75dc..e871f8e 100644 --- a/GangsImpl/SQL/SQL.csproj +++ b/GangsImpl/SQL/SQL.csproj @@ -14,7 +14,7 @@ - + diff --git a/GangsImpl/SQL/SQLGangManager.cs b/GangsImpl/SQL/SQLGangManager.cs new file mode 100644 index 0000000..3bced47 --- /dev/null +++ b/GangsImpl/SQL/SQLGangManager.cs @@ -0,0 +1,13 @@ +using System.Data.Common; +using GenericDB; +using MySqlConnector; + +namespace SQLImpl; + +public class SQLGangManager(string connectionString, + string table = "gang_gangs", bool testing = false) + : AbstractDBGangManager(connectionString, table, testing) { + override protected DbConnection CreateDbConnection(string connectionString) { + return new MySqlConnection(connectionString); + } +} \ No newline at end of file diff --git a/GangsImpl/SQL/SqlStatStatManager.cs b/GangsImpl/SQL/SQLStatManager.cs similarity index 53% rename from GangsImpl/SQL/SqlStatStatManager.cs rename to GangsImpl/SQL/SQLStatManager.cs index 96665bc..f74c463 100644 --- a/GangsImpl/SQL/SqlStatStatManager.cs +++ b/GangsImpl/SQL/SQLStatManager.cs @@ -4,14 +4,10 @@ namespace SQLImpl; -public class SqlStatStatManager(string connectionString, +public class SQLStatManager(string connectionString, string table = "gang_stats", bool testing = false) - : GenericDBStatManager(connectionString, table, testing) { + : AbstractDBStatManager(connectionString, table, testing) { public override DbConnection CreateDbConnection(string connectionString) { return new MySqlConnection(connectionString); } - - public override DbParameter CreateDbParameter(string key, object value) { - return new MySqlParameter(key, value); - } } \ No newline at end of file diff --git a/GangsImpl/SQLite/SQLite.csproj b/GangsImpl/SQLite/SQLite.csproj index bdcc785..f541f0b 100644 --- a/GangsImpl/SQLite/SQLite.csproj +++ b/GangsImpl/SQLite/SQLite.csproj @@ -7,7 +7,7 @@ - + diff --git a/GangsImpl/SQLite/SQLiteStatManager.cs b/GangsImpl/SQLite/SQLiteStatManager.cs index b980625..abaa933 100644 --- a/GangsImpl/SQLite/SQLiteStatManager.cs +++ b/GangsImpl/SQLite/SQLiteStatManager.cs @@ -6,12 +6,8 @@ namespace SQLite; public class SQLiteStatManager(string connectionString, string table = "gang_stats", bool testing = false) - : GenericDBStatManager(connectionString, table, testing) { + : AbstractDBStatManager(connectionString, table, testing) { public override DbConnection CreateDbConnection(string connectionString) { return new SqliteConnection(connectionString); } - - public override DbParameter CreateDbParameter(string key, object value) { - return new SqliteParameter(key, value); - } } \ No newline at end of file diff --git a/GangsTest/API/CommandWrapperTests.cs b/GangsTest/API/CommandWrapperTests.cs index eea182b..d82692c 100644 --- a/GangsTest/API/CommandWrapperTests.cs +++ b/GangsTest/API/CommandWrapperTests.cs @@ -1,5 +1,3 @@ namespace GangsTest.API; -public class CommandWrapperTests { - -} \ No newline at end of file +public class CommandWrapperTests { } \ No newline at end of file diff --git a/GangsTest/API/PlayerWrapperTests.cs b/GangsTest/API/PlayerWrapperTests.cs index f27376c..764dce2 100644 --- a/GangsTest/API/PlayerWrapperTests.cs +++ b/GangsTest/API/PlayerWrapperTests.cs @@ -1,16 +1,15 @@ 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"); + private static char USER_CHAR => PermissionCharacters.UserPermissionChar; + private static char GROUP_CHAR => PermissionCharacters.GroupPermissionChar; + [Fact] public void PlayerWrapper_Init() { Assert.Null(testPlayer.Player); diff --git a/GangsTest/Commands/CommandTests.cs b/GangsTest/Commands/CommandTests.cs index b2906c3..642c010 100644 --- a/GangsTest/Commands/CommandTests.cs +++ b/GangsTest/Commands/CommandTests.cs @@ -4,8 +4,8 @@ namespace GangsTest.Commands; public abstract class CommandTests { - protected readonly ICommandManager Commands; protected readonly ICommand Command; + protected readonly ICommandManager Commands; protected readonly PlayerWrapper TestPlayer = new((ulong)new Random().NextInt64(), "Test Player"); diff --git a/GangsTest/Commands/CreateTests.cs b/GangsTest/Commands/CreateTests.cs index edd4770..6163d34 100644 --- a/GangsTest/Commands/CreateTests.cs +++ b/GangsTest/Commands/CreateTests.cs @@ -1,10 +1,8 @@ -using System.Diagnostics; -using Commands.gang; +using Commands.gang; using GangsAPI.Data; using GangsAPI.Data.Command; using GangsAPI.Services; using GangsAPI.Services.Commands; -using Microsoft.VisualBasic; namespace GangsTest.Commands; diff --git a/GangsTest/Commands/GangCommandTests.cs b/GangsTest/Commands/GangCommandTests.cs index eaa7019..bcf09e6 100644 --- a/GangsTest/Commands/GangCommandTests.cs +++ b/GangsTest/Commands/GangCommandTests.cs @@ -25,7 +25,7 @@ await Command.Execute(TestPlayer, [Fact] public async Task Gang_TestInvalid_Null() { await Assert.ThrowsAnyAsync(async () => { - await Command.Execute(TestPlayer, new CommandInfoWrapper(TestPlayer, 0)); + await Command.Execute(TestPlayer, new CommandInfoWrapper(TestPlayer)); }); } diff --git a/GangsTest/Commands/LogicTests.cs b/GangsTest/Commands/LogicTests.cs index e0d8d50..5ffa3c9 100644 --- a/GangsTest/Commands/LogicTests.cs +++ b/GangsTest/Commands/LogicTests.cs @@ -1,13 +1,11 @@ -using GangsAPI.Data; -using GangsAPI.Data.Command; +using GangsAPI.Data.Command; using GangsAPI.Services.Commands; -using GangsTest.Commands.ManagerTests; namespace GangsTest.Commands.CommandLogic; public class LogicTests : ManagerTests.ManagerTests { [Theory] - [ClassData(typeof(ManagerData))] + [ClassData(typeof(ManagerTests.CommandTestData))] public async Task Command_Logic(ICommandManager mgr) { Assert.True(mgr.RegisterCommand(Dummy)); Assert.Equal(CommandResult.SUCCESS, @@ -15,7 +13,7 @@ public async Task Command_Logic(ICommandManager mgr) { } [Theory] - [ClassData(typeof(ManagerData))] + [ClassData(typeof(ManagerTests.CommandTestData))] public async Task Command_Logic_Fail(ICommandManager mgr) { Assert.True(mgr.RegisterCommand(Dummy)); Assert.Equal(CommandResult.FAILURE, diff --git a/GangsTest/Commands/ManagerTests/ManagerData.cs b/GangsTest/Commands/ManagerTests/CommandTestData.cs similarity index 85% rename from GangsTest/Commands/ManagerTests/ManagerData.cs rename to GangsTest/Commands/ManagerTests/CommandTestData.cs index 19504d8..1e34c72 100644 --- a/GangsTest/Commands/ManagerTests/ManagerData.cs +++ b/GangsTest/Commands/ManagerTests/CommandTestData.cs @@ -5,12 +5,12 @@ namespace GangsTest.Commands.ManagerTests; -public class ManagerData : IEnumerable { +public class CommandTestData : IEnumerable { private readonly IBehavior[] behaviors = [ new MockCommandManager(), new CommandManager(new MockGangManager()) ]; - public ManagerData() { + public CommandTestData() { foreach (var behavior in behaviors) behavior.Start(); } diff --git a/GangsTest/Commands/ManagerTests/ManagerHandling.cs b/GangsTest/Commands/ManagerTests/ManagerHandling.cs index 4540fd5..3bec04b 100644 --- a/GangsTest/Commands/ManagerTests/ManagerHandling.cs +++ b/GangsTest/Commands/ManagerTests/ManagerHandling.cs @@ -5,17 +5,8 @@ namespace GangsTest.Commands.ManagerTests; public class ManagerHandling : ManagerTests { - private class PlayerOnlyCommand : ICommand { - public string Name => "css_player"; - - public Task Execute(PlayerWrapper? executor, - CommandInfoWrapper info) { - return Task.FromResult(CommandResult.PLAYER_ONLY); - } - } - [Theory] - [ClassData(typeof(ManagerData))] + [ClassData(typeof(CommandTestData))] public async Task Command_PlayerOnly(ICommandManager mgr) { mgr.RegisterCommand(new PlayerOnlyCommand()); Assert.Equal(CommandResult.PLAYER_ONLY, @@ -23,4 +14,13 @@ public async Task Command_PlayerOnly(ICommandManager mgr) { Assert.Contains("This command can only be executed by a player", TestPlayer.ConsoleOutput); } + + private class PlayerOnlyCommand : ICommand { + public string Name => "css_player"; + + public Task Execute(PlayerWrapper? executor, + CommandInfoWrapper info) { + return Task.FromResult(CommandResult.PLAYER_ONLY); + } + } } \ No newline at end of file diff --git a/GangsTest/Commands/ManagerTests/RegistrationTests.cs b/GangsTest/Commands/ManagerTests/RegistrationTests.cs index c7ef66c..275d24d 100644 --- a/GangsTest/Commands/ManagerTests/RegistrationTests.cs +++ b/GangsTest/Commands/ManagerTests/RegistrationTests.cs @@ -5,7 +5,7 @@ namespace GangsTest.Commands.ManagerTests; public class RegistrationTests : ManagerTests { [Theory] - [ClassData(typeof(ManagerData))] + [ClassData(typeof(CommandTestData))] public async Task Command_Register(ICommandManager mgr) { Assert.True(mgr.RegisterCommand(Dummy)); Assert.Equal(CommandResult.SUCCESS, @@ -13,14 +13,14 @@ public async Task Command_Register(ICommandManager mgr) { } [Theory] - [ClassData(typeof(ManagerData))] + [ClassData(typeof(CommandTestData))] public async Task Command_Unregistered(ICommandManager mgr) { Assert.Equal(CommandResult.UNKNOWN_COMMAND, await mgr.ProcessCommand(TestPlayer, "css_dummy")); } [Theory] - [ClassData(typeof(ManagerData))] + [ClassData(typeof(CommandTestData))] public async Task Command_Unregister(ICommandManager mgr) { Assert.True(mgr.RegisterCommand(Dummy)); Assert.True(mgr.UnregisterCommand(Dummy)); @@ -29,7 +29,7 @@ public async Task Command_Unregister(ICommandManager mgr) { } [Theory] - [ClassData(typeof(ManagerData))] + [ClassData(typeof(CommandTestData))] public void Command_Unregister_Unregistered(ICommandManager mgr) { Assert.False(mgr.UnregisterCommand(Dummy)); } diff --git a/GangsTest/Commands/PermissionTests.cs b/GangsTest/Commands/PermissionTests.cs index 6f0b9b9..8a30183 100644 --- a/GangsTest/Commands/PermissionTests.cs +++ b/GangsTest/Commands/PermissionTests.cs @@ -1,26 +1,12 @@ -using CounterStrikeSharp.API.Modules.Commands; -using GangsAPI.Data; +using GangsAPI.Data; using GangsAPI.Data.Command; using GangsAPI.Services.Commands; -using GangsTest.Commands.ManagerTests; namespace GangsTest.Commands.CommandPerms; public class PermissionTests : ManagerTests.ManagerTests { - private class ElevatedCommand(string[] flags, string[] groups) : ICommand { - public string Name => "css_elevated"; - public string? Description => "Elevated command for testing"; - public string[] RequiredFlags { get; } = flags; - public string[] RequiredGroups { get; } = groups; - - public Task Execute(PlayerWrapper? executor, - CommandInfoWrapper info) { - return Task.FromResult(CommandResult.SUCCESS); - } - } - [Theory] - [ClassData(typeof(ManagerData))] + [ClassData(typeof(ManagerTests.CommandTestData))] public async Task Permission_Pass(ICommandManager mgr) { mgr.RegisterCommand(Dummy); Assert.Equal(CommandResult.SUCCESS, @@ -28,7 +14,7 @@ public async Task Permission_Pass(ICommandManager mgr) { } [Theory] - [ClassData(typeof(ManagerData))] + [ClassData(typeof(ManagerTests.CommandTestData))] public async Task Permission_Pass_Flag_Console(ICommandManager mgr) { mgr.RegisterCommand(new ElevatedCommand(["@test/flag"], [])); Assert.Equal(CommandResult.SUCCESS, @@ -36,7 +22,7 @@ public async Task Permission_Pass_Flag_Console(ICommandManager mgr) { } [Theory] - [ClassData(typeof(ManagerData))] + [ClassData(typeof(ManagerTests.CommandTestData))] public async Task Permission_Pass_Group_Console(ICommandManager mgr) { mgr.RegisterCommand(new ElevatedCommand([], ["#test/group"])); Assert.Equal(CommandResult.SUCCESS, @@ -44,7 +30,7 @@ public async Task Permission_Pass_Group_Console(ICommandManager mgr) { } [Theory] - [ClassData(typeof(ManagerData))] + [ClassData(typeof(ManagerTests.CommandTestData))] public async Task Permission_Fail_Flag(ICommandManager mgr) { mgr.RegisterCommand(new ElevatedCommand(["@test/flag"], [])); Assert.Equal(CommandResult.NO_PERMISSION, @@ -52,7 +38,7 @@ public async Task Permission_Fail_Flag(ICommandManager mgr) { } [Theory] - [ClassData(typeof(ManagerData))] + [ClassData(typeof(ManagerTests.CommandTestData))] public async Task Permission_Fail_Group(ICommandManager mgr) { mgr.RegisterCommand(new ElevatedCommand([], ["#test/group"])); Assert.Equal(CommandResult.NO_PERMISSION, @@ -60,7 +46,7 @@ public async Task Permission_Fail_Group(ICommandManager mgr) { } [Theory] - [ClassData(typeof(ManagerData))] + [ClassData(typeof(ManagerTests.CommandTestData))] public async Task Permission_Fail_Both_Flag(ICommandManager mgr) { mgr.RegisterCommand(new ElevatedCommand(["@test/flag"], ["#test/group"])); Assert.Equal(CommandResult.NO_PERMISSION, @@ -68,7 +54,7 @@ public async Task Permission_Fail_Both_Flag(ICommandManager mgr) { } [Theory] - [ClassData(typeof(ManagerData))] + [ClassData(typeof(ManagerTests.CommandTestData))] public async Task Permission_Fail_Both_Group(ICommandManager mgr) { mgr.RegisterCommand(new ElevatedCommand(["@test/flag"], ["#test/group"])); Assert.Equal(CommandResult.NO_PERMISSION, @@ -76,7 +62,7 @@ public async Task Permission_Fail_Both_Group(ICommandManager mgr) { } [Theory] - [ClassData(typeof(ManagerData))] + [ClassData(typeof(ManagerTests.CommandTestData))] public async Task Permission_Pass_Flag(ICommandManager mgr) { var elevatedPlayer = TestPlayer.WithFlags("@test/flag"); mgr.RegisterCommand(new ElevatedCommand(["@test/flag"], [])); @@ -85,7 +71,7 @@ public async Task Permission_Pass_Flag(ICommandManager mgr) { } [Theory] - [ClassData(typeof(ManagerData))] + [ClassData(typeof(ManagerTests.CommandTestData))] public async Task Permission_Pass_Group(ICommandManager mgr) { var elevatedPlayer = TestPlayer.WithGroups("#test/group"); mgr.RegisterCommand(new ElevatedCommand([], ["#test/group"])); @@ -94,7 +80,7 @@ public async Task Permission_Pass_Group(ICommandManager mgr) { } [Theory] - [ClassData(typeof(ManagerData))] + [ClassData(typeof(ManagerTests.CommandTestData))] public async Task Permission_Pass_Both(ICommandManager mgr) { var elevatedPlayer = TestPlayer.WithFlags("@test/flag").WithGroups("#test/group"); @@ -102,4 +88,16 @@ public async Task Permission_Pass_Both(ICommandManager mgr) { Assert.Equal(CommandResult.SUCCESS, await mgr.ProcessCommand(elevatedPlayer, "css_elevated")); } + + private class ElevatedCommand(string[] flags, string[] groups) : ICommand { + public string Name => "css_elevated"; + public string? Description => "Elevated command for testing"; + public string[] RequiredFlags { get; } = flags; + public string[] RequiredGroups { get; } = groups; + + public Task Execute(PlayerWrapper? executor, + CommandInfoWrapper info) { + return Task.FromResult(CommandResult.SUCCESS); + } + } } \ No newline at end of file diff --git a/GangsTest/GangTests/GangFetchTests.cs b/GangsTest/GangTests/GangFetchTests.cs index 3f1842f..4fde080 100644 --- a/GangsTest/GangTests/GangFetchTests.cs +++ b/GangsTest/GangTests/GangFetchTests.cs @@ -1,6 +1,5 @@ using GangsAPI.Data.Gang; using GangsAPI.Services; -using Mock; namespace GangsTest.GangTests; diff --git a/GangsTest/GangTests/GangManagerData.cs b/GangsTest/GangTests/GangManagerData.cs index 3e77809..f521cc5 100644 --- a/GangsTest/GangTests/GangManagerData.cs +++ b/GangsTest/GangTests/GangManagerData.cs @@ -1,11 +1,17 @@ using System.Collections; using GangsAPI; using Mock; +using SQLImpl; namespace GangsTest.GangTests; public class GangManagerData : IEnumerable { - private readonly IBehavior[] behaviors = [new MockGangManager()]; + private readonly IBehavior[] behaviors = [ + new MockGangManager(), + new SQLGangManager( + Environment.GetEnvironmentVariable("DB_CONNECTION_STRING") + ?? "Host=localhost;User=root;Database=gangs", "gang_unit_test", true) + ]; public GangManagerData() { foreach (var behavior in behaviors) behavior.Start(); diff --git a/GangsTest/GangsTest.csproj b/GangsTest/GangsTest.csproj index 9151c73..2fc5025 100644 --- a/GangsTest/GangsTest.csproj +++ b/GangsTest/GangsTest.csproj @@ -10,16 +10,16 @@ - - - - - - + + + + + + - + @@ -29,10 +29,10 @@ - - - - + + + + \ No newline at end of file diff --git a/GangsTest/Permissions/GangRankTests.cs b/GangsTest/Permissions/GangRankTests.cs index d0eec3a..5d41395 100644 --- a/GangsTest/Permissions/GangRankTests.cs +++ b/GangsTest/Permissions/GangRankTests.cs @@ -7,21 +7,19 @@ public class GangRankTests { [Fact] public void Rank_Owner_HasAllPerms() { var rank = new MockGangRank(0, "Owner", IGangRank.Permissions.OWNER); - foreach (var perm in Enum.GetValues()) { + foreach (var perm in Enum.GetValues()) Assert.True(rank.Perms.HasFlag(perm)); - } } [Fact] public void Rank_Admin_HasAllPerms() { var rank = new MockGangRank(1, "Admin", IGangRank.Permissions.ADMINISTRATOR); - foreach (var perm in Enum.GetValues()) { + foreach (var perm in Enum.GetValues()) if (perm == IGangRank.Permissions.OWNER) Assert.False(rank.Perms.HasFlag(perm)); else Assert.True(rank.Perms.HasFlag(perm)); - } } [Fact] diff --git a/GangsTest/Startup.cs b/GangsTest/Startup.cs index 3ccbb30..782009d 100644 --- a/GangsTest/Startup.cs +++ b/GangsTest/Startup.cs @@ -1,11 +1,7 @@ -using System.Text; -using GangsAPI.Services; +using GangsAPI.Services; using GangsAPI.Services.Commands; using Microsoft.Extensions.DependencyInjection; -using Microsoft.VisualBasic.CompilerServices; using Mock; -using Xunit.Abstractions; -using Xunit.DependencyInjection.Logging; namespace GangsTest; diff --git a/GangsTest/StatTests/StatManagerData.cs b/GangsTest/StatTests/StatManagerData.cs index bae8fad..9a4b8f3 100644 --- a/GangsTest/StatTests/StatManagerData.cs +++ b/GangsTest/StatTests/StatManagerData.cs @@ -9,10 +9,9 @@ namespace GangsTest.StatTests; public class StatManagerData : IEnumerable { private readonly IBehavior[] behaviors = [ new MockStatManager(), - new SqlStatStatManager( + new SQLStatManager( Environment.GetEnvironmentVariable("DB_CONNECTION_STRING") - ?? "Host=localhost;User=root;Database=gangs", - "gang_unit_test", true), + ?? "Host=localhost;User=root;Database=gangs", "gang_unit_test", true), new SQLiteStatManager("Data Source=:memory:", "gang_unit_test", true) ];