1+ using System . Reactive ;
12using System . Reactive . Linq ;
23using System . Reactive . Subjects ;
4+ using System . Reflection ;
35using ByteSync . Business ;
46using ByteSync . Business . Actions . Local ;
57using ByteSync . Business . Comparisons ;
1012using ByteSync . Interfaces . Factories . ViewModels ;
1113using ByteSync . Interfaces . Services . Localizations ;
1214using ByteSync . Models . Comparisons . Result ;
15+ using ByteSync . Tests . Helpers ;
1316using ByteSync . TestsCommon ;
1417using ByteSync . ViewModels . Sessions . Comparisons . Actions ;
1518using FluentAssertions ;
@@ -48,7 +51,7 @@ public void SetUp()
4851 . Returns ( "The action cannot be applied to some items:" ) ;
4952 _mockLocalizationService . Setup ( x => x [ "TargetedActionEditionGlobal_AffectedItemsTooltip" ] )
5053 . Returns ( "Affected items:" ) ;
51-
54+
5255 _mockFailureReasonService . Setup ( x => x . GetLocalizedMessage ( It . IsAny < AtomicActionValidationFailureReason > ( ) ) )
5356 . Returns ( "Test failure message" ) ;
5457
@@ -71,6 +74,7 @@ private ComparisonItem CreateMockComparisonItem(FileSystemTypes fileSystemType)
7174 // Create a real ComparisonItem instance since it cannot be mocked (no parameterless constructor)
7275 var pathIdentity = new PathIdentity ( fileSystemType , "test-file" , "test-file" , "test-file" ) ;
7376 var comparisonItem = new ComparisonItem ( pathIdentity ) ;
77+
7478 return comparisonItem ;
7579 }
7680
@@ -93,7 +97,7 @@ public void Constructor_ShouldInitializeProperties()
9397 viewModel . ComparisonItems . Should ( ) . HaveCount ( 2 ) ;
9498 viewModel . FailureSummaries . Should ( ) . NotBeNull ( ) ;
9599 viewModel . FailureSummaries . Should ( ) . BeEmpty ( ) ;
96-
100+
97101 viewModel . AddActionCommand . Should ( ) . NotBeNull ( ) ;
98102 viewModel . SaveCommand . Should ( ) . NotBeNull ( ) ;
99103 viewModel . ResetCommand . Should ( ) . NotBeNull ( ) ;
@@ -102,7 +106,7 @@ public void Constructor_ShouldInitializeProperties()
102106
103107 viewModel . ActionIssuesHeaderMessage . Should ( ) . Be ( "The action cannot be applied to some items:" ) ;
104108 viewModel . AffectedItemsTooltipHeader . Should ( ) . Be ( "Affected items:" ) ;
105-
109+
106110 viewModel . ShowWarning . Should ( ) . BeFalse ( ) ;
107111 viewModel . AreMissingFields . Should ( ) . BeFalse ( ) ;
108112 viewModel . IsInconsistentWithValidItems . Should ( ) . BeNull ( ) ;
@@ -124,7 +128,7 @@ public void AddAction_ShouldCallActionEditViewModelFactory()
124128 ) ;
125129
126130 // Act
127- viewModel . AddActionCommand . Execute ( System . Reactive . Unit . Default ) . Subscribe ( ) ;
131+ viewModel . AddActionCommand . Execute ( Unit . Default ) . Subscribe ( ) ;
128132
129133 // Assert
130134 // The constructor calls the factory once during initialization, and AddActionCommand calls it again
@@ -133,7 +137,7 @@ public void AddAction_ShouldCallActionEditViewModelFactory()
133137 }
134138
135139 [ Test ]
136- public async Task OnLocaleChanged_ShouldUpdateLocalizedMessages ( )
140+ public void OnLocaleChanged_ShouldUpdateLocalizedMessages ( )
137141 {
138142 // Arrange
139143 var viewModel = new TargetedActionGlobalViewModel (
@@ -157,13 +161,10 @@ public async Task OnLocaleChanged_ShouldUpdateLocalizedMessages()
157161
158162 // Act
159163 _cultureSubject . OnNext ( new CultureDefinition { Code = "fr" } ) ;
160-
161- // Allow time for the observable to process
162- await Task . Delay ( 100 ) ;
163164
164165 // Assert
165- viewModel . ActionIssuesHeaderMessage . Should ( ) . Be ( "Updated message" ) ;
166- viewModel . AffectedItemsTooltipHeader . Should ( ) . Be ( "Updated tooltip" ) ;
166+ viewModel . ShouldEventuallyBe ( vm => vm . ActionIssuesHeaderMessage , "Updated message" ) ;
167+ viewModel . ShouldEventuallyBe ( vm => vm . AffectedItemsTooltipHeader , "Updated tooltip" ) ;
167168 }
168169
169170 [ Test ]
@@ -198,7 +199,7 @@ public async Task OnLocaleChanged_WithFailureSummaries_ShouldUpdateLocalizedMess
198199
199200 // Act
200201 _cultureSubject . OnNext ( new CultureDefinition { Code = "fr" } ) ;
201-
202+
202203 // Allow time for the observable to process
203204 await Task . Delay ( 100 ) ;
204205
@@ -231,7 +232,7 @@ public void ResetWarning_ShouldClearAllWarningProperties()
231232
232233 // Use reflection or expose method for testing
233234 var resetWarningMethod = typeof ( TargetedActionGlobalViewModel )
234- . GetMethod ( "ResetWarning" , System . Reflection . BindingFlags . NonPublic | System . Reflection . BindingFlags . Instance ) ;
235+ . GetMethod ( "ResetWarning" , BindingFlags . NonPublic | BindingFlags . Instance ) ;
235236
236237 // Act
237238 resetWarningMethod ? . Invoke ( viewModel , null ) ;
@@ -243,7 +244,7 @@ public void ResetWarning_ShouldClearAllWarningProperties()
243244 viewModel . IsInconsistentWithNoValidItems . Should ( ) . BeFalse ( ) ;
244245 }
245246
246- [ Test ]
247+ [ Test ]
247248 public void ShowConsistencyWarning_WithValidAndInvalidItems_ShouldSetCorrectProperties ( )
248249 {
249250 // Arrange
@@ -260,11 +261,12 @@ public void ShowConsistencyWarning_WithValidAndInvalidItems_ShouldSetCorrectProp
260261 // Create real instance instead of mock
261262 var result = new AtomicActionConsistencyCheckCanAddResult ( _comparisonItems ) ;
262263 result . ValidationResults . Add ( new ComparisonItemValidationResult ( _comparisonItems [ 0 ] , true ) ) ; // Valid
263- result . ValidationResults . Add ( new ComparisonItemValidationResult ( _comparisonItems [ 1 ] , AtomicActionValidationFailureReason . InvalidSourceCount ) ) ; // Invalid
264+ result . ValidationResults . Add ( new ComparisonItemValidationResult ( _comparisonItems [ 1 ] ,
265+ AtomicActionValidationFailureReason . InvalidSourceCount ) ) ; // Invalid
264266
265267 // Use reflection to access private method
266268 var showConsistencyWarningMethod = typeof ( TargetedActionGlobalViewModel )
267- . GetMethod ( "ShowConsistencyWarning" , System . Reflection . BindingFlags . NonPublic | System . Reflection . BindingFlags . Instance ) ;
269+ . GetMethod ( "ShowConsistencyWarning" , BindingFlags . NonPublic | BindingFlags . Instance ) ;
268270
269271 // Act
270272 showConsistencyWarningMethod ? . Invoke ( viewModel , [ result ] ) ;
@@ -300,12 +302,14 @@ public void ShowConsistencyWarning_WithNoValidItems_ShouldSetNoValidItemsFlag()
300302
301303 // Create real instance instead of mock - all items fail validation
302304 var result = new AtomicActionConsistencyCheckCanAddResult ( _comparisonItems ) ;
303- result . ValidationResults . Add ( new ComparisonItemValidationResult ( _comparisonItems [ 0 ] , AtomicActionValidationFailureReason . InvalidSourceCount ) ) ; // Invalid
304- result . ValidationResults . Add ( new ComparisonItemValidationResult ( _comparisonItems [ 1 ] , AtomicActionValidationFailureReason . InvalidSourceCount ) ) ; // Invalid
305+ result . ValidationResults . Add ( new ComparisonItemValidationResult ( _comparisonItems [ 0 ] ,
306+ AtomicActionValidationFailureReason . InvalidSourceCount ) ) ; // Invalid
307+ result . ValidationResults . Add ( new ComparisonItemValidationResult ( _comparisonItems [ 1 ] ,
308+ AtomicActionValidationFailureReason . InvalidSourceCount ) ) ; // Invalid
305309
306310 // Use reflection to access private method
307311 var showConsistencyWarningMethod = typeof ( TargetedActionGlobalViewModel )
308- . GetMethod ( "ShowConsistencyWarning" , System . Reflection . BindingFlags . NonPublic | System . Reflection . BindingFlags . Instance ) ;
312+ . GetMethod ( "ShowConsistencyWarning" , BindingFlags . NonPublic | BindingFlags . Instance ) ;
309313
310314 // Act
311315 showConsistencyWarningMethod ? . Invoke ( viewModel , [ result ] ) ;
@@ -334,27 +338,30 @@ public void ShowConsistencyWarning_WithMultipleFailureReasons_ShouldGroupByReaso
334338
335339 // Create real instance instead of mock with multiple failure reasons
336340 var result = new AtomicActionConsistencyCheckCanAddResult ( _comparisonItems ) ;
337- result . ValidationResults . Add ( new ComparisonItemValidationResult ( _comparisonItems [ 0 ] , AtomicActionValidationFailureReason . InvalidSourceCount ) ) ; // First InvalidSourceCount
338- result . ValidationResults . Add ( new ComparisonItemValidationResult ( _comparisonItems [ 1 ] , AtomicActionValidationFailureReason . CreateOperationOnFileNotAllowed ) ) ; // Different reason
339- result . ValidationResults . Add ( new ComparisonItemValidationResult ( _comparisonItems [ 0 ] , AtomicActionValidationFailureReason . InvalidSourceCount ) ) ; // Duplicate InvalidSourceCount
341+ result . ValidationResults . Add ( new ComparisonItemValidationResult ( _comparisonItems [ 0 ] ,
342+ AtomicActionValidationFailureReason . InvalidSourceCount ) ) ; // First InvalidSourceCount
343+ result . ValidationResults . Add ( new ComparisonItemValidationResult ( _comparisonItems [ 1 ] ,
344+ AtomicActionValidationFailureReason . CreateOperationOnFileNotAllowed ) ) ; // Different reason
345+ result . ValidationResults . Add ( new ComparisonItemValidationResult ( _comparisonItems [ 0 ] ,
346+ AtomicActionValidationFailureReason . InvalidSourceCount ) ) ; // Duplicate InvalidSourceCount
340347
341348 _mockFailureReasonService . Setup ( x => x . GetLocalizedMessage ( AtomicActionValidationFailureReason . CreateOperationOnFileNotAllowed ) )
342349 . Returns ( "Cannot create files" ) ;
343350
344351 // Use reflection to access private method
345352 var showConsistencyWarningMethod = typeof ( TargetedActionGlobalViewModel )
346- . GetMethod ( "ShowConsistencyWarning" , System . Reflection . BindingFlags . NonPublic | System . Reflection . BindingFlags . Instance ) ;
353+ . GetMethod ( "ShowConsistencyWarning" , BindingFlags . NonPublic | BindingFlags . Instance ) ;
347354
348355 // Act
349356 showConsistencyWarningMethod ? . Invoke ( viewModel , [ result ] ) ;
350357
351358 // Assert
352359 viewModel . FailureSummaries . Should ( ) . HaveCount ( 2 ) ;
353-
360+
354361 // Should be ordered by count (most frequent first)
355362 viewModel . FailureSummaries [ 0 ] . Count . Should ( ) . Be ( 2 ) ; // InvalidSourceCount appears twice
356363 viewModel . FailureSummaries [ 0 ] . Reason . Should ( ) . Be ( AtomicActionValidationFailureReason . InvalidSourceCount ) ;
357-
364+
358365 viewModel . FailureSummaries [ 1 ] . Count . Should ( ) . Be ( 1 ) ; // CreateOperationOnFileNotAllowed appears once
359366 viewModel . FailureSummaries [ 1 ] . Reason . Should ( ) . Be ( AtomicActionValidationFailureReason . CreateOperationOnFileNotAllowed ) ;
360367 viewModel . FailureSummaries [ 1 ] . LocalizedMessage . Should ( ) . Be ( "Cannot create files" ) ;
@@ -384,7 +391,7 @@ public void ShowMissingFieldsWarning_ShouldClearFailureSummariesAndSetMissingFie
384391
385392 // Use reflection to access private method
386393 var showMissingFieldsWarningMethod = typeof ( TargetedActionGlobalViewModel )
387- . GetMethod ( "ShowMissingFieldsWarning" , System . Reflection . BindingFlags . NonPublic | System . Reflection . BindingFlags . Instance ) ;
394+ . GetMethod ( "ShowMissingFieldsWarning" , BindingFlags . NonPublic | BindingFlags . Instance ) ;
388395
389396 // Act
390397 showMissingFieldsWarningMethod ? . Invoke ( viewModel , null ) ;
@@ -411,7 +418,7 @@ public void Reset_ShouldCallActionEditViewModelFactory()
411418 ) ;
412419
413420 // Act
414- viewModel . ResetCommand . Execute ( System . Reactive . Unit . Default ) . Subscribe ( ) ;
421+ viewModel . ResetCommand . Execute ( Unit . Default ) . Subscribe ( ) ;
415422
416423 // Assert
417424 // Should call factory to create action edit view model (ResetToCreation behavior)
@@ -434,7 +441,7 @@ public void Cancel_ShouldCallActionEditViewModelFactory()
434441 ) ;
435442
436443 // Act
437- viewModel . CancelCommand . Execute ( System . Reactive . Unit . Default ) . Subscribe ( ) ;
444+ viewModel . CancelCommand . Execute ( Unit . Default ) . Subscribe ( ) ;
438445
439446 // Assert
440447 // Should call factory to create action edit view model (reset behavior)
@@ -519,4 +526,4 @@ public void ValidationFailureSummary_AffectedItemsTooltip_ShouldGenerateCorrectT
519526 // When FileName is null, it should use LinkingKeyValue
520527 tooltip . Should ( ) . Be ( "file1.txt\n directory1" ) ;
521528 }
522- }
529+ }
0 commit comments