using System; using Microsoft.Extensions.Caching.Hybrid; using Moq; using NUnit.Framework; using Umbraco.Cms.Infrastructure.HybridCache; using Umbraco.Cms.Infrastructure.HybridCache.Extensions; namespace Umbraco.Cms.Tests.UnitTests.Umbraco.PublishedCache.HybridCache.Extensions; /// /// Provides tests to cover the class. /// /// /// Hat-tip: https://github.com/dotnet/aspnetcore/discussions/57191 /// [TestFixture] public class HybridCacheExtensionsTests { private Mock _cacheMock; [SetUp] public void TestInitialize() { _cacheMock = new Mock(); } [Test] public async Task ExistsAsync_WhenKeyExists_ShouldReturnTrue() { // Arrange string key = "test-key"; var expectedValue = new ContentCacheNode { Id = 1234 }; _cacheMock .Setup(cache => cache.GetOrCreateAsync( key, It.IsAny>>(), It.IsAny>, CancellationToken, ValueTask>>(), It.IsAny(), null, CancellationToken.None)) .ReturnsAsync(expectedValue); // Act var exists = await HybridCacheExtensions.ExistsAsync(_cacheMock.Object, key, CancellationToken.None); // Assert Assert.IsTrue(exists); } [Test] public async Task ExistsAsync_WhenKeyDoesNotExist_ShouldReturnFalse() { // Arrange string key = "test-key"; _cacheMock .Setup(cache => cache.GetOrCreateAsync( key, It.IsAny>>(), It.IsAny>, CancellationToken, ValueTask>>(), It.IsAny(), null, CancellationToken.None)) .Returns(( string key, Func> state, Func>, CancellationToken, ValueTask> factory, HybridCacheEntryOptions? options, IEnumerable? tags, CancellationToken token) => { return factory(state, token); }); // Act var exists = await HybridCacheExtensions.ExistsAsync(_cacheMock.Object, key, CancellationToken.None); // Assert Assert.IsFalse(exists); } [Test] public async Task TryGetValueAsync_WhenKeyExists_ShouldReturnTrueAndValueAsString() { // Arrange string key = "test-key"; var expectedValue = "test-value"; _cacheMock .Setup(cache => cache.GetOrCreateAsync( key, It.IsAny>>(), It.IsAny>, CancellationToken, ValueTask>>(), It.IsAny(), null, CancellationToken.None)) .ReturnsAsync(expectedValue); // Act var (exists, value) = await HybridCacheExtensions.TryGetValueAsync(_cacheMock.Object, key, CancellationToken.None); // Assert Assert.IsTrue(exists); Assert.AreEqual(expectedValue, value); } [Test] public async Task TryGetValueAsync_WhenKeyExists_ShouldReturnTrueAndValueAsInteger() { // Arrange string key = "test-key"; var expectedValue = 5; _cacheMock .Setup(cache => cache.GetOrCreateAsync( key, It.IsAny>>(), It.IsAny>, CancellationToken, ValueTask>>(), It.IsAny(), null, CancellationToken.None)) .ReturnsAsync(expectedValue); // Act var (exists, value) = await HybridCacheExtensions.TryGetValueAsync(_cacheMock.Object, key, CancellationToken.None); // Assert Assert.IsTrue(exists); Assert.AreEqual(expectedValue, value); } [Test] public async Task TryGetValueAsync_WhenKeyExistsButValueIsNull_ShouldReturnTrueAndNullValue() { // Arrange string key = "test-key"; _cacheMock .Setup(cache => cache.GetOrCreateAsync( key, It.IsAny>>(), It.IsAny>, CancellationToken, ValueTask>>(), It.IsAny(), null, CancellationToken.None)) .ReturnsAsync(null!); // Act var (exists, value) = await HybridCacheExtensions.TryGetValueAsync(_cacheMock.Object, key, CancellationToken.None); // Assert Assert.IsTrue(exists); Assert.IsNull(value); } [Test] public async Task TryGetValueAsync_WhenKeyDoesNotExist_ShouldReturnFalseAndNull() { // Arrange string key = "test-key"; _cacheMock.Setup(cache => cache.GetOrCreateAsync( key, It.IsAny>>(), It.IsAny>, CancellationToken, ValueTask>>(), It.IsAny(), null, CancellationToken.None)) .Returns(( string key, Func> state, Func>, CancellationToken, ValueTask> factory, HybridCacheEntryOptions? options, IEnumerable? tags, CancellationToken token) => { return factory(state, token); }); // Act var (exists, value) = await HybridCacheExtensions.TryGetValueAsync(_cacheMock.Object, key, CancellationToken.None); // Assert Assert.IsFalse(exists); Assert.IsNull(value); } }