Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
278 changes: 274 additions & 4 deletions TickAPI/TickAPI.Tests/Tickets/Services/TicketServiceTests.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
using Microsoft.AspNetCore.Http;
using Moq;
using TickAPI.Common.Pagination.Abstractions;
using TickAPI.Common.Pagination.Responses;
using TickAPI.Common.Results.Generic;
using TickAPI.Tickets.Abstractions;
using TickAPI.Tickets.DTOs.Response;
using TickAPI.Tickets.Models;
using TickAPI.Tickets.Services;
using TickAPI.TicketTypes.Models;
Expand All @@ -17,13 +20,14 @@ public void GetNumberOfAvailableTicketsByType_AmountsAreCorrect_ShouldReturnCorr
var type = new TicketType { MaxCount = 30 };
var ticketList = new List<Ticket>(new Ticket[10]);

Mock<ITicketRepository> ticketRepositoryMock = new Mock<ITicketRepository>();
var ticketRepositoryMock = new Mock<ITicketRepository>();
var paginationServiceMock = new Mock<IPaginationService>();

ticketRepositoryMock
.Setup(m => m.GetAllTicketsByTicketType(type))
.Returns(ticketList.AsQueryable());

var sut = new TicketService(ticketRepositoryMock.Object);
var sut = new TicketService(ticketRepositoryMock.Object, paginationServiceMock.Object);

// Act
var result = sut.GetNumberOfAvailableTicketsByType(type);
Expand All @@ -40,13 +44,14 @@ public void GetNumberOfAvailableTicketsByType_WhenMoreTicketExistThanMaxCount_Sh
var type = new TicketType { MaxCount = 30 };
var ticketList = new List<Ticket>(new Ticket[50]);

Mock<ITicketRepository> ticketRepositoryMock = new Mock<ITicketRepository>();
var ticketRepositoryMock = new Mock<ITicketRepository>();
var paginationServiceMock = new Mock<IPaginationService>();

ticketRepositoryMock
.Setup(m => m.GetAllTicketsByTicketType(type))
.Returns(ticketList.AsQueryable());

var sut = new TicketService(ticketRepositoryMock.Object);
var sut = new TicketService(ticketRepositoryMock.Object, paginationServiceMock.Object);

// Act
var result = sut.GetNumberOfAvailableTicketsByType(type);
Expand All @@ -56,4 +61,269 @@ public void GetNumberOfAvailableTicketsByType_WhenMoreTicketExistThanMaxCount_Sh
Assert.Equal(StatusCodes.Status500InternalServerError, result.StatusCode);
Assert.Equal("The number of available tickets is negative.", result.ErrorMsg);
}

[Fact]
public async Task GetTicketsForResellAsync_WhenDataIsValid_ShouldReturnSuccess()
{
// Arrange
var eventId = Guid.NewGuid();
int pageSize = 10;
int page = 0;

var ticket1 = new Ticket
{
Id = Guid.NewGuid(),
ForResell = true,
Type = new TicketType
{
Price = 50m,
Currency = "USD",
Description = "VIP"
},
Seats = "A1"
};

var ticket2 = new Ticket
{
Id = Guid.NewGuid(),
ForResell = true,
Type = new TicketType
{
Price = 30m,
Currency = "USD",
Description = "Standard"
},
Seats = "B2"
};

var allTickets = new List<Ticket> { ticket1, ticket2 }.AsQueryable();

var ticketRepositoryMock = new Mock<ITicketRepository>();
ticketRepositoryMock.Setup(repo => repo.GetTicketsByEventId(eventId))
.Returns(allTickets);

var paginatedTickets = new PaginatedData<Ticket>(
new List<Ticket> { ticket1, ticket2 },
page,
pageSize,
false,
false,
new PaginationDetails(0, 2)
);

var paginationServiceMock = new Mock<IPaginationService>();
paginationServiceMock.Setup(p => p.PaginateAsync(It.IsAny<IQueryable<Ticket>>(), pageSize, page))
.ReturnsAsync(Result<PaginatedData<Ticket>>.Success(paginatedTickets));

var mappedDto1 = new GetTicketForResellResponseDto(
ticket1.Id,
ticket1.Type.Price,
ticket1.Type.Currency,
ticket1.Type.Description,
ticket1.Seats
);

var mappedDto2 = new GetTicketForResellResponseDto(
ticket2.Id,
ticket2.Type.Price,
ticket2.Type.Currency,
ticket2.Type.Description,
ticket2.Seats
);

var mappedData = new PaginatedData<GetTicketForResellResponseDto>(
new List<GetTicketForResellResponseDto> { mappedDto1, mappedDto2 },
page,
pageSize,
false,
false,
new PaginationDetails(0, 2)
);

paginationServiceMock.Setup(p => p.MapData(
paginatedTickets,
It.IsAny<Func<Ticket, GetTicketForResellResponseDto>>()))
.Returns(mappedData);

var sut = new TicketService(ticketRepositoryMock.Object, paginationServiceMock.Object);

// Act
var result = await sut.GetTicketsForResellAsync(eventId, page, pageSize);

// Assert
Assert.True(result.IsSuccess);
Assert.Equal(2, result.Value!.Data.Count);
Assert.Equal(mappedDto1, result.Value!.Data[0]);
Assert.Equal(mappedDto2, result.Value!.Data[1]);
}

[Fact]
public async Task GetTicketsForResellAsync_WhenNoTicketsForResell_ShouldReturnEmptyList()
{
// Arrange
var eventId = Guid.NewGuid();
int pageSize = 10;
int page = 0;

var tickets = new List<Ticket>
{
new Ticket
{
Id = Guid.NewGuid(),
ForResell = false,
Type = new TicketType
{
Price = 50m,
Currency = "USD",
Description = "VIP"
}
},
new Ticket
{
Id = Guid.NewGuid(),
ForResell = false,
Type = new TicketType
{
Price = 30m,
Currency = "USD",
Description = "Standard"
}
}
}.AsQueryable();

var ticketRepositoryMock = new Mock<ITicketRepository>();
ticketRepositoryMock.Setup(repo => repo.GetTicketsByEventId(eventId))
.Returns(tickets);

var paginatedData = new PaginatedData<Ticket>(
new List<Ticket>(),
page,
pageSize,
false,
false,
new PaginationDetails(0, 0)
);

var paginationServiceMock = new Mock<IPaginationService>();
paginationServiceMock.Setup(p => p.PaginateAsync(It.IsAny<IQueryable<Ticket>>(), pageSize, page))
.ReturnsAsync(Result<PaginatedData<Ticket>>.Success(paginatedData));

var mappedData = new PaginatedData<GetTicketForResellResponseDto>(
new List<GetTicketForResellResponseDto>(),
page,
pageSize,
false,
false,
new PaginationDetails(0, 0)
);

paginationServiceMock.Setup(p => p.MapData(
paginatedData,
It.IsAny<Func<Ticket, GetTicketForResellResponseDto>>()))
.Returns(mappedData);

var sut = new TicketService(ticketRepositoryMock.Object, paginationServiceMock.Object);

// Act
var result = await sut.GetTicketsForResellAsync(eventId, page, pageSize);

// Assert
Assert.True(result.IsSuccess);
Assert.Empty(result.Value!.Data);
}

[Fact]
public async Task GetTicketsForResellAsync_WhenPaginationFails_ShouldPropagateError()
{
// Arrange
var eventId = Guid.NewGuid();
int pageSize = 10;
int page = 0;
const string errorMsg = "Invalid pagination parameters";
const int statusCode = 400;

var tickets = new List<Ticket>
{
new Ticket
{
Id = Guid.NewGuid(),
ForResell = true,
Type = new TicketType
{
Price = 50m,
Currency = "USD",
Description = "VIP"
}
}
}.AsQueryable();

var ticketRepositoryMock = new Mock<ITicketRepository>();
ticketRepositoryMock.Setup(repo => repo.GetTicketsByEventId(eventId))
.Returns(tickets);

var paginationServiceMock = new Mock<IPaginationService>();
paginationServiceMock.Setup(p => p.PaginateAsync(It.IsAny<IQueryable<Ticket>>(), pageSize, page))
.ReturnsAsync(Result<PaginatedData<Ticket>>.Failure(statusCode, errorMsg));

var sut = new TicketService(ticketRepositoryMock.Object, paginationServiceMock.Object);

// Act
var result = await sut.GetTicketsForResellAsync(eventId, page, pageSize);

// Assert
Assert.True(result.IsError);
Assert.Equal(errorMsg, result.ErrorMsg);
Assert.Equal(statusCode, result.StatusCode);
}

[Fact]
public async Task GetTicketsForResellAsync_WhenNoTicketsForEvent_ShouldReturnEmptyList()
{
// Arrange
var eventId = Guid.NewGuid();
int pageSize = 10;
int page = 0;

var tickets = new List<Ticket>().AsQueryable();

var ticketRepositoryMock = new Mock<ITicketRepository>();
ticketRepositoryMock.Setup(repo => repo.GetTicketsByEventId(eventId))
.Returns(tickets);

var paginatedData = new PaginatedData<Ticket>(
new List<Ticket>(),
page,
pageSize,
false,
false,
new PaginationDetails(0, 0)
);

var paginationServiceMock = new Mock<IPaginationService>();
paginationServiceMock.Setup(p => p.PaginateAsync(It.IsAny<IQueryable<Ticket>>(), pageSize, page))
.ReturnsAsync(Result<PaginatedData<Ticket>>.Success(paginatedData));

var mappedData = new PaginatedData<GetTicketForResellResponseDto>(
new List<GetTicketForResellResponseDto>(),
page,
pageSize,
false,
false,
new PaginationDetails(0, 0)
);

paginationServiceMock.Setup(p => p.MapData(
paginatedData,
It.IsAny<Func<Ticket, GetTicketForResellResponseDto>>()))
.Returns(mappedData);

var sut = new TicketService(ticketRepositoryMock.Object, paginationServiceMock.Object);

// Act
var result = await sut.GetTicketsForResellAsync(eventId, page, pageSize);

// Assert
Assert.True(result.IsSuccess);
Assert.Empty(result.Value!.Data);
}
}
1 change: 1 addition & 0 deletions TickAPI/TickAPI/Tickets/Abstractions/ITicketRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ namespace TickAPI.Tickets.Abstractions;
public interface ITicketRepository
{
public IQueryable<Ticket> GetAllTicketsByTicketType(TicketType ticketType);
public IQueryable<Ticket> GetTicketsByEventId(Guid eventId);
}
9 changes: 6 additions & 3 deletions TickAPI/TickAPI/Tickets/Abstractions/ITicketService.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
using TickAPI.Common.Results.Generic;
using TickAPI.Common.Pagination.Responses;
using TickAPI.Common.Results.Generic;
using TickAPI.Tickets.DTOs.Response;
using TickAPI.TicketTypes.Models;

namespace TickAPI.Tickets.Abstractions;

public interface ITicketService
{
public Result<uint> GetNumberOfAvailableTicketsByType(TicketType ticketType);
{
Result<uint> GetNumberOfAvailableTicketsByType(TicketType ticketType);
Task<Result<PaginatedData<GetTicketForResellResponseDto>>> GetTicketsForResellAsync(Guid eventId, int page, int pageSize);
}
19 changes: 19 additions & 0 deletions TickAPI/TickAPI/Tickets/Controllers/TicketsController.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,29 @@
using Microsoft.AspNetCore.Mvc;
using TickAPI.Common.Pagination.Responses;
using TickAPI.Tickets.Abstractions;
using TickAPI.Tickets.DTOs.Response;

namespace TickAPI.Tickets.Controllers;

[ApiController]
[Route("api/[controller]")]
public class TicketsController : ControllerBase
{
private readonly ITicketService _ticketService;

public TicketsController(ITicketService ticketService)
{
_ticketService = ticketService;
}

[HttpGet("/for-resell")]
public async Task<ActionResult<PaginatedData<GetTicketForResellResponseDto>>> GetTicketsForResell([FromQuery] Guid eventId, [FromQuery] int pageSize, [FromQuery] int page)
{
var result = await _ticketService.GetTicketsForResellAsync(eventId, page, pageSize);
if (result.IsError)
{
return StatusCode(result.StatusCode, result.ErrorMsg);
}
return result.Value!;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace TickAPI.Tickets.DTOs.Response;

public record GetTicketForResellResponseDto(
Guid Id,
decimal Price,
string Currency,
string Description,
string? Seats
);
Loading
Loading