From 3727256a4acfffa4fa0eedc051f8a3ba8d66103a Mon Sep 17 00:00:00 2001 From: Nick Krantz Date: Wed, 8 Oct 2025 13:30:57 -0500 Subject: [PATCH] add unit test for folder/favorite sharing --- .../Controllers/CiphersControllerTests.cs | 233 ++++++++++++++++++ 1 file changed, 233 insertions(+) diff --git a/test/Api.Test/Vault/Controllers/CiphersControllerTests.cs b/test/Api.Test/Vault/Controllers/CiphersControllerTests.cs index 416b92f841..3026489271 100644 --- a/test/Api.Test/Vault/Controllers/CiphersControllerTests.cs +++ b/test/Api.Test/Vault/Controllers/CiphersControllerTests.cs @@ -1909,4 +1909,237 @@ public class CiphersControllerTests await Assert.ThrowsAsync(() => sutProvider.Sut.PostPurge(model, organizationId)); } + + [Theory, BitAutoData] + public async Task PutShare_WithNullFolderAndFalseFavorite_UpdatesFieldsCorrectly( + Guid cipherId, + Guid userId, + Guid organizationId, + Guid folderId, + SutProvider sutProvider) + { + var user = new User { Id = userId }; + var userIdKey = userId.ToString().ToUpperInvariant(); + + var existingCipher = new Cipher + { + Id = cipherId, + UserId = userId, + Type = CipherType.Login, + Data = JsonSerializer.Serialize(new { Username = "test", Password = "test" }), + Folders = JsonSerializer.Serialize(new Dictionary { { userIdKey, folderId.ToString().ToUpperInvariant() } }), + Favorites = JsonSerializer.Serialize(new Dictionary { { userIdKey, true } }) + }; + + // Clears folder and favorite when sharing + var model = new CipherShareRequestModel + { + Cipher = new CipherRequestModel + { + Type = CipherType.Login, + OrganizationId = organizationId.ToString(), + Name = "SharedCipher", + Data = JsonSerializer.Serialize(new { Username = "test", Password = "test" }), + FolderId = null, + Favorite = false, + EncryptedFor = userId + }, + CollectionIds = [Guid.NewGuid().ToString()] + }; + + sutProvider.GetDependency() + .GetUserByPrincipalAsync(Arg.Any()) + .Returns(user); + + sutProvider.GetDependency() + .GetByIdAsync(cipherId) + .Returns(existingCipher); + + sutProvider.GetDependency() + .OrganizationUser(organizationId) + .Returns(true); + + var sharedCipher = new CipherDetails + { + Id = cipherId, + OrganizationId = organizationId, + Type = CipherType.Login, + Data = JsonSerializer.Serialize(new { Username = "test", Password = "test" }), + FolderId = null, + Favorite = false + }; + + sutProvider.GetDependency() + .GetByIdAsync(cipherId, userId) + .Returns(sharedCipher); + + sutProvider.GetDependency() + .GetOrganizationAbilitiesAsync() + .Returns(new Dictionary + { + { organizationId, new OrganizationAbility { Id = organizationId } } + }); + + var result = await sutProvider.Sut.PutShare(cipherId, model); + + Assert.Null(result.FolderId); + Assert.False(result.Favorite); + } + + [Theory, BitAutoData] + public async Task PutShare_WithFolderAndFavoriteSet_AddsUserSpecificFields( + Guid cipherId, + Guid userId, + Guid organizationId, + Guid folderId, + SutProvider sutProvider) + { + var user = new User { Id = userId }; + var userIdKey = userId.ToString().ToUpperInvariant(); + + var existingCipher = new Cipher + { + Id = cipherId, + UserId = userId, + Type = CipherType.Login, + Data = JsonSerializer.Serialize(new { Username = "test", Password = "test" }), + Folders = null, + Favorites = null + }; + + // Sets folder and favorite when sharing + var model = new CipherShareRequestModel + { + Cipher = new CipherRequestModel + { + Type = CipherType.Login, + OrganizationId = organizationId.ToString(), + Name = "SharedCipher", + Data = JsonSerializer.Serialize(new { Username = "test", Password = "test" }), + FolderId = folderId.ToString(), + Favorite = true, + EncryptedFor = userId + }, + CollectionIds = [Guid.NewGuid().ToString()] + }; + + sutProvider.GetDependency() + .GetUserByPrincipalAsync(Arg.Any()) + .Returns(user); + + sutProvider.GetDependency() + .GetByIdAsync(cipherId) + .Returns(existingCipher); + + sutProvider.GetDependency() + .OrganizationUser(organizationId) + .Returns(true); + + var sharedCipher = new CipherDetails + { + Id = cipherId, + OrganizationId = organizationId, + Type = CipherType.Login, + Data = JsonSerializer.Serialize(new { Username = "test", Password = "test" }), + Folders = JsonSerializer.Serialize(new Dictionary { { userIdKey, folderId.ToString().ToUpperInvariant() } }), + Favorites = JsonSerializer.Serialize(new Dictionary { { userIdKey, true } }), + FolderId = folderId, + Favorite = true + }; + + sutProvider.GetDependency() + .GetByIdAsync(cipherId, userId) + .Returns(sharedCipher); + + sutProvider.GetDependency() + .GetOrganizationAbilitiesAsync() + .Returns(new Dictionary + { + { organizationId, new OrganizationAbility { Id = organizationId } } + }); + + var result = await sutProvider.Sut.PutShare(cipherId, model); + + Assert.Equal(folderId, result.FolderId); + Assert.True(result.Favorite); + } + + [Theory, BitAutoData] + public async Task PutShare_UpdateExistingFolderAndFavorite_UpdatesUserSpecificFields( + Guid cipherId, + Guid userId, + Guid organizationId, + Guid oldFolderId, + Guid newFolderId, + SutProvider sutProvider) + { + var user = new User { Id = userId }; + var userIdKey = userId.ToString().ToUpperInvariant(); + + // Existing cipher with old folder and not favorited + var existingCipher = new Cipher + { + Id = cipherId, + UserId = userId, + Type = CipherType.Login, + Data = JsonSerializer.Serialize(new { Username = "test", Password = "test" }), + Folders = JsonSerializer.Serialize(new Dictionary { { userIdKey, oldFolderId.ToString().ToUpperInvariant() } }), + Favorites = null + }; + + var model = new CipherShareRequestModel + { + Cipher = new CipherRequestModel + { + Type = CipherType.Login, + OrganizationId = organizationId.ToString(), + Name = "SharedCipher", + Data = JsonSerializer.Serialize(new { Username = "test", Password = "test" }), + FolderId = newFolderId.ToString(), // Update to new folder + Favorite = true, // Add favorite + EncryptedFor = userId + }, + CollectionIds = [Guid.NewGuid().ToString()] + }; + + sutProvider.GetDependency() + .GetUserByPrincipalAsync(Arg.Any()) + .Returns(user); + + sutProvider.GetDependency() + .GetByIdAsync(cipherId) + .Returns(existingCipher); + + sutProvider.GetDependency() + .OrganizationUser(organizationId) + .Returns(true); + + var sharedCipher = new CipherDetails + { + Id = cipherId, + OrganizationId = organizationId, + Type = CipherType.Login, + Data = JsonSerializer.Serialize(new { Username = "test", Password = "test" }), + Folders = JsonSerializer.Serialize(new Dictionary { { userIdKey, newFolderId.ToString().ToUpperInvariant() } }), + Favorites = JsonSerializer.Serialize(new Dictionary { { userIdKey, true } }), + FolderId = newFolderId, + Favorite = true + }; + + sutProvider.GetDependency() + .GetByIdAsync(cipherId, userId) + .Returns(sharedCipher); + + sutProvider.GetDependency() + .GetOrganizationAbilitiesAsync() + .Returns(new Dictionary + { + { organizationId, new OrganizationAbility { Id = organizationId } } + }); + + var result = await sutProvider.Sut.PutShare(cipherId, model); + + Assert.Equal(newFolderId, result.FolderId); + Assert.True(result.Favorite); + } }