Lighting Engine Test Plan - UQcsse3200/2026-studio-2 GitHub Wiki

Overview

This document outlines the comprehensive test strategy for the lighting system implementation, covering unit tests, integration tests, and performance tests.

Test Scope

In Scope

  • LightingEngine initialization and rendering
  • LightingService registration and retrieval
  • PointLightComponent lifecycle and updates
  • LightFactory entity creation
  • LightingDefaults constant values
  • Integration with ServiceLocator
  • Integration with game screens
  • Arrow projectile lighting
  • User settings brightness control

Out of Scope

  • Box2DLights library internals
  • libGDX rendering pipeline
  • Physics engine behavior

Unit Tests

LightingEngine Tests

Test 1: Initialization

Test Name: testLightingEngineInitialization

  • Objective: Verify that LightingEngine properly initializes with camera and world
  • Setup:
    • Mock CameraComponent with valid projection matrix
    • Mock World object
  • Steps:
    1. Create LightingEngine(camera, world)
    2. Verify RayHandler is created
    3. Verify ambient light is set from UserSettings
    4. Verify blur is enabled with correct blur count
  • Expected Result: Engine initializes without exceptions, all components configured

Test 2: Ambient Light Setter

Test Name: testSetAmbientLight

  • Objective: Verify ambient light level can be changed
  • Setup: Create initialized LightingEngine
  • Steps:
    1. Call setAmbientLight(0.5f)
    2. Verify internal state updated
    3. Call setAmbientLight(1.0f)
    4. Verify state updated again
  • Expected Result: Ambient light values are correctly set

Test 3: Render Method

Test Name: testRenderMethod

  • Objective: Verify render method executes without exceptions
  • Setup:
    • Create initialized LightingEngine
    • Mock projection matrix from camera
  • Steps:
    1. Call render()
    2. Verify no exceptions thrown
    3. Verify RayHandler.setCombinedMatrix() called
    4. Verify RayHandler.updateAndRender() called
  • Expected Result: Render completes successfully

Test 4: Dispose

Test Name: testLightingEngineDispose

  • Objective: Verify proper cleanup on disposal
  • Setup: Create initialized LightingEngine
  • Steps:
    1. Call dispose()
    2. Verify RayHandler.dispose() called
    3. Attempt to render after disposal
  • Expected Result: Resources released, no memory leaks

LightingService Tests

Test 5: Service Initialization with Engine

Test Name: testServiceInitializationWithEngine

  • Objective: Verify LightingService can be initialized with existing engine
  • Setup: Create mock LightingEngine
  • Steps:
    1. Create LightingService(lightingEngine)
    2. Call getEngine()
    3. Verify returned engine matches input
  • Expected Result: Service correctly stores and returns engine reference

Test 6: Service Initialization with Camera and World

Test Name: testServiceInitializationWithCameraAndWorld

  • Objective: Verify LightingService can create engine from camera and world
  • Setup:
    • Mock CameraComponent
    • Mock World
  • Steps:
    1. Create LightingService(camera, world)
    2. Call getEngine()
    3. Verify engine is not null
    4. Verify engine is initialized
  • Expected Result: Engine created and properly initialized

PointLightComponent Tests

Test 7: Component Initialization

Test Name: testPointLightComponentInitialization

  • Objective: Verify component initializes with correct parameters
  • Setup:
    • Mock RayHandler
    • Create test color and parameters
  • Steps:
    1. Create PointLightComponent(rayHandler, 128, Color.YELLOW, 4f)
    2. Verify parameters stored correctly
    3. Verify component not yet created (no light object)
  • Expected Result: Component stores all parameters, ready for entity attachment

Test 8: Component Create Method

Test Name: testPointLightComponentCreate

  • Objective: Verify light object is created when component attaches to entity
  • Setup:
    • Create component with mock RayHandler
    • Mock entity with position
  • Steps:
    1. Create test entity with position (5, 5)
    2. Call component.create() with entity
    3. Verify PointLight object created
    4. Verify light position set to entity position
    5. Verify light properties configured (softness, xray, contact filter)
  • Expected Result: Light object created and properly configured

Test 9: Component Update Positioning

Test Name: testPointLightComponentUpdatePositioning

  • Objective: Verify light moves with entity
  • Setup:
    • Create component with entity
    • Call create()
    • Mock TimeSource with delta time
  • Steps:
    1. Set entity position to (5, 5)
    2. Call update()
    3. Verify light position at (5, 5)
    4. Set entity position to (10, 10)
    5. Call update()
    6. Verify light position at (10, 10)
  • Expected Result: Light always synchronized with entity center

Test 10: Component Active/Inactive Toggle

Test Name: testPointLightComponentActiveToggle

  • Objective: Verify light can be toggled active/inactive
  • Setup:
    • Create component and attach to entity
    • Call create()
  • Steps:
    1. Call setActive(false)
    2. Call update()
    3. Verify light is inactive
    4. Call setActive(true)
    5. Call update()
    6. Verify light is active
  • Expected Result: Active state correctly toggled

Test 11: Component Color Modification

Test Name: testPointLightComponentSetColor

  • Objective: Verify color can be changed
  • Setup:
    • Create component with initial yellow color
  • Steps:
    1. Call setColor(Color.RED)
    2. Verify internal color updated
    3. Verify light color updated
    4. Call setColor(Color.BLUE)
    5. Verify both updated
  • Expected Result: Color changes applied to internal state and light

Test 12: Component Distance Modification

Test Name: testPointLightComponentSetDistance

  • Objective: Verify distance can be changed
  • Setup:
    • Create component with distance 4f
  • Steps:
    1. Call setDistance(8f)
    2. Verify distance stored
    3. Call getDistance()
    4. Verify returns 8f
  • Expected Result: Distance correctly updated and retrievable

Test 13: Component Softness

Test Name: testPointLightComponentSetSoftness

  • Objective: Verify softness can be configured
  • Setup:
    • Create component and attach to entity
    • Call create()
  • Steps:
    1. Call setSoftnessLength(2f)
    2. Verify light softness updated
    3. Call setSoftnessLength(0.5f)
    4. Verify updated again
  • Expected Result: Softness correctly applied to light

Test 14: Component Disposal

Test Name: testPointLightComponentDispose

  • Objective: Verify proper cleanup on disposal
  • Setup:
    • Create component with light
  • Steps:
    1. Call dispose()
    2. Verify light removed from RayHandler
    3. Verify internal reference set to null
    4. Call dispose() again
    5. Verify no exception thrown
  • Expected Result: Light properly removed, safe to dispose multiple times

Test 15: Component Method Chaining

Test Name: testPointLightComponentMethodChaining

  • Objective: Verify builder pattern works correctly
  • Setup:
    • Create component
  • Steps:
    1. Call setColor(Color.RED).setDistance(6f).setSoftnessLength(1.5f)
    2. Verify all changes applied
    3. Verify returns this from setColor, setDistance, setSoftnessLength
  • Expected Result: Method chaining works, all values correctly set

LightFactory Tests

Test 16: Create Point Light

Test Name: testLightFactoryCreatePointLight

  • Objective: Verify factory creates point light with defaults
  • Setup:
    • Register LightingService with mock LightingEngine
    • Register in ServiceLocator
  • Steps:
    1. Call LightFactory.createPointLight()
    2. Verify entity returned is not null
    3. Verify entity has PointLightComponent
    4. Verify component uses LightingDefaults values
  • Expected Result: Factory creates properly configured light entity

Test 17: Factory Exception on Missing Service

Test Name: testLightFactoryExceptionOnMissingService

  • Objective: Verify factory throws exception if service not registered
  • Setup:
    • Clear ServiceLocator
  • Steps:
    1. Call LightFactory.createPointLight()
    2. Expect IllegalStateException
  • Expected Result: Exception thrown with clear error message

Test 18: Factory Exception on Missing Engine

Test Name: testLightFactoryExceptionOnMissingEngine

  • Objective: Verify factory throws exception if engine null
  • Setup:
    • Register LightingService that returns null engine
  • Steps:
    1. Call LightFactory.createPointLight()
    2. Expect IllegalStateException
  • Expected Result: Exception thrown with clear error message

Test 19: Factory Non-Instantiable

Test Name: testLightFactoryNonInstantiable

  • Objective: Verify factory cannot be instantiated
  • Setup: None
  • Steps:
    1. Try to instantiate LightFactory() via reflection
    2. Expect exception
  • Expected Result: Constructor throws IllegalStateException

LightingDefaults Tests

Test 20: Constant Values

Test Name: testLightingDefaultsConstants

  • Objective: Verify all constants have expected values
  • Setup: None
  • Steps:
    1. Verify AMBIENT_LIGHT == 0.9f
    2. Verify BLUR_NUM == 3
    3. Verify RAYS == 128
    4. Verify DIST == 4f
    5. Verify NORMAL_COLOR is valid
  • Expected Result: All constants match specifications

Test 21: Color Validity

Test Name: testLightingDefaultsColorValidity

  • Objective: Verify default color is valid
  • Setup: None
  • Steps:
    1. Get NORMAL_COLOR
    2. Verify R, G, B in range [0, 1]
    3. Verify alpha in range [0, 1]
  • Expected Result: Color values valid

Integration Tests

ServiceLocator Integration Tests

Test 22: Service Registration and Retrieval

Test Name: testServiceLocatorRegistration

  • Objective: Verify service registers and retrieves correctly
  • Setup:
    • Create mock LightingService
  • Steps:
    1. Call ServiceLocator.registerLightingService(service)
    2. Call ServiceLocator.getLightingService()
    3. Verify returned service matches registered
  • Expected Result: Service correctly stored and retrieved

Test 23: Service Locator Clear

Test Name: testServiceLocatorClear

  • Objective: Verify service cleared when ServiceLocator.clear() called
  • Setup:
    • Register LightingService
  • Steps:
    1. Call ServiceLocator.clear()
    2. Call ServiceLocator.getLightingService()
    3. Verify returns null
  • Expected Result: Service cleared properly

Game Screen Integration Tests

Test 24: MainGameScreen Lighting Integration

Test Name: testMainGameScreenLightingIntegration

  • Objective: Verify lighting system integrated into main game screen
  • Setup:
    • Create mock game dependencies
    • Mock GdxGame, renderer, physics engine
  • Steps:
    1. Create MainGameScreen(game)
    2. Verify LightingService registered
    3. Verify lightingEngine field populated
    4. Call render(0.016f) (one frame)
    5. Verify no exceptions
    6. Call dispose()
    7. Verify lightingEngine.dispose() called
  • Expected Result: Lighting integrated and lifecycle managed correctly

Test 25: LevelsGameScreen Lighting Integration

Test Name: testLevelsGameScreenLightingIntegration

  • Objective: Verify lighting integrated into levels game screen
  • Setup: Mock game dependencies
  • Steps:
    1. Create LevelsGameScreen(game)
    2. Verify LightingService registered
    3. Call render(0.016f)
    4. Verify no exceptions
    5. Call dispose()
  • Expected Result: Screen renders with lighting, proper cleanup

Test 26: Level2GameScreen Lighting Integration

Test Name: testLevel2GameScreenLightingIntegration

  • Objective: Verify lighting integrated into level 2 screen
  • Setup: Mock game dependencies
  • Steps:
    1. Create Level2GameScreen(game)
    2. Verify service registered
    3. Call render(0.016f)
    4. Verify no exceptions
  • Expected Result: Screen renders with lighting

Test 27: SandboxGameScreen Lighting Integration

Test Name: testSandboxGameScreenLightingIntegration

  • Objective: Verify lighting integrated into sandbox screen
  • Setup: Mock game dependencies
  • Steps:
    1. Create SandboxGameScreen(game)
    2. Verify service registered
    3. Call render(0.016f)
    4. Verify no exceptions
  • Expected Result: Screen renders with lighting

Renderer Integration Tests

Test 28: Renderer with Lighting

Test Name: testRendererWithLighting

  • Objective: Verify renderer correctly calls lighting render
  • Setup:
    • Create mock renderer
    • Create mock LightingEngine
  • Steps:
    1. Call renderer.render(lightingEngine)
    2. Verify lighting engine's render() called
    3. Verify called after batch end
  • Expected Result: Lighting rendered in correct order

Projectile Lighting Integration Tests

Test 29: Fire Arrow Creates Light

Test Name: testFireArrowCreatesLight

  • Objective: Verify fire arrows emit correct colored light
  • Setup:
    • Register lighting service
    • Create shooter entity
  • Steps:
    1. Call ProjectileFactory.createFireArrow(shooter, pos, dir)
    2. Verify entity has PointLightComponent
    3. Verify component color is orange-red (0.55, 0.05, 0.02)
    4. Verify light distance is default
    5. Verify light rays is default
  • Expected Result: Fire arrow emits correct orange-red light

Test 30: Ice Arrow Creates Light

Test Name: testIceArrowCreatesLight

  • Objective: Verify ice arrows emit correct colored light
  • Setup: Register lighting service, create shooter
  • Steps:
    1. Call ProjectileFactory.createIceArrow(shooter, pos, dir)
    2. Verify component color is blue (0.05, 0.25, 0.65)
  • Expected Result: Ice arrow emits correct blue light

Test 31: Poison Arrow Creates Light

Test Name: testPoisonArrowCreatesLight

  • Objective: Verify poison arrows emit correct colored light
  • Setup: Register lighting service, create shooter
  • Steps:
    1. Call ProjectileFactory.createPoisonArrow(shooter, pos, dir)
    2. Verify component color is purple (0.20, 0.05, 0.25)
  • Expected Result: Poison arrow emits correct purple light

Test 32: Poison Potion Creates Light

Test Name: testPoisonPotionCreatesLight

  • Objective: Verify poison potions emit correct colored light
  • Setup: Register lighting service, create shooter
  • Steps:
    1. Call ProjectileFactory.createThrownPoisonPotion(shooter, pos, dir)
    2. Verify component color is purple (0.20, 0.05, 0.25)
  • Expected Result: Poison potion emits correct purple light

User Settings Integration Tests

Test 33: Brightness Setting Persistence

Test Name: testBrightnessSettingPersistence

  • Objective: Verify brightness saved and loaded
  • Setup: None
  • Steps:
    1. Get UserSettings
    2. Set brightnessValue = 0.5f
    3. Save settings
    4. Create new settings instance
    5. Verify brightnessValue == 0.5f
  • Expected Result: Brightness value persisted

Test 34: LightingEngine Uses User Brightness

Test Name: testLightingEngineUsesUserBrightness

  • Objective: Verify engine initializes with user brightness setting
  • Setup:
    • Set UserSettings.brightnessValue = 0.7f
    • Mock camera and world
  • Steps:
    1. Create LightingEngine(camera, world)
    2. Verify initial ambient light is 0.7f
  • Expected Result: Engine reads and applies user brightness

Performance Tests

Test 35: Render Performance with Multiple Lights

Test Name: testRenderPerformanceMultipleLights

  • Objective: Verify render time acceptable with many lights
  • Setup:
    • Create LightingEngine
    • Add 50 point lights to scene
  • Steps:
    1. Measure render time
    2. Call lightingEngine.render() 100 times
    3. Record average time
    4. Verify average < 16ms (60 FPS requirement)
  • Expected Result: Render time acceptable for target frame rate

Test 36: Memory Test Light Disposal

Test Name: testMemoryTestLightDisposal

  • Objective: Verify no memory leaks on light creation/destruction
  • Setup:
    • Create LightingEngine
    • Record initial memory
  • Steps:
    1. Create 1000 light components
    2. Dispose all lights
    3. Run garbage collection
    4. Verify final memory near initial
  • Expected Result: No memory leak detected

Test 37: Update Performance with Velocity

Test Name: testUpdatePerformanceWithVelocity

  • Objective: Verify update time acceptable with moving lights
  • Setup:
    • Create 20 lights with velocity
    • Mock TimeSource
  • Steps:
    1. Measure update time
    2. Call update() 1000 times
    3. Record average time
    4. Verify acceptable performance
  • Expected Result: Update completes in reasonable time

Edge Case Tests

Test 38: Null RayHandler Handling

Test Name: testNullRayHandlerHandling

  • Objective: Verify graceful handling of null ray handler
  • Setup: Create component with null ray handler
  • Steps:
    1. Call create()
    2. Call update()
    3. Call dispose()
  • Expected Result: Methods handle null gracefully or throw clear exceptions

Test 39: Null Entity Position

Test Name: testNullEntityPosition

  • Objective: Verify handling of entity without position
  • Setup:
    • Create component
    • Create entity without position set
  • Steps:
    1. Call create()
    2. Call update()
  • Expected Result: Default position or clear error

Test 40: Rapid Active/Inactive Toggle

Test Name: testRapidActiveInactiveToggle

  • Objective: Verify robustness under rapid state changes
  • Setup:
    • Create component with light
  • Steps:
    1. Toggle setActive() 1000 times rapidly
    2. Call update() after each toggle
  • Expected Result: No exceptions, state correctly tracked

Test 41: Zero Delta Time

Test Name: testZeroDeltaTime

  • Objective: Verify handling of zero delta time
  • Setup:
    • Create component with velocity
    • Mock TimeSource.getDeltaTime() returning 0
  • Steps:
    1. Call update()
    2. Verify entity position unchanged
  • Expected Result: No movement, no exceptions

Test 42: Negative Delta Time

Test Name: testNegativeDeltaTime

  • Objective: Verify handling of negative delta time
  • Setup:
    • Create component with velocity
    • Mock TimeSource.getDeltaTime() returning -0.016f
  • Steps:
    1. Call update()
    2. Verify clamped to 0
  • Expected Result: Delta clamped, no backward movement

Test Data / Fixtures

Mock Objects

  • MockCameraComponent: Returns valid projection matrix
  • MockWorld: Provides physics world for ray handler
  • MockRayHandler: Spy on light creation/disposal
  • MockEntity: Configurable position/center position
  • MockTimeSource: Controllable delta time
  • MockLightingEngine: Spy on render calls
  • MockLightingService: Wrapped engine reference

Test Constants

public static final Vector2 TEST_POSITION = new Vector2(5f, 5f);
public static final Vector2 TEST_DIRECTION = new Vector2(1f, 0f);
public static final Color TEST_COLOR = Color.RED;
public static final float TEST_DISTANCE = 4f;
public static final int TEST_RAYS = 128;
public static final float TEST_SOFTNESS = 1f;
public static final float DELTA_TIME = 0.016f; // 60 FPS

Test Execution Strategy

Phase 1: Unit Tests

  • Execute first
  • No dependencies on other systems
  • Fast feedback
  • Target: 100% code coverage for lighting classes

Phase 2: Integration Tests

  • Execute after unit tests pass
  • Verify interaction with game screens
  • Verify ServiceLocator integration
  • Target: All integration scenarios covered

Phase 3: Performance Tests

  • Execute on final build
  • Verify frame rate targets met
  • Identify optimization opportunities
  • Document baseline metrics

Phase 4: Edge Case Tests

  • Execute throughout development
  • Add new cases as issues discovered
  • Regression testing for fixes

Success Criteria

  • Unit Tests: 100% pass rate, ≥90% code coverage
  • Integration Tests: 100% pass rate on all game screens
  • Performance Tests: Render time < 16ms with 50+ lights
  • Edge Case Tests: All tests pass, no critical issues
  • Manual Testing: Visual verification of light rendering in-game

Regression Test Suite

Run after any changes to:

  • LightingEngine, LightingService, PointLightComponent
  • Game screen constructors or render methods
  • ProjectileFactory arrow creation
  • UserSettings brightness configuration