From 963e8b6585f2d00e8aac9dae1d4c9599d125c120 Mon Sep 17 00:00:00 2001 From: austin Date: Sun, 15 Sep 2024 15:47:58 -0400 Subject: [PATCH] ui tests --- docs/src/progress/renderertodo.md | 7 ++--- .../net/client/protocol/CombatProtocol.java | 3 -- .../renderer/ui/elements/ButtonTests.java | 26 ++++++++++++++++ .../renderer/ui/elements/ImagePanelTests.java | 26 ++++++++++++++++ .../renderer/ui/elements/LabelTests.java | 26 ++++++++++++++++ .../renderer/ui/elements/TestBoxTests.java | 27 ++++++++++++++++ .../renderer/ui/elements/TestInputTests.java | 29 ++++++++++++++++++ .../ui/elements/ToggleInputTests.java | 27 ++++++++++++++++ .../renderer/ui/elements/WindowTest.java | 2 +- .../renderer/ui/elements/WordTests.java | 27 ++++++++++++++++ test/java/renderer/ui/elements/button1.png | Bin 0 -> 11245 bytes .../java/renderer/ui/elements/imagepanel1.png | Bin 0 -> 11610 bytes test/java/renderer/ui/elements/label1.png | Bin 0 -> 11765 bytes test/java/renderer/ui/elements/textbox1.png | Bin 0 -> 11405 bytes test/java/renderer/ui/elements/textinput1.png | Bin 0 -> 11401 bytes .../renderer/ui/elements/toggleinput1.png | Bin 0 -> 10450 bytes test/java/renderer/ui/elements/word1.png | Bin 0 -> 11976 bytes 17 files changed, 191 insertions(+), 9 deletions(-) create mode 100644 src/test/java/electrosphere/renderer/ui/elements/ButtonTests.java create mode 100644 src/test/java/electrosphere/renderer/ui/elements/ImagePanelTests.java create mode 100644 src/test/java/electrosphere/renderer/ui/elements/LabelTests.java create mode 100644 src/test/java/electrosphere/renderer/ui/elements/TestBoxTests.java create mode 100644 src/test/java/electrosphere/renderer/ui/elements/TestInputTests.java create mode 100644 src/test/java/electrosphere/renderer/ui/elements/ToggleInputTests.java create mode 100644 src/test/java/electrosphere/renderer/ui/elements/WordTests.java create mode 100644 test/java/renderer/ui/elements/button1.png create mode 100644 test/java/renderer/ui/elements/imagepanel1.png create mode 100644 test/java/renderer/ui/elements/label1.png create mode 100644 test/java/renderer/ui/elements/textbox1.png create mode 100644 test/java/renderer/ui/elements/textinput1.png create mode 100644 test/java/renderer/ui/elements/toggleinput1.png create mode 100644 test/java/renderer/ui/elements/word1.png diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index 1fe18ae7..81be5451 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -766,6 +766,8 @@ Fix all items spawning above player head Fix items falling below terrain Fix gridded data cell manager saving attached items on realm save Fix render signals caching between frames (not reseting global flags per usual) +Capture image from opengl to pixel-check +Add ui tests # TODO @@ -778,11 +780,6 @@ Ability to fully reload game engine state without exiting client - Back out to main menu and load a new level without any values persisting - Receive a teleport packet from server and flush all game state before requesting state from server again -Unit Testing - - Capture image from opengl to pixel-check - - Ability to click through the ui via scripts - - Add ui tests - Bug Fixes - Fix hitbox placement does not scale with entity scale on server - Fix not all grass tiles update when updating a nearby voxel (ie it doesn't go into negative coordinates to scan for foliage updates) diff --git a/src/main/java/electrosphere/net/client/protocol/CombatProtocol.java b/src/main/java/electrosphere/net/client/protocol/CombatProtocol.java index a5c00009..961eec8b 100644 --- a/src/main/java/electrosphere/net/client/protocol/CombatProtocol.java +++ b/src/main/java/electrosphere/net/client/protocol/CombatProtocol.java @@ -5,7 +5,6 @@ import org.joml.Vector3d; import electrosphere.client.collision.ClientHitboxCollision; import electrosphere.engine.Globals; import electrosphere.entity.Entity; -import electrosphere.logger.LoggerInterface; import electrosphere.net.parser.net.message.CombatMessage; import electrosphere.net.template.ClientProtocolTemplate; @@ -28,8 +27,6 @@ public class CombatProtocol implements ClientProtocolTemplate { Entity receiverEntity = Globals.clientSceneWrapper.getEntityFromServerId(message.getreceiverEntityID()); if(senderEntity != null && receiverEntity != null){ ClientHitboxCollision.handleHitboxCollision(senderEntity, receiverEntity, position, message.gethitboxType(), message.gethurtboxType()); - } else { - LoggerInterface.loggerEngine.WARNING("Received collision event for entities that are undefined! " + senderEntity + " " + receiverEntity); } } break; } diff --git a/src/test/java/electrosphere/renderer/ui/elements/ButtonTests.java b/src/test/java/electrosphere/renderer/ui/elements/ButtonTests.java new file mode 100644 index 00000000..085c2bdf --- /dev/null +++ b/src/test/java/electrosphere/renderer/ui/elements/ButtonTests.java @@ -0,0 +1,26 @@ +package electrosphere.renderer.ui.elements; +import electrosphere.menu.WindowUtils; +import electrosphere.test.annotations.IntegrationTest; +import electrosphere.test.template.UITestTemplate; +import electrosphere.test.testutils.TestEngineUtils; + +/** + * Tests the button ui component + */ +public class ButtonTests extends UITestTemplate { + + @IntegrationTest + public void test_Create(){ + //setup + this.setupBlankView(); + WindowUtils.replaceMainMenuContents(Button.createButton("test", () -> {})); + + + //wait for ui updates + TestEngineUtils.flush(); + TestEngineUtils.simulateFrames(1); + + this.checkRender("Basic", "./test/java/renderer/ui/elements/button1.png"); + } + +} diff --git a/src/test/java/electrosphere/renderer/ui/elements/ImagePanelTests.java b/src/test/java/electrosphere/renderer/ui/elements/ImagePanelTests.java new file mode 100644 index 00000000..cfda24f1 --- /dev/null +++ b/src/test/java/electrosphere/renderer/ui/elements/ImagePanelTests.java @@ -0,0 +1,26 @@ +package electrosphere.renderer.ui.elements; +import electrosphere.menu.WindowUtils; +import electrosphere.test.annotations.IntegrationTest; +import electrosphere.test.template.UITestTemplate; +import electrosphere.test.testutils.TestEngineUtils; + +/** + * Tests the image panel ui component + */ +public class ImagePanelTests extends UITestTemplate { + + @IntegrationTest + public void test_Create(){ + //setup + this.setupBlankView(); + WindowUtils.replaceMainMenuContents(ImagePanel.createImagePanelAbsolute(0,0,50,50,"Textures/default_diffuse.png")); + + + //wait for ui updates + TestEngineUtils.flush(); + TestEngineUtils.simulateFrames(1); + + this.checkRender("Basic", "./test/java/renderer/ui/elements/imagepanel1.png"); + } + +} diff --git a/src/test/java/electrosphere/renderer/ui/elements/LabelTests.java b/src/test/java/electrosphere/renderer/ui/elements/LabelTests.java new file mode 100644 index 00000000..07c156a3 --- /dev/null +++ b/src/test/java/electrosphere/renderer/ui/elements/LabelTests.java @@ -0,0 +1,26 @@ +package electrosphere.renderer.ui.elements; +import electrosphere.menu.WindowUtils; +import electrosphere.test.annotations.IntegrationTest; +import electrosphere.test.template.UITestTemplate; +import electrosphere.test.testutils.TestEngineUtils; + +/** + * Tests the label ui component + */ +public class LabelTests extends UITestTemplate { + + @IntegrationTest + public void test_Create(){ + //setup + this.setupBlankView(); + WindowUtils.replaceMainMenuContents(Label.createLabel("Test Label")); + + + //wait for ui updates + TestEngineUtils.flush(); + TestEngineUtils.simulateFrames(1); + + this.checkRender("Basic", "./test/java/renderer/ui/elements/label1.png"); + } + +} diff --git a/src/test/java/electrosphere/renderer/ui/elements/TestBoxTests.java b/src/test/java/electrosphere/renderer/ui/elements/TestBoxTests.java new file mode 100644 index 00000000..ae1374b6 --- /dev/null +++ b/src/test/java/electrosphere/renderer/ui/elements/TestBoxTests.java @@ -0,0 +1,27 @@ +package electrosphere.renderer.ui.elements; + +import electrosphere.menu.WindowUtils; +import electrosphere.test.annotations.IntegrationTest; +import electrosphere.test.template.UITestTemplate; +import electrosphere.test.testutils.TestEngineUtils; + +/** + * Tests the text box ui component + */ +public class TestBoxTests extends UITestTemplate { + + @IntegrationTest + public void test_Create(){ + //setup + this.setupBlankView(); + WindowUtils.replaceMainMenuContents(TextBox.createTextBox("test text", false)); + + + //wait for ui updates + TestEngineUtils.flush(); + TestEngineUtils.simulateFrames(1); + + this.checkRender("Basic", "./test/java/renderer/ui/elements/textbox1.png"); + } + +} diff --git a/src/test/java/electrosphere/renderer/ui/elements/TestInputTests.java b/src/test/java/electrosphere/renderer/ui/elements/TestInputTests.java new file mode 100644 index 00000000..917ff048 --- /dev/null +++ b/src/test/java/electrosphere/renderer/ui/elements/TestInputTests.java @@ -0,0 +1,29 @@ +package electrosphere.renderer.ui.elements; + +import electrosphere.menu.WindowUtils; +import electrosphere.test.annotations.IntegrationTest; +import electrosphere.test.template.UITestTemplate; +import electrosphere.test.testutils.TestEngineUtils; + +/** + * Tests the text input ui component + */ +public class TestInputTests extends UITestTemplate { + + @IntegrationTest + public void test_Create(){ + //setup + this.setupBlankView(); + TextInput input = TextInput.createTextInput(); + input.setText("asdf"); + WindowUtils.replaceMainMenuContents(input); + + + //wait for ui updates + TestEngineUtils.flush(); + TestEngineUtils.simulateFrames(1); + + this.checkRender("Basic", "./test/java/renderer/ui/elements/textinput1.png"); + } + +} diff --git a/src/test/java/electrosphere/renderer/ui/elements/ToggleInputTests.java b/src/test/java/electrosphere/renderer/ui/elements/ToggleInputTests.java new file mode 100644 index 00000000..99d68649 --- /dev/null +++ b/src/test/java/electrosphere/renderer/ui/elements/ToggleInputTests.java @@ -0,0 +1,27 @@ +package electrosphere.renderer.ui.elements; + +import electrosphere.menu.WindowUtils; +import electrosphere.test.annotations.IntegrationTest; +import electrosphere.test.template.UITestTemplate; +import electrosphere.test.testutils.TestEngineUtils; + +/** + * Tests the text input ui component + */ +public class ToggleInputTests extends UITestTemplate { + + @IntegrationTest + public void test_Create(){ + //setup + this.setupBlankView(); + WindowUtils.replaceMainMenuContents(ToggleInput.createToggleInput()); + + + //wait for ui updates + TestEngineUtils.flush(); + TestEngineUtils.simulateFrames(1); + + this.checkRender("Basic", "./test/java/renderer/ui/elements/toggleinput1.png"); + } + +} diff --git a/src/test/java/electrosphere/renderer/ui/elements/WindowTest.java b/src/test/java/electrosphere/renderer/ui/elements/WindowTest.java index 44c52feb..56a7b924 100644 --- a/src/test/java/electrosphere/renderer/ui/elements/WindowTest.java +++ b/src/test/java/electrosphere/renderer/ui/elements/WindowTest.java @@ -24,7 +24,7 @@ public class WindowTest extends UITestTemplate { //wait for ui updates TestEngineUtils.flush(); - TestEngineUtils.simulateFrames(60); + TestEngineUtils.simulateFrames(1); // TestRenderingUtils.saveTestRender("./test/java/renderer/ui/elements/window.png"); this.checkRender("Basic", "./test/java/renderer/ui/elements/ui-test.png"); diff --git a/src/test/java/electrosphere/renderer/ui/elements/WordTests.java b/src/test/java/electrosphere/renderer/ui/elements/WordTests.java new file mode 100644 index 00000000..05a95140 --- /dev/null +++ b/src/test/java/electrosphere/renderer/ui/elements/WordTests.java @@ -0,0 +1,27 @@ +package electrosphere.renderer.ui.elements; + +import electrosphere.menu.WindowUtils; +import electrosphere.test.annotations.IntegrationTest; +import electrosphere.test.template.UITestTemplate; +import electrosphere.test.testutils.TestEngineUtils; + +/** + * Tests the text box ui component + */ +public class WordTests extends UITestTemplate { + + @IntegrationTest + public void test_Create(){ + //setup + this.setupBlankView(); + WindowUtils.replaceMainMenuContents(Word.createWord("some word")); + + + //wait for ui updates + TestEngineUtils.flush(); + TestEngineUtils.simulateFrames(1); + + this.checkRender("Basic", "./test/java/renderer/ui/elements/word1.png"); + } + +} diff --git a/test/java/renderer/ui/elements/button1.png b/test/java/renderer/ui/elements/button1.png new file mode 100644 index 0000000000000000000000000000000000000000..c9ab7b01399d7098a1d7e19e3addd2e5af56f001 GIT binary patch literal 11245 zcmeI2drVVT9LFz$V5F2dOmqq~>SD5?Sf}H$!fhNV;sfVg2BD>3kO5XGh)`Ietq)`b z6c;s$opc5jjiEye0xjvoDn!O(qJp&a#T)5^wa{YeV=Zlz_{aWRvL)yK^}DC1=l;&; ze!stS?rqDzjf?SFxo#x{K|Zm2qrZb7FFFKygst$jw@khiMnOY~N z^ni9{>}KrVzT2^zpO1c)c{$|r?aTY_1h1}WT-jfm?IA1;9{O1kXY<%S*?Dl+s_1*( zsf+gP}E zNEd00XszzlVeVS)1us>ESWByB|@2;zq$uLpOj zVve4$g`r&^j)bfeP_MKbs@&b3E$Hl8H&smL(k}hJg!FD?M(?(*^~Gtqe+`oi8jEOJ zuO}sm*%R+bf#D~WvLkh@9vIVNds_ZLo}AD!`${9-#@mjy8Av3qx+)p|X?9pQ$c}IK z3!V)}M3=~G6+Q5dd411Knr*(^FBEYa_3MFb6Sr#17CZqaXJ@U5;KFGT z!kOUA21Hap3Kdb9-;l`iCCH_Z#^j=jrqdex@YLJ|HJ{1yb(bskL6T;ENLCQV(ALn_ z*!ZQTXDpIZ!(>Hri39tq)N56^x6*7H%_ zDYYc#BL2FyRR8W}U3_3yQ;%z^kp2nWugvqjlHRz5HRpvhT@+eJr5fes z(3t&58QSCiM#wDCm?fvwKh#K?rpKnpf!7bP@C*ip#t9iRTTH{lrIbT8ZOSC!`j5Ye z!!=upoPr>cfNU|sMXEQQck;E%0ufp_>+p-(LtRK3=`qcJt@B#+-1R;wUZQTE70NA@j@lRBP8U-Dv895gTc-2+uyqG7LUk!c39@VdiDGqORQ~8f(738YN?d z(M+?Qy6PQ7t<|DBcCyHX!D4b0WOi@W(hN;*Dhlo~9#@ZQb7&xlQ?MP=u?5xJaG^5mJF=LsDB~+74LD~{bNPx*26Uj$3GNp}R69Y>&kYCoQPG9wne=*$r_#iE>D5 zYSNRX`E%D643TVV$=jRtIJsrWK68tn3EQXC)Y@uHX9l#jq;>=urMWTYtFv#G3?)UM zOG-?9*Z<3=HRl;EBKh`SWJVdk*xF~mN#^5nUV1WvNy{tLaLas?{nw8p;au~4=O%CO zYh{clq6>C;$nd38xZ(J3vtY<#CY!umZ3GumZ4xg8m%LPu&HCGJx|10Gq;BRMZy!|;+tbZorlZF%uifF@jh2D z^SSHJf=&=X01()JvH@-Z2!INJ5$r1@FakgTQ~-?N*eruu01yBb03(1};2;2M0YLCS zRzX9-=ym(Q_~=J3(FXj`%MXSXLcdKdTNE}#zw7M`pc}!iAcNxyK&O9~(-}{n%opJ* SekZ{JJa%_nH0zs`Gk*ga7L(`z literal 0 HcmV?d00001 diff --git a/test/java/renderer/ui/elements/imagepanel1.png b/test/java/renderer/ui/elements/imagepanel1.png new file mode 100644 index 0000000000000000000000000000000000000000..fa6802d500177de7b13c14ee27b2ccee37e7bc31 GIT binary patch literal 11610 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 Ry(=f4us<=rb>HdB{{_euUR(eG literal 0 HcmV?d00001