Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
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
5 changes: 5 additions & 0 deletions api.tests/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# .NET
bin/
obj/
*.user
*.suo
83 changes: 83 additions & 0 deletions api.tests/ReservationValidationTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
using Extensions;
using Models;
using Models.Errors;

namespace api.tests;

public class ReservationValidationTests
{
private static Reservation MakeValid() => new()
{
RoomNumber = "101",
GuestEmail = "guest@example.com",
Start = DateTime.Today,
End = DateTime.Today.AddDays(3),
};

[Fact]
public void ValidReservation_DoesNotThrow()
{
var r = MakeValid();
var ex = Record.Exception(() => r.Validate());
Assert.Null(ex);
}

[Theory]
[InlineData(null)]
[InlineData("")]
[InlineData(" ")]
public void MissingEmail_Throws(string? email)
{
var r = MakeValid();
r.GuestEmail = email!;
var ex = Assert.Throws<ValidationException>(() => r.Validate());
Assert.Contains(ex.Errors, e => e.Contains("Email", StringComparison.OrdinalIgnoreCase));
}

[Theory]
[InlineData("noatsign")]
[InlineData("trailing@")]
public void BadEmailFormat_Throws(string email)
{
var r = MakeValid();
r.GuestEmail = email;
var ex = Assert.Throws<ValidationException>(() => r.Validate());
Assert.Contains(ex.Errors, e => e.Contains("domain", StringComparison.OrdinalIgnoreCase));
}

[Fact]
public void StartInPast_Throws()
{
var r = MakeValid();
r.Start = DateTime.Today.AddDays(-1);
var ex = Assert.Throws<ValidationException>(() => r.Validate());
Assert.Contains(ex.Errors, e => e.Contains("past", StringComparison.OrdinalIgnoreCase));
}

[Fact]
public void StartAfterEnd_Throws()
{
var r = MakeValid();
r.End = r.Start.AddHours(-1);
var ex = Assert.Throws<ValidationException>(() => r.Validate());
Assert.Contains(ex.Errors, e => e.Contains("before the end", StringComparison.OrdinalIgnoreCase));
}

[Fact]
public void DurationOver30Days_Throws()
{
var r = MakeValid();
r.End = r.Start.AddDays(31);
var ex = Assert.Throws<ValidationException>(() => r.Validate());
Assert.Contains(ex.Errors, e => e.Contains("30 days", StringComparison.OrdinalIgnoreCase));
}

[Fact]
public void InvalidRoomNumber_Throws()
{
var r = MakeValid();
r.RoomNumber = "abc";
var ex = Assert.Throws<ValidationException>(() => r.Validate());
Assert.Contains(ex.Errors, e => e.Contains("digits", StringComparison.OrdinalIgnoreCase));
}
}
76 changes: 76 additions & 0 deletions api.tests/RoomValidationTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
using Extensions;
using Models;

namespace api.tests;

public class RoomValidationTests
{
[Theory]
[InlineData("101")]
[InlineData("999")]
[InlineData("010")]
[InlineData("001")]
public void ValidRoomNumbers_PassValidation(string number)
{
var room = new Room { Number = number };
var errors = room.Validate();
Assert.Empty(errors);
}

[Fact]
public void NullRoomNumber_ReturnsRequired()
{
var room = new Room { Number = null! };
var errors = room.Validate();
Assert.Single(errors);
Assert.Contains("required", errors[0], StringComparison.OrdinalIgnoreCase);
}

[Theory]
[InlineData("")]
[InlineData(" ")]
public void EmptyOrWhitespace_ReturnsRequired(string number)
{
var room = new Room { Number = number };
var errors = room.Validate();
Assert.Single(errors);
Assert.Contains("required", errors[0], StringComparison.OrdinalIgnoreCase);
}

[Theory]
[InlineData("1")]
[InlineData("12")]
[InlineData("1234")]
public void WrongLength_ReturnsLengthError(string number)
{
var room = new Room { Number = number };
var errors = room.Validate();
Assert.Single(errors);
Assert.Contains("exactly 3 digits", errors[0]);
}

[Theory]
[InlineData("abc")]
[InlineData("1a2")]
[InlineData("!!1")]
public void NonDigits_ReturnsDigitError(string number)
{
var room = new Room { Number = number };
var errors = room.Validate();
Assert.Single(errors);
Assert.Contains("only digits", errors[0]);
}

[Theory]
[InlineData("100")]
[InlineData("200")]
[InlineData("900")]
[InlineData("000")]
public void DoorZeroZero_ReturnsDoorError(string number)
{
var room = new Room { Number = number };
var errors = room.Validate();
Assert.Single(errors);
Assert.Contains("Door number cannot be \"00\"", errors[0]);
}
}
27 changes: 27 additions & 0 deletions api.tests/api.tests.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="xunit" Version="2.5.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3" />
</ItemGroup>

<ItemGroup>
<Using Include="Xunit" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\api\api.csproj" />
</ItemGroup>

</Project>
2 changes: 2 additions & 0 deletions api/Controllers/GuestController.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Models;
using Repositories;

namespace Controllers
{
[Tags("Guests"), Route("guest")]
[Authorize]
public class GuestController : Controller
{
private GuestRepository _repo;
Expand Down
Loading