Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
using System.Linq;
using System.Reflection;
using Grand.Domain.Permissions;
using Grand.Web.Admin.Controllers;
using Grand.Web.AdminShared.Controllers;
using Grand.Web.AdminShared.Models.Orders;
using Grand.Web.Common.Filters;
using Grand.Web.Common.Security.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Grand.Web.Admin.Tests.Controllers;

[TestClass]
public class GiftVoucherControllerAttributeTests
{
[TestMethod]
public void IsThinSubclassOfBaseGiftVoucherController()
{
Assert.IsTrue(typeof(BaseGiftVoucherController).IsAssignableFrom(typeof(GiftVoucherController)));
Assert.AreEqual(typeof(BaseGiftVoucherController), typeof(GiftVoucherController).BaseType);
}

[TestMethod]
public void HasAuthorizeAdminAttribute()
{
var attr = typeof(GiftVoucherController).GetCustomAttributes(typeof(AuthorizeAdminAttribute), inherit: false);
Assert.AreEqual(1, attr.Length);
}

[TestMethod]
public void HasAreaAdminAttribute()
{
var attr = typeof(GiftVoucherController)
.GetCustomAttributes(typeof(AreaAttribute), inherit: false)
.Cast<AreaAttribute>().Single();
Assert.AreEqual("Admin", attr.RouteValue);
}

[TestMethod]
public void HasAutoValidateAntiforgeryTokenAttribute()
{
var attr = typeof(GiftVoucherController)
.GetCustomAttributes(typeof(AutoValidateAntiforgeryTokenAttribute), inherit: true);
Assert.AreEqual(1, attr.Length);
}

[TestMethod]
public void HasAuthorizeMenuAttribute()
{
var attr = typeof(GiftVoucherController).GetCustomAttributes(typeof(AuthorizeMenuAttribute), inherit: false);
Assert.AreEqual(1, attr.Length);
}

// Regression test for the disclosed bug fix noted on BaseGiftVoucherController.Create(POST):
// pre-consolidation, Admin's own Create(POST) required PermissionActionName.Edit while
// everything else on Create required .Create. Pin the fixed permission via reflection so a
// future edit can't silently regress it.
[TestMethod]
public void CreatePost_RequiresCreatePermission()
{
var method = typeof(BaseGiftVoucherController).GetMethods(BindingFlags.Public | BindingFlags.Instance)
.Single(m => m.Name == "Create" && m.GetParameters().Length == 2
&& m.GetParameters()[0].ParameterType == typeof(GiftVoucherModel));

var attr = method.GetCustomAttributes(typeof(PermissionAuthorizeActionAttribute), inherit: false)
.Cast<PermissionAuthorizeActionAttribute>().Single();

Assert.AreEqual(PermissionActionName.Create, attr.PermissionAction);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
using Grand.Domain.Orders;
using Grand.Web.AdminShared.Services;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;

namespace Grand.Web.Admin.Tests.Controllers;

[TestClass]
public class RoutedGiftVoucherDataScopeTests
{
private static RoutedGiftVoucherDataScope CreateScope(string area, out StoreGiftVoucherDataScope storeScope)
{
var httpContext = new DefaultHttpContext();
httpContext.Request.RouteValues = new RouteValueDictionary { ["area"] = area };
var httpContextAccessor = new Mock<IHttpContextAccessor>();
httpContextAccessor.Setup(a => a.HttpContext).Returns(httpContext);

var contextAccessor = new Mock<Grand.Infrastructure.IContextAccessor>();
var workContext = new Mock<Grand.Infrastructure.IWorkContext>();
workContext.Setup(w => w.CurrentCustomer).Returns(new Grand.Domain.Customers.Customer { StaffStoreId = "store-1" });
contextAccessor.Setup(c => c.WorkContext).Returns(workContext.Object);

storeScope = new StoreGiftVoucherDataScope(contextAccessor.Object);
return new RoutedGiftVoucherDataScope(httpContextAccessor.Object,
new GlobalAdminDataScope<GiftVoucher>(), storeScope);
}

[TestMethod]
public async Task AdminArea_ResolvesToGlobalScope_HasAccessAlwaysTrue()
{
var scope = CreateScope("Admin", out _);
var result = await scope.HasAccess(new GiftVoucher { StoreId = "any-other-store" });
Assert.IsTrue(result);
}

[TestMethod]
public void AdminArea_DefaultStoreId_IsNull()
{
var scope = CreateScope("Admin", out _);
Assert.IsNull(scope.DefaultStoreId);
}

[TestMethod]
public async Task StoreArea_ResolvesToStoreScope_HasAccessMatchesOwnership()
{
var scope = CreateScope("Store", out _);
var owned = await scope.HasAccess(new GiftVoucher { StoreId = "store-1" });
var other = await scope.HasAccess(new GiftVoucher { StoreId = "store-2" });
Assert.IsTrue(owned);
Assert.IsFalse(other);
}

[TestMethod]
public void StoreArea_DefaultStoreId_IsStaffStoreId()
{
var scope = CreateScope("Store", out _);
Assert.AreEqual("store-1", scope.DefaultStoreId);
}

[TestMethod]
public async Task UnrecognizedArea_ThrowsInvalidOperationException()
{
var scope = CreateScope("Vendor", out _);
await Assert.ThrowsAsync<InvalidOperationException>(
() => scope.HasAccess(new GiftVoucher { StoreId = "store-1" }));
}

[TestMethod]
public async Task MissingArea_ThrowsInvalidOperationException()
{
var scope = CreateScope(null, out _);
await Assert.ThrowsAsync<InvalidOperationException>(
() => scope.HasAccess(new GiftVoucher { StoreId = "store-1" }));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
using Grand.Domain.Customers;
using Grand.Domain.Orders;
using Grand.Infrastructure;
using Grand.Web.AdminShared.Services;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;

namespace Grand.Web.Admin.Tests.Controllers;

[TestClass]
public class StoreGiftVoucherDataScopeTests
{
private static StoreGiftVoucherDataScope CreateScope(string staffStoreId)
{
var customer = new Customer { StaffStoreId = staffStoreId };
var workContext = new Mock<IWorkContext>();
workContext.Setup(w => w.CurrentCustomer).Returns(customer);
var contextAccessor = new Mock<IContextAccessor>();
contextAccessor.Setup(c => c.WorkContext).Returns(workContext.Object);
return new StoreGiftVoucherDataScope(contextAccessor.Object);
}

[TestMethod]
public async Task HasAccess_OwnStore_ReturnsTrue()
{
var scope = CreateScope("store-1");
var result = await scope.HasAccess(new GiftVoucher { StoreId = "store-1" });
Assert.IsTrue(result);
}

[TestMethod]
public async Task HasAccess_OtherStore_ReturnsFalse()
{
var scope = CreateScope("store-1");
var result = await scope.HasAccess(new GiftVoucher { StoreId = "store-2" });
Assert.IsFalse(result);
}

[TestMethod]
public async Task HasAccess_GlobalVoucher_ReturnsFalse()
{
var scope = CreateScope("store-1");
var result = await scope.HasAccess(new GiftVoucher { StoreId = "" });
Assert.IsFalse(result);
}

[TestMethod]
public async Task HasAccess_NullEntity_ReturnsFalse()
{
var scope = CreateScope("store-1");
var result = await scope.HasAccess(null);
Assert.IsFalse(result);
}

[TestMethod]
public async Task CanView_OwnStore_ReturnsTrue()
{
var scope = CreateScope("store-1");
var result = await scope.CanView(new GiftVoucher { StoreId = "store-1" });
Assert.IsTrue(result);
}

[TestMethod]
public async Task CanView_GlobalVoucher_ReturnsTrue()
{
var scope = CreateScope("store-1");
var result = await scope.CanView(new GiftVoucher { StoreId = "" });
Assert.IsTrue(result);
}

[TestMethod]
public async Task CanView_NullStoreId_ReturnsTrue()
{
var scope = CreateScope("store-1");
var result = await scope.CanView(new GiftVoucher { StoreId = null });
Assert.IsTrue(result);
}

[TestMethod]
public async Task CanView_OtherStore_ReturnsFalse()
{
var scope = CreateScope("store-1");
var result = await scope.CanView(new GiftVoucher { StoreId = "store-2" });
Assert.IsFalse(result);
}

[TestMethod]
public async Task CanView_NullEntity_ReturnsFalse()
{
var scope = CreateScope("store-1");
var result = await scope.CanView(null);
Assert.IsFalse(result);
}

[TestMethod]
public void DefaultStoreId_ReturnsStaffStoreId()
{
var scope = CreateScope("store-1");
Assert.AreEqual("store-1", scope.DefaultStoreId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
using Grand.Business.Core.Interfaces.Checkout.GiftVouchers;
using Grand.Business.Core.Interfaces.Common.Localization;
using Grand.Domain.Orders;
using Grand.Web.AdminShared.Controllers;
using Grand.Web.AdminShared.Interfaces;
using Grand.Web.Common.Filters;
using Grand.Web.Common.Security.Authorization;
using Grand.Web.Store.Controllers;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.Extensions.Logging;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;

namespace Grand.Web.Store.Tests.Controllers;

[TestClass]
public class GiftVoucherControllerAttributeTests
{
[TestMethod]
public void IsThinSubclassOfBaseGiftVoucherController()
{
Assert.IsTrue(typeof(BaseGiftVoucherController).IsAssignableFrom(typeof(GiftVoucherController)));
}

[TestMethod]
public void HasAuthorizeStoreAttribute()
{
var attr = typeof(GiftVoucherController).GetCustomAttributes(typeof(AuthorizeStoreAttribute), inherit: false);
Assert.AreEqual(1, attr.Length);
}

[TestMethod]
public void HasAreaStoreAttribute()
{
var attr = typeof(GiftVoucherController)
.GetCustomAttributes(typeof(AreaAttribute), inherit: false)
.Cast<AreaAttribute>().Single();
Assert.AreEqual("Store", attr.RouteValue);
}

[TestMethod]
public void HasAuthorizeMenuAttribute()
{
var attr = typeof(GiftVoucherController).GetCustomAttributes(typeof(AuthorizeMenuAttribute), inherit: false);
Assert.AreEqual(1, attr.Length);
}

[TestMethod]
public void HasAutoValidateAntiforgeryTokenAttribute()
{
var attr = typeof(GiftVoucherController)
.GetCustomAttributes(typeof(AutoValidateAntiforgeryTokenAttribute), inherit: true);
Assert.AreEqual(1, attr.Length);
}

// --- EditWarningCheck ----------------------------------------------------------------------
//
// Behavioral tests for GiftVoucherController.EditWarningCheck, exercised indirectly through
// the public Edit(GET) action since EditWarningCheck itself is protected. Mirrors
// BrandControllerTests.EditWarningCheckTests's pattern.

[TestClass]
public class EditWarningCheckTests
{
private const string PermissionsResourceKey = "Admin.GiftVouchers.Permissions";
private const string DefaultStoreId = "store-1";

private GiftVoucherController _controller;
private Mock<IGiftVoucherViewModelService> _viewModelServiceMock;
private Mock<IGiftVoucherService> _giftVoucherServiceMock;
private Mock<ITranslationService> _translationServiceMock;
private Mock<IAdminDataScope<GiftVoucher>> _scopeMock;

[TestInitialize]
public void Setup()
{
_viewModelServiceMock = new Mock<IGiftVoucherViewModelService>();
_viewModelServiceMock.Setup(s => s.PrepareGiftVoucherModel(It.IsAny<GiftVoucher>()))
.ReturnsAsync(new Grand.Web.AdminShared.Models.Orders.GiftVoucherModel());
_giftVoucherServiceMock = new Mock<IGiftVoucherService>();
_translationServiceMock = new Mock<ITranslationService>();
_translationServiceMock.Setup(t => t.GetResource(It.IsAny<string>())).Returns("resource");

_scopeMock = new Mock<IAdminDataScope<GiftVoucher>>();
_scopeMock.Setup(s => s.DefaultStoreId).Returns(DefaultStoreId);
_scopeMock.Setup(s => s.CanView(It.IsAny<GiftVoucher>())).ReturnsAsync(true);

_controller = new GiftVoucherController(
_viewModelServiceMock.Object,
_giftVoucherServiceMock.Object,
_translationServiceMock.Object,
_scopeMock.Object);

var httpContext = new DefaultHttpContext();
var loggerFactoryMock = new Mock<ILoggerFactory>();
loggerFactoryMock.Setup(l => l.CreateLogger(It.IsAny<string>())).Returns(new Mock<ILogger>().Object);
var urlHelperFactoryMock = new Mock<IUrlHelperFactory>();
urlHelperFactoryMock.Setup(f => f.GetUrlHelper(It.IsAny<ActionContext>())).Returns(new Mock<IUrlHelper>().Object);
var requestServicesMock = new Mock<IServiceProvider>();
requestServicesMock.Setup(s => s.GetService(typeof(ILoggerFactory))).Returns(loggerFactoryMock.Object);
requestServicesMock.Setup(s => s.GetService(typeof(IUrlHelperFactory))).Returns(urlHelperFactoryMock.Object);
httpContext.RequestServices = requestServicesMock.Object;
_controller.ControllerContext = new ControllerContext { HttpContext = httpContext };
_controller.TempData = new TempDataDictionary(httpContext, new Mock<ITempDataProvider>().Object);
}

private bool WarningWasRaised()
{
return _controller.TempData["grand.notifications.Warning"] is List<string> warnings
&& warnings.Contains("resource");
}

[TestMethod]
public async Task EditGet_GlobalVoucher_RaisesPermissionsWarning()
{
var giftVoucher = new GiftVoucher { Id = "gv-1", StoreId = "" };
_giftVoucherServiceMock.Setup(s => s.GetGiftVoucherById("gv-1")).ReturnsAsync(giftVoucher);

await _controller.Edit("gv-1");

Assert.IsTrue(WarningWasRaised());
_translationServiceMock.Verify(t => t.GetResource(PermissionsResourceKey), Times.Once);
}

[TestMethod]
public async Task EditGet_OwnStoreVoucher_DoesNotRaiseWarning()
{
var giftVoucher = new GiftVoucher { Id = "gv-1", StoreId = DefaultStoreId };
_giftVoucherServiceMock.Setup(s => s.GetGiftVoucherById("gv-1")).ReturnsAsync(giftVoucher);

await _controller.Edit("gv-1");

Assert.IsFalse(WarningWasRaised());
_translationServiceMock.Verify(t => t.GetResource(PermissionsResourceKey), Times.Never);
}
}
}
Loading
Loading