aspnetcore/test/Microsoft.JSInterop.Test/DotNetDispatcherTest.cs

164 lines
5.9 KiB
C#

// 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 System;
using System.Linq;
using Xunit;
namespace Microsoft.JSInterop.Test
{
public class DotNetDispatcherTest
{
private readonly static string thisAssemblyName
= typeof(DotNetDispatcherTest).Assembly.GetName().Name;
[Fact]
public void CannotInvokeWithEmptyAssemblyName()
{
var ex = Assert.Throws<ArgumentException>(() =>
{
DotNetDispatcher.Invoke(" ", "SomeMethod", "[]");
});
Assert.StartsWith("Cannot be null, empty, or whitespace.", ex.Message);
Assert.Equal("assemblyName", ex.ParamName);
}
[Fact]
public void CannotInvokeWithEmptyMethodIdentifier()
{
var ex = Assert.Throws<ArgumentException>(() =>
{
DotNetDispatcher.Invoke("SomeAssembly", " ", "[]");
});
Assert.StartsWith("Cannot be null, empty, or whitespace.", ex.Message);
Assert.Equal("methodIdentifier", ex.ParamName);
}
[Fact]
public void CannotInvokeMethodsOnUnloadedAssembly()
{
var assemblyName = "Some.Fake.Assembly";
var ex = Assert.Throws<ArgumentException>(() =>
{
DotNetDispatcher.Invoke(assemblyName, "SomeMethod", null);
});
Assert.Equal($"There is no loaded assembly with the name '{assemblyName}'.", ex.Message);
}
// Note: Currently it's also not possible to invoke instance or generic methods.
// That's not something determined by DotNetDispatcher, but rather by the fact that we
// don't pass any 'target' or close over the generics in the reflection code.
// Not defining this behavior through unit tests because the default outcome is
// fine (an exception stating what info is missing), plus we're likely to add support
// for invoking instance methods in the near future.
[Theory]
[InlineData("MethodOnInternalType")]
[InlineData("PrivateMethod")]
[InlineData("ProtectedMethod")]
[InlineData("MethodWithoutAttribute")] // That's not really its identifier; just making the point that there's no way to invoke it
public void CannotInvokeUnsuitableMethods(string methodIdentifier)
{
var ex = Assert.Throws<ArgumentException>(() =>
{
DotNetDispatcher.Invoke(thisAssemblyName, methodIdentifier, null);
});
Assert.Equal($"The assembly '{thisAssemblyName}' does not contain a public method with [JSInvokableAttribute(\"{methodIdentifier}\")].", ex.Message);
}
[Fact]
public void CanInvokeStaticVoidMethod()
{
// Arrange/Act
SomePublicType.DidInvokeMyInvocableVoid = false;
var resultJson = DotNetDispatcher.Invoke(thisAssemblyName, "InvocableStaticVoid", null);
// Assert
Assert.Null(resultJson);
Assert.True(SomePublicType.DidInvokeMyInvocableVoid);
}
[Fact]
public void CanInvokeStaticNonVoidMethod()
{
// Arrange/Act
var resultJson = DotNetDispatcher.Invoke(thisAssemblyName, "InvocableStaticNonVoid", null);
var result = Json.Deserialize<TestDTO>(resultJson);
// Assert
Assert.Equal("Test", result.StringVal);
Assert.Equal(123, result.IntVal);
}
[Fact]
public void CanInvokeStaticWithParams()
{
// Arrange
var argsJson = Json.Serialize(new object[] {
new TestDTO { StringVal = "Another string", IntVal = 456 },
new[] { 100, 200 }
});
// Act
var resultJson = DotNetDispatcher.Invoke(thisAssemblyName, "InvocableStaticWithParams", argsJson);
var result = Json.Deserialize<TestDTO>(resultJson);
// Assert
Assert.Equal("ANOTHER STRING", result.StringVal);
Assert.Equal(756, result.IntVal);
}
[Fact]
public void CannotInvokeWithIncorrectNumberOfParams()
{
// Arrange
var argsJson = Json.Serialize(new object[] { 1, 2, 3, 4 });
// Act/Assert
var ex = Assert.Throws<ArgumentException>(() =>
{
DotNetDispatcher.Invoke(thisAssemblyName, "InvocableStaticWithParams", argsJson);
});
Assert.Equal("In call to 'InvocableStaticWithParams', expected 2 parameters but received 4.", ex.Message);
}
internal class SomeInteralType
{
[JSInvokable("MethodOnInternalType")] public void MyMethod() { }
}
public class SomePublicType
{
public static bool DidInvokeMyInvocableVoid;
[JSInvokable("PrivateMethod")] private void MyPrivateMethod() { }
[JSInvokable("ProtectedMethod")] protected void MyProtectedMethod() { }
protected void MethodWithoutAttribute() { }
[JSInvokable("InvocableStaticVoid")] public static void MyInvocableVoid()
{
DidInvokeMyInvocableVoid = true;
}
[JSInvokable("InvocableStaticNonVoid")]
public static object MyInvocableNonVoid()
=> new TestDTO { StringVal = "Test", IntVal = 123 };
[JSInvokable("InvocableStaticWithParams")]
public static TestDTO MyInvocableWithParams(TestDTO dto, int[] incrementAmounts)
=> new TestDTO { StringVal = dto.StringVal.ToUpperInvariant(), IntVal = dto.IntVal + incrementAmounts.Sum() };
}
public class TestDTO
{
public string StringVal { get; set; }
public int IntVal { get; set; }
}
}
}