2021-04-01 19:36:56 +02:00
using System ;
2021-06-25 12:45:00 +02:00
using System.Diagnostics ;
2021-04-01 19:36:56 +02:00
using System.Linq ;
using Microsoft.Xna.Framework ;
2024-07-19 20:02:28 +02:00
using MLEM.Maths ;
2021-04-01 19:36:56 +02:00
using MLEM.Ui ;
using MLEM.Ui.Elements ;
using MLEM.Ui.Style ;
using NUnit.Framework ;
2022-12-13 13:11:36 +01:00
namespace Tests ;
2021-04-01 19:36:56 +02:00
2022-10-27 10:22:25 +02:00
public class UiTests {
2021-04-02 17:12:27 +02:00
2022-10-27 10:22:25 +02:00
private TestGame game ;
2021-04-02 17:12:27 +02:00
2022-10-27 10:22:25 +02:00
[SetUp]
public void SetUp ( ) {
this . game = TestGame . Create ( ) ;
}
2021-04-02 17:12:27 +02:00
2022-10-27 10:22:25 +02:00
[TearDown]
public void TearDown ( ) {
this . game ? . Dispose ( ) ;
}
2021-04-27 21:17:06 +02:00
2022-10-27 10:22:25 +02:00
[Test]
public void TestInvalidPanel ( ) {
var invalidPanel = new Panel ( Anchor . Center , Vector2 . Zero , Vector2 . Zero ) {
SetWidthBasedOnChildren = true ,
SetHeightBasedOnChildren = true
} ;
invalidPanel . AddChild ( new Paragraph ( Anchor . AutoRight , 1 , "This is some test text!" , true ) ) ;
invalidPanel . AddChild ( new VerticalSpace ( 1 ) ) ;
2024-10-07 18:32:22 +02:00
Assert . Throws < ArithmeticException > ( ( ) = > this . AddAndUpdate ( invalidPanel , out _ , out _ ) ) ;
2022-10-27 10:22:25 +02:00
}
2021-04-01 19:36:56 +02:00
2022-10-27 10:22:25 +02:00
[Test]
public void TestOddlyAlignedPanel ( ) {
var oddPanel = new Panel ( Anchor . Center , Vector2 . One , Vector2 . Zero , true ) { SetWidthBasedOnChildren = true } ;
oddPanel . AddChild ( new Group ( Anchor . TopCenter , new Vector2 ( 100 ) , false ) ) ;
oddPanel . AddChild ( new Group ( Anchor . AutoRight , new Vector2 ( 120 ) , false ) ) ;
2024-10-07 18:32:22 +02:00
this . AddAndUpdate ( oddPanel , out _ , out _ ) ;
2022-10-27 10:22:25 +02:00
Assert . AreEqual ( 120 + 10 , oddPanel . DisplayArea . Width ) ;
}
2021-04-01 19:36:56 +02:00
2022-10-27 10:22:25 +02:00
[Test]
public void TestComplexPanel ( ) {
var group = new Group ( Anchor . TopLeft , Vector2 . One , false ) ;
var panel = group . AddChild ( new Panel ( Anchor . Center , new Vector2 ( 150 , 150 ) , Vector2 . Zero , false , true , false ) {
ChildPadding = new Padding ( 5 , 5 , 5 , 5 )
} ) ;
for ( var i = 0 ; i < 5 ; i + + ) {
var button = panel . AddChild ( new Button ( Anchor . AutoLeft , new Vector2 ( 1 ) ) {
SetHeightBasedOnChildren = true ,
Padding = new Padding ( 0 , 0 , 0 , 1 ) ,
ChildPadding = new Padding ( 3 )
2022-08-16 14:20:32 +02:00
} ) ;
2022-10-27 10:22:25 +02:00
button . AddChild ( new Group ( Anchor . AutoLeft , new Vector2 ( 0.5F , 30 ) , false ) {
CanBeMoused = false
2022-08-16 14:20:32 +02:00
} ) ;
}
2024-10-07 18:32:22 +02:00
this . AddAndUpdate ( group , out _ , out _ ) ;
2022-10-27 10:22:25 +02:00
// group has 1 panel with 1 scroll bar, and the panel's 10 children
Assert . AreEqual ( 1 , group . GetChildren ( ) . Count ( ) ) ;
Assert . AreEqual ( 12 , group . GetChildren ( regardGrandchildren : true ) . Count ( ) ) ;
// panel 1 scroll bar and 5 buttons, each button has 1 group, so 11 grandchildren
Assert . AreEqual ( 6 , panel . GetChildren ( ) . Count ( ) ) ;
Assert . AreEqual ( 11 , panel . GetChildren ( regardGrandchildren : true ) . Count ( ) ) ;
var testBtn = panel . GetChildren < Button > ( ) . First ( ) ;
// panel's width is 150, minus child padding of 5 on each side, and scroll bar's width of 5 and gap of 1
const int panelContentWidth = 150 - 5 - 5 - 5 - 1 ;
Assert . AreEqual ( testBtn . DisplayArea . Width , panelContentWidth ) ;
// button's width, minus child padding of 3 left and 3 right, divided by 2 because of group's width
Assert . AreEqual ( testBtn . GetChildren < Group > ( ) . Single ( ) . DisplayArea . Width , ( panelContentWidth - 3 - 3 ) * 0.5F ) ;
}
2022-08-16 14:20:32 +02:00
2022-10-27 10:22:25 +02:00
[Test]
public void TestAbsoluteAutoSize ( ) {
var parent = new Panel ( Anchor . AutoLeft , new Vector2 ( 200 , 100 ) , Vector2 . Zero ) {
ChildPadding = Padding . Empty
} ;
var el1 = parent . AddChild ( new Button ( Anchor . AutoLeft , new Vector2 ( 0.5F , 0.75F ) ) {
AutoSizeAddedAbsolute = new Vector2 ( - 50 , 25 )
} ) ;
var el2 = parent . AddChild ( new Button ( Anchor . AutoLeft , new Vector2 ( 0.25F , - 0.5F ) ) {
AutoSizeAddedAbsolute = new Vector2 ( - 25 , 50 )
} ) ;
2024-10-07 18:32:22 +02:00
this . AddAndUpdate ( parent , out _ , out _ ) ;
2022-10-27 10:22:25 +02:00
Assert . AreEqual ( 0.5F * 200 - 50 , el1 . DisplayArea . Width ) ;
Assert . AreEqual ( 0.75F * 100 + 25 , el1 . DisplayArea . Height ) ;
const float el2Width = 0.25F * 200 - 25 ;
Assert . AreEqual ( el2Width , el2 . DisplayArea . Width ) ;
Assert . AreEqual ( 0.5F * el2Width + 50 , el2 . DisplayArea . Height ) ;
}
[Test]
public void TestStyle ( ) {
var style = new StyleProp < string > ( ) ;
Assert . AreEqual ( null , style . Value ) ;
style = style . OrStyle ( "from style" ) ;
Assert . AreEqual ( "from style" , style . Value ) ;
style = "custom" ;
Assert . AreEqual ( "custom" , style . Value ) ;
style = style . OrStyle ( "from style again" ) ;
Assert . AreEqual ( "custom" , style . Value ) ;
var copy = style . OrStyle ( "copy from style" , byte . MaxValue ) ;
var weakCopy = style . OrStyle ( "weak copy" ) ;
Assert . AreEqual ( "copy from style" , copy . Value ) ;
Assert . AreEqual ( "custom" , weakCopy . Value ) ;
Assert . AreEqual ( "custom" , style . Value ) ;
}
2021-04-04 18:31:51 +02:00
2022-10-27 10:22:25 +02:00
[Test]
2024-10-07 18:32:22 +02:00
public void TestAutoAreaPerformanceDeep ( ) {
2022-10-27 10:22:25 +02:00
for ( var i = 1 ; i < = 100 ; i + + ) {
2024-10-07 21:51:35 +02:00
var main = new Group ( Anchor . TopLeft , new Vector2 ( 50 ) ) ;
2022-10-27 10:22:25 +02:00
var group = main ;
2024-10-07 21:51:35 +02:00
for ( var g = 0 ; g < i ; g + + )
group = group . AddChild ( new Group ( Anchor . TopLeft , Vector2 . One ) ) ;
2024-10-07 18:32:22 +02:00
this . AddAndUpdate ( main , out var addTime , out var updateTime ) ;
2022-10-27 10:22:25 +02:00
var allChildren = main . GetChildren ( regardGrandchildren : true ) ;
2024-10-07 21:51:35 +02:00
TestContext . WriteLine ( $"{allChildren.Count()} children, took {addTime.TotalMilliseconds * 1000000}ns to add, {updateTime.TotalMilliseconds * 1000000}ns to update, metrics {this.game.UiSystem.Metrics}" ) ;
2021-06-25 12:45:00 +02:00
}
2022-10-27 10:22:25 +02:00
}
2021-06-25 12:45:00 +02:00
2024-10-07 18:32:22 +02:00
[Test]
public void TestAutoAreaPerformanceSideBySide ( ) {
for ( var i = 1 ; i < = 100 ; i + + ) {
2024-10-07 21:51:35 +02:00
var main = new Group ( Anchor . TopLeft , new Vector2 ( 50 ) ) ;
for ( var g = 0 ; g < i ; g + + )
main . AddChild ( new Group ( Anchor . AutoInlineIgnoreOverflow , new Vector2 ( 1F / i , 1 ) ) ) ;
2024-10-07 18:32:22 +02:00
this . AddAndUpdate ( main , out var addTime , out var updateTime ) ;
var allChildren = main . GetChildren ( regardGrandchildren : true ) ;
2024-10-07 21:51:35 +02:00
TestContext . WriteLine ( $"{allChildren.Count()} children, took {addTime.TotalMilliseconds * 1000000}ns to add, {updateTime.TotalMilliseconds * 1000000}ns to update, metrics {this.game.UiSystem.Metrics}" ) ;
2024-10-07 18:32:22 +02:00
}
}
[Test]
public void TestAutoAreaPerformanceRandom ( ) {
for ( var i = 0 ; i < = 1000 ; i + = 10 ) {
var random = new Random ( 93829345 ) ;
2024-10-07 21:51:35 +02:00
var main = new Group ( Anchor . TopLeft , new Vector2 ( 50 ) ) ;
2024-10-07 18:32:22 +02:00
var group = main ;
for ( var g = 0 ; g < i ; g + + ) {
2024-10-07 21:51:35 +02:00
var newGroup = group . AddChild ( new Group ( Anchor . TopLeft , Vector2 . One ) ) ;
2024-10-07 18:32:22 +02:00
if ( random . NextSingle ( ) < = 0.25F )
group = newGroup ;
}
this . AddAndUpdate ( main , out var addTime , out var updateTime ) ;
var allChildren = main . GetChildren ( regardGrandchildren : true ) ;
2024-10-07 21:51:35 +02:00
TestContext . WriteLine ( $"{allChildren.Count()} children, took {addTime.TotalMilliseconds * 1000000}ns to add, {updateTime.TotalMilliseconds * 1000000}ns to update, metrics {this.game.UiSystem.Metrics}" ) ;
2024-10-07 18:32:22 +02:00
}
}
private void AddAndUpdate ( Element element , out TimeSpan addTime , out TimeSpan updateTime ) {
2022-10-27 10:22:25 +02:00
foreach ( var root in this . game . UiSystem . GetRootElements ( ) )
this . game . UiSystem . Remove ( root . Name ) ;
2024-10-07 21:51:35 +02:00
this . game . UiSystem . Metrics . ResetUpdates ( ) ;
2021-04-04 18:31:51 +02:00
2024-10-07 18:32:22 +02:00
var stopwatch = Stopwatch . StartNew ( ) ;
2022-10-27 10:22:25 +02:00
this . game . UiSystem . Add ( "Test" , element ) ;
2024-10-07 18:32:22 +02:00
stopwatch . Stop ( ) ;
addTime = stopwatch . Elapsed ;
stopwatch . Restart ( ) ;
2022-10-27 10:22:25 +02:00
element . ForceUpdateArea ( ) ;
2024-10-07 18:32:22 +02:00
stopwatch . Stop ( ) ;
updateTime = stopwatch . Elapsed ;
2021-04-01 19:36:56 +02:00
}
2022-10-27 10:22:25 +02:00
2022-06-17 18:23:47 +02:00
}