public async Task Refresh_ShouldSynchronizeVpns(int[] initialIds, int[] fromDriverIds, int[] expectedIds)
        {
            // ARRANGE
            var driver = Substitute.For <IVpnEnumeratorDriver>();

            driver.GetVpns().Returns(
                Task.FromResult(
                    fromDriverIds
                    .Select(i => new Vpn($"ID{i}", $"VPN{i}"))
                    .ToArray()));

            var sut = new VpnEnumerator(driver);

            sut.Vpns.AddRange(initialIds
                              .Select(i => new Vpn($"ID{i}", $"VPN{i}")));

            var expected = expectedIds
                           .Select(i => new Vpn($"ID{i}", $"VPN{i}"))
                           .ToList();

            // ACT
            await sut.Refresh();

            // ASSERT
            sut.Vpns.Should().BeEquivalentTo(expected);
        }
        public async Task Refresh_ShouldNotRaiseEvents_WhenNothingChanged()
        {
            // ARRANGE
            var driver = Substitute.For <IVpnEnumeratorDriver>();

            driver.GetVpns().Returns(Task.FromResult(new[]
            {
                new Vpn("ID1", "VPN1"),
                new Vpn("ID2", "VPN2"),
                new Vpn("ID3", "VPN3"),
                new Vpn("ID4", "VPN4")
            }));

            var sut = new VpnEnumerator(driver)
            {
                Vpns =
                {
                    new Vpn("ID1", "VPN1"),
                    new Vpn("ID2", "VPN2"),
                    new Vpn("ID3", "VPN3"),
                    new Vpn("ID4", "VPN4")
                }
            };

            using (var monitor = sut.Monitor())
            {
                // ACT
                await sut.Refresh();

                // ASSERT
                monitor.Should().NotRaise(nameof(VpnEnumerator.Added));
                monitor.Should().NotRaise(nameof(VpnEnumerator.Removed));
                monitor.Should().NotRaise(nameof(VpnEnumerator.Error));
            }
        }
        public async Task Refresh_ShouldRaiseErrorEvent_WhenDriverThrowsException()
        {
            // ARRANGE
            var driver = Substitute.For <IVpnEnumeratorDriver>();

            var exception = new Exception("IVpnEnumeratorDriver Exception");

            driver.GetVpns().Throws(exception);

            var sut = new VpnEnumerator(driver);

            using (var monitor = sut.Monitor())
            {
                // ACT
                await sut.Refresh();

                // ASSERT
                monitor.Should().Raise(nameof(VpnEnumerator.Error))
                .WithSender(sut)
                .WithArgs <ErrorEventArgs>(e => e.GetException().IsSameOrEqualTo(exception));

                monitor.Should().NotRaise(nameof(VpnEnumerator.Added));
                monitor.Should().NotRaise(nameof(VpnEnumerator.Removed));
            }
        }
        public async Task Refresh_ShouldCallDriverGetVpns()
        {
            // ARRANGE
            var driver = Substitute.For <IVpnEnumeratorDriver>();

            var sut = new VpnEnumerator(driver);

            // ACT
            await sut.Refresh();

            // ASSERT
            await driver.Received(1).GetVpns();
        }
        public async Task Refresh_ShouldRaiseAddedAndRemovedEvents_WhenSomeVpnsAppearAndSomeDisappear()
        {
            // ARRANGE
            var driver = Substitute.For <IVpnEnumeratorDriver>();

            driver.GetVpns().Returns(Task.FromResult(new[]
            {
                new Vpn("ID3", "VPN3"),
                new Vpn("ID4", "VPN4"),
                new Vpn("ID5", "VPN5"),
                new Vpn("ID6", "VPN6")
            }));

            var sut = new VpnEnumerator(driver)
            {
                Vpns =
                {
                    new Vpn("ID1", "VPN1"),
                    new Vpn("ID2", "VPN2"),
                    new Vpn("ID3", "VPN3"),
                    new Vpn("ID4", "VPN4")
                }
            };

            using (var monitor = sut.Monitor())
            {
                // ACT
                await sut.Refresh();

                // ASSERT
                monitor.Should().Raise(nameof(VpnEnumerator.Added))
                .WithSender(sut)
                .WithArgs <VpnEventArgs>(e => e.Vpn.Id == "ID5" && e.Vpn.Name == "VPN5");
                monitor.Should().Raise(nameof(VpnEnumerator.Added))
                .WithSender(sut)
                .WithArgs <VpnEventArgs>(e => e.Vpn.Id == "ID6" && e.Vpn.Name == "VPN6");

                monitor.Should().Raise(nameof(VpnEnumerator.Removed))
                .WithSender(sut)
                .WithArgs <VpnEventArgs>(e => e.Vpn.Id == "ID1" && e.Vpn.Name == "VPN1");
                monitor.Should().Raise(nameof(VpnEnumerator.Removed))
                .WithSender(sut)
                .WithArgs <VpnEventArgs>(e => e.Vpn.Id == "ID2" && e.Vpn.Name == "VPN2");

                monitor.Should().NotRaise(nameof(VpnEnumerator.Error));
            }
        }
        public async Task Refresh_ShouldRaiseErrorEvent_WhenDriverReturnsNull()
        {
            // ARRANGE
            var driver = Substitute.For <IVpnEnumeratorDriver>();

            driver.GetVpns().Returns(Task.FromResult <Vpn[]>(null));

            var sut = new VpnEnumerator(driver);

            using (var monitor = sut.Monitor())
            {
                // ACT
                await sut.Refresh();

                // ASSERT
                monitor.Should().Raise(nameof(VpnEnumerator.Error))
                .WithSender(sut);

                monitor.Should().NotRaise(nameof(VpnEnumerator.Added));
                monitor.Should().NotRaise(nameof(VpnEnumerator.Removed));
            }
        }