@@ -209,7 +209,7 @@ public async Task PropertyListCategoryFiltered ()
209209 [ Test ]
210210 public async Task PropertyListCategoryGroupedWithNullCategory ( )
211211 {
212- // Purposefully a null catgory
212+ // Purposefully a null category
213213 var normalProp = new Mock < IPropertyInfo > ( ) ;
214214 normalProp . SetupGet ( p => p . Type ) . Returns ( typeof ( string ) ) ;
215215 normalProp . SetupGet ( p => p . Name ) . Returns ( "name" ) ;
@@ -414,6 +414,176 @@ public void AutoExpandChosenGroups ()
414414 Assert . That ( vm . GetIsExpanded ( normalProp . Object . Category ) , Is . True ) ;
415415 }
416416
417+ [ Test ]
418+ public void GroupedTypesDoNotLeavePhantomCategory ( )
419+ {
420+ var target = new object ( ) ;
421+
422+ var property = new Mock < IPropertyInfo > ( ) ;
423+ property . SetupGet ( p => p . Type ) . Returns ( typeof ( string ) ) ;
424+ property . SetupGet ( p => p . Category ) . Returns ( ( string ) null ) ;
425+ property . SetupGet ( p => p . Name ) . Returns ( "name" ) ;
426+
427+ var provider = new Mock < IEditorProvider > ( ) ;
428+ provider . Setup ( ep => ep . GetObjectEditorAsync ( target ) )
429+ . ReturnsAsync ( new MockObjectEditor ( property . Object ) { Target = target } ) ;
430+
431+ var platform = new TargetPlatform ( provider . Object ) {
432+ GroupedTypes = new Dictionary < Type , string > {
433+ { typeof ( string ) , "strings" }
434+ }
435+ } ;
436+
437+ var vm = CreateVm ( platform ) ;
438+ vm . ArrangeMode = PropertyArrangeMode . Category ;
439+ vm . AutoExpand = true ;
440+ vm . SelectedObjects . Add ( target ) ;
441+
442+ Assert . That ( vm . ArrangedEditors . Count , Is . EqualTo ( 1 ) ) ;
443+ }
444+
445+ [ Test ]
446+ [ Description ( "https://github.com/xamarin/Xamarin.PropertyEditing/issues/525" ) ]
447+ public void SwitchingFromObjectWithGroupedType ( )
448+ {
449+ var targetWithProperties = new object ( ) ;
450+ var targetWithoutProperties = new object ( ) ;
451+
452+ var property = new Mock < IPropertyInfo > ( ) ;
453+ property . SetupGet ( p => p . Type ) . Returns ( typeof ( string ) ) ;
454+ property . SetupGet ( p => p . Category ) . Returns ( ( string ) null ) ;
455+ property . SetupGet ( p => p . Name ) . Returns ( "name" ) ;
456+
457+ var property2 = new Mock < IPropertyInfo > ( ) ;
458+ property2 . SetupGet ( p => p . Type ) . Returns ( typeof ( string ) ) ;
459+ property2 . SetupGet ( p => p . Category ) . Returns ( ( string ) null ) ;
460+ property2 . SetupGet ( p => p . Name ) . Returns ( "name2" ) ;
461+
462+ var provider = new Mock < IEditorProvider > ( ) ;
463+ provider . Setup ( ep => ep . GetObjectEditorAsync ( targetWithProperties ) )
464+ . ReturnsAsync ( new MockObjectEditor ( property . Object , property2 . Object ) { Target = targetWithProperties } ) ;
465+ provider . Setup ( ep => ep . GetObjectEditorAsync ( targetWithoutProperties ) )
466+ . ReturnsAsync ( new MockObjectEditor ( new IPropertyInfo [ 0 ] ) { Target = targetWithoutProperties } ) ;
467+
468+ var platform = new TargetPlatform ( provider . Object ) {
469+ GroupedTypes = new Dictionary < Type , string > {
470+ { typeof ( string ) , "strings" }
471+ }
472+ } ;
473+
474+ var vm = CreateVm ( platform ) ;
475+ vm . ArrangeMode = PropertyArrangeMode . Category ;
476+ vm . AutoExpand = true ;
477+ vm . SelectedObjects . Add ( targetWithProperties ) ;
478+
479+ Assume . That ( vm . ArrangedEditors . Count , Is . EqualTo ( 1 ) ) ;
480+
481+ Assert . That ( ( ) => vm . SelectedObjects . ReplaceOrAdd ( targetWithProperties , targetWithoutProperties ) ,
482+ Throws . Nothing ) ;
483+ Assert . That ( vm . ArrangedEditors . Count , Is . EqualTo ( 0 ) ) ;
484+ }
485+
486+ [ Test ]
487+ public void SwitchingToObjectWithGroupedType ( )
488+ {
489+ var targetWithProperties = new object ( ) ;
490+ var targetWithoutProperties = new object ( ) ;
491+
492+ var property = new Mock < IPropertyInfo > ( ) ;
493+ property . SetupGet ( p => p . Type ) . Returns ( typeof ( string ) ) ;
494+ property . SetupGet ( p => p . Category ) . Returns ( ( string ) null ) ;
495+ property . SetupGet ( p => p . Name ) . Returns ( "name" ) ;
496+
497+ var property2 = new Mock < IPropertyInfo > ( ) ;
498+ property2 . SetupGet ( p => p . Type ) . Returns ( typeof ( string ) ) ;
499+ property2 . SetupGet ( p => p . Category ) . Returns ( ( string ) null ) ;
500+ property2 . SetupGet ( p => p . Name ) . Returns ( "name2" ) ;
501+
502+ var provider = new Mock < IEditorProvider > ( ) ;
503+ provider . Setup ( ep => ep . GetObjectEditorAsync ( targetWithProperties ) )
504+ . ReturnsAsync ( new MockObjectEditor ( property . Object , property2 . Object ) { Target = targetWithProperties } ) ;
505+ provider . Setup ( ep => ep . GetObjectEditorAsync ( targetWithoutProperties ) )
506+ . ReturnsAsync ( new MockObjectEditor ( new IPropertyInfo [ 0 ] ) { Target = targetWithoutProperties } ) ;
507+
508+ var platform = new TargetPlatform ( provider . Object ) {
509+ GroupedTypes = new Dictionary < Type , string > {
510+ { typeof ( string ) , "strings" }
511+ }
512+ } ;
513+
514+ var vm = CreateVm ( platform ) ;
515+ vm . ArrangeMode = PropertyArrangeMode . Category ;
516+ vm . AutoExpand = true ;
517+ vm . SelectedObjects . Add ( targetWithoutProperties ) ;
518+
519+ Assume . That ( vm . ArrangedEditors . Count , Is . EqualTo ( 0 ) ) ;
520+
521+ Assert . That ( ( ) => vm . SelectedObjects . ReplaceOrAdd ( targetWithoutProperties , targetWithProperties ) ,
522+ Throws . Nothing ) ;
523+ Assert . That ( vm . ArrangedEditors . Count , Is . EqualTo ( 1 ) ) ;
524+
525+ var group = vm . ArrangedEditors [ 0 ] . Editors [ 0 ] as PropertyGroupViewModel ;
526+ Assert . That ( group , Is . Not . Null ) ;
527+ Assert . That ( group . Properties . Count , Is . EqualTo ( 2 ) ) ;
528+ }
529+
530+ [ Test ]
531+ public void GroupedTypeMultiselect ( )
532+ {
533+ var outer = new object ( ) ;
534+ var inner = new object ( ) ;
535+
536+ var property = new Mock < IPropertyInfo > ( ) ;
537+ property . SetupGet ( p => p . Type ) . Returns ( typeof ( string ) ) ;
538+ property . SetupGet ( p => p . Category ) . Returns ( ( string ) null ) ;
539+ property . SetupGet ( p => p . Name ) . Returns ( "name" ) ;
540+
541+ var property2 = new Mock < IPropertyInfo > ( ) ;
542+ property2 . SetupGet ( p => p . Type ) . Returns ( typeof ( string ) ) ;
543+ property2 . SetupGet ( p => p . Category ) . Returns ( ( string ) null ) ;
544+ property2 . SetupGet ( p => p . Name ) . Returns ( "name2" ) ;
545+
546+ var provider = new Mock < IEditorProvider > ( ) ;
547+ provider . Setup ( ep => ep . GetObjectEditorAsync ( outer ) )
548+ . ReturnsAsync ( new MockObjectEditor ( property . Object , property2 . Object ) { Target = outer } ) ;
549+ provider . Setup ( ep => ep . GetObjectEditorAsync ( inner ) )
550+ . ReturnsAsync ( new MockObjectEditor ( property . Object ) { Target = inner } ) ;
551+
552+ var platform = new TargetPlatform ( provider . Object ) {
553+ GroupedTypes = new Dictionary < Type , string > {
554+ { typeof ( string ) , "strings" }
555+ }
556+ } ;
557+
558+ var vm = CreateVm ( platform ) ;
559+ vm . ArrangeMode = PropertyArrangeMode . Category ;
560+ vm . AutoExpand = true ;
561+ vm . SelectedObjects . Add ( outer ) ;
562+
563+ Assume . That ( vm . ArrangedEditors . Count , Is . EqualTo ( 1 ) ) ;
564+
565+ var group = vm . ArrangedEditors [ 0 ] . Editors [ 0 ] as PropertyGroupViewModel ;
566+ Assume . That ( group , Is . Not . Null ) ;
567+ Assume . That ( group . Properties . Count , Is . EqualTo ( 2 ) ) ;
568+
569+ bool shouldChange = false , changed = false ;
570+ if ( group . Properties is INotifyCollectionChanged incc ) {
571+ shouldChange = true ;
572+ incc . CollectionChanged += ( o , e ) => changed = true ;
573+ }
574+
575+ vm . SelectedObjects . Add ( inner ) ;
576+ Assert . That ( vm . ArrangedEditors [ 0 ] . Editors [ 0 ] as PropertyGroupViewModel , Is . SameAs ( group ) ) ;
577+ Assert . That ( group . Properties . Count , Is . EqualTo ( 1 ) , "Number of remaining properties isn't correct" ) ;
578+ Assert . That ( group . Properties [ 0 ] . Property , Is . EqualTo ( property . Object ) , "Wrong property found in the group" ) ;
579+ Assert . That ( changed , Is . EqualTo ( shouldChange ) , "Changed status didn't match expected" ) ;
580+
581+ vm . SelectedObjects . Remove ( inner ) ;
582+ group = vm . ArrangedEditors [ 0 ] . Editors [ 0 ] as PropertyGroupViewModel ;
583+ Assert . That ( group , Is . Not . Null ) ;
584+ Assert . That ( group . Properties . Count , Is . EqualTo ( 2 ) , "Outer properties didn't restore" ) ;
585+ }
586+
417587 internal override PanelViewModel CreateVm ( TargetPlatform platform )
418588 {
419589 return new PanelViewModel ( platform ) ;
0 commit comments