Clean up and include routing unit tests

This commit is contained in:
Steve Sanderson 2018-02-20 22:29:00 +00:00
parent 87fc15cc23
commit 7073429cd5
12 changed files with 142 additions and 7 deletions

View File

@ -66,6 +66,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AngleSharpBuilder", "src\an
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Blazor.Razor.Extensions", "src\Microsoft.AspNetCore.Blazor.Razor.Extensions\Microsoft.AspNetCore.Blazor.Razor.Extensions.csproj", "{D652A019-B765-4922-B7B8-3AB1C58338D7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.Blazor.Browser.Test", "test\Microsoft.AspNetCore.Blazor.Browser.Test\Microsoft.AspNetCore.Blazor.Browser.Test.csproj", "{EC2A38BF-6E77-4A8E-A731-15929544F29C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -160,6 +162,10 @@ Global
{D652A019-B765-4922-B7B8-3AB1C58338D7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D652A019-B765-4922-B7B8-3AB1C58338D7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D652A019-B765-4922-B7B8-3AB1C58338D7}.Release|Any CPU.Build.0 = Release|Any CPU
{EC2A38BF-6E77-4A8E-A731-15929544F29C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EC2A38BF-6E77-4A8E-A731-15929544F29C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EC2A38BF-6E77-4A8E-A731-15929544F29C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EC2A38BF-6E77-4A8E-A731-15929544F29C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -192,6 +198,7 @@ Global
{4E3BD19A-6159-4548-A88F-700443E6D934} = {B867E038-B3CE-43E3-9292-61568C46CDEB}
{36706AC2-C851-4038-B161-9C1E44B668C8} = {4E3BD19A-6159-4548-A88F-700443E6D934}
{D652A019-B765-4922-B7B8-3AB1C58338D7} = {B867E038-B3CE-43E3-9292-61568C46CDEB}
{EC2A38BF-6E77-4A8E-A731-15929544F29C} = {ADA3AE29-F6DE-49F6-8C7C-B321508CAE8E}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {504DA352-6788-4DC0-8705-82167E72A4D3}

View File

@ -0,0 +1,3 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Blazor.Browser.Test")]

View File

@ -10,18 +10,35 @@ using Microsoft.AspNetCore.Blazor.RenderTree;
namespace Microsoft.AspNetCore.Blazor.Browser.Routing
{
/// <summary>
/// A component that displays whichever other component corresponds to the
/// browser's changing navigation state.
/// </summary>
public class BrowserRouter : IComponent, IDisposable
{
RenderHandle _renderHandle;
string _baseUriPrefix;
string _locationAbsolute;
/// <summary>
/// Gets or sets the assembly that should be searched, along with its referenced
/// assemblies, for components matching the URI.
/// </summary>
public Assembly AppAssembly { get; set; }
/// <summary>
/// Gets or sets the namespace prefix that should be prepended when searching
/// for matching components.
/// </summary>
public string PagesNamespace { get; set; }
/// <summary>
/// Gets or sets the component name that will be used if the URI ends with
/// a slash.
/// </summary>
public string DefaultComponentName { get; set; } = "Index";
/// <inheritdoc />
public void Init(RenderHandle renderHandle)
{
_renderHandle = renderHandle;
@ -32,12 +49,14 @@ namespace Microsoft.AspNetCore.Blazor.Browser.Routing
_locationAbsolute = UriHelper.GetAbsoluteUri();
}
/// <inheritdoc />
public void SetParameters(ParameterCollection parameters)
{
parameters.AssignToProperties(this);
Refresh();
}
/// <inheritdoc />
public void Dispose()
{
UriHelper.OnLocationChanged -= OnLocationChanged;

View File

@ -6,29 +6,59 @@ using System;
namespace Microsoft.AspNetCore.Blazor.Browser.Routing
{
// TODO: Make this not static, and wrap it in an interface that can be injected through DI.
// We can make EnableNavigationInteception private, and call it automatically when the any
// concrete instance is instantiated.
/// <summary>
/// Helpers for working with URIs and navigation state.
/// </summary>
public static class UriHelper
{
static readonly string _functionPrefix = typeof(UriHelper).FullName;
/// <summary>
/// An event that fires when the navigation location has changed.
/// </summary>
public static event EventHandler<string> OnLocationChanged;
/// <summary>
/// Prevents default navigation on all links whose href is inside the base URI space,
/// causing clicks on those links to trigger <see cref="OnLocationChanged"/> instead.
/// </summary>
public static void EnableNavigationInteception()
=> RegisteredFunction.InvokeUnmarshalled<object>(
$"{_functionPrefix}.enableNavigationInteception");
/// <summary>
/// Gets the URI prefix that can be prepended before URI paths to produce an absolute URI.
/// Typically this corresponds to the 'href' attribute on the document's &lt;base&gt; element.
/// </summary>
/// <returns>The URI prefix.</returns>
public static string GetBaseUriPrefix()
{
var baseUri = RegisteredFunction.InvokeUnmarshalled<string>(
$"{_functionPrefix}.getBaseURI");
return ToBaseURIPrefix(baseUri);
return ToBaseUriPrefix(baseUri);
}
/// <summary>
/// Gets the browser's current absolute URI.
/// </summary>
/// <returns>The browser's current absolute URI.</returns>
public static string GetAbsoluteUri()
{
return RegisteredFunction.InvokeUnmarshalled<string>(
$"{_functionPrefix}.getLocationHref");
}
/// <summary>
/// Given a base URI prefix (e.g., one previously returned by <see cref="GetBaseUriPrefix"/>),
/// converts an absolute URI into one relative to the base URI prefix.
/// </summary>
/// <param name="baseUriPrefix">The base URI prefix (e.g., previously returned by <see cref="GetBaseUriPrefix"/>).</param>
/// <param name="absoluteUri">An absolute URI that is within the space of the base URI prefix.</param>
/// <returns>A relative URI path.</returns>
public static string ToBaseRelativePath(string baseUriPrefix, string absoluteUri)
{
// The absolute URI must be of the form "{baseUriPrefix}/something",
@ -49,13 +79,14 @@ namespace Microsoft.AspNetCore.Blazor.Browser.Routing
=> OnLocationChanged?.Invoke(null, newAbsoluteUri);
/// <summary>
/// Given the href value from the document's <base> element, returns the URI
/// prefix that can be prepended to URI paths to produce an absolute URI.
/// Given the document's document.baseURI value, returns the URI prefix
/// that can be prepended to URI paths to produce an absolute URI.
/// This is computed by removing the final slash and any following characters.
/// Internal for tests.
/// </summary>
/// <param name="baseUri">The href value from a document's <base> element.</param>
/// <param name="baseUri">The page's document.baseURI value.</param>
/// <returns>The URI prefix</returns>
private static string ToBaseURIPrefix(string baseUri)
internal static string ToBaseUriPrefix(string baseUri)
{
if (baseUri != null)
{

View File

@ -1,3 +1,4 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Blazor.Test")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Blazor.Browser.Test")]

View File

@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" />
<PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
<DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Blazor.Browser\Microsoft.AspNetCore.Blazor.Browser.csproj" />
<!-- Shared sources -->
<Compile Include="..\shared\**\*.cs" Link="Helpers\%(Filename)%(Extension)" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,51 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Blazor.Browser.Routing;
using System;
using Xunit;
namespace Microsoft.AspNetCore.Blazor.Browser.Test
{
public class UriHelperTest
{
[Theory]
[InlineData("scheme://host/", "scheme://host")]
[InlineData("scheme://host:123/", "scheme://host:123")]
[InlineData("scheme://host/path", "scheme://host")]
[InlineData("scheme://host/path/", "scheme://host/path")]
[InlineData("scheme://host/path/page?query=string&another=here", "scheme://host/path")]
public void ComputesCorrectBaseUriPrefix(string baseUri, string expectedResult)
{
var actualResult = UriHelper.ToBaseUriPrefix(baseUri);
Assert.Equal(expectedResult, actualResult);
}
[Theory]
[InlineData("scheme://host", "scheme://host/", "/")]
[InlineData("scheme://host", "scheme://host/path", "/path")]
[InlineData("scheme://host/path", "scheme://host/path/", "/")]
[InlineData("scheme://host/path", "scheme://host/path/more", "/more")]
public void ComputesCorrectValidBaseRelativePaths(string baseUriPrefix, string absoluteUri, string expectedResult)
{
var actualResult = UriHelper.ToBaseRelativePath(baseUriPrefix, absoluteUri);
Assert.Equal(expectedResult, actualResult);
}
[Theory]
[InlineData("scheme://host", "otherscheme://host/")] // Mismatched prefix is error
[InlineData("scheme://host", "scheme://otherhost/")] // Mismatched prefix is error
[InlineData("scheme://host/path", "scheme://host/path")] // URI isn't within base URI space
public void ThrowsForInvalidBaseRelativePaths(string baseUriPrefix, string absoluteUri)
{
var ex = Assert.Throws<ArgumentException>(() =>
{
UriHelper.ToBaseRelativePath(baseUriPrefix, absoluteUri);
});
Assert.Equal(
$"The URI '{absoluteUri}' is not contained by the base URI '{baseUriPrefix}'.",
ex.Message);
}
}
}

View File

@ -17,7 +17,7 @@
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Blazor\Microsoft.AspNetCore.Blazor.csproj" />
<!-- Shared sources -->
<Compile Include="..\shared\AssertFrame.cs" Link="Helpers\AssertFrame.cs" />
<Compile Include="..\shared\**\*.cs" Link="Helpers\%(Filename)%(Extension)" />
</ItemGroup>
</Project>

View File

@ -5,7 +5,7 @@ using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Blazor.RenderTree;
namespace Microsoft.AspNetCore.Blazor.Test
namespace Microsoft.AspNetCore.Blazor.Test.Helpers
{
public class CapturedBatch
{