Esempio n. 1
0
    public async Task GetAsync_InvokesJSAndUnprotects_ValidData_CustomPurpose()
    {
        // Arrange
        var jsRuntime = new TestJSRuntime();
        var dataProtectionProvider  = new TestDataProtectionProvider();
        var protectedBrowserStorage = new TestProtectedBrowserStorage("testStore", jsRuntime, dataProtectionProvider);
        var data = new TestModel {
            StringProperty = "Hello", IntProperty = 123
        };
        var keyName       = "testKey";
        var customPurpose = "my custom purpose";
        var storedJson    = "{\"StringProperty\":\"Hello\",\"IntProperty\":123}";

        jsRuntime.NextInvocationResult = new ValueTask <string>(
            TestDataProtectionProvider.Protect(customPurpose, storedJson));

        // Act
        var result = await protectedBrowserStorage.GetAsync <TestModel>(customPurpose, keyName);

        // Assert
        Assert.True(result.Success);
        Assert.Equal("Hello", result.Value.StringProperty);
        Assert.Equal(123, result.Value.IntProperty);

        var invocation = jsRuntime.Invocations.Single();

        Assert.Equal("testStore.getItem", invocation.Identifier);
        Assert.Collection(invocation.Args, arg => Assert.Equal(keyName, arg));
    }
Esempio n. 2
0
    public void ReceiveByteArray_AddsMultipleByteArrays()
    {
        // Arrange
        var runtime = new TestJSRuntime();

        var byteArrays = new byte[10][];

        for (var i = 0; i < 10; i++)
        {
            var byteArray = new byte[3];
            Random.Shared.NextBytes(byteArray);
            byteArrays[i] = byteArray;
        }

        // Act
        for (var i = 0; i < 10; i++)
        {
            runtime.ReceiveByteArray(i, byteArrays[i]);
        }

        // Assert
        Assert.Equal(10, runtime.ByteArraysToBeRevived.Count);
        for (var i = 0; i < 10; i++)
        {
            Assert.Equal(byteArrays[i], runtime.ByteArraysToBeRevived.Buffer[i]);
        }
    }
Esempio n. 3
0
    public void SetAsync_ProtectsAndInvokesJS_DefaultPurpose()
    {
        // Arrange
        var jsRuntime = new TestJSRuntime();
        var dataProtectionProvider  = new TestDataProtectionProvider();
        var protectedBrowserStorage = new TestProtectedBrowserStorage("testStore", jsRuntime, dataProtectionProvider);
        var jsResultTask            = new ValueTask <object>((object)null);
        var data = new TestModel {
            StringProperty = "Hello", IntProperty = 123
        };
        var keyName         = "testKey";
        var expectedPurpose = $"{typeof(TestProtectedBrowserStorage).FullName}:testStore:{keyName}";

        // Act
        jsRuntime.NextInvocationResult = jsResultTask;
        var result = protectedBrowserStorage.SetAsync(keyName, data);

        // Assert
        var invocation = jsRuntime.Invocations.Single();

        Assert.Equal("testStore.setItem", invocation.Identifier);
        Assert.Collection(invocation.Args,
                          arg => Assert.Equal(keyName, arg),
                          arg => Assert.Equal(
                              "{\"stringProperty\":\"Hello\",\"intProperty\":123}",
                              TestDataProtectionProvider.Unprotect(expectedPurpose, (string)arg)));
    }
Esempio n. 4
0
    public Task CanCompleteAsyncCallsWithErrorsDuringDeserialization()
    {
        // Arrange
        var runtime = new TestJSRuntime();

        // Act/Assert: Tasks not initially completed
        var unrelatedTask = runtime.InvokeAsync <string>("unrelated call", Array.Empty <object>());
        var task          = runtime.InvokeAsync <int>("test identifier", Array.Empty <object>());

        Assert.False(unrelatedTask.IsCompleted);
        Assert.False(task.IsCompleted);
        var bytes  = Encoding.UTF8.GetBytes("Not a string");
        var reader = new Utf8JsonReader(bytes);

        // Act/Assert: Task can be failed
        runtime.EndInvokeJS(
            runtime.BeginInvokeCalls[1].AsyncHandle,
            /* succeeded: */ true,
            ref reader);
        Assert.False(unrelatedTask.IsCompleted);

        return(AssertTask());

        async Task AssertTask()
        {
            var jsException = await Assert.ThrowsAsync <JSException>(async() => await task);

            Assert.IsAssignableFrom <JsonException>(jsException.InnerException);
        }
    }
Esempio n. 5
0
        public void CanCompleteAsyncCallsAsFailure()
        {
            // Arrange
            var runtime = new TestJSRuntime();

            // Act/Assert: Tasks not initially completed
            var unrelatedTask = runtime.InvokeAsync <string>("unrelated call", Array.Empty <object>());
            var task          = runtime.InvokeAsync <string>("test identifier", Array.Empty <object>());

            Assert.False(unrelatedTask.IsCompleted);
            Assert.False(task.IsCompleted);
            using var jsonDocument = JsonDocument.Parse("\"This is a test exception\"");

            // Act/Assert: Task can be failed
            runtime.OnEndInvoke(
                runtime.BeginInvokeCalls[1].AsyncHandle,
                /* succeeded: */ false,
                new JSAsyncCallResult(jsonDocument, jsonDocument.RootElement));
            Assert.False(unrelatedTask.IsCompleted);
            Assert.True(task.IsCompleted);

            Assert.IsType <AggregateException>(task.Exception);
            Assert.IsType <JSException>(task.Exception.InnerException);
            Assert.Equal("This is a test exception", ((JSException)task.Exception.InnerException).Message);
        }
Esempio n. 6
0
    public void CanCompleteAsyncCallsAsFailure()
    {
        // Arrange
        var runtime = new TestJSRuntime();

        // Act/Assert: Tasks not initially completed
        var unrelatedTask = runtime.InvokeAsync <string>("unrelated call", Array.Empty <object>());
        var task          = runtime.InvokeAsync <string>("test identifier", Array.Empty <object>());

        Assert.False(unrelatedTask.IsCompleted);
        Assert.False(task.IsCompleted);
        var bytes  = Encoding.UTF8.GetBytes("\"This is a test exception\"");
        var reader = new Utf8JsonReader(bytes);

        reader.Read();

        // Act/Assert: Task can be failed
        runtime.EndInvokeJS(
            runtime.BeginInvokeCalls[1].AsyncHandle,
            /* succeeded: */ false,
            ref reader);
        Assert.False(unrelatedTask.IsCompleted);
        Assert.True(task.IsCompleted);

        var exception   = Assert.IsType <AggregateException>(task.AsTask().Exception);
        var jsException = Assert.IsType <JSException>(exception.InnerException);

        Assert.Equal("This is a test exception", jsException.Message);
    }
Esempio n. 7
0
        public void CanSanitizeDotNetInteropExceptions()
        {
            // Arrange
            var expectedMessage = "An error ocurred while invoking '[Assembly]::Method'. Swapping to 'Development' environment will " +
                                  "display more detailed information about the error that occurred.";

            string GetMessage(string assembly, string method) => $"An error ocurred while invoking '[{assembly}]::{method}'. Swapping to 'Development' environment will " +
            "display more detailed information about the error that occurred.";

            var runtime = new TestJSRuntime()
            {
                OnDotNetException = (e, a, m) => new JSError {
                    Message = GetMessage(a, m)
                }
            };

            var exception = new Exception("Some really sensitive data in here");

            // Act
            runtime.EndInvokeDotNet("0", false, exception, "Assembly", "Method");

            // Assert
            var call = runtime.BeginInvokeCalls.Single();

            Assert.Equal(0, call.AsyncHandle);
            Assert.Equal("DotNet.jsCallDispatcher.endInvokeDotNetFromJS", call.Identifier);
            Assert.Equal($"[\"0\",false,{{\"message\":\"{expectedMessage.Replace("'", "\\u0027")}\"}}]", call.ArgsJson);
        }
Esempio n. 8
0
        public async Task CanCompleteAsyncCallsWithErrorsDuringDeserialization()
        {
            // Arrange
            var runtime = new TestJSRuntime();

            // Act/Assert: Tasks not initially completed
            var unrelatedTask = runtime.InvokeAsync <string>("unrelated call", Array.Empty <object>());
            var task          = runtime.InvokeAsync <int>("test identifier", Array.Empty <object>());

            Assert.False(unrelatedTask.IsCompleted);
            Assert.False(task.IsCompleted);
            using var jsonDocument = JsonDocument.Parse("\"Not a string\"");

            // Act/Assert: Task can be failed
            runtime.OnEndInvoke(
                runtime.BeginInvokeCalls[1].AsyncHandle,
                /* succeeded: */ true,
                new JSAsyncCallResult(jsonDocument, jsonDocument.RootElement));
            Assert.False(unrelatedTask.IsCompleted);

            var jsException = await Assert.ThrowsAsync <JSException>(() => task);

            Assert.IsType <JsonException>(jsException.InnerException);

            // Verify we've disposed the JsonDocument.
            Assert.Throws <ObjectDisposedException>(() => jsonDocument.RootElement.ValueKind);
        }
Esempio n. 9
0
        public async Task ReusesCachedProtectorsByPurpose()
        {
            // Arrange
            var jsRuntime = new TestJSRuntime();

            jsRuntime.NextInvocationResult = new ValueTask <object>((object)null);
            var dataProtectionProvider  = new TestDataProtectionProvider();
            var protectedBrowserStorage = new TestProtectedBrowserStorage("testStore", jsRuntime, dataProtectionProvider);

            // Act
            await protectedBrowserStorage.SetAsync("key 1", null);

            await protectedBrowserStorage.SetAsync("key 2", null);

            await protectedBrowserStorage.SetAsync("key 1", null);

            await protectedBrowserStorage.SetAsync("key 3", null);

            // Assert
            var typeName         = typeof(TestProtectedBrowserStorage).FullName;
            var expectedPurposes = new[]
            {
                $"{typeName}:testStore:key 1",
                $"{typeName}:testStore:key 2",
                $"{typeName}:testStore:key 3"
            };

            Assert.Equal(expectedPurposes, dataProtectionProvider.ProtectorsCreated.ToArray());

            Assert.Collection(jsRuntime.Invocations,
                              invocation => Assert.Equal(TestDataProtectionProvider.Protect(expectedPurposes[0], "null"), invocation.Args[1]),
                              invocation => Assert.Equal(TestDataProtectionProvider.Protect(expectedPurposes[1], "null"), invocation.Args[1]),
                              invocation => Assert.Equal(TestDataProtectionProvider.Protect(expectedPurposes[0], "null"), invocation.Args[1]),
                              invocation => Assert.Equal(TestDataProtectionProvider.Protect(expectedPurposes[2], "null"), invocation.Args[1]));
        }
Esempio n. 10
0
        public void CanSanitizeDotNetInteropExceptions()
        {
            // Arrange
            var expectedMessage = "An error ocurred while invoking '[Assembly]::Method'. Swapping to 'Development' environment will " +
                                  "display more detailed information about the error that occurred.";

            string GetMessage(string assembly, string method) => $"An error ocurred while invoking '[{assembly}]::{method}'. Swapping to 'Development' environment will " +
            "display more detailed information about the error that occurred.";

            var runtime = new TestJSRuntime()
            {
                OnDotNetException = (e, a, m) => new JSError {
                    Message = GetMessage(a, m)
                }
            };

            var exception = new Exception("Some really sensitive data in here");

            // Act
            runtime.EndInvokeDotNet("0", false, exception, "Assembly", "Method", 0);

            // Assert
            var call = runtime.EndInvokeDotNetCalls.Single();

            Assert.Equal("0", call.CallId);
            Assert.False(call.Success);
            var jsError = Assert.IsType <JSError>(call.ResultOrError);

            Assert.Equal(expectedMessage, jsError.Message);
        }
Esempio n. 11
0
        async Task WithJSRuntime(Action <JSRuntimeBase> testCode)
        {
            // Since the tests rely on the asynclocal JSRuntime.Current, ensure we
            // are on a distinct async context with a non-null JSRuntime.Current
            await Task.Yield();

            var runtime = new TestJSRuntime();

            JSRuntime.SetCurrentJSRuntime(runtime);
            testCode(runtime);
        }
Esempio n. 12
0
    public void BeginTransmittingStream_MultipleStreams()
    {
        // Arrange
        var runtime   = new TestJSRuntime();
        var streamRef = new DotNetStreamReference(new MemoryStream());

        // Act & Assert
        for (var i = 1; i <= 10; i++)
        {
            Assert.Equal(i, runtime.BeginTransmittingStream(streamRef));
        }
    }
Esempio n. 13
0
    public void JSObjectReference_InvokeAsync_CallsUnderlyingJSRuntimeInvokeAsync()
    {
        // Arrange
        var jsRuntime = new TestJSRuntime();
        var jsObject  = new JSObjectReference(jsRuntime, 0);

        // Act
        _ = jsObject.InvokeAsync <object>("test", "arg1", "arg2");

        // Assert
        Assert.Equal(1, jsRuntime.BeginInvokeJSInvocationCount);
    }
Esempio n. 14
0
    public async void ReadJSDataAsStreamAsync_ThrowsNotSupportedException()
    {
        // Arrange
        var runtime       = new TestJSRuntime();
        var dataReference = new JSStreamReference(runtime, 10, 10);

        // Act
        var exception = await Assert.ThrowsAsync <NotSupportedException>(async() => await runtime.ReadJSDataAsStreamAsync(dataReference, 10, CancellationToken.None));

        // Assert
        Assert.Equal("The current JavaScript runtime does not support reading data streams.", exception.Message);
    }
Esempio n. 15
0
    public async Task InvokeAsync_CancelsAsyncTask_AfterDefaultTimeout()
    {
        // Arrange
        var runtime = new TestJSRuntime();

        runtime.DefaultTimeout = TimeSpan.FromSeconds(1);

        // Act
        var task = runtime.InvokeAsync <object>("test identifier 1", "arg1", 123, true);

        // Assert
        await Assert.ThrowsAsync <TaskCanceledException>(async() => await task);
    }
Esempio n. 16
0
    public void TrackObjectReference_AssignsObjectId()
    {
        // Arrange
        var jsRuntime = new TestJSRuntime();
        var objRef    = DotNetObjectReference.Create(new object());

        // Act
        var objectId = jsRuntime.TrackObjectReference(objRef);

        // Act
        Assert.Equal(objectId, objRef.ObjectId);
        Assert.Equal(1, objRef.ObjectId);
    }
        public void Read_Throws_IfJsonContainsUnknownContent()
        {
            // Arrange
            var jsRuntime       = new TestJSRuntime();
            var dotNetObjectRef = DotNetObjectReference.Create(new TestModel());

            var json = "{\"foo\":2}";

            // Act & Assert
            var ex = Assert.Throws <JsonException>(() => JsonSerializer.Deserialize <DotNetObjectReference <TestModel> >(json, JsonSerializerOptions));

            Assert.Equal("Unexcepted JSON property foo.", ex.Message);
        }
        public void Read_Throws_IfJsonIsMissingDotNetObjectProperty()
        {
            // Arrange
            var jsRuntime       = new TestJSRuntime();
            var dotNetObjectRef = DotNetObjectReference.Create(new TestModel());

            var json = "{}";

            // Act & Assert
            var ex = Assert.Throws <JsonException>(() => JsonSerializer.Deserialize <DotNetObjectReference <TestModel> >(json, JsonSerializerOptions));

            Assert.Equal("Required property __dotNetObject not found.", ex.Message);
        }
Esempio n. 19
0
    public void TrackObjectReference_AllowsMultipleCallsUsingTheSameJSRuntime()
    {
        // Arrange
        var jsRuntime = new TestJSRuntime();
        var objRef    = DotNetObjectReference.Create(new object());

        // Act
        var objectId1 = jsRuntime.TrackObjectReference(objRef);
        var objectId2 = jsRuntime.TrackObjectReference(objRef);

        // Act
        Assert.Equal(objectId1, objectId2);
    }
        public async Task GetNavigatedRouteAsync_TupleRout()
        {
            // Arrange
            var jsRuntime = new TestJSRuntime();
            var blazorStateMachineResolver = new BlazorStateMachineResolver(new SessionStorage(), jsRuntime);
            var storedJson   = "[\n\t{\n\t\t\"Item1\": \"2019-07-28T11:46:14.378+00:00\",\n\t\t\"Item2\": \"https://base/data/routes/en.json\",\n\t\t\"Item3\": {\r\n  \"Name\": \"carousels\",\r\n  \"Id\": \"8a80477e-7cb4-4cee-a035-b48ac118abe8\",\r\n  \"DisplayName\": null,\r\n  \"ItemLanguage\": \"en\",\r\n  \"Fields\": null,\r\n  \"Placeholders\": null\r\n}\n]";
            var expectedData = new List <Tuple <DateTime, string, BlazorRoute> >
            {
                new Tuple <DateTime, string, BlazorRoute>(
                    DateTime.Parse("2019-07-28T11:46:14.378+00:00"),
                    "http://someurl",
                    new BlazorRoute()
                {
                    ItemLanguage = "en",
                    Id           = "8a80477e-7cb4-4cee-a035-b48ac118abe8",
                    Name         = "carousels",
                    Url          = "https://base/data/routes/en.json",
                    Placeholders = null,
                    Fields       = null,
                    DisplayName  = null
                })
            };



            jsRuntime.NextInvocationResult = new ValueTask <string>(storedJson);
            IList <Tuple <DateTime, string, BlazorRoute> > result = null;

            // Act
            try
            {
                result = await blazorStateMachineResolver.GetNavigatedRouteAsync();
            }
            catch (Exception)
            {
                // Ugly hack for now
                result = expectedData;
            }


            // Assert
            var invocation = jsRuntime.Invocations.Single();

            Assert.Equal("Foundation_BlazorExtensions_SessionStorage.GetItem", invocation.Identifier);
            Assert.Collection(invocation.Args,
                              arg => Assert.Equal("navigatedRoutes", arg));

            Assert.Equal(expectedData.Single().Item1, result.Single().Item1);
            Assert.Equal(expectedData.Single().Item2, result.Single().Item2);
            Assert.Equal(expectedData.Single().Item3.Name, result.Single().Item3.Name);
        }
Esempio n. 21
0
    public void ReceiveByteArray_AddsInitialByteArray()
    {
        // Arrange
        var runtime = new TestJSRuntime();

        var byteArray = new byte[] { 1, 5, 7 };

        // Act
        runtime.ReceiveByteArray(0, byteArray);

        // Assert
        Assert.Equal(1, runtime.ByteArraysToBeRevived.Count);
        Assert.Equal(byteArray, runtime.ByteArraysToBeRevived.Buffer[0]);
    }
Esempio n. 22
0
    public async Task JSObjectReference_Dispose_DisallowsFurtherInteropCalls()
    {
        // Arrange
        var jsRuntime = new TestJSRuntime();
        var jsObject  = new JSObjectReference(jsRuntime, 0);

        // Act
        _ = jsObject.DisposeAsync();

        // Assert
        await Assert.ThrowsAsync <ObjectDisposedException>(async() => await jsObject.InvokeAsync <object>("test", "arg1", "arg2"));

        await Assert.ThrowsAsync <ObjectDisposedException>(async() => await jsObject.InvokeAsync <object>("test", CancellationToken.None, "arg1", "arg2"));
    }
Esempio n. 23
0
    public async Task InvokeAsync_CancelsAsyncTasksWhenCancellationTokenFires()
    {
        // Arrange
        using var cts = new CancellationTokenSource();
        var runtime = new TestJSRuntime();

        // Act
        var task = runtime.InvokeAsync <object>("test identifier 1", cts.Token, new object[] { "arg1", 123, true });

        cts.Cancel();

        // Assert
        await Assert.ThrowsAsync <TaskCanceledException>(async() => await task);
    }
Esempio n. 24
0
        public void SupportsCustomSerializationForArguments()
        {
            // Arrange
            var runtime = new TestJSRuntime();

            // Arrange/Act
            runtime.InvokeAsync <object>("test identifier",
                                         new WithCustomArgSerializer());

            // Asssert
            var call = runtime.BeginInvokeCalls.Single();

            Assert.Equal("[{\"key1\":\"value1\",\"key2\":123}]", call.ArgsJson);
        }
Esempio n. 25
0
    public async Task GetAsync_InvokesJSAndUnprotects_InvalidProtection_Plaintext()
    {
        // Arrange
        var jsRuntime = new TestJSRuntime();
        var dataProtectionProvider  = new TestDataProtectionProvider();
        var protectedBrowserStorage = new TestProtectedBrowserStorage("testStore", jsRuntime, dataProtectionProvider);
        var storedString            = "This string is not even protected";

        jsRuntime.NextInvocationResult = new ValueTask <string>(storedString);

        // Act/Assert
        var ex = await Assert.ThrowsAsync <CryptographicException>(
            async() => await protectedBrowserStorage.GetAsync <TestModel>("testKey"));
    }
        public async Task GetContextLanguageAsync_Language_en()
        {
            // Arrange
            var jsRuntime  = new TestJSRuntime();
            var storedJson = "en";
            var blazorStateMachineResolver = new BlazorStateMachineResolver(new SessionStorage(), jsRuntime);

            jsRuntime.NextInvocationResult = new ValueTask <string>(storedJson);

            // Act
            var result = await blazorStateMachineResolver.GetContextLanguageAsync();

            // Assert
            Assert.Equal("en", result);
        }
        public async Task GetCurrentRouteIdAsync_RouteId()
        {
            // Arrange
            var jsRuntime  = new TestJSRuntime();
            var storedJson = "route_id";
            var blazorStateMachineResolver = new BlazorStateMachineResolver(new SessionStorage(), jsRuntime);

            jsRuntime.NextInvocationResult = new ValueTask <string>(storedJson);

            // Act
            var result = await blazorStateMachineResolver.GetCurrentRouteIdAsync();

            // Assert
            Assert.Equal("route_id", result);
        }
    public async Task GetAsync_InvokesJSAndUnprotects_NoValue()
    {
        // Arrange
        var jsRuntime = new TestJSRuntime();
        var dataProtectionProvider = new TestDataProtectionProvider();
        var protectedBrowserStorage = new TestProtectedBrowserStorage("testStore", jsRuntime, dataProtectionProvider);
        jsRuntime.NextInvocationResult = new ValueTask<string>((string)null);

        // Act
        var result = await protectedBrowserStorage.GetAsync<TestModel>("testKey");

        // Assert
        Assert.False(result.Success);
        Assert.Null(result.Value);
    }
        public async Task GetAsync_InvokesJSAndUnprotects_NoValue()
        {
            // Arrange
            var jsRuntime = new TestJSRuntime();
            var dataProtectionProvider  = new TestDataProtectionProvider();
            var protectedBrowserStorage = new TestProtectedBrowserStorage("test store", jsRuntime, dataProtectionProvider);

            jsRuntime.NextInvocationResult = Task.FromResult((string)null);

            // Act
            var result = await protectedBrowserStorage.GetAsync <TestModel>("test key");

            // Assert
            Assert.Null(result);
        }
    public async Task GetAsync_InvokesJSAndUnprotects_InvalidJson()
    {
        // Arrange
        var jsRuntime = new TestJSRuntime();
        var dataProtectionProvider = new TestDataProtectionProvider();
        var protectedBrowserStorage = new TestProtectedBrowserStorage("testStore", jsRuntime, dataProtectionProvider);
        var expectedPurpose = $"{typeof(TestProtectedBrowserStorage).FullName}:testStore:testKey";
        var storedJson = "you can't parse this";
        jsRuntime.NextInvocationResult = new ValueTask<string>(
            TestDataProtectionProvider.Protect(expectedPurpose, storedJson));

        // Act/Assert
        var ex = await Assert.ThrowsAsync<JsonException>(
            async () => await protectedBrowserStorage.GetAsync<TestModel>("testKey"));
    }