using System; using System.Collections.Generic; using System.Data; using System.Linq; using System.Threading.Tasks; using AngleSharp.Common; using AutoFixture.NUnit3; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Moq; using NUnit.Framework; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Cache; using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.ContentApps; using Umbraco.Cms.Core.Dictionary; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.Hosting; using Umbraco.Cms.Core.Mapping; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.ContentEditing; using Umbraco.Cms.Core.Models.Mapping; using Umbraco.Cms.Core.Models.Membership; using Umbraco.Cms.Core.PropertyEditors; using Umbraco.Cms.Core.Scoping; using Umbraco.Cms.Core.Security; using Umbraco.Cms.Core.Serialization; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Strings; using Umbraco.Cms.Infrastructure.Serialization; using Umbraco.Cms.Tests.Common.Builders; using Umbraco.Cms.Tests.UnitTests.AutoFixture; using Umbraco.Cms.Tests.UnitTests.Umbraco.Core.ShortStringHelper; using Umbraco.Cms.Web.BackOffice.Controllers; using Umbraco.Cms.Web.BackOffice.Mapping; using Umbraco.Cms.Web.Common.ActionsResults; using Umbraco.Cms.Web.Common.Security; using MemberMapDefinition = Umbraco.Cms.Web.BackOffice.Mapping.MemberMapDefinition; namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.BackOffice.Controllers { [TestFixture] public class MemberControllerUnitTests { private UmbracoMapper _mapper; [Test] [AutoMoqData] public void PostSaveMember_WhenMemberIsNull_ExpectFailureResponse( MemberController sut) { // arrange // act ArgumentNullException exception = Assert.ThrowsAsync(() => sut.PostSave(null)); // assert Assert.That(exception.Message, Is.EqualTo("Value cannot be null. (Parameter 'The member content item was null')")); } [Test] [AutoMoqData] public void PostSaveMember_WhenModelStateIsNotValid_ExpectFailureResponse( [Frozen] IMemberManager umbracoMembersUserManager, IMemberService memberService, IMemberTypeService memberTypeService, IMemberGroupService memberGroupService, IDataTypeService dataTypeService, IBackOfficeSecurityAccessor backOfficeSecurityAccessor, IPasswordChanger passwordChanger, IOptions globalSettings, IUser user) { // arrange Member member = SetupMemberTestData(out MemberSave fakeMemberData, out MemberDisplay memberDisplay, ContentSaveAction.SaveNew); MemberController sut = CreateSut(memberService, memberTypeService, memberGroupService, umbracoMembersUserManager, dataTypeService, backOfficeSecurityAccessor, passwordChanger, globalSettings, user); sut.ModelState.AddModelError("key", "Invalid model state"); Mock.Get(umbracoMembersUserManager) .Setup(x => x.CreateAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(() => IdentityResult.Success); Mock.Get(umbracoMembersUserManager) .Setup(x => x.ValidatePasswordAsync(It.IsAny())) .ReturnsAsync(() => IdentityResult.Success); var value = new MemberDisplay(); // act ActionResult result = sut.PostSave(fakeMemberData).Result; var validation = result.Result as ValidationErrorResult; // assert Assert.IsNotNull(result.Result); Assert.IsNull(result.Value); Assert.AreEqual(StatusCodes.Status400BadRequest, validation?.StatusCode); } [Test] [AutoMoqData] public async Task PostSaveMember_SaveNew_NoCustomField_WhenAllIsSetupCorrectly_ExpectSuccessResponse( [Frozen] IMemberManager umbracoMembersUserManager, IMemberService memberService, IMemberTypeService memberTypeService, IMemberGroupService memberGroupService, IDataTypeService dataTypeService, IBackOfficeSecurityAccessor backOfficeSecurityAccessor, IBackOfficeSecurity backOfficeSecurity, IPasswordChanger passwordChanger, IOptions globalSettings, IUser user) { // arrange Member member = SetupMemberTestData(out MemberSave fakeMemberData, out MemberDisplay memberDisplay, ContentSaveAction.SaveNew); Mock.Get(umbracoMembersUserManager) .Setup(x => x.CreateAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(() => IdentityResult.Success); Mock.Get(umbracoMembersUserManager) .Setup(x => x.ValidatePasswordAsync(It.IsAny())) .ReturnsAsync(() => IdentityResult.Success); Mock.Get(memberTypeService).Setup(x => x.GetDefault()).Returns("fakeAlias"); Mock.Get(backOfficeSecurityAccessor).Setup(x => x.BackOfficeSecurity).Returns(backOfficeSecurity); Mock.Get(memberService).SetupSequence( x => x.GetByEmail(It.IsAny())) .Returns(() => null) .Returns(() => member); Mock.Get(memberService).Setup(x => x.GetByUsername(It.IsAny())).Returns(() => member); MemberController sut = CreateSut(memberService, memberTypeService, memberGroupService, umbracoMembersUserManager, dataTypeService, backOfficeSecurityAccessor, passwordChanger, globalSettings, user); // act ActionResult result = await sut.PostSave(fakeMemberData); // assert Assert.IsNull(result.Result); Assert.IsNotNull(result.Value); AssertMemberDisplayPropertiesAreEqual(memberDisplay, result.Value); } [Test] [AutoMoqData] public async Task PostSaveMember_SaveNew_CustomField_WhenAllIsSetupCorrectly_ExpectSuccessResponse( [Frozen] IMemberManager umbracoMembersUserManager, IMemberService memberService, IMemberTypeService memberTypeService, IMemberGroupService memberGroupService, IDataTypeService dataTypeService, IBackOfficeSecurityAccessor backOfficeSecurityAccessor, IBackOfficeSecurity backOfficeSecurity, IPasswordChanger passwordChanger, IOptions globalSettings, IUser user) { // arrange Member member = SetupMemberTestData(out MemberSave fakeMemberData, out MemberDisplay memberDisplay, ContentSaveAction.SaveNew); Mock.Get(umbracoMembersUserManager) .Setup(x => x.CreateAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(() => IdentityResult.Success); Mock.Get(umbracoMembersUserManager) .Setup(x => x.ValidatePasswordAsync(It.IsAny())) .ReturnsAsync(() => IdentityResult.Success); Mock.Get(memberTypeService).Setup(x => x.GetDefault()).Returns("fakeAlias"); Mock.Get(backOfficeSecurityAccessor).Setup(x => x.BackOfficeSecurity).Returns(backOfficeSecurity); Mock.Get(memberService).SetupSequence( x => x.GetByEmail(It.IsAny())) .Returns(() => null) .Returns(() => member); Mock.Get(memberService).Setup(x => x.GetByUsername(It.IsAny())).Returns(() => member); MemberController sut = CreateSut(memberService, memberTypeService, memberGroupService, umbracoMembersUserManager, dataTypeService, backOfficeSecurityAccessor, passwordChanger, globalSettings, user); // act ActionResult result = await sut.PostSave(fakeMemberData); // assert Assert.IsNull(result.Result); Assert.IsNotNull(result.Value); AssertMemberDisplayPropertiesAreEqual(memberDisplay, result.Value); } [Test] [AutoMoqData] public async Task PostSaveMember_SaveExisting_WhenAllIsSetupCorrectly_ExpectSuccessResponse( [Frozen] IMemberManager umbracoMembersUserManager, IMemberService memberService, IMemberTypeService memberTypeService, IMemberGroupService memberGroupService, IDataTypeService dataTypeService, IBackOfficeSecurityAccessor backOfficeSecurityAccessor, IBackOfficeSecurity backOfficeSecurity, IPasswordChanger passwordChanger, IOptions globalSettings, IUser user) { // arrange Member member = SetupMemberTestData(out MemberSave fakeMemberData, out MemberDisplay memberDisplay, ContentSaveAction.Save); var membersIdentityUser = new MemberIdentityUser(123); Mock.Get(umbracoMembersUserManager) .Setup(x => x.FindByIdAsync(It.IsAny())) .ReturnsAsync(() => membersIdentityUser); Mock.Get(umbracoMembersUserManager) .Setup(x => x.ValidatePasswordAsync(It.IsAny())) .ReturnsAsync(() => IdentityResult.Success); Mock.Get(umbracoMembersUserManager) .Setup(x => x.UpdateAsync(It.IsAny())) .ReturnsAsync(() => IdentityResult.Success); Mock.Get(memberTypeService).Setup(x => x.GetDefault()).Returns("fakeAlias"); Mock.Get(globalSettings); SetupUserAccess(backOfficeSecurityAccessor, backOfficeSecurity, user); SetupPasswordSuccess(umbracoMembersUserManager, passwordChanger); Mock.Get(memberService).Setup(x => x.GetByUsername(It.IsAny())).Returns(() => member); Mock.Get(memberService).Setup(x => x.GetById(It.IsAny())).Returns(() => member); Mock.Get(memberService).SetupSequence( x => x.GetByEmail(It.IsAny())) .Returns(() => null) .Returns(() => member); MemberController sut = CreateSut(memberService, memberTypeService, memberGroupService, umbracoMembersUserManager, dataTypeService, backOfficeSecurityAccessor, passwordChanger, globalSettings, user); // act ActionResult result = await sut.PostSave(fakeMemberData); // assert Assert.IsNull(result.Result); Assert.IsNotNull(result.Value); AssertMemberDisplayPropertiesAreEqual(memberDisplay, result.Value); } [Test] [AutoMoqData] public async Task PostSaveMember_SaveExisting_WhenAllIsSetupWithPasswordIncorrectly_ExpectFailureResponse( [Frozen] IMemberManager umbracoMembersUserManager, IMemberService memberService, IMemberTypeService memberTypeService, IMemberGroupService memberGroupService, IDataTypeService dataTypeService, IBackOfficeSecurityAccessor backOfficeSecurityAccessor, IBackOfficeSecurity backOfficeSecurity, IPasswordChanger passwordChanger, IOptions globalSettings, IUser user) { // arrange Member member = SetupMemberTestData(out MemberSave fakeMemberData, out MemberDisplay memberDisplay, ContentSaveAction.Save); var membersIdentityUser = new MemberIdentityUser(123); Mock.Get(umbracoMembersUserManager) .Setup(x => x.FindByIdAsync(It.IsAny())) .ReturnsAsync(() => membersIdentityUser); Mock.Get(umbracoMembersUserManager) .Setup(x => x.ValidatePasswordAsync(It.IsAny())) .ReturnsAsync(() => IdentityResult.Success); Mock.Get(umbracoMembersUserManager) .Setup(x => x.UpdateAsync(It.IsAny())) .ReturnsAsync(() => IdentityResult.Success); Mock.Get(memberTypeService).Setup(x => x.GetDefault()).Returns("fakeAlias"); Mock.Get(globalSettings); SetupUserAccess(backOfficeSecurityAccessor, backOfficeSecurity, user); SetupPasswordSuccess(umbracoMembersUserManager, passwordChanger, false); Mock.Get(memberService).Setup(x => x.GetByUsername(It.IsAny())).Returns(() => member); Mock.Get(memberService).SetupSequence( x => x.GetByEmail(It.IsAny())) .Returns(() => null) .Returns(() => member); MemberController sut = CreateSut(memberService, memberTypeService, memberGroupService, umbracoMembersUserManager, dataTypeService, backOfficeSecurityAccessor, passwordChanger, globalSettings, user); // act ActionResult result = await sut.PostSave(fakeMemberData); // assert Assert.IsNotNull(result.Result); Assert.IsNull(result.Value); } private static void SetupUserAccess(IBackOfficeSecurityAccessor backOfficeSecurityAccessor, IBackOfficeSecurity backOfficeSecurity, IUser user) { Mock.Get(backOfficeSecurityAccessor).Setup(x => x.BackOfficeSecurity).Returns(backOfficeSecurity); Mock.Get(user).Setup(x => x.AllowedSections).Returns(new[] { "member" }); Mock.Get(backOfficeSecurity).Setup(x => x.CurrentUser).Returns(user); } private static void SetupPasswordSuccess(IMemberManager umbracoMembersUserManager, IPasswordChanger passwordChanger, bool successful = true) { var passwordChanged = new PasswordChangedModel() { ChangeError = null, ResetPassword = null }; if (!successful) { var attempt = Attempt.Fail(passwordChanged); Mock.Get(passwordChanger) .Setup(x => x.ChangePasswordWithIdentityAsync(It.IsAny(), umbracoMembersUserManager)) .ReturnsAsync(() => attempt); } else { var attempt = Attempt.Succeed(passwordChanged); Mock.Get(passwordChanger) .Setup(x => x.ChangePasswordWithIdentityAsync(It.IsAny(), umbracoMembersUserManager)) .ReturnsAsync(() => attempt); } } [Test] [AutoMoqData] public void PostSaveMember_SaveNew_WhenMemberEmailAlreadyExists_ExpectFailResponse( [Frozen] IMemberManager umbracoMembersUserManager, IMemberService memberService, IMemberTypeService memberTypeService, IMemberGroupService memberGroupService, IDataTypeService dataTypeService, IBackOfficeSecurityAccessor backOfficeSecurityAccessor, IBackOfficeSecurity backOfficeSecurity, IPasswordChanger passwordChanger, IOptions globalSettings, IUser user) { // arrange Member member = SetupMemberTestData(out MemberSave fakeMemberData, out MemberDisplay memberDisplay, ContentSaveAction.SaveNew); Mock.Get(umbracoMembersUserManager) .Setup(x => x.CreateAsync(It.IsAny())) .ReturnsAsync(() => IdentityResult.Success); Mock.Get(memberTypeService).Setup(x => x.GetDefault()).Returns("fakeAlias"); Mock.Get(backOfficeSecurityAccessor).Setup(x => x.BackOfficeSecurity).Returns(backOfficeSecurity); Mock.Get(umbracoMembersUserManager) .Setup(x => x.ValidatePasswordAsync(It.IsAny())) .ReturnsAsync(() => IdentityResult.Success); Mock.Get(umbracoMembersUserManager) .Setup(x => x.AddToRolesAsync(It.IsAny(), It.IsAny>())) .ReturnsAsync(() => IdentityResult.Success); Mock.Get(memberService).SetupSequence( x => x.GetByEmail(It.IsAny())) .Returns(() => member); MemberController sut = CreateSut(memberService, memberTypeService, memberGroupService, umbracoMembersUserManager, dataTypeService, backOfficeSecurityAccessor, passwordChanger, globalSettings, user); // act ActionResult result = sut.PostSave(fakeMemberData).Result; var validation = result.Result as ValidationErrorResult; // assert Assert.IsNotNull(result.Result); Assert.IsNull(result.Value); Assert.AreEqual(StatusCodes.Status400BadRequest, validation?.StatusCode); } [Test] [AutoMoqData] public async Task PostSaveMember_SaveExistingMember_WithNoRoles_Add1Role_ExpectSuccessResponse( [Frozen] IMemberManager umbracoMembersUserManager, IMemberService memberService, IMemberTypeService memberTypeService, IMemberGroupService memberGroupService, IDataTypeService dataTypeService, IBackOfficeSecurityAccessor backOfficeSecurityAccessor, IBackOfficeSecurity backOfficeSecurity, IPasswordChanger passwordChanger, IOptions globalSettings, IUser user) { // arrange var roleName = "anyrole"; IMember member = SetupMemberTestData(out MemberSave fakeMemberData, out MemberDisplay memberDisplay, ContentSaveAction.Save); fakeMemberData.Groups = new List() { roleName }; var membersIdentityUser = new MemberIdentityUser(123); Mock.Get(umbracoMembersUserManager) .Setup(x => x.FindByIdAsync(It.IsAny())) .ReturnsAsync(() => membersIdentityUser); Mock.Get(umbracoMembersUserManager) .Setup(x => x.ValidatePasswordAsync(It.IsAny())) .ReturnsAsync(() => IdentityResult.Success); Mock.Get(umbracoMembersUserManager) .Setup(x => x.UpdateAsync(It.IsAny())) .ReturnsAsync(() => IdentityResult.Success); Mock.Get(umbracoMembersUserManager) .Setup(x => x.AddToRolesAsync(It.IsAny(), It.IsAny>())) .ReturnsAsync(() => IdentityResult.Success); Mock.Get(memberTypeService).Setup(x => x.GetDefault()).Returns("fakeAlias"); Mock.Get(backOfficeSecurityAccessor).Setup(x => x.BackOfficeSecurity).Returns(backOfficeSecurity); Mock.Get(memberService).Setup(x => x.GetByUsername(It.IsAny())).Returns(() => member); Mock.Get(memberService).Setup(x => x.GetById(It.IsAny())).Returns(() => member); SetupUserAccess(backOfficeSecurityAccessor, backOfficeSecurity, user); SetupPasswordSuccess(umbracoMembersUserManager, passwordChanger); Mock.Get(memberService).SetupSequence( x => x.GetByEmail(It.IsAny())) .Returns(() => null) .Returns(() => member); MemberController sut = CreateSut(memberService, memberTypeService, memberGroupService, umbracoMembersUserManager, dataTypeService, backOfficeSecurityAccessor, passwordChanger, globalSettings, user); // act ActionResult result = await sut.PostSave(fakeMemberData); // assert Assert.IsNull(result.Result); Assert.IsNotNull(result.Value); Mock.Get(umbracoMembersUserManager) .Verify(u => u.GetRolesAsync(membersIdentityUser)); Mock.Get(umbracoMembersUserManager) .Verify(u => u.AddToRolesAsync(membersIdentityUser, new[] { roleName })); Mock.Get(memberService) .Verify(m => m.Save(It.IsAny(), true)); AssertMemberDisplayPropertiesAreEqual(memberDisplay, result.Value); } /// /// Create member controller to test /// /// Member service /// Member type service /// Member group service /// Members user manager /// Data type service /// Back office security accessor /// Password changer class /// A member controller for the tests private MemberController CreateSut( IMemberService memberService, IMemberTypeService memberTypeService, IMemberGroupService memberGroupService, IUmbracoUserManager membersUserManager, IDataTypeService dataTypeService, IBackOfficeSecurityAccessor backOfficeSecurityAccessor, IPasswordChanger passwordChanger, IOptions globalSettings, IUser user) { var httpContextAccessor = new HttpContextAccessor(); var mockShortStringHelper = new MockShortStringHelper(); var textService = new Mock(); var contentTypeBaseServiceProvider = new Mock(); contentTypeBaseServiceProvider.Setup(x => x.GetContentTypeOf(It.IsAny())).Returns(new ContentType(mockShortStringHelper, 123)); var contentAppFactories = new Mock>(); var mockContentAppFactoryCollection = new Mock>(); var hybridBackOfficeSecurityAccessor = new BackOfficeSecurityAccessor(httpContextAccessor); var contentAppFactoryCollection = new ContentAppFactoryCollection( contentAppFactories.Object, mockContentAppFactoryCollection.Object, hybridBackOfficeSecurityAccessor); var mockUserService = new Mock(); var commonMapper = new CommonMapper( mockUserService.Object, contentTypeBaseServiceProvider.Object, contentAppFactoryCollection, textService.Object); var mockCultureDictionary = new Mock(); var mockPasswordConfig = new Mock>(); mockPasswordConfig.Setup(x => x.Value).Returns(() => new MemberPasswordConfigurationSettings()); IDataEditor dataEditor = Mock.Of( x => x.Type == EditorType.PropertyValue && x.Alias == Constants.PropertyEditors.Aliases.Label); Mock.Get(dataEditor).Setup(x => x.GetValueEditor()).Returns(new TextOnlyValueEditor(Mock.Of(), Mock.Of(), new DataEditorAttribute(Constants.PropertyEditors.Aliases.TextBox, "Test Textbox", "textbox"), textService.Object, Mock.Of(), Mock.Of())); var propertyEditorCollection = new PropertyEditorCollection(new DataEditorCollection(new[] { dataEditor })); IMapDefinition memberMapDefinition = new MemberMapDefinition( commonMapper, new CommonTreeNodeMapper(Mock.Of()), new MemberTabsAndPropertiesMapper( mockCultureDictionary.Object, backOfficeSecurityAccessor, textService.Object, memberTypeService, memberService, memberGroupService, mockPasswordConfig.Object, contentTypeBaseServiceProvider.Object, propertyEditorCollection), httpContextAccessor); var map = new MapDefinitionCollection(new List() { new global::Umbraco.Cms.Core.Models.Mapping.MemberMapDefinition(), memberMapDefinition, new ContentTypeMapDefinition( commonMapper, propertyEditorCollection, dataTypeService, new Mock().Object, new Mock().Object, new Mock().Object, memberTypeService, new Mock().Object, mockShortStringHelper, globalSettings, new Mock().Object) }); _mapper = new UmbracoMapper(map); return new MemberController( new DefaultCultureDictionary( new Mock().Object, NoAppCache.Instance), new LoggerFactory(), mockShortStringHelper, new DefaultEventMessagesFactory( new Mock().Object), textService.Object, propertyEditorCollection, _mapper, memberService, memberTypeService, (IMemberManager)membersUserManager, dataTypeService, backOfficeSecurityAccessor, new ConfigurationEditorJsonSerializer(), passwordChanger, Mock.Of(x => x.CreateScope( It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()) == Mock.Of())); } /// /// Setup all standard member data for test /// private Member SetupMemberTestData( out MemberSave fakeMemberData, out MemberDisplay memberDisplay, ContentSaveAction contentAction) { // arrange MemberType memberType = MemberTypeBuilder.CreateSimpleMemberType(); Member member = MemberBuilder.CreateSimpleMember(memberType, "Test Member", "test@example.com", "123", "test"); var memberId = 123; member.Id = memberId; // TODO: replace with builder for MemberSave and MemberDisplay fakeMemberData = new MemberSave() { Id = memberId, SortOrder = member.SortOrder, ContentTypeId = memberType.Id, Key = member.Key, Password = new ChangingPasswordModel() { Id = 456, NewPassword = member.RawPasswordValue, OldPassword = null }, Name = member.Name, Email = member.Email, Username = member.Username, PersistedContent = member, PropertyCollectionDto = new ContentPropertyCollectionDto() { }, Groups = new List(), //Alias = "fakeAlias", ContentTypeAlias = member.ContentTypeAlias, Action = contentAction, Icon = "icon-document", Path = member.Path }; memberDisplay = new MemberDisplay() { Id = memberId, SortOrder = member.SortOrder, ContentTypeId = memberType.Id, Key = member.Key, Name = member.Name, Email = member.Email, Username = member.Username, //Alias = "fakeAlias", ContentTypeAlias = member.ContentTypeAlias, ContentType = new ContentTypeBasic(), ContentTypeName = member.ContentType.Name, Icon = fakeMemberData.Icon, Path = member.Path, Tabs = new List>() { new Tab() { Alias = "test", Id = 77, Properties = new List() { new ContentPropertyDisplay() { Alias = "_umb_id", View = "idwithguid", Value = new [] { "123", "guid" } }, new ContentPropertyDisplay() { Alias = "_umb_doctype" }, new ContentPropertyDisplay() { Alias = "_umb_login" }, new ContentPropertyDisplay() { Alias= "_umb_email" }, new ContentPropertyDisplay() { Alias = "_umb_password" }, new ContentPropertyDisplay() { Alias = "_umb_membergroup" } } } } }; return member; } /// /// Check all member properties are equal /// /// /// private void AssertMemberDisplayPropertiesAreEqual(MemberDisplay memberDisplay, MemberDisplay resultValue) { Assert.AreNotSame(memberDisplay, resultValue); Assert.AreEqual(memberDisplay.Id, resultValue.Id); Assert.AreEqual(memberDisplay.Alias, resultValue.Alias); Assert.AreEqual(memberDisplay.Username, resultValue.Username); Assert.AreEqual(memberDisplay.Email, resultValue.Email); Assert.AreEqual(memberDisplay.AdditionalData, resultValue.AdditionalData); Assert.AreEqual(memberDisplay.ContentApps, resultValue.ContentApps); Assert.AreEqual(memberDisplay.ContentType.Alias, resultValue.ContentType.Alias); Assert.AreEqual(memberDisplay.ContentTypeAlias, resultValue.ContentTypeAlias); Assert.AreEqual(memberDisplay.ContentTypeName, resultValue.ContentTypeName); Assert.AreEqual(memberDisplay.ContentTypeId, resultValue.ContentTypeId); Assert.AreEqual(memberDisplay.Icon, resultValue.Icon); Assert.AreEqual(memberDisplay.Errors, resultValue.Errors); Assert.AreEqual(memberDisplay.Key, resultValue.Key); Assert.AreEqual(memberDisplay.Name, resultValue.Name); Assert.AreEqual(memberDisplay.Path, resultValue.Path); Assert.AreEqual(memberDisplay.SortOrder, resultValue.SortOrder); Assert.AreEqual(memberDisplay.Trashed, resultValue.Trashed); Assert.AreEqual(memberDisplay.TreeNodeUrl, resultValue.TreeNodeUrl); //TODO: can we check create/update dates when saving? //Assert.AreEqual(memberDisplay.CreateDate, resultValue.CreateDate); //Assert.AreEqual(memberDisplay.UpdateDate, resultValue.UpdateDate); //TODO: check all properties Assert.AreEqual(memberDisplay.Properties.Count(), resultValue.Properties.Count()); Assert.AreNotSame(memberDisplay.Properties, resultValue.Properties); for (var index = 0; index < resultValue.Properties.Count(); index++) { Assert.AreNotSame(memberDisplay.Properties.GetItemByIndex(index), resultValue.Properties.GetItemByIndex(index)); //Assert.AreEqual(memberDisplay.Properties.GetItemByIndex(index), resultValue.Properties.GetItemByIndex(index)); } } } }