test(backend): add submission workflow, keyword and controller tests
This commit is contained in:
@@ -0,0 +1,46 @@
|
|||||||
|
using TarninaHub.Application.Mappings;
|
||||||
|
using TarninaHub.Application.Text;
|
||||||
|
using TarninaHub.Domain.Enums;
|
||||||
|
|
||||||
|
namespace TarninaHub.Tests.Application;
|
||||||
|
|
||||||
|
public class KeywordExtractorTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void Extract_RemovesStopWordsAndShortTokens()
|
||||||
|
{
|
||||||
|
var keywords = KeywordExtractor.Extract("To jest problem dla seniorów i seniorów w gminie");
|
||||||
|
|
||||||
|
Assert.Contains("seniorów", keywords);
|
||||||
|
Assert.Contains("problem", keywords);
|
||||||
|
Assert.DoesNotContain("jest", keywords);
|
||||||
|
Assert.DoesNotContain("dla", keywords);
|
||||||
|
Assert.DoesNotContain("i", keywords);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Extract_RespectsMaxAndOrdersByFrequency()
|
||||||
|
{
|
||||||
|
var keywords = KeywordExtractor.Extract("transport transport transport zdrowie zdrowie rodzina", max: 2);
|
||||||
|
|
||||||
|
Assert.Equal(2, keywords.Count);
|
||||||
|
Assert.Equal("transport", keywords[0]);
|
||||||
|
Assert.Equal("zdrowie", keywords[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Extract_ReturnsEmptyForBlankText()
|
||||||
|
{
|
||||||
|
Assert.Empty(KeywordExtractor.Extract(" "));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(SubmissionStatus.New, "new")]
|
||||||
|
[InlineData(SubmissionStatus.InProgress, "in_progress")]
|
||||||
|
[InlineData(SubmissionStatus.Rejected, "rejected")]
|
||||||
|
public void StatusWire_RoundTrips(SubmissionStatus status, string wire)
|
||||||
|
{
|
||||||
|
Assert.Equal(wire, status.ToWire());
|
||||||
|
Assert.Equal(status, SubmissionStatusWire.Parse(wire));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
using System.Security.Claims;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using TarninaHub.Application.Abstractions;
|
||||||
|
using TarninaHub.Application.Dtos;
|
||||||
|
using TarninaHub.Controllers;
|
||||||
|
|
||||||
|
namespace TarninaHub.Tests.Controllers;
|
||||||
|
|
||||||
|
public class SubmissionsControllerTests
|
||||||
|
{
|
||||||
|
private static SubmissionsController CreateController(ISubmissionService service, string role = "operator")
|
||||||
|
{
|
||||||
|
var controller = new SubmissionsController(service);
|
||||||
|
var identity = new ClaimsIdentity(
|
||||||
|
[new Claim("sub", "user:tester"), new Claim("role", role)],
|
||||||
|
authenticationType: "test");
|
||||||
|
|
||||||
|
controller.ControllerContext = new ControllerContext
|
||||||
|
{
|
||||||
|
HttpContext = new DefaultHttpContext { User = new ClaimsPrincipal(identity) },
|
||||||
|
};
|
||||||
|
|
||||||
|
return controller;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SubmissionResponse SampleSubmission(string status) => new(
|
||||||
|
"submission:abc",
|
||||||
|
"problem:xyz",
|
||||||
|
"Title",
|
||||||
|
"Description",
|
||||||
|
"social_challenge:seniorzy",
|
||||||
|
"location:krakow",
|
||||||
|
"user:tester",
|
||||||
|
status,
|
||||||
|
["seniorzy"],
|
||||||
|
DateTimeOffset.UtcNow,
|
||||||
|
null);
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task UpdateStatus_RejectsInvalidTransition()
|
||||||
|
{
|
||||||
|
var service = new StubSubmissionService { Current = SampleSubmission("new") };
|
||||||
|
var controller = CreateController(service);
|
||||||
|
|
||||||
|
var result = await controller.UpdateStatus(
|
||||||
|
"submission:abc",
|
||||||
|
new UpdateSubmissionStatusRequest("matched"),
|
||||||
|
CancellationToken.None);
|
||||||
|
|
||||||
|
Assert.IsType<ObjectResult>(result.Result);
|
||||||
|
Assert.Null(service.LastRequestedStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task UpdateStatus_AcceptsValidTransition()
|
||||||
|
{
|
||||||
|
var service = new StubSubmissionService
|
||||||
|
{
|
||||||
|
Current = SampleSubmission("new"),
|
||||||
|
UpdateResult = SampleSubmission("triaged"),
|
||||||
|
};
|
||||||
|
var controller = CreateController(service);
|
||||||
|
|
||||||
|
var result = await controller.UpdateStatus(
|
||||||
|
"submission:abc",
|
||||||
|
new UpdateSubmissionStatusRequest("triaged"),
|
||||||
|
CancellationToken.None);
|
||||||
|
|
||||||
|
Assert.IsType<OkObjectResult>(result.Result);
|
||||||
|
Assert.Equal("triaged", service.LastRequestedStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetById_ReturnsNotFoundWhenMissing()
|
||||||
|
{
|
||||||
|
var controller = CreateController(new StubSubmissionService());
|
||||||
|
|
||||||
|
var result = await controller.GetById("submission:missing", CancellationToken.None);
|
||||||
|
|
||||||
|
Assert.IsType<NotFoundResult>(result.Result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class StubSubmissionService : ISubmissionService
|
||||||
|
{
|
||||||
|
public SubmissionResponse? Current { get; set; }
|
||||||
|
|
||||||
|
public SubmissionResponse? UpdateResult { get; set; }
|
||||||
|
|
||||||
|
public string? LastRequestedStatus { get; private set; }
|
||||||
|
|
||||||
|
public Task<SubmissionResponse> CreateAsync(
|
||||||
|
string authorId,
|
||||||
|
CreateSubmissionRequest request,
|
||||||
|
CancellationToken cancellationToken) => Task.FromResult(SampleSubmission("new"));
|
||||||
|
|
||||||
|
public Task<PagedResponse<SubmissionResponse>> ListAsync(
|
||||||
|
string viewerId,
|
||||||
|
bool isStaff,
|
||||||
|
string? status,
|
||||||
|
int page,
|
||||||
|
int pageSize,
|
||||||
|
CancellationToken cancellationToken) => Task.FromResult(
|
||||||
|
new PagedResponse<SubmissionResponse>([], page, pageSize, 0));
|
||||||
|
|
||||||
|
public Task<SubmissionResponse?> GetAsync(string submissionId, CancellationToken cancellationToken) =>
|
||||||
|
Task.FromResult(Current);
|
||||||
|
|
||||||
|
public Task<SubmissionResponse?> UpdateStatusAsync(
|
||||||
|
string submissionId,
|
||||||
|
string newStatus,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
LastRequestedStatus = newStatus;
|
||||||
|
|
||||||
|
return Task.FromResult(UpdateResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
using TarninaHub.Domain.Enums;
|
||||||
|
using TarninaHub.Domain.Rules;
|
||||||
|
|
||||||
|
namespace TarninaHub.Tests.Domain;
|
||||||
|
|
||||||
|
public class SubmissionWorkflowTests
|
||||||
|
{
|
||||||
|
[Theory]
|
||||||
|
[InlineData(SubmissionStatus.New, SubmissionStatus.Triaged, true)]
|
||||||
|
[InlineData(SubmissionStatus.New, SubmissionStatus.Matched, false)]
|
||||||
|
[InlineData(SubmissionStatus.Triaged, SubmissionStatus.Matched, true)]
|
||||||
|
[InlineData(SubmissionStatus.Matched, SubmissionStatus.InProgress, true)]
|
||||||
|
[InlineData(SubmissionStatus.InProgress, SubmissionStatus.Closed, true)]
|
||||||
|
[InlineData(SubmissionStatus.Closed, SubmissionStatus.Triaged, false)]
|
||||||
|
[InlineData(SubmissionStatus.Rejected, SubmissionStatus.New, false)]
|
||||||
|
public void CanTransition_EnforcesWorkflow(SubmissionStatus from, SubmissionStatus to, bool expected)
|
||||||
|
{
|
||||||
|
Assert.Equal(expected, SubmissionWorkflow.CanTransition(from, to));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void CanTransition_AllowsSameStatus()
|
||||||
|
{
|
||||||
|
Assert.True(SubmissionWorkflow.CanTransition(SubmissionStatus.New, SubmissionStatus.New));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(SubmissionStatus.Closed, true)]
|
||||||
|
[InlineData(SubmissionStatus.Rejected, true)]
|
||||||
|
[InlineData(SubmissionStatus.New, false)]
|
||||||
|
public void IsTerminal_RecognizesFinalStates(SubmissionStatus status, bool expected)
|
||||||
|
{
|
||||||
|
Assert.Equal(expected, SubmissionWorkflow.IsTerminal(status));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user