Skip to content
Closed
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
137 changes: 137 additions & 0 deletions src/WebExpress.WebApp.Test/WebIdentity/UnitTestIdentityProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
using WebExpress.WebApp.Test.Fixture;
using WebExpress.WebApp.WebIdentity;
using WebExpress.WebCore.WebIdentity;

namespace WebExpress.WebApp.Test.WebIdentity
{
/// <summary>
/// Tests the abstract identity provider base class.
/// </summary>
[Collection("NonParallelTests")]
public class UnitTestIdentityProvider
{
/// <summary>
/// A minimal concrete implementation for testing.
/// </summary>
private sealed class TestIdentityProvider : IdentityProvider
{
public bool ValidateBasicCalled { get; private set; }
public bool ValidateTokenCalled { get; private set; }
public string LastUsername { get; private set; }
public string LastToken { get; private set; }
public IIdentity IdentityToReturn { get; set; }

public override IEnumerable<IIdentity> GetIdentities() => [];

public override IEnumerable<IIdentityGroup> GetGroups() => [];

protected override IIdentity ValidateBasicCredentials(string username, string password)
{
ValidateBasicCalled = true;
LastUsername = username;
return IdentityToReturn;
}

protected override IIdentity ValidateToken(string token)
{
ValidateTokenCalled = true;
LastToken = token;
return IdentityToReturn;
}
}

/// <summary>
/// Tests that Authenticate returns null when request is null.
/// </summary>
[Fact]
public void Authenticate_NullRequest_ReturnsNull()
{
// arrange
_ = UnitTestControlFixture.CreateAndRegisterComponentHubMock();
var provider = new TestIdentityProvider();

// act
var result = provider.Authenticate(null);

// validation
Assert.Null(result);
}

/// <summary>
/// Tests that Authenticate returns null when the request has no authorization header.
/// </summary>
[Fact]
public void Authenticate_NoAuthorizationHeader_ReturnsNull()
{
// arrange
_ = UnitTestControlFixture.CreateAndRegisterComponentHubMock();
var provider = new TestIdentityProvider();
var request = UnitTestControlFixture.CreateRequestMock();

// act
var result = provider.Authenticate(request);

// validation
Assert.Null(result);
}

/// <summary>
/// Tests that Authenticate calls ValidateBasicCredentials for Basic auth headers.
/// </summary>
[Fact]
public void Authenticate_BasicAuthHeader_CallsValidateBasicCredentials()
{
// arrange
_ = UnitTestControlFixture.CreateAndRegisterComponentHubMock();
var provider = new TestIdentityProvider();
var content = $"GET / HTTP/1.1\r\nHost: localhost\r\nAuthorization: Basic {Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes("user:pass"))}\r\n\r\n";
var request = UnitTestControlFixture.CreateRequestMock(content, "");

// act
provider.Authenticate(request);

// validation
Assert.True(provider.ValidateBasicCalled);
}

/// <summary>
/// Tests that Authenticate calls ValidateToken for Bearer auth headers.
/// </summary>
[Fact]
public void Authenticate_BearerAuthHeader_CallsValidateToken()
{
// arrange
_ = UnitTestControlFixture.CreateAndRegisterComponentHubMock();
var provider = new TestIdentityProvider();
// bearer token must be base64-encoded as "<token>:" so Identification contains the token
var bearerToken = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes("mytoken123:"));
var content = $"GET / HTTP/1.1\r\nHost: localhost\r\nAuthorization: Bearer {bearerToken}\r\n\r\n";
var request = UnitTestControlFixture.CreateRequestMock(content, "");

// act
provider.Authenticate(request);

// validation
Assert.True(provider.ValidateTokenCalled);
}

/// <summary>
/// Tests that GetIdentities and GetGroups can be called on the provider.
/// </summary>
[Fact]
public void GetIdentities_ReturnsEmpty()
{
// arrange
_ = UnitTestControlFixture.CreateAndRegisterComponentHubMock();
var provider = new TestIdentityProvider();

// act
var identities = provider.GetIdentities();
var groups = provider.GetGroups();

// validation
Assert.Empty(identities);
Assert.Empty(groups);
}
}
}
101 changes: 101 additions & 0 deletions src/WebExpress.WebApp.Test/WebPage/UnitTestPageWebAppForbidden.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
using WebExpress.WebApp.Test.Fixture;
using WebExpress.WebApp.WebPage;
using WebExpress.WebUI.WebPage;

namespace WebExpress.WebApp.Test.WebPage
{
/// <summary>
/// Tests the access-denied page.
/// </summary>
[Collection("NonParallelTests")]
public class UnitTestPageWebAppForbidden
{
/// <summary>
/// Tests that the forbidden page can be processed without throwing an exception.
/// </summary>
[Fact]
public void Process_DoesNotThrow()
{
// arrange
var componentHub = UnitTestControlFixture.CreateAndRegisterComponentHubMock();
var context = UnitTestControlFixture.CreateRenderContextMock();
var visualTree = new VisualTreeWebAppLogin(componentHub, context.PageContext);
var page = new PageWebAppForbidden();

// act
var exception = Record.Exception(() => page.Process(context, visualTree));

// validation
Assert.Null(exception);
}

/// <summary>
/// Tests that the forbidden page populates the visual tree content area.
/// </summary>
[Fact]
public void Process_PopulatesContent()
{
// arrange
var componentHub = UnitTestControlFixture.CreateAndRegisterComponentHubMock();
var context = UnitTestControlFixture.CreateRenderContextMock();
var visualTree = new VisualTreeWebAppLogin(componentHub, context.PageContext);
var page = new PageWebAppForbidden();

// act
page.Process(context, visualTree);

// validation
Assert.NotEmpty(visualTree.Content.MainPanel.Primary);
}

/// <summary>
/// Tests that the forbidden page sets the visual tree title.
/// </summary>
[Fact]
public void Process_SetsTitle()
{
// arrange
var componentHub = UnitTestControlFixture.CreateAndRegisterComponentHubMock();
var context = UnitTestControlFixture.CreateRenderContextMock();
var visualTree = new VisualTreeWebAppLogin(componentHub, context.PageContext);
var page = new PageWebAppForbidden();

// act
page.Process(context, visualTree);

// validation
Assert.NotNull(visualTree.Title);
}

/// <summary>
/// Tests that Process throws ArgumentNullException when renderContext is null.
/// </summary>
[Fact]
public void Process_NullRenderContext_ThrowsArgumentNullException()
{
// arrange
var componentHub = UnitTestControlFixture.CreateAndRegisterComponentHubMock();
var context = UnitTestControlFixture.CreateRenderContextMock();
var visualTree = new VisualTreeWebAppLogin(componentHub, context.PageContext);
var page = new PageWebAppForbidden();

// act & validation
Assert.Throws<ArgumentNullException>(() => page.Process(null, visualTree));
}

/// <summary>
/// Tests that Process throws ArgumentNullException when visualTree is null.
/// </summary>
[Fact]
public void Process_NullVisualTree_ThrowsArgumentNullException()
{
// arrange
var componentHub = UnitTestControlFixture.CreateAndRegisterComponentHubMock();
var context = UnitTestControlFixture.CreateRenderContextMock();
var page = new PageWebAppForbidden();

// act & validation
Assert.Throws<ArgumentNullException>(() => page.Process(context, null));
}
}
}
101 changes: 101 additions & 0 deletions src/WebExpress.WebApp.Test/WebPage/UnitTestPageWebAppLogin.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
using WebExpress.WebApp.Test.Fixture;
using WebExpress.WebApp.WebPage;
using WebExpress.WebUI.WebPage;

namespace WebExpress.WebApp.Test.WebPage
{
/// <summary>
/// Tests the login page.
/// </summary>
[Collection("NonParallelTests")]
public class UnitTestPageWebAppLogin
{
/// <summary>
/// Tests that the login page can be processed without throwing an exception.
/// </summary>
[Fact]
public void Process_DoesNotThrow()
{
// arrange
var componentHub = UnitTestControlFixture.CreateAndRegisterComponentHubMock();
var context = UnitTestControlFixture.CreateRenderContextMock();
var visualTree = new VisualTreeWebAppLogin(componentHub, context.PageContext);
var page = new PageWebAppLogin();

// act
var exception = Record.Exception(() => page.Process(context, visualTree));

// validation
Assert.Null(exception);
}

/// <summary>
/// Tests that the login page populates the visual tree content area.
/// </summary>
[Fact]
public void Process_PopulatesContent()
{
// arrange
var componentHub = UnitTestControlFixture.CreateAndRegisterComponentHubMock();
var context = UnitTestControlFixture.CreateRenderContextMock();
var visualTree = new VisualTreeWebAppLogin(componentHub, context.PageContext);
var page = new PageWebAppLogin();

// act
page.Process(context, visualTree);

// validation
Assert.NotEmpty(visualTree.Content.MainPanel.Primary);
}

/// <summary>
/// Tests that the login page sets the visual tree title.
/// </summary>
[Fact]
public void Process_SetsTitle()
{
// arrange
var componentHub = UnitTestControlFixture.CreateAndRegisterComponentHubMock();
var context = UnitTestControlFixture.CreateRenderContextMock();
var visualTree = new VisualTreeWebAppLogin(componentHub, context.PageContext);
var page = new PageWebAppLogin();

// act
page.Process(context, visualTree);

// validation
Assert.NotNull(visualTree.Title);
}

/// <summary>
/// Tests that Process throws ArgumentNullException when renderContext is null.
/// </summary>
[Fact]
public void Process_NullRenderContext_ThrowsArgumentNullException()
{
// arrange
var componentHub = UnitTestControlFixture.CreateAndRegisterComponentHubMock();
var context = UnitTestControlFixture.CreateRenderContextMock();
var visualTree = new VisualTreeWebAppLogin(componentHub, context.PageContext);
var page = new PageWebAppLogin();

// act & validation
Assert.Throws<ArgumentNullException>(() => page.Process(null, visualTree));
}

/// <summary>
/// Tests that Process throws ArgumentNullException when visualTree is null.
/// </summary>
[Fact]
public void Process_NullVisualTree_ThrowsArgumentNullException()
{
// arrange
var componentHub = UnitTestControlFixture.CreateAndRegisterComponentHubMock();
var context = UnitTestControlFixture.CreateRenderContextMock();
var page = new PageWebAppLogin();

// act & validation
Assert.Throws<ArgumentNullException>(() => page.Process(context, null));
}
}
}
Loading