using System.Security.Claims;
using System.Text;
using System.Text.Json;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using RadicadeServer.API.Accounts;
using RadicadeServer.API.Events;
using RadicadeServer.API.Relationships.V1;
using RadicadeServer.API;
using RadicadeServer.Clubs;
using RadicadeServer.DB;
using RadicadeServer.RecNet.Auth;
using RadicadeServer.RecNet.Events;
using RadicadeServer.RecNet.Messages;
using RadicadeServer.RecNet.Relationships;
using Xunit;
namespace RadicadeServer.Tests;
///
/// The routes a single player report named, each of which failed in a different way:
/// a missing route (404), a route registered under another verb (405), and a handler
/// that refused a request whose id arrived somewhere it did not look (400).
///
/// The tests below pin the behaviour rather than the implementation: a request of the
/// shape the client sends has to reach a handler, find its record, and act on it.
///
public class PlayerReportedRouteTests
{
private const long CallerId = 42;
private const long OtherId = 77;
private static RecDBContext CreateDb()
{
var options = TestDbOptions.Create()
.UseInMemoryDatabase(Guid.NewGuid().ToString())
.Options;
return new RecDBContext(options);
}
private static T CreateController(RecDBContext db, long? userId = CallerId) where T : Controller
{
var identity = new ClaimsIdentity("TestAuth");
if (userId.HasValue)
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, userId.Value.ToString()));
var controller = (T)Activator.CreateInstance(typeof(T), db)!;
controller.ControllerContext = new ControllerContext
{
HttpContext = new DefaultHttpContext { User = new ClaimsPrincipal(identity) }
};
return controller;
}
private static void SetJsonBody(Controller controller, string jsonBody)
{
var bytes = Encoding.UTF8.GetBytes(jsonBody);
controller.HttpContext.Request.Body = new MemoryStream(bytes);
controller.HttpContext.Request.ContentType = "application/json";
controller.HttpContext.Request.ContentLength = bytes.Length;
}
private static ChatThread ThreadWith(params long[] playerIds) => new()
{
chatThreadName = "",
messages = "[]",
playerIds = JsonSerializer.Serialize(playerIds)
};
// ---- POST /chat/thread/party -> 405 ----------------------------------------------------
[Fact]
public void PartyThreadIsRegisteredForBothGetAndPost()
{
var attributes = typeof(ThreadAPI).GetMethod(nameof(ThreadAPI.GetPartyThread))!
.GetCustomAttributes(typeof(Microsoft.AspNetCore.Mvc.Routing.HttpMethodAttribute), true)
.Cast()
.ToList();
// The client's party lookup POSTs; with only the GET registered that is a 405,
// which reads in the log as the party simply never loading.
Assert.Contains(attributes, a => a.HttpMethods.Contains("GET"));
Assert.Contains(attributes, a => a.HttpMethods.Contains("POST"));
// And both verbs answer the same empty list, which is the "no party" spelling.
var controller = CreateController(CreateDb());
var result = Assert.IsType(controller.GetPartyThread());
Assert.Empty(Assert.IsAssignableFrom(result.Value).Cast