| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523 |
- #nullable enable
- using Xunit;
- namespace Terminal.Gui.ViewTests;
- [Trait ("Category", "View.Scheme")]
- public class SchemeTests
- {
- [Fact]
- public void GetScheme_Default_ReturnsBaseScheme ()
- {
- var view = new View ();
- var baseScheme = SchemeManager.GetHardCodedSchemes ()? ["Base"];
- Assert.Equal (baseScheme, view.GetScheme ());
- view.Dispose ();
- }
- [Fact]
- public void SetScheme_Explicitly_SetsSchemeCorrectly ()
- {
- var view = new View ();
- var dialogScheme = SchemeManager.GetHardCodedSchemes ()? ["Dialog"];
- view.SetScheme (dialogScheme);
- Assert.True (view.HasScheme);
- Assert.Equal (dialogScheme, view.GetScheme ());
- view.Dispose ();
- }
- [Fact]
- public void GetScheme_InheritsFromSuperView_WhenNotExplicitlySet ()
- {
- var superView = new View ();
- var subView = new View ();
- superView.Add (subView);
- var dialogScheme = SchemeManager.GetHardCodedSchemes ()? ["Dialog"];
- superView.SetScheme (dialogScheme);
- Assert.Equal (dialogScheme, subView.GetScheme ());
- Assert.False (subView.HasScheme);
- subView.Dispose ();
- superView.Dispose ();
- }
- [Fact]
- public void SetSchemeName_OverridesInheritedScheme ()
- {
- var view = new View ();
- view.SchemeName = "Dialog";
- var dialogScheme = SchemeManager.GetHardCodedSchemes ()? ["Dialog"];
- Assert.Equal (dialogScheme, view.GetScheme ());
- view.Dispose ();
- }
- [Fact]
- public void GetAttribute_ReturnsCorrectAttribute_Via_Mock ()
- {
- var view = new View { SchemeName = "Base" };
- view.Driver = new MockConsoleDriver ();
- view.Driver.SetAttribute (new Attribute (Color.Red, Color.Green));
- // Act
- var attribute = view.GetCurrentAttribute ();
- // Assert
- Assert.Equal (new Attribute (Color.Red, Color.Green), attribute);
- }
- [Fact]
- public void GetAttributeForRole_ReturnsCorrectAttribute ()
- {
- var view = new View { SchemeName = "Base" };
- Assert.Equal (view.GetScheme ().Normal, view.GetAttributeForRole (VisualRole.Normal));
- Assert.Equal (view.GetScheme ().HotNormal, view.GetAttributeForRole (VisualRole.HotNormal));
- Assert.Equal (view.GetScheme ().Focus, view.GetAttributeForRole (VisualRole.Focus));
- Assert.Equal (view.GetScheme ().HotFocus, view.GetAttributeForRole (VisualRole.HotFocus));
- Assert.Equal (view.GetScheme ().Disabled, view.GetAttributeForRole (VisualRole.Disabled));
- view.Dispose ();
- }
- [Fact]
- public void GetAttributeForRole_DisabledView_ReturnsCorrectAttribute ()
- {
- var view = new View { SchemeName = "Base" };
- view.Enabled = false;
- Assert.Equal (view.GetScheme ().Disabled, view.GetAttributeForRole (VisualRole.Normal));
- Assert.Equal (view.GetScheme ().Disabled, view.GetAttributeForRole (VisualRole.HotNormal));
- view.Dispose ();
- }
- [Fact]
- public void SetAttributeForRole_SetsCorrectAttribute ()
- {
- var view = new View { SchemeName = "Base" };
- view.Driver = new MockConsoleDriver ();
- view.Driver.SetAttribute (new Attribute (Color.Red, Color.Green));
- var previousAttribute = view.SetAttributeForRole (VisualRole.Focus);
- Assert.Equal (view.GetScheme ().Focus, view.GetCurrentAttribute ());
- Assert.NotEqual (previousAttribute, view.GetCurrentAttribute ());
- view.Dispose ();
- }
- [Fact]
- public void OnGettingScheme_Override_StopsDefaultBehavior ()
- {
- var view = new CustomView ();
- var customScheme = SchemeManager.GetHardCodedSchemes ()? ["Error"];
- Assert.Equal (customScheme, view.GetScheme ());
- view.Dispose ();
- }
- [Fact]
- public void OnSettingScheme_Override_PreventsSettingScheme ()
- {
- var view = new CustomView ();
- var dialogScheme = SchemeManager.GetHardCodedSchemes ()? ["Dialog"];
- view.SetScheme (dialogScheme);
- Assert.NotEqual (dialogScheme, view.GetScheme ());
- view.Dispose ();
- }
- [Fact]
- public void GettingScheme_Event_CanOverrideScheme ()
- {
- var view = new View ();
- var customScheme = SchemeManager.GetHardCodedSchemes ()? ["Error"]! with { Normal = Attribute.Default };
- Assert.NotEqual (Attribute.Default, view.GetScheme ().Normal);
- view.GettingScheme += (sender, args) =>
- {
- args.Result = customScheme;
- args.Handled = true;
- };
- Assert.Equal (customScheme, view.GetScheme ());
- Assert.Equal (Attribute.Default, view.GetScheme ().Normal);
- view.Dispose ();
- }
- [Fact]
- public void SettingScheme_Event_CanCancelSchemeChange ()
- {
- var view = new View ();
- var dialogScheme = SchemeManager.GetHardCodedSchemes ()? ["Dialog"];
- view.SchemeChanging += (sender, args) => args.Handled = true;
- view.SetScheme (dialogScheme);
- Assert.NotEqual (dialogScheme, view.GetScheme ());
- view.Dispose ();
- }
- [Fact]
- public void GetAttributeForRole_Event_CanOverrideAttribute ()
- {
- var view = new View { SchemeName = "Base" };
- var customAttribute = new Attribute (Color.BrightRed, Color.BrightYellow);
- view.GettingAttributeForRole += (sender, args) =>
- {
- if (args.Role == VisualRole.Focus)
- {
- args.Result = customAttribute;
- args.Handled = true;
- }
- };
- Assert.Equal (customAttribute, view.GetAttributeForRole (VisualRole.Focus));
- view.Dispose ();
- }
- [Fact]
- public void GetHardCodedSchemes_ReturnsExpectedSchemes ()
- {
- var schemes = Scheme.GetHardCodedSchemes ();
- Assert.NotNull (schemes);
- Assert.Contains ("Base", schemes.Keys);
- Assert.Contains ("Dialog", schemes.Keys);
- Assert.Contains ("Error", schemes.Keys);
- Assert.Contains ("Menu", schemes.Keys);
- Assert.Contains ("Toplevel", schemes.Keys);
- }
- [Fact]
- public void SchemeName_OverridesSuperViewScheme ()
- {
- var superView = new View ();
- var subView = new View ();
- superView.Add (subView);
- subView.SchemeName = "Error";
- var errorScheme = SchemeManager.GetHardCodedSchemes ()? ["Error"];
- Assert.Equal (errorScheme, subView.GetScheme ());
- subView.Dispose ();
- superView.Dispose ();
- }
- [Fact]
- public void Scheme_DefaultsToBase_WhenNotSet ()
- {
- var view = new View ();
- var baseScheme = SchemeManager.GetHardCodedSchemes ()? ["Base"];
- Assert.Equal (baseScheme, view.GetScheme ());
- view.Dispose ();
- }
- [Fact]
- public void Scheme_HandlesNullSuperViewGracefully ()
- {
- var view = new View ();
- view.SchemeName = "Dialog";
- var dialogScheme = SchemeManager.GetHardCodedSchemes ()? ["Dialog"];
- Assert.Equal (dialogScheme, view.GetScheme ());
- view.Dispose ();
- }
- private class CustomView : View
- {
- protected override bool OnGettingScheme (out Scheme? scheme)
- {
- scheme = SchemeManager.GetHardCodedSchemes ()? ["Error"];
- return true;
- }
- protected override bool OnSettingScheme (ValueChangingEventArgs<Scheme?> args)
- {
- return true; // Prevent setting the scheme
- }
- }
- [Fact]
- public void GetAttributeForRole_SubView_DefersToSuperView_WhenNoExplicitScheme ()
- {
- var parentView = new View { SchemeName = "Base" };
- var childView = new View ();
- parentView.Add (childView);
- // Parent customizes attribute resolution
- var customAttribute = new Attribute (Color.BrightMagenta, Color.BrightGreen);
- parentView.GettingAttributeForRole += (sender, args) =>
- {
- if (args.Role == VisualRole.Normal)
- {
- args.Result = customAttribute;
- args.Handled = true;
- }
- };
- // Child without explicit scheme should get customized attribute from parent
- Assert.Equal (customAttribute, childView.GetAttributeForRole (VisualRole.Normal));
- childView.Dispose ();
- parentView.Dispose ();
- }
- [Fact]
- public void GetAttributeForRole_SubView_UsesOwnScheme_WhenExplicitlySet ()
- {
- var parentView = new View { SchemeName = "Base" };
- var childView = new View ();
- parentView.Add (childView);
- // Set explicit scheme on child
- var childScheme = SchemeManager.GetHardCodedSchemes ()? ["Dialog"];
- childView.SetScheme (childScheme);
- // Parent customizes attribute resolution
- var customAttribute = new Attribute (Color.BrightMagenta, Color.BrightGreen);
- parentView.GettingAttributeForRole += (sender, args) =>
- {
- if (args.Role == VisualRole.Normal)
- {
- args.Result = customAttribute;
- args.Handled = true;
- }
- };
- // Child with explicit scheme should NOT get customized attribute from parent
- Assert.NotEqual (customAttribute, childView.GetAttributeForRole (VisualRole.Normal));
- Assert.Equal (childScheme!.Normal, childView.GetAttributeForRole (VisualRole.Normal));
- childView.Dispose ();
- parentView.Dispose ();
- }
- [Fact]
- public void GetAttributeForRole_Adornment_UsesParentScheme ()
- {
- // Border (an Adornment) doesn't have a SuperView but should use its Parent's scheme
- var view = new View { SchemeName = "Dialog" };
- var border = view.Border!;
-
- Assert.NotNull (border);
- Assert.Null (border.SuperView); // Adornments don't have SuperView
- Assert.NotNull (border.Parent);
-
- var dialogScheme = SchemeManager.GetHardCodedSchemes ()? ["Dialog"];
-
- // Border should use its Parent's scheme, not Base
- Assert.Equal (dialogScheme!.Normal, border.GetAttributeForRole (VisualRole.Normal));
-
- view.Dispose ();
- }
- [Fact]
- public void GetAttributeForRole_SubView_UsesSchemeName_WhenSet ()
- {
- var parentView = new View { SchemeName = "Base" };
- var childView = new View ();
- parentView.Add (childView);
- // Set SchemeName on child (not explicit scheme)
- childView.SchemeName = "Dialog";
- // Parent customizes attribute resolution
- var customAttribute = new Attribute (Color.BrightMagenta, Color.BrightGreen);
- parentView.GettingAttributeForRole += (sender, args) =>
- {
- if (args.Role == VisualRole.Normal)
- {
- args.Result = customAttribute;
- args.Handled = true;
- }
- };
- // Child with SchemeName should NOT get customized attribute from parent
- // It should use the Dialog scheme instead
- var dialogScheme = SchemeManager.GetHardCodedSchemes ()? ["Dialog"];
- Assert.NotEqual (customAttribute, childView.GetAttributeForRole (VisualRole.Normal));
- Assert.Equal (dialogScheme!.Normal, childView.GetAttributeForRole (VisualRole.Normal));
- childView.Dispose ();
- parentView.Dispose ();
- }
- [Fact]
- public void GetAttributeForRole_NestedHierarchy_DefersCorrectly ()
- {
- // Test: grandchild without explicit scheme defers through parent to grandparent
- // Would fail without the SuperView deferral fix (commit 154ac15)
-
- var grandparentView = new View { SchemeName = "Base" };
- var parentView = new View (); // No scheme or SchemeName
- var childView = new View (); // No scheme or SchemeName
-
- grandparentView.Add (parentView);
- parentView.Add (childView);
- // Grandparent customizes attributes
- var customAttribute = new Attribute (Color.BrightYellow, Color.BrightBlue);
- grandparentView.GettingAttributeForRole += (sender, args) =>
- {
- if (args.Role == VisualRole.Normal)
- {
- args.Result = customAttribute;
- args.Handled = true;
- }
- };
- // Child should get attribute from grandparent through parent
- Assert.Equal (customAttribute, childView.GetAttributeForRole (VisualRole.Normal));
-
- // Parent should also get attribute from grandparent
- Assert.Equal (customAttribute, parentView.GetAttributeForRole (VisualRole.Normal));
- childView.Dispose ();
- parentView.Dispose ();
- grandparentView.Dispose ();
- }
- [Fact]
- public void GetAttributeForRole_ParentWithSchemeNameBreaksChain ()
- {
- // Test: parent with SchemeName stops deferral chain
- // Would fail without the SchemeName check (commit 866e002)
-
- var grandparentView = new View { SchemeName = "Base" };
- var parentView = new View { SchemeName = "Dialog" }; // Sets SchemeName
- var childView = new View (); // No scheme or SchemeName
-
- grandparentView.Add (parentView);
- parentView.Add (childView);
- // Grandparent customizes attributes
- var customAttribute = new Attribute (Color.BrightYellow, Color.BrightBlue);
- grandparentView.GettingAttributeForRole += (sender, args) =>
- {
- if (args.Role == VisualRole.Normal)
- {
- args.Result = customAttribute;
- args.Handled = true;
- }
- };
- // Parent should NOT get grandparent's customization (it has SchemeName)
- var dialogScheme = SchemeManager.GetHardCodedSchemes ()? ["Dialog"];
- Assert.NotEqual (customAttribute, parentView.GetAttributeForRole (VisualRole.Normal));
- Assert.Equal (dialogScheme!.Normal, parentView.GetAttributeForRole (VisualRole.Normal));
-
- // Child should get parent's Dialog scheme (defers to parent, parent uses Dialog scheme)
- Assert.Equal (dialogScheme!.Normal, childView.GetAttributeForRole (VisualRole.Normal));
- childView.Dispose ();
- parentView.Dispose ();
- grandparentView.Dispose ();
- }
- [Fact]
- public void GetAttributeForRole_OnGettingAttributeForRole_TakesPrecedence ()
- {
- // Test: view's own OnGettingAttributeForRole takes precedence over parent
- // This should work with or without the fix, but validates precedence
-
- var parentView = new View { SchemeName = "Base" };
- var childView = new TestViewWithAttributeOverride ();
- parentView.Add (childView);
- // Parent customizes attributes
- var parentAttribute = new Attribute (Color.BrightYellow, Color.BrightBlue);
- parentView.GettingAttributeForRole += (sender, args) =>
- {
- if (args.Role == VisualRole.Normal)
- {
- args.Result = parentAttribute;
- args.Handled = true;
- }
- };
- // Child's own override should take precedence
- var childOverrideAttribute = new Attribute (Color.BrightRed, Color.BrightCyan);
- childView.OverrideAttribute = childOverrideAttribute;
-
- Assert.Equal (childOverrideAttribute, childView.GetAttributeForRole (VisualRole.Normal));
- childView.Dispose ();
- parentView.Dispose ();
- }
- [Fact]
- public void GetAttributeForRole_MultipleRoles_DeferCorrectly ()
- {
- // Test: multiple VisualRoles all defer correctly
- // Would fail without the SuperView deferral fix for any role
-
- var parentView = new View { SchemeName = "Base" };
- var childView = new View ();
- parentView.Add (childView);
- var normalAttr = new Attribute (Color.Red, Color.Blue);
- var focusAttr = new Attribute (Color.Green, Color.Yellow);
- var hotNormalAttr = new Attribute (Color.Magenta, Color.Cyan);
- parentView.GettingAttributeForRole += (sender, args) =>
- {
- switch (args.Role)
- {
- case VisualRole.Normal:
- args.Result = normalAttr;
- args.Handled = true;
- break;
- case VisualRole.Focus:
- args.Result = focusAttr;
- args.Handled = true;
- break;
- case VisualRole.HotNormal:
- args.Result = hotNormalAttr;
- args.Handled = true;
- break;
- }
- };
- // All roles should defer to parent
- Assert.Equal (normalAttr, childView.GetAttributeForRole (VisualRole.Normal));
- Assert.Equal (focusAttr, childView.GetAttributeForRole (VisualRole.Focus));
- Assert.Equal (hotNormalAttr, childView.GetAttributeForRole (VisualRole.HotNormal));
- childView.Dispose ();
- parentView.Dispose ();
- }
- private class TestViewWithAttributeOverride : View
- {
- public Attribute? OverrideAttribute { get; set; }
- protected override bool OnGettingAttributeForRole (in VisualRole role, ref Attribute currentAttribute)
- {
- if (OverrideAttribute.HasValue && role == VisualRole.Normal)
- {
- currentAttribute = OverrideAttribute.Value;
- return true;
- }
- return base.OnGettingAttributeForRole (role, ref currentAttribute);
- }
- }
- }
|