mirror of
https://github.com/JogmansonReal/Radicade.git
synced 2026-10-25 15:09:26 -07:00
Radicade Public Code
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
using System.Text.Json;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using RadicadeServer.Admin;
|
||||
using RadicadeServer.DB;
|
||||
using RadicadeServer.RecNet.Auth;
|
||||
using RadicadeServer.RecNet.Moderation;
|
||||
using Xunit;
|
||||
|
||||
namespace RadicadeServer.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// PATCH admin/panel/players/{id} with the values the panel echoes back from its own GET.
|
||||
///
|
||||
/// Noteriety and ReputationScore are doubles on Reputation (NoterietyPerCheer is 0.5), so an account
|
||||
/// that has been cheered carries a fractional value. The endpoint used to read them with GetInt32,
|
||||
/// which throws System.FormatException on a fractional JSON number - the whole edit answered 500 and
|
||||
/// saved nothing. Because only accounts with a fractional score hit it, it looked account-specific.
|
||||
/// </summary>
|
||||
public class AdminPanelFractionalReputationTests
|
||||
{
|
||||
private const string Secret = "test-bot-secret";
|
||||
private const long Player = 3;
|
||||
|
||||
private static RecDBContext NewDb() => new(
|
||||
TestDbOptions.Create()
|
||||
.UseInMemoryDatabase(Guid.NewGuid().ToString())
|
||||
.Options);
|
||||
|
||||
private static async Task<RecDBContext> WithPlayer()
|
||||
{
|
||||
var db = NewDb();
|
||||
db.Profiles.Add(new Profile
|
||||
{
|
||||
accountId = Player,
|
||||
username = "fractional",
|
||||
displayName = "Fractional Player",
|
||||
profileImage = ""
|
||||
});
|
||||
db.Reputations.Add(new Reputation
|
||||
{
|
||||
AccountId = Player,
|
||||
Noteriety = 0.5,
|
||||
ReputationScore = 7.5
|
||||
});
|
||||
await db.SaveChangesAsync();
|
||||
return db;
|
||||
}
|
||||
|
||||
private static async Task<IActionResult> Patch(RecDBContext db, string json)
|
||||
{
|
||||
var payload = JsonDocument.Parse(json).RootElement.Clone();
|
||||
var api = new AdminPanelAPI(db);
|
||||
var original = DBConfig.AdminApiKey;
|
||||
DBConfig.AdminApiKey = Secret;
|
||||
try
|
||||
{
|
||||
return await api.Update("players", Player, Secret, payload);
|
||||
}
|
||||
finally
|
||||
{
|
||||
DBConfig.AdminApiKey = original;
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AFractionalNoterietyIsAcceptedAndStoredAsADouble()
|
||||
{
|
||||
using var db = await WithPlayer();
|
||||
|
||||
// Exactly what the panel sends for an account whose score is not a whole number.
|
||||
var result = await Patch(db, """
|
||||
{
|
||||
"display_name": "Fractional Player",
|
||||
"reputation": 9.5,
|
||||
"noteriety": 1.5,
|
||||
"cheer_general": 3
|
||||
}
|
||||
""");
|
||||
|
||||
Assert.IsType<OkObjectResult>(result);
|
||||
|
||||
var rep = await db.Reputations.SingleAsync(x => x.AccountId == Player);
|
||||
Assert.Equal(1.5, rep.Noteriety);
|
||||
Assert.Equal(9.5, rep.ReputationScore);
|
||||
Assert.Equal(3, rep.CheerGeneral);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AnOutOfRangeOrNumericStringIntegerDoesNotThrow()
|
||||
{
|
||||
using var db = await WithPlayer();
|
||||
|
||||
// A value Int32 cannot hold, and an integer sent as a string, must both land (clamped /
|
||||
// parsed) rather than 500 the edit.
|
||||
var result = await Patch(db, """
|
||||
{
|
||||
"noteriety": 0.5,
|
||||
"cheer_helpful": "4",
|
||||
"cheer_creative": 9999999999999999999
|
||||
}
|
||||
""");
|
||||
|
||||
Assert.IsType<OkObjectResult>(result);
|
||||
|
||||
var rep = await db.Reputations.SingleAsync(x => x.AccountId == Player);
|
||||
Assert.Equal(4, rep.CheerHelpful);
|
||||
Assert.Equal(int.MaxValue, rep.CheerCreative);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user