Files
SlipItIn/SlipItIn.Server.Tests/AuthControllerTests.cs
Tim Krampitz 660fc4d311
All checks were successful
Build / build (pull_request) Successful in 2m16s
Fix CI build workflow, index casing, and test assertions
2026-08-23 14:46:09 +02:00

213 lines
7.3 KiB
C#

using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using SlipItIn.Server.Controllers;
using SlipItIn.Server.Data;
using SlipItIn.Shared.DTOs;
using SlipItIn.Shared.Models;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
namespace SlipItIn.Server.Tests;
public class AuthControllerTests
{
private readonly IDbContextFactory<SlipItInDbContext> _factory = TestDbHelper.CreateFactory();
private readonly AuthController _sut;
public AuthControllerTests()
{
var config = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string?>
{
["Jwt:Key"] = "TestKeyThatIsAtLeast32CharactersLong!!",
["Jwt:Issuer"] = "TestIssuer",
["Jwt:Audience"] = "TestAudience",
["Jwt:ExpirationMinutes"] = "60"
})
.Build();
_sut = new AuthController(_factory, config, new TestHostEnvironment());
}
private sealed class TestHostEnvironment : IHostEnvironment
{
public string EnvironmentName { get; set; } = Environments.Development;
public string ApplicationName { get; set; } = "SlipItIn.Server.Tests";
public string ContentRootPath { get; set; } = AppContext.BaseDirectory;
public Microsoft.Extensions.FileProviders.IFileProvider ContentRootFileProvider { get; set; } = null!;
}
// ---------- Register ----------
[Fact]
public async Task Register_ReturnsOk_WithTokenAndUserData()
{
var result = await _sut.Register(new RegisterRequestDto
{
Username = " Alice ",
Email = " ALICE@Test.Local ",
Password = "Secret123!"
});
var ok = Assert.IsType<OkObjectResult>(result.Result);
var dto = Assert.IsType<AuthResponseDto>(ok.Value);
Assert.Equal("Alice", dto.Username); // getrimmt
Assert.Equal("alice@test.local", dto.Email); // getrimmt + lowercase
Assert.True(dto.UserId > 0);
Assert.False(string.IsNullOrWhiteSpace(dto.Token));
Assert.True(dto.ExpiresAtUtc > DateTime.UtcNow);
// Token enthält die erwarteten Claims und ist valide lesbar
var token = new JwtSecurityTokenHandler().ReadJwtToken(dto.Token);
Assert.Equal("TestIssuer", token.Issuer);
Assert.Contains("TestAudience", token.Audiences);
Assert.Equal(dto.UserId.ToString(), token.Claims.First(c => c.Type == ClaimTypes.NameIdentifier).Value);
}
[Theory]
[InlineData("", "a@b.c", "pw")]
[InlineData("user", "", "pw")]
[InlineData("user", "a@b.c", "")]
[InlineData(" ", "a@b.c", "pw")]
public async Task Register_ReturnsBadRequest_WhenFieldsMissing(string username, string email, string password)
{
var result = await _sut.Register(new RegisterRequestDto { Username = username, Email = email, Password = password });
Assert.IsType<BadRequestObjectResult>(result.Result);
}
[Fact]
public async Task Register_ReturnsConflict_WhenEmailExists_CaseInsensitive()
{
using var db = _factory.CreateDbContext();
TestDbHelper.SeedUser(db, "existing", "alice@test.local");
var result = await _sut.Register(new RegisterRequestDto
{
Username = "newuser",
Email = "ALICE@TEST.LOCAL",
Password = "Secret123!"
});
Assert.IsType<ConflictObjectResult>(result.Result);
}
[Fact]
public async Task Register_ReturnsConflict_WhenUsernameExists_CaseInsensitive()
{
using var db = _factory.CreateDbContext();
TestDbHelper.SeedUser(db, "alice", "other@test.local");
var result = await _sut.Register(new RegisterRequestDto
{
Username = "ALICE",
Email = "new@test.local",
Password = "Secret123!"
});
Assert.IsType<ConflictObjectResult>(result.Result);
}
// ---------- Login ----------
[Fact]
public async Task Login_ReturnsOk_WithValidCredentials()
{
using var db = _factory.CreateDbContext();
db.Users.Add(new User
{
Username = "bob",
Email = "bob@test.local",
PasswordHash = BCrypt.Net.BCrypt.HashPassword("Secret123!")
});
await db.SaveChangesAsync();
var result = await _sut.Login(new LoginRequestDto { Email = " BOB@test.local ", Password = "Secret123!" });
var ok = Assert.IsType<OkObjectResult>(result.Result);
var dto = Assert.IsType<AuthResponseDto>(ok.Value);
Assert.Equal("bob", dto.Username);
Assert.False(string.IsNullOrWhiteSpace(dto.Token));
}
[Theory]
[InlineData("", "pw")]
[InlineData("a@b.c", "")]
public async Task Login_ReturnsBadRequest_WhenFieldsMissing(string email, string password)
{
var result = await _sut.Login(new LoginRequestDto { Email = email, Password = password });
Assert.IsType<BadRequestObjectResult>(result.Result);
}
[Fact]
public async Task Login_ReturnsUnauthorized_WhenUserNotFound()
{
var result = await _sut.Login(new LoginRequestDto { Email = "ghost@test.local", Password = "Secret123!" });
Assert.IsType<UnauthorizedObjectResult>(result.Result);
}
[Fact]
public async Task Login_ReturnsUnauthorized_WhenPasswordWrong()
{
using var db = _factory.CreateDbContext();
db.Users.Add(new User
{
Username = "bob",
Email = "bob@test.local",
PasswordHash = BCrypt.Net.BCrypt.HashPassword("CorrectPassword")
});
await db.SaveChangesAsync();
var result = await _sut.Login(new LoginRequestDto { Email = "bob@test.local", Password = "WrongPassword" });
Assert.IsType<UnauthorizedObjectResult>(result.Result);
}
// ---------- Me ----------
[Fact]
public void Me_ReturnsUserData_FromClaims()
{
var identity = new ClaimsIdentity([
new Claim(ClaimTypes.NameIdentifier, "42"),
new Claim(ClaimTypes.Name, "alice"),
new Claim(ClaimTypes.Email, "alice@test.local")
], "TestAuth");
_sut.ControllerContext = new ControllerContext
{
HttpContext = new Microsoft.AspNetCore.Http.DefaultHttpContext
{
User = new ClaimsPrincipal(identity)
}
};
var result = _sut.Me();
var ok = Assert.IsType<OkObjectResult>(result.Result);
var value = ok.Value!;
Assert.Equal(42, (int)value.GetType().GetProperty("UserId")!.GetValue(value)!);
Assert.Equal("alice", (string)value.GetType().GetProperty("Username")!.GetValue(value)!);
Assert.Equal("alice@test.local", (string)value.GetType().GetProperty("Email")!.GetValue(value)!);
}
[Fact]
public void Me_ReturnsUnauthorized_WhenNameIdentifierClaimMissing()
{
var identity = new ClaimsIdentity([new Claim(ClaimTypes.Name, "alice")], "TestAuth");
_sut.ControllerContext = new ControllerContext
{
HttpContext = new Microsoft.AspNetCore.Http.DefaultHttpContext
{
User = new ClaimsPrincipal(identity)
}
};
var result = _sut.Me();
Assert.IsType<UnauthorizedResult>(result.Result);
}
}