Skip to content

Commit 12c559d

Browse files
committed
test: improve tests
1 parent 582a14e commit 12c559d

File tree

1 file changed

+159
-2
lines changed

1 file changed

+159
-2
lines changed

tests/ByteSync.Client.UnitTests/ViewModels/Sessions/Comparisons/Actions/TargetedActionGlobalViewModelTests.cs

Lines changed: 159 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using System.Collections;
2+
using System.Collections.ObjectModel;
13
using System.Reactive;
24
using System.Reactive.Linq;
35
using System.Reactive.Subjects;
@@ -8,12 +10,16 @@
810
using ByteSync.Business.Inventories;
911
using ByteSync.Client.UnitTests.Helpers;
1012
using ByteSync.Common.Business.Actions;
13+
using ByteSync.Common.Business.EndPoints;
1114
using ByteSync.Common.Business.Inventories;
15+
using ByteSync.Common.Business.Misc;
1216
using ByteSync.Interfaces.Controls.Comparisons;
1317
using ByteSync.Interfaces.Dialogs;
1418
using ByteSync.Interfaces.Factories.ViewModels;
1519
using ByteSync.Interfaces.Services.Localizations;
20+
using ByteSync.Interfaces.Services.Sessions;
1621
using ByteSync.Models.Comparisons.Result;
22+
using ByteSync.Models.Inventories;
1723
using ByteSync.TestsCommon;
1824
using ByteSync.ViewModels.Sessions.Comparisons.Actions;
1925
using FluentAssertions;
@@ -73,10 +79,10 @@ public void SetUp()
7379
.Returns(mockActionEditViewModel.Object);
7480
}
7581

76-
private ComparisonItem CreateMockComparisonItem(FileSystemTypes fileSystemType)
82+
private ComparisonItem CreateMockComparisonItem(FileSystemTypes fileSystemType, string linkingKey = "test-file")
7783
{
7884
// Create a real ComparisonItem instance since it cannot be mocked (no parameterless constructor)
79-
var pathIdentity = new PathIdentity(fileSystemType, "test-file", "test-file", "test-file");
85+
var pathIdentity = new PathIdentity(fileSystemType, linkingKey, linkingKey, linkingKey);
8086
var comparisonItem = new ComparisonItem(pathIdentity);
8187

8288
return comparisonItem;
@@ -546,4 +552,155 @@ public void ValidationFailureSummary_AffectedItemsTooltip_ShouldGenerateCorrectT
546552
// When FileName is null, it should use LinkingKeyValue
547553
tooltip.Should().Be("file1.txt\ndirectory1");
548554
}
555+
556+
[Test]
557+
public void Save_WithValidAction_ShouldLogConsistencySuccess()
558+
{
559+
var comparisonItems = new List<ComparisonItem>
560+
{
561+
CreateMockComparisonItem(FileSystemTypes.File, "file1"),
562+
CreateMockComparisonItem(FileSystemTypes.File, "file2")
563+
};
564+
565+
var dataPartIndexer = BuildDataPartIndexer();
566+
var actionEditViewModel = new AtomicActionEditViewModel(FileSystemTypes.File, false, comparisonItems, dataPartIndexer);
567+
568+
_mockActionEditViewModelFactory.Setup(x => x.BuildAtomicActionEditViewModel(
569+
It.IsAny<FileSystemTypes>(), It.IsAny<bool>(), It.IsAny<AtomicAction>(), It.IsAny<List<ComparisonItem>>()))
570+
.Returns(actionEditViewModel);
571+
572+
var viewModel = new TargetedActionGlobalViewModel(
573+
comparisonItems,
574+
_mockDialogService.Object,
575+
_mockLocalizationService.Object,
576+
_mockTargetedActionsService.Object,
577+
_mockAtomicActionConsistencyChecker.Object,
578+
_mockActionEditViewModelFactory.Object,
579+
_mockLogger.Object,
580+
_mockFailureReasonService.Object
581+
);
582+
583+
ConfigureValidAction(actionEditViewModel);
584+
585+
var result = new AtomicActionConsistencyCheckCanAddResult(comparisonItems);
586+
_mockAtomicActionConsistencyChecker.Setup(x => x.CheckCanAdd(It.IsAny<AtomicAction>(), comparisonItems))
587+
.Returns(result);
588+
589+
viewModel.SaveCommand.Execute(Unit.Default).Subscribe();
590+
591+
_mockLogger.Verify(
592+
x => x.Log(
593+
LogLevel.Information,
594+
It.IsAny<EventId>(),
595+
It.Is<It.IsAnyType>((v, t) =>
596+
v.ToString()!.Contains("Targeted action created.")
597+
&& v.ToString()!.Contains("Items=file1, file2")),
598+
It.IsAny<Exception?>(),
599+
It.IsAny<Func<It.IsAnyType, Exception?, string>>()),
600+
Times.Once);
601+
}
602+
603+
private static void ConfigureValidAction(AtomicActionEditViewModel actionEditViewModel)
604+
{
605+
var actions = GetInternalEnumerable(actionEditViewModel, "Actions");
606+
var sources = GetInternalEnumerable(actionEditViewModel, "Sources");
607+
var destinations = GetInternalEnumerable(actionEditViewModel, "Destinations");
608+
609+
var selectedAction = GetActionByOperator(actions, ActionOperatorTypes.Copy);
610+
611+
SetInternalProperty(actionEditViewModel, "SelectedAction", selectedAction);
612+
SetInternalProperty(actionEditViewModel, "SelectedSource", FirstItem(sources));
613+
SetInternalProperty(actionEditViewModel, "SelectedDestination", FirstItem(destinations));
614+
}
615+
616+
private sealed class TestDataPartIndexer : IDataPartIndexer
617+
{
618+
private readonly ReadOnlyCollection<DataPart> _dataParts;
619+
620+
public TestDataPartIndexer(IReadOnlyCollection<DataPart> dataParts)
621+
{
622+
_dataParts = new ReadOnlyCollection<DataPart>(dataParts.ToList());
623+
}
624+
625+
public void BuildMap(List<Inventory> inventories)
626+
{
627+
}
628+
629+
public ReadOnlyCollection<DataPart> GetAllDataParts()
630+
{
631+
return _dataParts;
632+
}
633+
634+
public DataPart? GetDataPart(string? dataPartName)
635+
{
636+
return _dataParts.FirstOrDefault(dp => dp.Name == dataPartName);
637+
}
638+
639+
public void Remap(ICollection<SynchronizationRule> synchronizationRules)
640+
{
641+
}
642+
}
643+
644+
private static IDataPartIndexer BuildDataPartIndexer()
645+
{
646+
var endpoint = new ByteSyncEndpoint
647+
{
648+
ClientId = "c",
649+
ClientInstanceId = "ci",
650+
Version = "v",
651+
OSPlatform = OSPlatforms.Windows,
652+
IpAddress = "127.0.0.1"
653+
};
654+
655+
var inventoryA = new Inventory { InventoryId = "INV_A", Code = "A", Endpoint = endpoint, MachineName = "M" };
656+
var inventoryB = new Inventory { InventoryId = "INV_B", Code = "B", Endpoint = endpoint, MachineName = "M" };
657+
var partA = new InventoryPart(inventoryA, "c:\\a", FileSystemTypes.Directory) { Code = "A1" };
658+
var partB = new InventoryPart(inventoryB, "c:\\b", FileSystemTypes.Directory) { Code = "B1" };
659+
660+
var dataParts = new List<DataPart>
661+
{
662+
new("A", partA),
663+
new("B", partB)
664+
};
665+
666+
return new TestDataPartIndexer(dataParts);
667+
}
668+
669+
private static IEnumerable GetInternalEnumerable(object target, string propertyName)
670+
{
671+
var property = target.GetType().GetProperty(propertyName, BindingFlags.Instance | BindingFlags.NonPublic);
672+
673+
return (IEnumerable)property!.GetValue(target)!;
674+
}
675+
676+
private static object FirstItem(IEnumerable items)
677+
{
678+
foreach (var item in items)
679+
{
680+
return item!;
681+
}
682+
683+
throw new InvalidOperationException("Empty collection");
684+
}
685+
686+
private static void SetInternalProperty(object target, string propertyName, object? value)
687+
{
688+
var property = target.GetType().GetProperty(propertyName, BindingFlags.Instance | BindingFlags.NonPublic);
689+
property!.SetValue(target, value);
690+
}
691+
692+
private static object GetActionByOperator(IEnumerable actions, ActionOperatorTypes operatorType)
693+
{
694+
foreach (var action in actions)
695+
{
696+
var property = action!.GetType().GetProperty("ActionOperatorType", BindingFlags.Instance | BindingFlags.Public);
697+
var value = (ActionOperatorTypes)property!.GetValue(action)!;
698+
if (value == operatorType)
699+
{
700+
return action;
701+
}
702+
}
703+
704+
throw new InvalidOperationException("Action not found");
705+
}
549706
}

0 commit comments

Comments
 (0)