@@ -414,11 +414,211 @@ 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+
587+ [ Test ]
588+ public void GroupedTypeWhileNamed ( )
589+ {
590+ var outer = new object ( ) ;
591+
592+ var property = new Mock < IPropertyInfo > ( ) ;
593+ property . SetupGet ( p => p . Type ) . Returns ( typeof ( string ) ) ;
594+ property . SetupGet ( p => p . Category ) . Returns ( ( string ) null ) ;
595+ property . SetupGet ( p => p . Name ) . Returns ( "name" ) ;
596+
597+ var provider = new Mock < IEditorProvider > ( ) ;
598+ provider . Setup ( ep => ep . GetObjectEditorAsync ( outer ) )
599+ . ReturnsAsync ( new MockObjectEditor ( property . Object ) { Target = outer } ) ;
600+
601+ var platform = new TargetPlatform ( provider . Object ) {
602+ GroupedTypes = new Dictionary < Type , string > {
603+ { typeof ( string ) , "strings" }
604+ }
605+ } ;
606+
607+ var vm = CreateVm ( platform ) ;
608+ vm . ArrangeMode = PropertyArrangeMode . Name ;
609+ vm . SelectedObjects . Add ( outer ) ;
610+
611+ Assume . That ( vm . ArrangedEditors . Count , Is . EqualTo ( 1 ) ) ;
612+
613+ var group = vm . ArrangedEditors [ 0 ] . Editors [ 0 ] as StringPropertyViewModel ;
614+ Assert . That ( group , Is . Not . Null ) ;
615+ }
616+
417617 internal override PanelViewModel CreateVm ( TargetPlatform platform )
418618 {
419619 return new PanelViewModel ( platform ) ;
420620 }
421621
422622 private TestContext context ;
423623 }
424- }
624+ }
0 commit comments