mirror of https://github.com/Squidex/squidex.git
15 changed files with 429 additions and 83 deletions
@ -0,0 +1,113 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using Squidex.Domain.Apps.Core.Apps; |
||||
|
using Squidex.Domain.Apps.Entities.Contents; |
||||
|
using Squidex.Infrastructure; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Entities; |
||||
|
|
||||
|
public class ContextHeadersTests |
||||
|
{ |
||||
|
private readonly Context sut = Context.Anonymous(new App { Name = "my-app" }); |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_return_empty_when_header_is_not_set() |
||||
|
{ |
||||
|
Assert.Empty(sut.AsStrings("X-Fields")); |
||||
|
} |
||||
|
|
||||
|
[Theory] |
||||
|
[InlineData("a,b", new[] { "a", "b" })] |
||||
|
[InlineData("a, b", new[] { "a", "b" })] |
||||
|
[InlineData(" a ; b ", new[] { "a", "b" })] |
||||
|
[InlineData("a,,b", new[] { "a", "b" })] |
||||
|
[InlineData("a,a,b", new[] { "a", "b" })] |
||||
|
public void Should_split_and_trim_header(string value, string[] expected) |
||||
|
{ |
||||
|
var context = sut.Clone(b => b.SetHeader("X-Fields", value)); |
||||
|
|
||||
|
Assert.Equal(expected, context.AsStrings("X-Fields").ToArray()); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_ignore_entries_that_are_only_whitespace() |
||||
|
{ |
||||
|
// These used to survive as an empty string, which made Languages() throw.
|
||||
|
var context = sut.Clone(b => b.SetHeader("X-Fields", " , ")); |
||||
|
|
||||
|
Assert.Empty(context.AsStrings("X-Fields")); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_reuse_parsed_header() |
||||
|
{ |
||||
|
var context = sut.Clone(b => b.SetHeader("X-Fields", "a,b")); |
||||
|
|
||||
|
var actual1 = context.AsStrings("X-Fields"); |
||||
|
var actual2 = context.AsStrings("X-Fields"); |
||||
|
|
||||
|
Assert.Same(actual1, actual2); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_not_share_parsed_headers_with_clone() |
||||
|
{ |
||||
|
var context1 = sut.Clone(b => b.SetHeader("X-Fields", "a,b")); |
||||
|
|
||||
|
// Parse before cloning, so that a shared cache would be visible.
|
||||
|
Assert.Equal(["a", "b"], context1.AsStrings("X-Fields").ToArray()); |
||||
|
|
||||
|
var context2 = context1.Clone(b => b.SetHeader("X-Fields", "c")); |
||||
|
|
||||
|
Assert.Equal(["c"], context2.AsStrings("X-Fields").ToArray()); |
||||
|
Assert.Equal(["a", "b"], context1.AsStrings("X-Fields").ToArray()); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_not_see_header_that_has_been_removed_in_clone() |
||||
|
{ |
||||
|
var context1 = sut.Clone(b => b.SetHeader("X-Fields", "a,b")); |
||||
|
|
||||
|
Assert.NotEmpty(context1.AsStrings("X-Fields")); |
||||
|
|
||||
|
var context2 = context1.Clone(b => b.Remove("X-Fields")); |
||||
|
|
||||
|
Assert.Empty(context2.AsStrings("X-Fields")); |
||||
|
Assert.NotEmpty(context1.AsStrings("X-Fields")); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_return_same_context_when_nothing_is_changed() |
||||
|
{ |
||||
|
var context = sut.Clone(_ => { }); |
||||
|
|
||||
|
Assert.Same(sut, context); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_parse_languages_from_header() |
||||
|
{ |
||||
|
var context = sut.Clone(b => b.WithLanguages(["en", "de", "en"])); |
||||
|
|
||||
|
Assert.Equal([Language.EN, Language.DE], context.Languages().ToArray()); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_keep_headers_when_app_is_replaced() |
||||
|
{ |
||||
|
var context1 = sut.Clone(b => b.SetHeader("X-Fields", "a,b")); |
||||
|
|
||||
|
var context2 = context1.WithApp(new App { Name = "other-app" }); |
||||
|
|
||||
|
Assert.Equal("other-app", context2.App.Name); |
||||
|
Assert.Equal(["a", "b"], context2.AsStrings("X-Fields").ToArray()); |
||||
|
|
||||
|
// The original must not be affected.
|
||||
|
Assert.Equal("my-app", context1.App.Name); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,122 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using Microsoft.AspNetCore.Http; |
||||
|
using Squidex.Domain.Apps.Core.Apps; |
||||
|
using RequestContext = Squidex.Domain.Apps.Entities.Context; |
||||
|
|
||||
|
namespace Squidex.Web; |
||||
|
|
||||
|
public class ContextProviderTests |
||||
|
{ |
||||
|
private readonly IHttpContextAccessor httpContextAccessor = A.Fake<IHttpContextAccessor>(); |
||||
|
private readonly HttpContext httpContext = new DefaultHttpContext(); |
||||
|
private readonly App app = new App { Name = "my-app" }; |
||||
|
private readonly ContextProvider sut; |
||||
|
|
||||
|
public ContextProviderTests() |
||||
|
{ |
||||
|
// A fake would return a dummy http context, but the fallback is only used when it is null.
|
||||
|
A.CallTo(() => httpContextAccessor.HttpContext) |
||||
|
.Returns(null); |
||||
|
|
||||
|
sut = new ContextProvider(httpContextAccessor); |
||||
|
} |
||||
|
|
||||
|
private void UseHttpContext() |
||||
|
{ |
||||
|
A.CallTo(() => httpContextAccessor.HttpContext) |
||||
|
.Returns(httpContext); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_provide_context_from_http_context() |
||||
|
{ |
||||
|
UseHttpContext(); |
||||
|
|
||||
|
var context = new RequestContext(httpContext.User, app); |
||||
|
|
||||
|
httpContext.Features.Set(context); |
||||
|
|
||||
|
Assert.Same(context, sut.Context); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_create_context_when_http_context_has_none() |
||||
|
{ |
||||
|
UseHttpContext(); |
||||
|
|
||||
|
Assert.NotNull(sut.Context); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_reuse_created_context_of_http_context() |
||||
|
{ |
||||
|
UseHttpContext(); |
||||
|
|
||||
|
Assert.Same(sut.Context, sut.Context); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_read_headers_from_request() |
||||
|
{ |
||||
|
UseHttpContext(); |
||||
|
|
||||
|
httpContext.Request.Headers["X-Fields"] = "a,b"; |
||||
|
|
||||
|
Assert.Equal("a,b", sut.Context.Headers["X-Fields"]); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_write_context_to_http_context() |
||||
|
{ |
||||
|
UseHttpContext(); |
||||
|
|
||||
|
var context = new RequestContext(httpContext.User, app); |
||||
|
|
||||
|
sut.Context = context; |
||||
|
|
||||
|
Assert.Same(context, httpContext.Features.Get<RequestContext>()); |
||||
|
Assert.Same(context, sut.Context); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_replace_context_of_http_context() |
||||
|
{ |
||||
|
UseHttpContext(); |
||||
|
|
||||
|
var context1 = sut.Context; |
||||
|
var context2 = context1.Clone(b => b.SetHeader("X-Fields", "a,b")); |
||||
|
|
||||
|
sut.Context = context2; |
||||
|
|
||||
|
Assert.NotSame(context1, sut.Context); |
||||
|
Assert.Same(context2, sut.Context); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_provide_anonymous_context_without_http_context() |
||||
|
{ |
||||
|
Assert.NotNull(sut.Context); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_reuse_anonymous_context_without_http_context() |
||||
|
{ |
||||
|
Assert.Same(sut.Context, sut.Context); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_write_context_without_http_context() |
||||
|
{ |
||||
|
var context = new RequestContext(httpContext.User, app); |
||||
|
|
||||
|
sut.Context = context; |
||||
|
|
||||
|
Assert.Same(context, sut.Context); |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue