using Sandbox.UI; namespace UITests.Controls; [TestClass] [DoNotParallelize] // Modifies UI System Global public class LabelTextTest { bool previousRenderText; /// /// Label layout finalization rebuilds the text texture (TextBlock.RebuildTexture), which needs /// the native render system that this tier never boots. Turn the convar off for the duration of /// each test - text measurement is pure RichTextKit (CPU) and is unaffected. /// [TestInitialize] public void DisableTextTextures() { previousRenderText = TextBlock.ui_rendertext; TextBlock.ui_rendertext = false; } /// /// Restores the text texture convar so this class doesn't leak state into other tests. /// [TestCleanup] public void RestoreTextTextures() { TextBlock.ui_rendertext = previousRenderText; } /// /// Creates a root sized 1000x1000 whose children are content-sized in both axes - the default /// align-items: stretch would otherwise stretch label boxes to fill the cross axis. /// static RootPanel CreateRoot() { var root = new RootPanel(); root.PanelBounds = new Rect( 0, 0, 1000, 1000 ); root.Style.Set( "flex-direction: row; align-items: flex-start;" ); return root; } /// /// Text starts null, round-trips through the setter, and assigning null is coalesced to an /// empty string rather than stored as null. The constructor also adds the "label" class. /// [TestMethod] public void TextGetSetRoundTrip() { var label = new Label(); Assert.IsTrue( label.Class.Contains( "label" ) ); Assert.IsNull( label.Text ); label.Text = "Hello"; Assert.AreEqual( "Hello", label.Text ); label.Text = null; Assert.AreEqual( "", label.Text ); } /// /// The text+classname constructor sets the text and adds the extra class on top of the /// built-in "label" class. /// [TestMethod] public void ConstructorSetsTextAndClass() { var label = new Label( "Hi", "greeting" ); Assert.AreEqual( "Hi", label.Text ); Assert.IsTrue( label.Class.Contains( "label" ) ); Assert.IsTrue( label.Class.Contains( "greeting" ) ); } /// /// SetContent (markup inner text) and SetProperty( "text", ... ) (markup attribute) are both /// equivalent to assigning the Text property directly. /// [TestMethod] public void SetContentAndSetPropertyMatchTextProperty() { var viaProperty = new Label(); viaProperty.Text = "Hello"; var viaContent = new Label(); viaContent.SetContent( "Hello" ); var viaSetProperty = new Label(); viaSetProperty.SetProperty( "text", "Hello" ); Assert.AreEqual( viaProperty.Text, viaContent.Text ); Assert.AreEqual( viaProperty.Text, viaSetProperty.Text ); } /// /// With Tokenize disabled, text starting with '#' is stored verbatim instead of being run /// through the language phrase lookup. /// [TestMethod] public void TokenizeDisabledKeepsHashPrefixedText() { var label = new Label { Tokenize = false, Text = "#some.token" }; Assert.AreEqual( "#some.token", label.Text ); } /// /// TextLength counts text elements (graphemes), not chars - a surrogate-pair emoji is one /// element even though it is two chars. /// [TestMethod] public void TextLengthCountsGraphemes() { var label = new Label(); label.Text = "a\U0001F44Db"; Assert.AreEqual( 4, label.Text.Length ); Assert.AreEqual( 3, label.TextLength ); } /// /// A label with text and a fixed font size measures to a non-zero, content-sized box after /// layout - the measure function runs through RichTextKit on the CPU. /// [TestMethod] public void MeasuredBoxIsNonZeroAfterLayout() { var root = CreateRoot(); var label = root.AddChild