// Copyright (c) Umbraco. // See LICENSE for more details. using Microsoft.Extensions.Logging; using Moq; using NUnit.Framework; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Persistence.Repositories; using Umbraco.Cms.Core.Scoping; using Umbraco.Cms.Core.Services; namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Services; /// /// Unit tests for ContentServiceBase (shared infrastructure for extracted services). /// These tests establish the expected contract for the base class before it's created. /// /// /// ContentServiceBase will be created in Phase 1. These tests validate the design requirements: /// - Audit helper method behavior /// - Scope provider access patterns /// - Logger injection patterns /// [TestFixture] public class ContentServiceBaseTests { // Note: These tests will be uncommented when ContentServiceBase is created in Phase 1. // For now, they serve as documentation of the expected behavior. /* private Mock _scopeProviderMock; private Mock _auditServiceMock; private Mock _eventMessagesFactoryMock; private Mock> _loggerMock; private TestContentService _service; [SetUp] public void Setup() { _scopeProviderMock = new Mock(); _auditServiceMock = new Mock(); _eventMessagesFactoryMock = new Mock(); _loggerMock = new Mock>(); _eventMessagesFactoryMock.Setup(x => x.Get()).Returns(new EventMessages()); _service = new TestContentService( _scopeProviderMock.Object, _auditServiceMock.Object, _eventMessagesFactoryMock.Object, _loggerMock.Object); } #region Audit Helper Method Tests [Test] public void Audit_WithValidParameters_CreatesAuditEntry() { // Arrange var userId = 1; var objectId = 100; var message = "Test audit message"; // Act _service.TestAudit(AuditType.Save, userId, objectId, message); // Assert _auditServiceMock.Verify(x => x.Write( userId, message, It.IsAny(), objectId), Times.Once); } [Test] public void Audit_WithNullMessage_UsesDefaultMessage() { // Arrange var userId = 1; var objectId = 100; // Act _service.TestAudit(AuditType.Save, userId, objectId, null); // Assert _auditServiceMock.Verify(x => x.Write( userId, It.Is(s => !string.IsNullOrEmpty(s)), It.IsAny(), objectId), Times.Once); } #endregion #region Scope Provider Access Pattern Tests [Test] public void CreateScope_ReturnsValidCoreScope() { // Arrange var scopeMock = new Mock(); _scopeProviderMock.Setup(x => x.CreateCoreScope( It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Returns(scopeMock.Object); // Act var scope = _service.TestCreateScope(); // Assert Assert.That(scope, Is.Not.Null); _scopeProviderMock.Verify(x => x.CreateCoreScope( It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Once); } [Test] public void CreateScope_WithAmbientScope_ReusesExisting() { // Arrange var ambientScopeMock = new Mock(); _scopeProviderMock.SetupGet(x => x.AmbientScope).Returns(ambientScopeMock.Object); // When ambient scope exists, CreateCoreScope should still be called // but the scope provider handles the nesting _scopeProviderMock.Setup(x => x.CreateCoreScope( It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Returns(ambientScopeMock.Object); // Act var scope = _service.TestCreateScope(); // Assert - scope should be the ambient scope (or nested in it) Assert.That(scope, Is.Not.Null); } #endregion #region Logger Injection Tests [Test] public void Logger_IsInjectedCorrectly() { // Assert Assert.That(_service.TestLogger, Is.Not.Null); Assert.That(_service.TestLogger, Is.EqualTo(_loggerMock.Object)); } [Test] public void Logger_UsesCorrectCategoryName() { // The logger should be typed to the concrete service class // This is verified by the generic type parameter Assert.That(_service.TestLogger, Is.InstanceOf>()); } #endregion #region Repository Access Tests [Test] public void DocumentRepository_IsAccessibleWithinScope() { // This test validates that the base class provides access to the document repository // The actual repository access pattern will be tested in integration tests Assert.Pass("Repository access validated in integration tests"); } #endregion /// /// Test implementation of ContentServiceBase for unit testing. /// private class TestContentService : ContentServiceBase { public TestContentService( ICoreScopeProvider scopeProvider, IAuditService auditService, IEventMessagesFactory eventMessagesFactory, ILogger logger) : base(scopeProvider, auditService, eventMessagesFactory, logger) { } // Expose protected members for testing public void TestAudit(AuditType type, int userId, int objectId, string? message) => Audit(type, userId, objectId, message); public ICoreScope TestCreateScope() => ScopeProvider.CreateCoreScope(); public ILogger TestLogger => Logger; } */ /// /// v1.3: Tracking test that fails when ContentServiceBase is created. /// When this test fails, uncomment all tests in this file and delete this placeholder. /// [Test] public void ContentServiceBase_WhenCreated_UncommentTests() { // This tracking test uses reflection to detect when ContentServiceBase is created. // When you see this test fail, it means Phase 1 has created ContentServiceBase. // At that point: // 1. Uncomment all the tests in this file (the commented section above) // 2. Delete this tracking test // 3. Verify all tests pass var type = Type.GetType("Umbraco.Cms.Core.Services.ContentServiceBase, Umbraco.Core"); Assert.That(type, Is.Null, "ContentServiceBase now exists! Uncomment all tests in this file and delete this tracking test."); } }