mirror of
https://github.com/edgegamers/Gangs.git
synced 2025-12-05 20:40:30 -08:00
Dev (#9)
* Normalize paths * Update workflows * Update workflows * Update workflows * Update csproj build dirs * Update csproj build dirs * Fix bugs * Directories are hard * Dont zip zip * Rename to support CS# * Fix nightly file name * Debug * Try referencing class directly * Update dependabot * Update gitignore and command tests * More tests: * Basic gang creation working
This commit is contained in:
7
.github/dependabot.yml
vendored
7
.github/dependabot.yml
vendored
@@ -9,3 +9,10 @@ updates:
|
||||
directory: "/" # Location of package manifests
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
target-branch: dev
|
||||
- package-ecosystem: "nuget" # See documentation for possible values
|
||||
directory: "/" # Location of package manifests
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
target-branch: main
|
||||
open-pull-requests-limit: 0
|
||||
|
||||
52
.github/workflows/codeql.yml
vendored
52
.github/workflows/codeql.yml
vendored
@@ -14,8 +14,18 @@ name: "CodeQL"
|
||||
on:
|
||||
push:
|
||||
branches: [ "main", "dev" ]
|
||||
paths:
|
||||
- 'Gangs*/**'
|
||||
- '.github/workflows/nightly.yml'
|
||||
- 'Core/**'
|
||||
- 'Commands/**'
|
||||
pull_request:
|
||||
branches: [ "main" ]
|
||||
paths:
|
||||
- 'Gangs*/**'
|
||||
- '.github/workflows/nightly.yml'
|
||||
- 'Core/**'
|
||||
- 'Commands/**'
|
||||
schedule:
|
||||
- cron: '34 12 * * 6'
|
||||
|
||||
@@ -43,8 +53,8 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- language: csharp
|
||||
build-mode: none
|
||||
- language: csharp
|
||||
build-mode: none
|
||||
# CodeQL supports the following values keywords for 'language': 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift'
|
||||
# Use `c-cpp` to analyze code written in C, C++ or both
|
||||
# Use 'java-kotlin' to analyze code written in Java, Kotlin or both
|
||||
@@ -54,23 +64,23 @@ jobs:
|
||||
# If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how
|
||||
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
build-mode: ${{ matrix.build-mode }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
|
||||
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
||||
# queries: security-extended,security-and-quality
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
build-mode: ${{ matrix.build-mode }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
|
||||
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
||||
# queries: security-extended,security-and-quality
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v3
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v3
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
||||
|
||||
8
.github/workflows/dotnet.yml
vendored
8
.github/workflows/dotnet.yml
vendored
@@ -4,11 +4,15 @@ on:
|
||||
push:
|
||||
paths:
|
||||
- 'Gangs*/**'
|
||||
- '.github/workflows/dotnet.yml'
|
||||
- '.github/workflows/nightly.yml'
|
||||
- 'Core/**'
|
||||
- 'Commands/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'Gangs*/**'
|
||||
- '.github/workflows/dotnet.yml'
|
||||
- '.github/workflows/nightly.yml'
|
||||
- 'Core/**'
|
||||
- 'Commands/**'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
7
.github/workflows/nightly.yml
vendored
7
.github/workflows/nightly.yml
vendored
@@ -11,6 +11,9 @@ on:
|
||||
paths:
|
||||
- 'Gangs*/**'
|
||||
- '.github/workflows/nightly.yml'
|
||||
- '.github/workflows/release.yml'
|
||||
- 'Core/**'
|
||||
- 'Commands/**'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -29,8 +32,8 @@ jobs:
|
||||
|
||||
- run: |
|
||||
dotnet restore
|
||||
dotnet build Core/Core.csproj --no-restore
|
||||
dotnet publish Core/Core.csproj --no-build --no-restore
|
||||
dotnet build Gangs/Gangs.csproj --no-restore
|
||||
dotnet publish Gangs/Gangs.csproj --no-build --no-restore
|
||||
|
||||
- uses: actions/upload-artifact@v4.0.0
|
||||
with:
|
||||
|
||||
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -30,7 +30,7 @@ jobs:
|
||||
- uses: actions/upload-artifact@v4.0.0
|
||||
with:
|
||||
name: gangs
|
||||
path: build/Gangs
|
||||
path: build/
|
||||
# If build didn't put any artifacts in the build folder, consider it an error
|
||||
if-no-files-found: error
|
||||
|
||||
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -2,4 +2,8 @@ bin/
|
||||
obj/
|
||||
/packages/
|
||||
riderModule.iml
|
||||
/_ReSharper.Caches/
|
||||
/_ReSharper.Caches/
|
||||
Gangs.zip
|
||||
build
|
||||
.idea/
|
||||
*.DotSettings.user
|
||||
@@ -11,10 +11,9 @@ namespace Commands;
|
||||
|
||||
public class CommandManager(IGangManager gangMgr)
|
||||
: MockCommandManager, IPluginBehavior {
|
||||
private BasePlugin plugin = null!;
|
||||
private BasePlugin? plugin;
|
||||
|
||||
public void Start(BasePlugin? basePlugin, bool hotReload) {
|
||||
ArgumentNullException.ThrowIfNull(basePlugin, nameof(basePlugin));
|
||||
plugin = basePlugin;
|
||||
|
||||
RegisterCommand(new GangCommand(gangMgr));
|
||||
@@ -22,7 +21,7 @@ public class CommandManager(IGangManager gangMgr)
|
||||
|
||||
public override bool RegisterCommand(ICommand command) {
|
||||
base.RegisterCommand(command);
|
||||
plugin.AddCommand(command.Name, command.Description ?? string.Empty,
|
||||
plugin?.AddCommand(command.Name, command.Description ?? string.Empty,
|
||||
(player, info) => {
|
||||
var wrapper = player == null ? null : new PlayerWrapper(player);
|
||||
var args = info.GetCommandString.Split(" ");
|
||||
|
||||
@@ -25,18 +25,19 @@ public class GangCommand(IGangManager gangMgr) : ICommand {
|
||||
|
||||
public async Task<CommandResult> Execute(PlayerWrapper? executor,
|
||||
CommandInfoWrapper info) {
|
||||
if (info.ArgCount == 0 || info[0] != Name) {
|
||||
if (info.ArgCount == 0)
|
||||
throw new InvalidOperationException(
|
||||
"Attempted to execute GangCommand with no arguments");
|
||||
if (info.ArgCount == 0)
|
||||
throw new InvalidOperationException(
|
||||
"Attempted to execute GangCommand with no arguments");
|
||||
if (info[0] != Name)
|
||||
throw new InvalidOperationException(
|
||||
$"Attempted to execute GangCommand with invalid name: {info[0]}");
|
||||
}
|
||||
|
||||
|
||||
if (info.ArgCount == 1) return CommandResult.INVALID_ARGS;
|
||||
|
||||
if (!sub.TryGetValue(info[1], out var command)) {
|
||||
// print usage
|
||||
// info.ReplySync("Usage: /css_gang [create|help]");
|
||||
return CommandResult.UNKNOWN_COMMAND;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ namespace Commands.gang;
|
||||
public class CreateCommand(IGangManager gang) : ICommand {
|
||||
public string Name => "create";
|
||||
public string? Description => "Creates a new gang";
|
||||
public string Usage => "[name]";
|
||||
|
||||
public async Task<CommandResult> Execute(PlayerWrapper? executor,
|
||||
CommandInfoWrapper info) {
|
||||
@@ -18,7 +19,7 @@ public class CreateCommand(IGangManager gang) : ICommand {
|
||||
|
||||
if (info.ArgCount < 2) {
|
||||
info.ReplySync("Please provide a name for the gang");
|
||||
return CommandResult.FAILURE;
|
||||
return CommandResult.INVALID_ARGS;
|
||||
}
|
||||
|
||||
var name = string.Join(' ', info.ArgString.Split(" ").Skip(1));
|
||||
@@ -33,6 +34,14 @@ public class CreateCommand(IGangManager gang) : ICommand {
|
||||
return CommandResult.FAILURE;
|
||||
}
|
||||
|
||||
throw new NotImplementedException();
|
||||
var newGang = await gang.CreateGang(name, executor.Steam);
|
||||
|
||||
if (newGang == null) {
|
||||
info.ReplySync("Failed to create gang");
|
||||
return CommandResult.FAILURE;
|
||||
}
|
||||
|
||||
info.ReplySync($"Gang '{name}' (#{newGang.GangId}) created successfully");
|
||||
return CommandResult.SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -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}") = "Core", "Core\Core.csproj", "{3EA38296-9022-4874-8309-872388D884DE}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Gangs", "Gangs\Gangs.csproj", "{3EA38296-9022-4874-8309-872388D884DE}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GangsTest", "GangsTest\GangsTest.csproj", "{B1D1E7C7-BDF3-4238-9025-4FEB2B7DAB89}"
|
||||
EndProject
|
||||
|
||||
@@ -19,6 +19,9 @@ public class CS2Gangs(IServiceProvider provider) : BasePlugin, IGangPlugin {
|
||||
var extensions = scope.ServiceProvider.GetServices<IPluginBehavior>()
|
||||
.ToImmutableList();
|
||||
|
||||
Logger.LogInformation("[Gangs] Loading {Count} extensions",
|
||||
extensions.Count);
|
||||
|
||||
foreach (var ext in extensions) {
|
||||
RegisterAllAttributes(ext);
|
||||
try {
|
||||
@@ -8,7 +8,7 @@ using Mock;
|
||||
|
||||
namespace GangsImpl;
|
||||
|
||||
public class GangServiceCollection : IPluginServiceCollection<IGangPlugin> {
|
||||
public class GangServiceCollection : IPluginServiceCollection<CS2Gangs> {
|
||||
public void ConfigureServices(IServiceCollection serviceCollection) {
|
||||
serviceCollection.AddPluginBehavior<IGangManager, MockGangManager>();
|
||||
serviceCollection.AddPluginBehavior<IPlayerManager, MockPlayerManager>();
|
||||
@@ -17,9 +17,22 @@
|
||||
<PackageReference Include="xunit" Version="2.9.0"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="build\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Remove="build\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="build\**" />
|
||||
<None Remove="Gangs.zip" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<!--Publish Configuration-->
|
||||
<PublishBaseDirectory>$(MSBuildThisFileDirectory)/../../build</PublishBaseDirectory>
|
||||
<PublishBaseDirectory>$(MSBuildThisFileDirectory)/../build</PublishBaseDirectory>
|
||||
<PublishDir>$(PublishBaseDirectory)/Gangs</PublishDir>
|
||||
|
||||
<PublishRelease>false</PublishRelease>
|
||||
@@ -1,10 +1,38 @@
|
||||
namespace GangsAPI.Data.Command;
|
||||
|
||||
public enum CommandResult {
|
||||
/// <summary>
|
||||
/// The command completed successfully
|
||||
/// </summary>
|
||||
SUCCESS,
|
||||
|
||||
/// <summary>
|
||||
/// The command encountered an error or other
|
||||
/// scenario that prevented success
|
||||
/// </summary>
|
||||
FAILURE,
|
||||
|
||||
/// <summary>
|
||||
/// The command was improperly formatted
|
||||
/// </summary>
|
||||
UNKNOWN_COMMAND,
|
||||
|
||||
/// <summary>
|
||||
/// The command has improper arguments, or
|
||||
/// no sufficient arguments
|
||||
/// </summary>
|
||||
INVALID_ARGS,
|
||||
|
||||
/// <summary>
|
||||
/// The executor of the command did not have
|
||||
/// the required permissions
|
||||
/// </summary>
|
||||
NO_PERMISSION,
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This command can only be executed by a player
|
||||
/// (i.e. not from the console)
|
||||
/// </summary>
|
||||
PLAYER_ONLY
|
||||
}
|
||||
@@ -67,12 +67,14 @@ public interface IGangRank {
|
||||
/// <summary>
|
||||
/// The member has full access to all permissions.
|
||||
/// </summary>
|
||||
ADMINISTRATOR = 1 << 10,
|
||||
ADMINISTRATOR = 1 << 10 | INVITE_OTHERS | KICK_OTHERS | BANK_DEPOSIT
|
||||
| BANK_WITHDRAW | PROMOTE_OTHERS | DEMOTE_OTHERS | PURCHASE_PERKS
|
||||
| MANAGE_PERKS | MANAGE_RANKS | CREATE_RANKS,
|
||||
|
||||
/// <summary>
|
||||
/// The member is the owner of the gang, and can not be kicked.
|
||||
/// </summary>
|
||||
OWNER = 1 << 11
|
||||
OWNER = 1 << 11 | ADMINISTRATOR
|
||||
}
|
||||
|
||||
string Name { get; }
|
||||
|
||||
@@ -5,7 +5,8 @@ namespace GangsAPI.Services.Commands;
|
||||
|
||||
public interface ICommand : IPluginBehavior {
|
||||
string Name { get; }
|
||||
string? Description { get; }
|
||||
string? Description => null;
|
||||
string Usage => "";
|
||||
string[] RequiredFlags => [];
|
||||
string[] RequiredGroups => [];
|
||||
|
||||
|
||||
@@ -24,11 +24,15 @@ public class MockCommandManager : ICommandManager {
|
||||
if (!command.CanExecute(executor)) return CommandResult.NO_PERMISSION;
|
||||
|
||||
var result = CommandResult.FAILURE;
|
||||
var info = new CommandInfoWrapper(executor, args: args);
|
||||
|
||||
await Task.Run(async () => {
|
||||
result = await command.Execute(executor,
|
||||
new CommandInfoWrapper(executor, args: args));
|
||||
result = await command.Execute(executor, info);
|
||||
});
|
||||
|
||||
if (result == CommandResult.PLAYER_ONLY)
|
||||
info.ReplySync("This command can only be executed by a player");
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -13,8 +13,10 @@ public class MockGang : IGang {
|
||||
Stats = new HashSet<IStat>();
|
||||
Ranks = new HashSet<IGangRank>();
|
||||
|
||||
Members.Add(owner,
|
||||
new MockGangRank(0, "Owner", IGangRank.Permissions.OWNER));
|
||||
var ownerRank = new MockGangRank(0, "Owner", IGangRank.Permissions.OWNER);
|
||||
|
||||
Members.Add(owner, ownerRank);
|
||||
Ranks.Add(ownerRank);
|
||||
}
|
||||
|
||||
public int GangId { get; }
|
||||
|
||||
@@ -4,23 +4,23 @@ using GangsAPI.Services;
|
||||
namespace Mock;
|
||||
|
||||
public class MockGangManager : IGangManager {
|
||||
private readonly HashSet<IGang> gangs = [];
|
||||
private readonly HashSet<IGang> cachedGangs = [], backendGangs = [];
|
||||
|
||||
public Task<IEnumerable<IGang>> GetGangs() {
|
||||
return Task.FromResult(gangs.AsEnumerable());
|
||||
return Task.FromResult(cachedGangs.AsEnumerable());
|
||||
}
|
||||
|
||||
public Task<IGang?> GetGang(int id) {
|
||||
return Task.FromResult(gangs.FirstOrDefault(g => g.GangId == id));
|
||||
return Task.FromResult(cachedGangs.FirstOrDefault(g => g.GangId == id));
|
||||
}
|
||||
|
||||
public Task<IGang?> GetGang(ulong steam) {
|
||||
return Task.FromResult(
|
||||
gangs.FirstOrDefault(g => g.Members.ContainsKey(steam)));
|
||||
cachedGangs.FirstOrDefault(g => g.Members.ContainsKey(steam)));
|
||||
}
|
||||
|
||||
public Task<bool> UpdateGang(IGang gang) {
|
||||
var g = gangs.FirstOrDefault(g => g.GangId == gang.GangId);
|
||||
var g = cachedGangs.FirstOrDefault(g => g.GangId == gang.GangId);
|
||||
if (g == null) return Task.FromResult(false);
|
||||
g.Name = gang.Name;
|
||||
g.Members.Clear();
|
||||
@@ -29,16 +29,23 @@ public class MockGangManager : IGangManager {
|
||||
}
|
||||
|
||||
public Task<bool> DeleteGang(int id) {
|
||||
return Task.FromResult(gangs.RemoveWhere(g => g.GangId == id) > 0);
|
||||
return Task.FromResult(cachedGangs.RemoveWhere(g => g.GangId == id) > 0);
|
||||
}
|
||||
|
||||
public Task<IGang?> CreateGang(string name, ulong owner) {
|
||||
var id = gangs.Count + 1;
|
||||
var id = cachedGangs.Count + 1;
|
||||
var gang = new MockGang(id, name, owner);
|
||||
return Task.FromResult((IGang?)(gangs.Add(gang) ? gang.Clone() : null));
|
||||
if (cachedGangs.Any(g => g.GangId == id))
|
||||
return Task.FromResult<IGang?>(null);
|
||||
cachedGangs.Add(gang);
|
||||
backendGangs.Add(gang);
|
||||
return Task.FromResult(gang.Clone() as IGang);
|
||||
}
|
||||
|
||||
public void ClearCache() { gangs.Clear(); }
|
||||
public void ClearCache() { cachedGangs.Clear(); }
|
||||
|
||||
public Task Load() { return Task.CompletedTask; }
|
||||
public Task Load() {
|
||||
cachedGangs.UnionWith(backendGangs);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ using GangsAPI.Data.Stat;
|
||||
|
||||
namespace Mock;
|
||||
|
||||
public class MockStat(string statId, string name, string? desc) : IStat {
|
||||
public class MockStat(string statId, string name, string? desc = null) : IStat {
|
||||
public string StatId { get; } = statId;
|
||||
public string Name { get; } = name;
|
||||
public string? Description { get; } = desc;
|
||||
@@ -31,6 +31,5 @@ public class MockGangStat<T>(string statId, string name, string? desc, T value)
|
||||
public MockGangStat(IStat b, T value) : this(b.StatId, b.Name, b.Description,
|
||||
value) { }
|
||||
|
||||
public int Key { get; init; }
|
||||
public T Value { get; set; } = value;
|
||||
}
|
||||
26
GangsTest/Commands/CommandTestData.cs
Normal file
26
GangsTest/Commands/CommandTestData.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using System.Collections;
|
||||
using Commands;
|
||||
using Commands.gang;
|
||||
using GangsAPI;
|
||||
using GangsAPI.Services;
|
||||
using Mock;
|
||||
|
||||
namespace GangsTest.Commands;
|
||||
|
||||
public class CommandTestData : IEnumerable<object[]> {
|
||||
private static readonly IGangManager manager = new MockGangManager();
|
||||
|
||||
private readonly IBehavior[] behaviors = [
|
||||
new CreateCommand(manager), new HelpCommand(), new GangCommand(manager)
|
||||
];
|
||||
|
||||
public CommandTestData() {
|
||||
foreach (var behavior in behaviors) behavior.Start();
|
||||
}
|
||||
|
||||
public IEnumerator<object[]> GetEnumerator() {
|
||||
return behaviors.Select(behavior => (object[]) [behavior]).GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
|
||||
}
|
||||
@@ -14,15 +14,81 @@ public class CreateTests(ICommandManager commands, IGangManager gangMgr)
|
||||
"Test Player");
|
||||
|
||||
[Fact]
|
||||
public async Task Create_TestNonPlayer() {
|
||||
public async Task Create_NonPlayer() {
|
||||
Assert.Equal(CommandResult.PLAYER_ONLY,
|
||||
await Commands.ProcessCommand(null, "create"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Create_TestNoName() {
|
||||
Assert.Equal(CommandResult.FAILURE,
|
||||
public async Task Create_NoName() {
|
||||
Assert.Equal(CommandResult.INVALID_ARGS,
|
||||
await Commands.ProcessCommand(player, "create"));
|
||||
Assert.Contains("Please provide a name for the gang", player.ConsoleOutput);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Create_Simple() {
|
||||
var gang = await gangMgr.GetGang(player.Steam);
|
||||
Assert.Null(gang);
|
||||
Assert.Equal(CommandResult.SUCCESS,
|
||||
await Commands.ProcessCommand(player, "create", "foobar"));
|
||||
gang = await gangMgr.GetGang(player.Steam);
|
||||
Assert.NotNull(gang);
|
||||
Assert.Equal("foobar", gang.Name);
|
||||
Assert.Contains($"Gang 'foobar' (#{gang.GangId}) created successfully",
|
||||
player.ConsoleOutput);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Create_MultiWord() {
|
||||
var gang = await gangMgr.GetGang(player.Steam);
|
||||
Assert.Null(gang);
|
||||
Assert.Equal(CommandResult.SUCCESS,
|
||||
await Commands.ProcessCommand(player, "create", "foo bar"));
|
||||
gang = await gangMgr.GetGang(player.Steam);
|
||||
Assert.NotNull(gang);
|
||||
Assert.Equal("foo bar", gang.Name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Create_MultiParam() {
|
||||
var gang = await gangMgr.GetGang(player.Steam);
|
||||
Assert.Null(gang);
|
||||
Assert.Equal(CommandResult.SUCCESS,
|
||||
await Commands.ProcessCommand(player, "create", "foo bar", "baz"));
|
||||
gang = await gangMgr.GetGang(player.Steam);
|
||||
Assert.NotNull(gang);
|
||||
Assert.Equal("foo bar baz", gang.Name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Create_Already_Ganged() {
|
||||
Assert.Equal(CommandResult.SUCCESS,
|
||||
await Commands.ProcessCommand(player, "create", "foo bar"));
|
||||
Assert.Equal(CommandResult.FAILURE,
|
||||
await Commands.ProcessCommand(player, "create", "bar foo"));
|
||||
Assert.Contains("You are already in a gang", player.ConsoleOutput);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Create_Already_Ganged_Uncached() {
|
||||
Assert.Equal(CommandResult.SUCCESS,
|
||||
await Commands.ProcessCommand(player, "create", "foo bar"));
|
||||
gangMgr.ClearCache();
|
||||
await gangMgr.Load();
|
||||
Assert.Equal(CommandResult.FAILURE,
|
||||
await Commands.ProcessCommand(player, "create", "bar foo"));
|
||||
Assert.Contains("You are already in a gang", player.ConsoleOutput);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Create_Duplicate_Name() {
|
||||
var other =
|
||||
new PlayerWrapper((ulong)new Random().NextInt64(), "Other Player");
|
||||
Assert.Equal(CommandResult.SUCCESS,
|
||||
await Commands.ProcessCommand(player, "create", "foo bar"));
|
||||
Assert.Equal(CommandResult.FAILURE,
|
||||
await Commands.ProcessCommand(other, "create", "foo bar"));
|
||||
Assert.Contains("Gang 'foo bar' already exists", other.ConsoleOutput);
|
||||
}
|
||||
}
|
||||
13
GangsTest/Commands/FieldTests.cs
Normal file
13
GangsTest/Commands/FieldTests.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using GangsAPI.Services.Commands;
|
||||
|
||||
namespace GangsTest.Commands;
|
||||
|
||||
public class FieldTests {
|
||||
[Theory]
|
||||
[ClassData(typeof(CommandTestData))]
|
||||
public void Command_Fields(ICommand cmd) {
|
||||
Assert.NotEmpty(cmd.Name);
|
||||
Assert.False(cmd.Usage.StartsWith(cmd.Name),
|
||||
"Command usage should not start with the command name");
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,21 @@ public class GangCommandTests(ICommandManager commands, IGangManager gangMgr)
|
||||
await Commands.ProcessCommand(TestPlayer, Command.Name));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Gang_TestInvalid_Name() {
|
||||
await Assert.ThrowsAnyAsync<InvalidOperationException>(async () => {
|
||||
await Command.Execute(TestPlayer,
|
||||
new CommandInfoWrapper(TestPlayer, 0, "foobar"));
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Gang_TestInvalid_Null() {
|
||||
await Assert.ThrowsAnyAsync<InvalidOperationException>(async () => {
|
||||
await Command.Execute(TestPlayer, new CommandInfoWrapper(TestPlayer, 0));
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Gang_TestUnknown() {
|
||||
Assert.Equal(CommandResult.UNKNOWN_COMMAND,
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
using System.Collections;
|
||||
using Commands;
|
||||
using GangsAPI;
|
||||
using Mock;
|
||||
|
||||
namespace GangsTest.Commands.ManagerTests;
|
||||
|
||||
public class ManagerData : IEnumerable<object[]> {
|
||||
private readonly IBehavior[] behaviors = [new MockCommandManager()];
|
||||
private readonly IBehavior[] behaviors = [
|
||||
new MockCommandManager(), new CommandManager(new MockGangManager())
|
||||
];
|
||||
|
||||
public ManagerData() {
|
||||
foreach (var behavior in behaviors) behavior.Start();
|
||||
|
||||
26
GangsTest/Commands/ManagerTests/ManagerHandling.cs
Normal file
26
GangsTest/Commands/ManagerTests/ManagerHandling.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using GangsAPI.Data;
|
||||
using GangsAPI.Data.Command;
|
||||
using GangsAPI.Services.Commands;
|
||||
|
||||
namespace GangsTest.Commands.ManagerTests;
|
||||
|
||||
public class ManagerHandling : ManagerTests {
|
||||
private class PlayerOnlyCommand : ICommand {
|
||||
public string Name => "css_player";
|
||||
|
||||
public Task<CommandResult> Execute(PlayerWrapper? executor,
|
||||
CommandInfoWrapper info) {
|
||||
return Task.FromResult(CommandResult.PLAYER_ONLY);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[ClassData(typeof(ManagerData))]
|
||||
public async Task Command_PlayerOnly(ICommandManager mgr) {
|
||||
mgr.RegisterCommand(new PlayerOnlyCommand());
|
||||
Assert.Equal(CommandResult.PLAYER_ONLY,
|
||||
await mgr.ProcessCommand(TestPlayer, "css_player"));
|
||||
Assert.Contains("This command can only be executed by a player",
|
||||
TestPlayer.ConsoleOutput);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
using GangsAPI.Services;
|
||||
using GangsAPI.Data.Gang;
|
||||
using GangsAPI.Services;
|
||||
using Mock;
|
||||
|
||||
namespace GangsTest.GangTests;
|
||||
|
||||
@@ -11,6 +13,7 @@ public class GangCreationTests(IPlayerManager playerMgr) {
|
||||
Assert.Equal("foobar", dummy.Name);
|
||||
Assert.Equal((ulong)0, dummy.Owner);
|
||||
Assert.Single(dummy.Members);
|
||||
Assert.Single(dummy.Ranks);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
@@ -22,20 +25,76 @@ public class GangCreationTests(IPlayerManager playerMgr) {
|
||||
Assert.Equal("foobar", dummy.Name);
|
||||
Assert.Equal((ulong)0, dummy.Owner);
|
||||
Assert.Single(dummy.Members);
|
||||
Assert.Single(dummy.Ranks);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[ClassData(typeof(GangManagerData))]
|
||||
public async Task Gang_Clone(IGangManager mgr) {
|
||||
var dummy = await mgr.CreateGang("foobar", 0);
|
||||
Assert.NotNull(dummy);
|
||||
var clone = dummy.Clone() as IGang;
|
||||
Assert.NotNull(clone);
|
||||
|
||||
Assert.Equivalent(dummy, clone, true);
|
||||
|
||||
Assert.NotSame(dummy, clone);
|
||||
Assert.NotSame(dummy.Members, clone.Members);
|
||||
Assert.NotSame(dummy.Ranks, clone.Ranks);
|
||||
Assert.NotSame(dummy.Perks, clone.Perks);
|
||||
Assert.NotSame(dummy.Stats, clone.Stats);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[ClassData(typeof(GangManagerData))]
|
||||
public async Task Gang_Clone_WithPerks(IGangManager mgr) {
|
||||
var dummy = await mgr.CreateGang("foobar", 0);
|
||||
Assert.NotNull(dummy);
|
||||
dummy.Perks.Add(new MockStat("test_perk", "Test Perk"));
|
||||
var clone = dummy.Clone() as IGang;
|
||||
Assert.NotNull(clone);
|
||||
|
||||
Assert.Equivalent(dummy, clone, true);
|
||||
|
||||
Assert.NotSame(dummy, clone);
|
||||
Assert.NotSame(dummy.Members, clone.Members);
|
||||
Assert.NotSame(dummy.Ranks, clone.Ranks);
|
||||
Assert.NotSame(dummy.Perks, clone.Perks);
|
||||
Assert.NotSame(dummy.Stats, clone.Stats);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[ClassData(typeof(GangManagerData))]
|
||||
public async Task Gang_Clone_WithStats(IGangManager mgr) {
|
||||
var dummy = await mgr.CreateGang("foobar", 0);
|
||||
Assert.NotNull(dummy);
|
||||
dummy.Stats.Add(new MockStat("test_stats", "Test Stat"));
|
||||
var clone = dummy.Clone() as IGang;
|
||||
Assert.NotNull(clone);
|
||||
|
||||
Assert.Equivalent(dummy, clone, true);
|
||||
|
||||
Assert.NotSame(dummy, clone);
|
||||
Assert.NotSame(dummy.Members, clone.Members);
|
||||
Assert.NotSame(dummy.Ranks, clone.Ranks);
|
||||
Assert.NotSame(dummy.Perks, clone.Perks);
|
||||
Assert.NotSame(dummy.Stats, clone.Stats);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[ClassData(typeof(GangManagerData))]
|
||||
public async Task Gang_CreateMultiple(IGangManager mgr) {
|
||||
var dummy1 = await mgr.CreateGang("foobar", 0);
|
||||
var steam1 = (ulong)new Random().NextInt64();
|
||||
var steam2 = (ulong)new Random().NextInt64();
|
||||
var dummy1 = await mgr.CreateGang("foobar", steam1);
|
||||
Assert.NotNull(dummy1);
|
||||
Assert.Equal("foobar", dummy1.Name);
|
||||
Assert.Equal((ulong)0, dummy1.Owner);
|
||||
Assert.Equal(steam1, dummy1.Owner);
|
||||
Assert.Single(dummy1.Members);
|
||||
var dummy2 = await mgr.CreateGang("barfoo", 0);
|
||||
var dummy2 = await mgr.CreateGang("barfoo", steam2);
|
||||
Assert.NotNull(dummy2);
|
||||
Assert.Equal("barfoo", dummy2.Name);
|
||||
Assert.Equal((ulong)0, dummy2.Owner);
|
||||
Assert.Equal(steam2, dummy2.Owner);
|
||||
Assert.Single(dummy2.Members);
|
||||
Assert.NotSame(dummy1, dummy2);
|
||||
Assert.NotEqual(dummy1.GangId, dummy2.GangId);
|
||||
@@ -44,11 +103,19 @@ public class GangCreationTests(IPlayerManager playerMgr) {
|
||||
[Theory]
|
||||
[ClassData(typeof(GangManagerData))]
|
||||
public async Task Gang_CreateMultipleFromGangPlayer(IGangManager mgr) {
|
||||
var player = await playerMgr.CreatePlayer(0);
|
||||
var dummy = await mgr.CreateGang("foobar", player);
|
||||
Assert.NotNull(dummy);
|
||||
Assert.Equal("foobar", dummy.Name);
|
||||
Assert.Equal((ulong)0, dummy.Owner);
|
||||
Assert.Single(dummy.Members);
|
||||
var player1 = await playerMgr.CreatePlayer((ulong)new Random().NextInt64());
|
||||
var player2 = await playerMgr.CreatePlayer((ulong)new Random().NextInt64());
|
||||
var dummy1 = await mgr.CreateGang("foobar", player1);
|
||||
var dummy2 = await mgr.CreateGang("barfoo", player2);
|
||||
Assert.NotNull(dummy1);
|
||||
Assert.NotNull(dummy2);
|
||||
Assert.Equal("foobar", dummy1.Name);
|
||||
Assert.Equal(player1.Steam, dummy1.Owner);
|
||||
Assert.Single(dummy1.Members);
|
||||
Assert.Equal("barfoo", dummy2.Name);
|
||||
Assert.Equal(player2.Steam, dummy2.Owner);
|
||||
Assert.Single(dummy2.Members);
|
||||
Assert.NotSame(dummy1, dummy2);
|
||||
Assert.NotEqual(dummy1.GangId, dummy2.GangId);
|
||||
}
|
||||
}
|
||||
76
GangsTest/GangTests/GangFetchTests.cs
Normal file
76
GangsTest/GangTests/GangFetchTests.cs
Normal file
@@ -0,0 +1,76 @@
|
||||
using GangsAPI.Data.Gang;
|
||||
using GangsAPI.Services;
|
||||
using Mock;
|
||||
|
||||
namespace GangsTest.GangTests;
|
||||
|
||||
public class GangFetchTests(IPlayerManager playerMgr) {
|
||||
[Theory]
|
||||
[ClassData(typeof(GangManagerData))]
|
||||
public async Task Gang_Create(IGangManager mgr) {
|
||||
Assert.Empty(await mgr.GetGangs());
|
||||
var dummy = await mgr.CreateGang("foobar", 0);
|
||||
var gangs = (await mgr.GetGangs()).ToHashSet();
|
||||
Assert.NotNull(dummy);
|
||||
Assert.NotNull(gangs);
|
||||
Assert.Single(gangs);
|
||||
Assert.Equal(dummy, gangs.First());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[ClassData(typeof(GangManagerData))]
|
||||
public async Task Gang_CreateFromGangPlayer(IGangManager mgr) {
|
||||
Assert.Empty(await mgr.GetGangs());
|
||||
var player = await playerMgr.CreatePlayer(0);
|
||||
var dummy = await mgr.CreateGang("foobar", player);
|
||||
var gangs = (await mgr.GetGangs()).ToHashSet();
|
||||
Assert.NotNull(dummy);
|
||||
Assert.NotNull(gangs);
|
||||
Assert.Single(gangs);
|
||||
Assert.Equal(dummy, gangs.First());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[ClassData(typeof(GangManagerData))]
|
||||
public async Task Gang_Clone(IGangManager mgr) {
|
||||
var dummy = await mgr.CreateGang("foobar", 0);
|
||||
Assert.NotNull(dummy);
|
||||
var clone = dummy.Clone() as IGang;
|
||||
Assert.Single(await mgr.GetGangs());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[ClassData(typeof(GangManagerData))]
|
||||
public async Task Gang_CreateMultiple(IGangManager mgr) {
|
||||
var dummy1 = await mgr.CreateGang("foobar", 0);
|
||||
Assert.NotNull(dummy1);
|
||||
var dummy2 = await mgr.CreateGang("barfoo", 1);
|
||||
Assert.NotNull(dummy2);
|
||||
Assert.NotSame(dummy1, dummy2);
|
||||
var gangs = (await mgr.GetGangs()).ToHashSet();
|
||||
Assert.NotNull(gangs);
|
||||
Assert.Equal(2, gangs.Count);
|
||||
Assert.Contains(gangs, g => g.GangId == dummy1.GangId);
|
||||
Assert.Contains(gangs, g => g.GangId == dummy2.GangId);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[ClassData(typeof(GangManagerData))]
|
||||
public async Task Gang_FetchId(IGangManager mgr) {
|
||||
var dummy = await mgr.CreateGang("foobar", (ulong)new Random().NextInt64());
|
||||
Assert.NotNull(dummy);
|
||||
var gang = await mgr.GetGang(dummy.GangId);
|
||||
Assert.NotNull(gang);
|
||||
Assert.Equal(dummy, gang);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[ClassData(typeof(GangManagerData))]
|
||||
public async Task Gang_FetchSteam(IGangManager mgr) {
|
||||
var dummy = await mgr.CreateGang("foobar", (ulong)new Random().NextInt64());
|
||||
Assert.NotNull(dummy);
|
||||
var gang = await mgr.GetGang(dummy.Owner);
|
||||
Assert.NotNull(gang);
|
||||
Assert.Equal(dummy, gang);
|
||||
}
|
||||
}
|
||||
@@ -32,7 +32,7 @@
|
||||
<ProjectReference Include="..\GangsImpl\Mock\Mock.csproj" />
|
||||
<ProjectReference Include="..\GangsImpl\SQLite\SQLite.csproj" />
|
||||
<ProjectReference Include="..\GangsImpl\SQL\SQL.csproj" />
|
||||
<ProjectReference Include="..\Core\Core.csproj" />
|
||||
<ProjectReference Include="..\Gangs\Gangs.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
34
GangsTest/Permissions/GangRankTests.cs
Normal file
34
GangsTest/Permissions/GangRankTests.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using GangsAPI.Permissions;
|
||||
using Mock;
|
||||
|
||||
namespace GangsTest.Permissions;
|
||||
|
||||
public class GangRankTests {
|
||||
[Fact]
|
||||
public void Rank_Owner_HasAllPerms() {
|
||||
var rank = new MockGangRank(0, "Owner", IGangRank.Permissions.OWNER);
|
||||
foreach (var perm in Enum.GetValues<IGangRank.Permissions>()) {
|
||||
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<IGangRank.Permissions>()) {
|
||||
if (perm == IGangRank.Permissions.OWNER)
|
||||
Assert.False(rank.Perms.HasFlag(perm));
|
||||
else
|
||||
Assert.True(rank.Perms.HasFlag(perm));
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Rank_Admin_Fields() {
|
||||
var rank = new MockGangRank(0, "Owner");
|
||||
Assert.Equal("Owner", rank.Name);
|
||||
Assert.Equal(0, rank.Rank);
|
||||
Assert.Equal(0, (int)rank.Perms);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user