using Moq; namespace LibreMetaverse.RLV.Tests.Commands { public class AttachAllCommandTests : RestrictionsBase { #region @attachallover @attachalloverorreplace @attachall:=force [Theory] [InlineData("attachall", true)] [InlineData("attachalloverorreplace", true)] [InlineData("attachallover", false)] public async Task AttachForce_Recursive(string command, bool replaceExistingAttachments) { var sampleTree = SampleInventoryTree.BuildInventoryTree(); var sharedFolder = sampleTree.Root; _queryCallbacks.Setup(e => e.TryGetSharedFolderAsync(default) ).ReturnsAsync((true, sharedFolder)); _actionCallbacks.Setup(e => e.AttachAsync(It.IsAny>(), It.IsAny()) ).Returns(Task.CompletedTask); // Attach everything inside of of the Clothing folder, and all of its subfolders recursively var expected = new HashSet() { new(sampleTree.Root_Clothing_RetroPants.Id, RlvAttachmentPoint.Default, replaceExistingAttachments), new(sampleTree.Root_Clothing_HappyShirt.Id, RlvAttachmentPoint.Default, replaceExistingAttachments), new(sampleTree.Root_Clothing_BusinessPants_Pelvis.Id, RlvAttachmentPoint.Pelvis, replaceExistingAttachments), new(sampleTree.Root_Clothing_Hats_FancyHat_Chin.Id, RlvAttachmentPoint.Chin, replaceExistingAttachments), new(sampleTree.Root_Clothing_Hats_PartyHat_Spine.Id, RlvAttachmentPoint.Spine, replaceExistingAttachments), }; // Act await _rlv.ProcessMessage($"@{command}:Clothing=force", _sender.Id, _sender.Name); // Assert _actionCallbacks.Verify(e => e.AttachAsync( It.Is>(ids => ids != null && ids.Count == expected.Count && expected.SetEquals(ids) ), It.IsAny() ), Times.Once ); _actionCallbacks.VerifyNoOtherCalls(); } [Theory] [InlineData("attachall", true)] [InlineData("attachalloverorreplace", true)] [InlineData("attachallover", false)] public async Task AttachForce_Recursive_WithHiddenSubfolder(string command, bool replaceExistingAttachments) { var sampleTree = SampleInventoryTree.BuildInventoryTree(); var sharedFolder = sampleTree.Root; sampleTree.Clothing_Hats_Folder.Name = ".hats"; _queryCallbacks.Setup(e => e.TryGetSharedFolderAsync(default) ).ReturnsAsync((true, sharedFolder)); _actionCallbacks.Setup(e => e.AttachAsync(It.IsAny>(), It.IsAny()) ).Returns(Task.CompletedTask); // Attach everything inside of of the Clothing folder, and all of its subfolders recursively. The hats folder has a special . prefix, which means it will be ignored var expected = new HashSet() { new(sampleTree.Root_Clothing_RetroPants.Id, RlvAttachmentPoint.Default, replaceExistingAttachments), new(sampleTree.Root_Clothing_HappyShirt.Id, RlvAttachmentPoint.Default, replaceExistingAttachments), new(sampleTree.Root_Clothing_BusinessPants_Pelvis.Id, RlvAttachmentPoint.Pelvis, replaceExistingAttachments), }; // Act await _rlv.ProcessMessage($"@{command}:Clothing=force", _sender.Id, _sender.Name); // Assert _actionCallbacks.Verify(e => e.AttachAsync( It.Is>(ids => ids != null && ids.Count == expected.Count && expected.SetEquals(ids) ), It.IsAny() ), Times.Once ); _actionCallbacks.VerifyNoOtherCalls(); } [Theory] [InlineData("attachall", true)] [InlineData("attachalloverorreplace", true)] [InlineData("attachallover", false)] public async Task AttachForce_Recursive_FolderNameSpecifiesToAddInsteadOfReplace(string command, bool replaceExistingAttachments) { var sampleTree = SampleInventoryTree.BuildInventoryTree(); var sharedFolder = sampleTree.Root; sampleTree.Clothing_Hats_Folder.Name = "+hats"; _queryCallbacks.Setup(e => e.TryGetSharedFolderAsync(default) ).ReturnsAsync((true, sharedFolder)); _actionCallbacks.Setup(e => e.AttachAsync(It.IsAny>(), It.IsAny()) ).Returns(Task.CompletedTask); // Attach everything inside of of the Clothing folder, and all of its subfolders recursively. The hats folder has a special + prefix, which means it will use 'add to' logic instead of 'replace' logic when attaching var expected = new HashSet() { new(sampleTree.Root_Clothing_HappyShirt.Id, RlvAttachmentPoint.Default, replaceExistingAttachments), new(sampleTree.Root_Clothing_RetroPants.Id, RlvAttachmentPoint.Default, replaceExistingAttachments), new(sampleTree.Root_Clothing_BusinessPants_Pelvis.Id, RlvAttachmentPoint.Pelvis, replaceExistingAttachments), new(sampleTree.Root_Clothing_Hats_FancyHat_Chin.Id, RlvAttachmentPoint.Chin, false), new(sampleTree.Root_Clothing_Hats_PartyHat_Spine.Id, RlvAttachmentPoint.Spine, false), }; // Act await _rlv.ProcessMessage($"@{command}:Clothing=force", _sender.Id, _sender.Name); // Assert _actionCallbacks.Verify(e => e.AttachAsync( It.Is>(ids => ids != null && ids.Count == expected.Count && expected.SetEquals(ids) ), It.IsAny() ), Times.Once ); _actionCallbacks.VerifyNoOtherCalls(); } [Theory] [InlineData("attachall", true)] [InlineData("attachalloverorreplace", true)] [InlineData("attachallover", false)] public async Task AttachForce_Recursive_SourceFolderPrivate(string command, bool replaceExistingAttachments) { var sampleTree = SampleInventoryTree.BuildInventoryTree(); var sharedFolder = sampleTree.Root; sampleTree.Clothing_Folder.Name = ".auto_attach"; _queryCallbacks.Setup(e => e.TryGetSharedFolderAsync(default) ).ReturnsAsync((true, sharedFolder)); _actionCallbacks.Setup(e => e.AttachAsync(It.IsAny>(), It.IsAny()) ).Returns(Task.CompletedTask); // Attach everything inside of of the Clothing folder, and all of its subfolders recursively. The hats folder has a special + prefix, which means it will use 'add to' logic instead of 'replace' logic when attaching var expected = new HashSet() { new(sampleTree.Root_Clothing_HappyShirt.Id, RlvAttachmentPoint.Default, replaceExistingAttachments), new(sampleTree.Root_Clothing_RetroPants.Id, RlvAttachmentPoint.Default, replaceExistingAttachments), new(sampleTree.Root_Clothing_BusinessPants_Pelvis.Id, RlvAttachmentPoint.Pelvis, replaceExistingAttachments), new(sampleTree.Root_Clothing_Hats_FancyHat_Chin.Id, RlvAttachmentPoint.Chin, replaceExistingAttachments), new(sampleTree.Root_Clothing_Hats_PartyHat_Spine.Id, RlvAttachmentPoint.Spine, replaceExistingAttachments), }; // Act await _rlv.ProcessMessage($"@{command}:.auto_attach=force", _sender.Id, _sender.Name); // Assert _actionCallbacks.Verify(e => e.AttachAsync( It.Is>(ids => ids != null && ids.Count == expected.Count && expected.SetEquals(ids) ), It.IsAny() ), Times.Once ); _actionCallbacks.VerifyNoOtherCalls(); } #endregion } }