fall tree tests, testing utils, assertion macros
	
		
			
	
		
	
	
		
	
		
			Some checks failed
		
		
	
	
		
			
				
	
				studiorailgun/Renderer/pipeline/head There was a failure building this commit
				
			
		
		
	
	
				
					
				
			
		
			Some checks failed
		
		
	
	studiorailgun/Renderer/pipeline/head There was a failure building this commit
				
			This commit is contained in:
		
							parent
							
								
									9cdfac7898
								
							
						
					
					
						commit
						eff082ca76
					
				| @ -98,12 +98,15 @@ public class MovementAudioService { | ||||
|      * @return The path to the audio file to play | ||||
|      */ | ||||
|     public String getAudioPath(int voxelType, InteractionType type){ | ||||
|         String rVal = null; | ||||
|         SurfaceAudioType surfaceAudio = this.defaultSurfaceAudio; | ||||
| 
 | ||||
|         //Check if ignored | ||||
|         for(int ignoredVoxelType : this.ignoredVoxelTypes){ | ||||
|             if(ignoredVoxelType == voxelType){ | ||||
|                 return null; | ||||
|         if(this.ignoredVoxelTypes != null){ | ||||
|             for(int ignoredVoxelType : this.ignoredVoxelTypes){ | ||||
|                 if(ignoredVoxelType == voxelType){ | ||||
|                     return null; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
| @ -115,31 +118,33 @@ public class MovementAudioService { | ||||
|         } | ||||
| 
 | ||||
|         //gets the list to pull from | ||||
|         List<String> availableFiles = surfaceAudio.getFootstepRegularBareAudioPaths(); | ||||
|         switch(type){ | ||||
|             case STEP_BARE_REG: { | ||||
|                 availableFiles = surfaceAudio.getFootstepRegularBareAudioPaths(); | ||||
|             } break; | ||||
|             case STEP_BARE_HEAVY: { | ||||
|                 availableFiles = surfaceAudio.getFootstepHeavyBareAudioPaths(); | ||||
|             } break; | ||||
|             case STEP_SHOE_REG: { | ||||
|                 availableFiles = surfaceAudio.getFootstepRegularShoeAudioPaths(); | ||||
|             } break; | ||||
|             case STEP_SHOE_HEAVY: { | ||||
|                 availableFiles = surfaceAudio.getFootstepHeavyShoeAudioPaths(); | ||||
|             } break; | ||||
|             case JUMP: { | ||||
|                 availableFiles = surfaceAudio.getJumpAudioPaths(); | ||||
|             } break; | ||||
|             case LAND: { | ||||
|                 availableFiles = surfaceAudio.getLandAudioPaths(); | ||||
|             } break; | ||||
|         if(surfaceAudio != null){ | ||||
|             List<String> availableFiles = surfaceAudio.getFootstepRegularBareAudioPaths(); | ||||
|             switch(type){ | ||||
|                 case STEP_BARE_REG: { | ||||
|                     availableFiles = surfaceAudio.getFootstepRegularBareAudioPaths(); | ||||
|                 } break; | ||||
|                 case STEP_BARE_HEAVY: { | ||||
|                     availableFiles = surfaceAudio.getFootstepHeavyBareAudioPaths(); | ||||
|                 } break; | ||||
|                 case STEP_SHOE_REG: { | ||||
|                     availableFiles = surfaceAudio.getFootstepRegularShoeAudioPaths(); | ||||
|                 } break; | ||||
|                 case STEP_SHOE_HEAVY: { | ||||
|                     availableFiles = surfaceAudio.getFootstepHeavyShoeAudioPaths(); | ||||
|                 } break; | ||||
|                 case JUMP: { | ||||
|                     availableFiles = surfaceAudio.getJumpAudioPaths(); | ||||
|                 } break; | ||||
|                 case LAND: { | ||||
|                     availableFiles = surfaceAudio.getLandAudioPaths(); | ||||
|                 } break; | ||||
|             } | ||||
|             int roll = random.nextInt(availableFiles.size()); | ||||
|             rVal = availableFiles.get(roll); | ||||
|         } | ||||
| 
 | ||||
|         //return the audio | ||||
|         int roll = random.nextInt(availableFiles.size()); | ||||
|         return availableFiles.get(roll); | ||||
|         return rVal; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | ||||
| @ -466,10 +466,13 @@ public class CollisionEngine { | ||||
|                     DBody rigidBody = PhysicsEntityUtils.getDBody(physicsEntity); | ||||
|                     Matrix4d inverseTransform = new Matrix4d(); | ||||
|                     Vector4d rawPos = inverseTransform.transform(new Vector4d(PhysicsUtils.getRigidBodyPosition(rigidBody),1)); | ||||
|                     Vector3d newPosition = new Vector3d(rawPos.x,rawPos.y,rawPos.z); | ||||
|                     newPosition = this.suggestMovementPosition(collisionWorldData, newPosition); | ||||
|                     Vector3d calculatedPosition = new Vector3d(rawPos.x,rawPos.y,rawPos.z); | ||||
|                     Vector3d suggestedPosition = this.suggestMovementPosition(collisionWorldData, calculatedPosition); | ||||
|                     if(calculatedPosition.distance(suggestedPosition) > 0){ | ||||
|                         collidable.addImpulse(new Impulse(new Vector3d(), new Vector3d(), new Vector3d(), 0, Collidable.TYPE_WORLD_BOUND)); | ||||
|                     } | ||||
|                     Quaterniond newRotation = PhysicsUtils.getRigidBodyRotation(rigidBody); | ||||
|                     EntityUtils.getPosition(physicsEntity).set(newPosition); | ||||
|                     EntityUtils.getPosition(physicsEntity).set(suggestedPosition); | ||||
|                     EntityUtils.getRotation(physicsEntity).set(newRotation); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
| @ -47,6 +47,9 @@ public class Collidable { | ||||
|     public static final String TYPE_FOLIAGE_STATIC = "foliageStatic"; | ||||
|     public static final long TYPE_FOLIAGE_BIT = 0x80; | ||||
| 
 | ||||
|     public static final String TYPE_WORLD_BOUND = "worldBound"; | ||||
|     public static final long TYPE_WORLD_BOUND_BIT = 0x100; | ||||
| 
 | ||||
|      | ||||
|     /** | ||||
|      * Constructor | ||||
|  | ||||
| @ -44,29 +44,23 @@ public class ServerCollidableTree implements BehaviorTree { | ||||
|     public void simulate(float deltaTime){ | ||||
|         Vector3d position = EntityUtils.getPosition(parent); | ||||
|         Quaterniond rotation = EntityUtils.getRotation(parent); | ||||
|         Vector3d offsetVector = new Vector3d(); | ||||
|         Vector3d newPosition = new Vector3d(position); | ||||
|         //have we hit a terrain impulse? | ||||
|         boolean hitTerrain = false; | ||||
|         //handle impulses | ||||
|         for(Impulse impulse : collidable.getImpulses()){ | ||||
| //            collidable.getImpulses().remove(impulse); | ||||
|             if(impulse.type.matches(Collidable.TYPE_TERRAIN)){ | ||||
|                 hitTerrain = true; | ||||
|             //    System.out.println("Impulse force: " + impulseForce); | ||||
| //                System.out.println("Position: " + position); | ||||
|             } | ||||
|             if(impulse.type.matches(Collidable.TYPE_ITEM)){ | ||||
|                 if(ServerGravityTree.getServerGravityTree(parent)!=null){ | ||||
|                     ServerGravityTree.getServerGravityTree(parent).start(); | ||||
|                 } | ||||
|             } | ||||
|             if(impulse.type.matches(Collidable.TYPE_CREATURE)){ | ||||
| //                System.out.println(System.currentTimeMillis() + " creature hit!"); | ||||
|                 if(ServerGravityTree.getServerGravityTree(parent)!=null){ | ||||
|                     ServerGravityTree.getServerGravityTree(parent).start(); | ||||
|                 } | ||||
|             } | ||||
|             if(impulse.type.matches(Collidable.TYPE_WORLD_BOUND)){ | ||||
|                 this.resetGravityFall(); | ||||
|             } | ||||
|         } | ||||
|         Realm realm = Globals.realmManager.getEntityRealm(parent); | ||||
|         //bound to world bounds | ||||
| @ -100,6 +94,18 @@ public class ServerCollidableTree implements BehaviorTree { | ||||
|     public static ServerCollidableTree getServerCollidableTree(Entity e){ | ||||
|         return (ServerCollidableTree)e.getData(EntityDataStrings.SERVER_COLLIDABLE_TREE); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Adds a terrain collision to the collidable list | ||||
|      */ | ||||
|     protected void resetGravityFall(){ | ||||
|         if(ServerGravityTree.getServerGravityTree(parent)!=null){ | ||||
|             ServerGravityTree.getServerGravityTree(parent).stop(); | ||||
|         } | ||||
|         if(ServerFallTree.getFallTree(parent)!=null){ | ||||
|             ServerFallTree.getFallTree(parent).land(); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|      | ||||
| } | ||||
|  | ||||
| @ -63,6 +63,10 @@ public class ServerGravityTree implements BehaviorTree { | ||||
|         if(state == GravityTreeState.NOT_ACTIVE){ | ||||
|             frameCurrent = 0; | ||||
|         } | ||||
|         ServerFallTree fallTree; | ||||
|         if((fallTree = ServerFallTree.getFallTree(parent))!=null){ | ||||
|             fallTree.start(); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     public void interrupt(){ | ||||
|  | ||||
| @ -0,0 +1,61 @@ | ||||
| package electrosphere.entity.state.movement.fall; | ||||
| 
 | ||||
| import static org.junit.jupiter.api.Assertions.*; | ||||
| 
 | ||||
| import org.joml.Vector3d; | ||||
| 
 | ||||
| import electrosphere.engine.Globals; | ||||
| import electrosphere.entity.Entity; | ||||
| import electrosphere.entity.state.movement.jump.ClientJumpTree; | ||||
| import electrosphere.entity.types.creature.CreatureTemplate; | ||||
| import electrosphere.entity.types.creature.CreatureUtils; | ||||
| import electrosphere.test.annotations.IntegrationTest; | ||||
| import electrosphere.test.template.EntityTestTemplate; | ||||
| import electrosphere.test.testutils.TestEngineUtils; | ||||
| import static electrosphere.test.testutils.Assertions.*; | ||||
| 
 | ||||
| /** | ||||
|  * Tests the fall tree | ||||
|  */ | ||||
| public class ClientFallTreeTests extends EntityTestTemplate { | ||||
|      | ||||
|     @IntegrationTest | ||||
|     public void isFalling_AtRest_false(){ | ||||
|         Entity serverEntity = CreatureUtils.serverSpawnBasicCreature(Globals.realmManager.first(), new Vector3d(), "human", CreatureTemplate.createDefault("human")); | ||||
|         Entity clientEntity = TestEngineUtils.getClientEquivalent(serverEntity); | ||||
| 
 | ||||
|         ClientFallTree clientFallTree = ClientFallTree.getFallTree(clientEntity); | ||||
|         assertEquals(false, clientFallTree.isFalling()); | ||||
|     } | ||||
| 
 | ||||
|     @IntegrationTest | ||||
|     public void isFalling_AfterJump_true(){ | ||||
|         Entity serverEntity = CreatureUtils.serverSpawnBasicCreature(Globals.realmManager.first(), new Vector3d(), "human", CreatureTemplate.createDefault("human")); | ||||
|         Entity clientEntity = TestEngineUtils.getClientEquivalent(serverEntity); | ||||
| 
 | ||||
|         ClientFallTree clientFallTree = ClientFallTree.getFallTree(clientEntity); | ||||
|         ClientJumpTree clientJumpTree = ClientJumpTree.getClientJumpTree(clientEntity); | ||||
|         clientJumpTree.start(); | ||||
| 
 | ||||
|         //make sure we're in in the air | ||||
|         assertEventually(() -> clientFallTree.isFalling(), 100); | ||||
|     } | ||||
|      | ||||
|     @IntegrationTest | ||||
|     public void isFalling_AfterLand_false(){ | ||||
|         Entity serverEntity = CreatureUtils.serverSpawnBasicCreature(Globals.realmManager.first(), new Vector3d(), "human", CreatureTemplate.createDefault("human")); | ||||
|         Entity clientEntity = TestEngineUtils.getClientEquivalent(serverEntity); | ||||
| 
 | ||||
|         ClientFallTree clientFallTree = ClientFallTree.getFallTree(clientEntity); | ||||
|         ClientJumpTree clientJumpTree = ClientJumpTree.getClientJumpTree(clientEntity); | ||||
|         clientJumpTree.start(); | ||||
| 
 | ||||
|         //make sure we're in in the air | ||||
|         TestEngineUtils.simulateFrames(3); | ||||
| 
 | ||||
|         assertEventually(() -> { | ||||
|             return !clientFallTree.isFalling(); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,61 @@ | ||||
| package electrosphere.entity.state.movement.fall; | ||||
| 
 | ||||
| import static org.junit.jupiter.api.Assertions.*; | ||||
| 
 | ||||
| 
 | ||||
| import org.joml.Vector3d; | ||||
| 
 | ||||
| import electrosphere.engine.Globals; | ||||
| import electrosphere.entity.Entity; | ||||
| import electrosphere.entity.state.movement.jump.ServerJumpTree; | ||||
| import electrosphere.entity.types.creature.CreatureTemplate; | ||||
| import electrosphere.entity.types.creature.CreatureUtils; | ||||
| import electrosphere.test.annotations.IntegrationTest; | ||||
| import electrosphere.test.template.EntityTestTemplate; | ||||
| import static electrosphere.test.testutils.Assertions.*; | ||||
| import electrosphere.test.testutils.TestEngineUtils; | ||||
| 
 | ||||
| /** | ||||
|  * Tests the server fall tree | ||||
|  */ | ||||
| public class ServerFallTreeTests extends EntityTestTemplate { | ||||
| 
 | ||||
|     @IntegrationTest | ||||
|     public void isFalling_AtRest_false(){ | ||||
|         Entity creature = CreatureUtils.serverSpawnBasicCreature(Globals.realmManager.first(), new Vector3d(0,0,0), "human", CreatureTemplate.createDefault("human")); | ||||
| 
 | ||||
|         ServerFallTree serverFallTree = ServerFallTree.getFallTree(creature); | ||||
|         assertEquals(false, serverFallTree.isFalling()); | ||||
|     } | ||||
| 
 | ||||
|     @IntegrationTest | ||||
|     public void isFalling_AfterJump_true(){ | ||||
|         Entity creature = CreatureUtils.serverSpawnBasicCreature(Globals.realmManager.first(), new Vector3d(0,0,0), "human", CreatureTemplate.createDefault("human")); | ||||
| 
 | ||||
|         ServerFallTree serverFallTree = ServerFallTree.getFallTree(creature); | ||||
|         ServerJumpTree serverJumpTree = ServerJumpTree.getServerJumpTree(creature); | ||||
|         serverJumpTree.start(); | ||||
| 
 | ||||
|         //make sure we're in in the air | ||||
|         TestEngineUtils.waitForCondition(() -> !serverJumpTree.isJumping(), 100); | ||||
| 
 | ||||
|         assertEquals(true, serverFallTree.isFalling()); | ||||
|     } | ||||
|      | ||||
|     @IntegrationTest | ||||
|     public void isFalling_AfterLand_false(){ | ||||
|         Entity creature = CreatureUtils.serverSpawnBasicCreature(Globals.realmManager.first(), new Vector3d(0,0,0), "human", CreatureTemplate.createDefault("human")); | ||||
| 
 | ||||
|         ServerFallTree serverFallTree = ServerFallTree.getFallTree(creature); | ||||
|         ServerJumpTree serverJumpTree = ServerJumpTree.getServerJumpTree(creature); | ||||
|         serverJumpTree.start(); | ||||
| 
 | ||||
|         //make sure we're in in the air | ||||
|         TestEngineUtils.simulateFrames(3); | ||||
| 
 | ||||
|         assertEventually(() -> { | ||||
|             return !serverFallTree.isFalling(); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -6,6 +6,7 @@ import org.junit.jupiter.api.Tag; | ||||
| import org.junit.jupiter.api.extension.ExtendWith; | ||||
| 
 | ||||
| import electrosphere.test.template.extensions.RenderingExtension; | ||||
| import static electrosphere.test.testutils.Assertions.*; | ||||
| import electrosphere.test.testutils.TestRenderingUtils; | ||||
| 
 | ||||
| /** | ||||
| @ -26,7 +27,7 @@ public class RenderingTestTemplate { | ||||
|         String canonicalName = this.getClass().getCanonicalName(); | ||||
| 
 | ||||
|         //check the render | ||||
|         TestRenderingUtils.assertEqualsRender(existingRenderPath, () -> { | ||||
|         assertEqualsRender(existingRenderPath, () -> { | ||||
| 
 | ||||
|             //on failure, save the failed render | ||||
|             String failureSavePath = "./.testcache/" + canonicalName + "-" + renderName + ".png"; | ||||
|  | ||||
							
								
								
									
										110
									
								
								src/test/java/electrosphere/test/testutils/Assertions.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								src/test/java/electrosphere/test/testutils/Assertions.java
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,110 @@ | ||||
| package electrosphere.test.testutils; | ||||
| 
 | ||||
| import static org.junit.jupiter.api.Assertions.*; | ||||
| 
 | ||||
| import java.io.File; | ||||
| import java.io.IOException; | ||||
| 
 | ||||
| import java.util.function.Supplier; | ||||
| import javax.imageio.ImageIO; | ||||
| import java.awt.image.BufferedImage; | ||||
| 
 | ||||
| import electrosphere.engine.Globals; | ||||
| 
 | ||||
| /** | ||||
|  * Custom assertion macros | ||||
|  */ | ||||
| public class Assertions { | ||||
|      | ||||
|     /** | ||||
|      * The threshold at which we say the colors are 'close enough' | ||||
|      */ | ||||
|     static final int COLOR_COMPARE_THRESHOLD = 3; | ||||
|      | ||||
|     /** | ||||
|      * Asserts that the most recent render matches the image stored at the provided filepath | ||||
|      * @param existingRenderPath The filepath of the existing render | ||||
|      */ | ||||
|     public static void assertEqualsRender(String existingRenderPath, Runnable onFailure){ | ||||
|         BufferedImage testData = null; | ||||
|         try { | ||||
|             testData = ImageIO.read(new File(existingRenderPath)); | ||||
|         } catch (IOException e){ | ||||
|             fail("Failed to read existing image path " + existingRenderPath); | ||||
|         } | ||||
|         BufferedImage screenshot = Globals.renderingEngine.defaultFramebuffer.getPixels(Globals.renderingEngine.getOpenGLState()); | ||||
|         //check basic data | ||||
|         // | ||||
|         //width | ||||
|         if(testData.getWidth() != screenshot.getWidth()){ | ||||
|             onFailure.run(); | ||||
|         } | ||||
|         assertEquals(testData.getWidth(), screenshot.getWidth()); | ||||
| 
 | ||||
|         // | ||||
|         //height | ||||
|         if(testData.getHeight() != screenshot.getHeight()){ | ||||
|             onFailure.run(); | ||||
|         } | ||||
|         assertEquals(testData.getHeight(), screenshot.getHeight()); | ||||
| 
 | ||||
|         // | ||||
|         //pixel-by-pixel check | ||||
|         // | ||||
|         for(int x = 0; x < testData.getWidth(); x++){ | ||||
|             for(int y = 0; y < testData.getHeight(); y++){ | ||||
| 
 | ||||
|                 //get from-disk rgba | ||||
|                 int sourceRed = testData.getRGB(x, y) & 0xff; | ||||
|                 int sourceGreen = (testData.getRGB(x, y) & 0xff00) >> 8; | ||||
|                 int sourceBlue = (testData.getRGB(x, y) & 0xff0000) >> 16; | ||||
|                 int sourceAlpha = (testData.getRGB(x, y) & 0xff000000) >>> 24; | ||||
| 
 | ||||
|                 //get from-render rgba | ||||
|                 int renderRed = screenshot.getRGB(x, y) & 0xff; | ||||
|                 int renderGreen = (screenshot.getRGB(x, y) & 0xff00) >> 8; | ||||
|                 int renderBlue = (screenshot.getRGB(x, y) & 0xff0000) >> 16; | ||||
|                 int renderAlpha = (screenshot.getRGB(x, y) & 0xff000000) >>> 24; | ||||
| 
 | ||||
|                 if( | ||||
|                     Math.abs(sourceRed - renderRed) > COLOR_COMPARE_THRESHOLD || | ||||
|                     Math.abs(sourceGreen - renderGreen) > COLOR_COMPARE_THRESHOLD || | ||||
|                     Math.abs(sourceBlue - renderBlue) > COLOR_COMPARE_THRESHOLD || | ||||
|                     Math.abs(sourceAlpha - renderAlpha) > COLOR_COMPARE_THRESHOLD | ||||
|                 ){ | ||||
| 
 | ||||
|                     onFailure.run(); | ||||
|                     String failMessage = "Colors aren't approximately the same!\n" + | ||||
|                     "Color from disk:   " + sourceRed + "," + sourceGreen + "," + sourceBlue + "," + sourceAlpha + "\n" + | ||||
|                     "Color from render: " + renderRed + "," + renderGreen + "," + renderBlue + "," + renderAlpha + "\n" | ||||
|                     ; | ||||
|                     fail(failMessage); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Asserts that some test is true within a given number of frame simulations | ||||
|      * @param test The test | ||||
|      * @param maxFrames The number of frames | ||||
|      */ | ||||
|     public static void assertEventually(Supplier<Boolean> test, int maxFrames){ | ||||
|         int frameCount = 0; | ||||
|         boolean testResult = false; | ||||
|         while(!(testResult = test.get()) && frameCount < maxFrames){ | ||||
|             TestEngineUtils.simulateFrames(1); | ||||
|             frameCount++; | ||||
|         } | ||||
|         org.junit.jupiter.api.Assertions.assertTrue(testResult); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Asserts that some runnable | ||||
|      * @param test | ||||
|      */ | ||||
|     public static void assertEventually(Supplier<Boolean> test){ | ||||
|         assertEventually(test, 100); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,8 +1,13 @@ | ||||
| package electrosphere.test.testutils; | ||||
| 
 | ||||
| import static org.junit.jupiter.api.Assertions.*; | ||||
| 
 | ||||
| import java.util.function.Supplier; | ||||
| 
 | ||||
| import electrosphere.engine.Globals; | ||||
| import electrosphere.engine.Main; | ||||
| import electrosphere.engine.profiler.Profiler; | ||||
| import electrosphere.entity.Entity; | ||||
| import electrosphere.net.NetUtils; | ||||
| 
 | ||||
| /** | ||||
| @ -57,4 +62,53 @@ public class TestEngineUtils { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     /** | ||||
|      * The maximum number of frames to wait before an entity propagates to the client | ||||
|      */ | ||||
|     static final int MAX_FRAMES_TO_WAIT_FOR_CLIENT_PROPAGATION = 10; | ||||
| 
 | ||||
|     /** | ||||
|      * Gets the client equivalent of an entity | ||||
|      * @param serverEntity The server entity | ||||
|      * @return The client entity | ||||
|      */ | ||||
|     public static Entity getClientEquivalent(Entity serverEntity){ | ||||
|         int frames = 0; | ||||
|         while(frames < MAX_FRAMES_TO_WAIT_FOR_CLIENT_PROPAGATION && !Globals.clientSceneWrapper.containsServerId(serverEntity.getId())){ | ||||
|             TestEngineUtils.simulateFrames(1); | ||||
|         } | ||||
|         if(Globals.clientSceneWrapper.containsServerId(serverEntity.getId())){ | ||||
|             Entity rVal = Globals.clientSceneWrapper.getEntityFromServerId(serverEntity.getId()); | ||||
|             if(rVal == null){ | ||||
|                 fail("Failed to find client entity at server id lookup for id: " + serverEntity.getId()); | ||||
|             } | ||||
|             return rVal; | ||||
|         } | ||||
|         fail("Failed to find client entity at server id lookup for id: " + serverEntity.getId()); | ||||
|         return null; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Waits for a given test to be true | ||||
|      * @param test The test to wait for | ||||
|      */ | ||||
|     public static void waitForCondition(Supplier<Boolean> test, int maxFrames){ | ||||
|         int frameCount = 0; | ||||
|         boolean testResult = false; | ||||
|         while(!(testResult = test.get()) && frameCount < maxFrames){ | ||||
|             TestEngineUtils.simulateFrames(1); | ||||
|             frameCount++; | ||||
|         } | ||||
|         org.junit.jupiter.api.Assertions.assertTrue(testResult); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Waits for a given test to be true | ||||
|      * @param test The test to wait for | ||||
|      */ | ||||
|     public static void waitForCondition(Supplier<Boolean> test){ | ||||
|         waitForCondition(test,100); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -6,8 +6,6 @@ import java.io.IOException; | ||||
| 
 | ||||
| import javax.imageio.ImageIO; | ||||
| 
 | ||||
| import static org.junit.jupiter.api.Assertions.*; | ||||
| 
 | ||||
| import electrosphere.engine.Globals; | ||||
| 
 | ||||
| /** | ||||
| @ -15,74 +13,6 @@ import electrosphere.engine.Globals; | ||||
|  */ | ||||
| public class TestRenderingUtils { | ||||
| 
 | ||||
|     /** | ||||
|      * The threshold at which we say the colors are 'close enough' | ||||
|      */ | ||||
|     static final int COLOR_COMPARE_THRESHOLD = 3; | ||||
|      | ||||
|     /** | ||||
|      * Asserts that the most recent render matches the image stored at the provided filepath | ||||
|      * @param existingRenderPath The filepath of the existing render | ||||
|      */ | ||||
|     public static void assertEqualsRender(String existingRenderPath, Runnable onFailure){ | ||||
|         BufferedImage testData = null; | ||||
|         try { | ||||
|             testData = ImageIO.read(new File(existingRenderPath)); | ||||
|         } catch (IOException e){ | ||||
|             fail("Failed to read existing image path " + existingRenderPath); | ||||
|         } | ||||
|         BufferedImage screenshot = Globals.renderingEngine.defaultFramebuffer.getPixels(Globals.renderingEngine.getOpenGLState()); | ||||
|         //check basic data | ||||
|         // | ||||
|         //width | ||||
|         if(testData.getWidth() != screenshot.getWidth()){ | ||||
|             onFailure.run(); | ||||
|         } | ||||
|         assertEquals(testData.getWidth(), screenshot.getWidth()); | ||||
| 
 | ||||
|         // | ||||
|         //height | ||||
|         if(testData.getHeight() != screenshot.getHeight()){ | ||||
|             onFailure.run(); | ||||
|         } | ||||
|         assertEquals(testData.getHeight(), screenshot.getHeight()); | ||||
| 
 | ||||
|         // | ||||
|         //pixel-by-pixel check | ||||
|         // | ||||
|         for(int x = 0; x < testData.getWidth(); x++){ | ||||
|             for(int y = 0; y < testData.getHeight(); y++){ | ||||
| 
 | ||||
|                 //get from-disk rgba | ||||
|                 int sourceRed = testData.getRGB(x, y) & 0xff; | ||||
|                 int sourceGreen = (testData.getRGB(x, y) & 0xff00) >> 8; | ||||
|                 int sourceBlue = (testData.getRGB(x, y) & 0xff0000) >> 16; | ||||
|                 int sourceAlpha = (testData.getRGB(x, y) & 0xff000000) >>> 24; | ||||
| 
 | ||||
|                 //get from-render rgba | ||||
|                 int renderRed = screenshot.getRGB(x, y) & 0xff; | ||||
|                 int renderGreen = (screenshot.getRGB(x, y) & 0xff00) >> 8; | ||||
|                 int renderBlue = (screenshot.getRGB(x, y) & 0xff0000) >> 16; | ||||
|                 int renderAlpha = (screenshot.getRGB(x, y) & 0xff000000) >>> 24; | ||||
| 
 | ||||
|                 if( | ||||
|                     Math.abs(sourceRed - renderRed) > COLOR_COMPARE_THRESHOLD || | ||||
|                     Math.abs(sourceGreen - renderGreen) > COLOR_COMPARE_THRESHOLD || | ||||
|                     Math.abs(sourceBlue - renderBlue) > COLOR_COMPARE_THRESHOLD || | ||||
|                     Math.abs(sourceAlpha - renderAlpha) > COLOR_COMPARE_THRESHOLD | ||||
|                 ){ | ||||
| 
 | ||||
|                     onFailure.run(); | ||||
|                     String failMessage = "Colors aren't approximately the same!\n" + | ||||
|                     "Color from disk:   " + sourceRed + "," + sourceGreen + "," + sourceBlue + "," + sourceAlpha + "\n" + | ||||
|                     "Color from render: " + renderRed + "," + renderGreen + "," + renderBlue + "," + renderAlpha + "\n" | ||||
|                     ; | ||||
|                     fail(failMessage); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Used for saving a copy of the current render (ie for generating test data) | ||||
|      * @param existingRenderPath The filepath of the existing render | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user