public void UpdateStatusWhenOperationFails(
            [Values(true, false)] bool async,
            [Values(true, false)] bool useDefaultException)
        {
            RequestFailedException originalException = new RequestFailedException("");
            MockResponse           mockResponse      = new MockResponse(200);
            TestOperation          testOperation     = new TestOperation()
            {
                OnUpdateState = _ => useDefaultException
                    ? OperationState <int> .Failure(mockResponse)
                    : OperationState <int> .Failure(mockResponse, originalException)
            };
            MockOperationInternal <int> operationInternal = testOperation.MockOperationInternal;

            RequestFailedException thrownException = async
                ? Assert.ThrowsAsync <RequestFailedException>(async() => await operationInternal.UpdateStatusAsync(CancellationToken.None))
                : Assert.Throws <RequestFailedException>(() => operationInternal.UpdateStatus(CancellationToken.None));

            if (!useDefaultException)
            {
                Assert.AreEqual(originalException, thrownException);
            }

            Assert.AreEqual(mockResponse, operationInternal.RawResponse);
            Assert.True(operationInternal.HasCompleted);
            Assert.False(operationInternal.HasValue);

            RequestFailedException valueException = Assert.Throws <RequestFailedException>(() => _ = operationInternal.Value);

            Assert.AreEqual(thrownException, valueException);
        }
        public async Task UpdateStatusSetsFailedScopeWhenOperationFails(bool async)
        {
            using ClientDiagnosticListener testListener = new ClientDiagnosticListener(DiagnosticNamespace);

            RequestFailedException originalException = new RequestFailedException("");
            MockResponse           mockResponse      = new MockResponse(200);
            TestOperation          testOperation     = new TestOperation()
            {
                OnUpdateState = _ => OperationState <int> .Failure(mockResponse, originalException)
            };
            MockOperationInternal <int> operationInternal = testOperation.MockOperationInternal;

            try
            {
                _ = async
                    ? await operationInternal.UpdateStatusAsync(CancellationToken.None)
                    : operationInternal.UpdateStatus(CancellationToken.None);
            }
            catch { }

            testListener.AssertScopeException($"{nameof(TestOperation)}.UpdateStatus", (Exception scopeException) =>
            {
                Assert.AreEqual(originalException, scopeException);
            });
        }
        public async Task UpdateStatusCreatesDiagnosticScope(
            [Values(true, false)] bool async,
            [Values(true, false)] bool useDefaultTypeName)
        {
            const string customTypeName = "CustomTypeName";

            using ClientDiagnosticListener testListener = new ClientDiagnosticListener(DiagnosticNamespace);

            string expectedTypeName = useDefaultTypeName ? nameof(TestOperation) : customTypeName;

            KeyValuePair <string, string>[] expectedAttributes = new KeyValuePair <string, string>[]
            {
                new KeyValuePair <string, string>("key1", "value1"),
                new KeyValuePair <string, string>("key2", "value2")
            };

            MockResponse  mockResponse  = new MockResponse(200);
            TestOperation testOperation = new TestOperation(operationTypeName: useDefaultTypeName ? null : customTypeName, scopeAttributes: expectedAttributes)
            {
                OnUpdateState = _ => OperationState <int> .Pending(mockResponse)
            };
            MockOperationInternal <int> operationInternal = testOperation.MockOperationInternal;

            _ = async
                ? await operationInternal.UpdateStatusAsync(CancellationToken.None)
                : operationInternal.UpdateStatus(CancellationToken.None);

            testListener.AssertScope($"{expectedTypeName}.UpdateStatus", expectedAttributes);
        }
        public async Task UpdateStatusWhenOperationIsPending(bool async)
        {
            MockResponse  mockResponse  = new MockResponse(200);
            TestOperation testOperation = new TestOperation()
            {
                OnUpdateState = _ => OperationState <int> .Pending(mockResponse)
            };
            MockOperationInternal <int> operationInternal = testOperation.MockOperationInternal;

            Response operationResponse = async
                ? await operationInternal.UpdateStatusAsync(CancellationToken.None)
                : operationInternal.UpdateStatus(CancellationToken.None);

            Assert.AreEqual(mockResponse, operationResponse);

            Assert.AreEqual(mockResponse, operationInternal.RawResponse);
            Assert.False(operationInternal.HasCompleted);
            Assert.False(operationInternal.HasValue);
            Assert.Throws <InvalidOperationException>(() => _ = operationInternal.Value);
        }
        public void UpdateStatusWhenOperationThrows(bool async)
        {
            StackOverflowException originalException = new StackOverflowException();
            TestOperation          testOperation     = new TestOperation()
            {
                OnUpdateState = _ => throw originalException
            };
            MockOperationInternal <int> operationInternal = testOperation.MockOperationInternal;

            StackOverflowException thrownException = async
                ? Assert.ThrowsAsync <StackOverflowException>(async() => await operationInternal.UpdateStatusAsync(CancellationToken.None))
                : Assert.Throws <StackOverflowException>(() => operationInternal.UpdateStatus(CancellationToken.None));

            Assert.AreEqual(originalException, thrownException);

            Assert.IsNull(operationInternal.RawResponse);
            Assert.False(operationInternal.HasCompleted);
            Assert.False(operationInternal.HasValue);
            Assert.Throws <InvalidOperationException>(() => _ = operationInternal.Value);
        }
        public async Task UpdateStatusWhenOperationSucceeds(bool async)
        {
            int           expectedValue = 50;
            MockResponse  mockResponse  = new MockResponse(200);
            TestOperation testOperation = new TestOperation()
            {
                OnUpdateState = _ => OperationState <int> .Success(mockResponse, expectedValue)
            };
            MockOperationInternal <int> operationInternal = testOperation.MockOperationInternal;

            Response operationResponse = async
                ? await operationInternal.UpdateStatusAsync(CancellationToken.None)
                : operationInternal.UpdateStatus(CancellationToken.None);

            Assert.AreEqual(mockResponse, operationResponse);

            Assert.AreEqual(mockResponse, operationInternal.RawResponse);
            Assert.True(operationInternal.HasCompleted);
            Assert.True(operationInternal.HasValue);
            Assert.AreEqual(expectedValue, operationInternal.Value);
        }
        public async Task UpdateStatusSetsFailedScopeWhenOperationThrows(bool async)
        {
            using ClientDiagnosticListener testListener = new ClientDiagnosticListener(DiagnosticNamespace);

            StackOverflowException originalException = new StackOverflowException();
            TestOperation          testOperation     = new TestOperation()
            {
                OnUpdateState = _ => throw originalException
            };
            MockOperationInternal <int> operationInternal = testOperation.MockOperationInternal;

            try
            {
                _ = async
                    ? await operationInternal.UpdateStatusAsync(CancellationToken.None)
                    : operationInternal.UpdateStatus(CancellationToken.None);
            }
            catch { }

            testListener.AssertScopeException($"{nameof(TestOperation)}.UpdateStatus", (Exception scopeException) =>
                                              Assert.AreEqual(originalException, scopeException));
        }
        public async Task UpdateStatusPassesTheCancellationTokenToUpdateState(bool async)
        {
            using CancellationTokenSource tokenSource = new CancellationTokenSource();
            CancellationToken originalToken = tokenSource.Token;
            CancellationToken passedToken   = default;

            MockResponse  mockResponse  = new MockResponse(200);
            TestOperation testOperation = new TestOperation()
            {
                OnUpdateState = cancellationToken =>
                {
                    passedToken = cancellationToken;
                    return(OperationState <int> .Pending(mockResponse));
                }
            };
            MockOperationInternal <int> operationInternal = testOperation.MockOperationInternal;

            _ = async
                ? await operationInternal.UpdateStatusAsync(originalToken)
                : operationInternal.UpdateStatus(originalToken);

            Assert.AreEqual(originalToken, passedToken);
        }