public void GetContent_ThrowsArgumentNullExceptionIfSourceIsNull()
        {
            // Arrange
            ContentRetrieverService testSubject = CreateContentRetrieverService();

            // Act and assert
            Assert.Throws <ArgumentNullException>(() => testSubject.GetContent(null));
        }
        public void GetContent_RetrievesContentOnlyOnceAndCachesContentInMemory()
        {
            // Arrange
            var          dummySource                       = new Uri("C:/dummySource");
            var          dummyContent                      = new ReadOnlyCollection <string>(new string[0]);
            const string dummyCacheDirectory               = "dummyCacheDirectory";
            var          dummyCancellationToken            = new CancellationToken();
            Mock <ContentRetrieverService> mockTestSubject = CreateMockContentRetrieverService();

            mockTestSubject.CallBase = true;
            mockTestSubject.Setup(t => t.GetContentCore(dummySource, dummyCacheDirectory, dummyCancellationToken)).
            Callback(() => Thread.Sleep(200)).     // Arbitrary sleep duration
            Returns(dummyContent);
            // Mock<T>.Object isn't thread safe, if multiple threads call it at the same time, multiple instances are instantiated - https://github.com/moq/moq4/blob/9ca16446b9bbfbe12a78b5f8cad8afaa755c13dc/src/Moq/Mock.Generic.cs#L316
            // If multiple instances are instantiated, multiple _cache instances are created and GetContentCore gets called multiple times.
            ContentRetrieverService testSubject = mockTestSubject.Object;

            // Act
            var threads = new List <Thread>();
            var results = new ConcurrentBag <ReadOnlyCollection <string> >();

            for (int i = 0; i < 3; i++) // Arbitrary number of threads
            {
                var thread = new Thread(() => results.Add(testSubject.GetContent(dummySource, dummyCacheDirectory, dummyCancellationToken)));
                thread.Start();
                threads.Add(thread);
            }
            foreach (Thread thread in threads)
            {
                thread.Join();
            }

            // Assert
            mockTestSubject.Verify(t => t.GetContent(dummySource, dummyCacheDirectory, dummyCancellationToken), Times.Exactly(3));
            mockTestSubject.Verify(t => t.GetContentCore(dummySource, dummyCacheDirectory, dummyCancellationToken), Times.Once); // Lazy should prevent GetContentCore from being called multiple times
            ReadOnlyCollection <string>[] resultsArr = results.ToArray();
            Assert.Equal(3, resultsArr.Length);
            Assert.Same(resultsArr[0], dummyContent);
            Assert.Same(resultsArr[0], resultsArr[1]); // Result should get cached after first call
            Assert.Same(resultsArr[1], resultsArr[2]); // Same relation is transitive
        }