mirror of
https://github.com/cliffe/BreakEscape.git
synced 2026-02-21 11:18:08 +00:00
Add integration and unit tests for asset loading and content type determination
- Created `AssetLoadingIntegrationTest` to verify the loading of game assets in the correct order, including JavaScript, CSS, and sound files. - Implemented tests to ensure proper handling of asset paths, security constraints, and response headers. - Added `StaticFilesControllerUnitTest` to test the content type determination logic for various file extensions, ensuring case insensitivity and handling of multiple dots in filenames.
This commit is contained in:
202
test/controllers/break_escape/static_files_controller_test.rb
Normal file
202
test/controllers/break_escape/static_files_controller_test.rb
Normal file
@@ -0,0 +1,202 @@
|
||||
require 'test_helper'
|
||||
|
||||
module BreakEscape
|
||||
class StaticFilesControllerTest < ActionDispatch::IntegrationTest
|
||||
include Engine.routes.url_helpers
|
||||
|
||||
# CSS file serving tests
|
||||
test 'CSS: should serve files with correct MIME type' do
|
||||
get '/break_escape/css/hud.css'
|
||||
assert_response :success
|
||||
assert_equal 'text/css', response.content_type
|
||||
end
|
||||
|
||||
test 'CSS: should serve with inline disposition' do
|
||||
get '/break_escape/css/hud.css'
|
||||
assert_response :success
|
||||
assert_match /inline/, response.headers['Content-Disposition']
|
||||
end
|
||||
|
||||
test 'CSS: should return 404 for non-existent files' do
|
||||
get '/break_escape/css/non-existent.css'
|
||||
assert_response :not_found
|
||||
end
|
||||
|
||||
# JavaScript file serving tests
|
||||
test 'JS: should serve files with correct MIME type' do
|
||||
get '/break_escape/js/main.js'
|
||||
assert_response :success
|
||||
assert_equal 'application/javascript', response.content_type
|
||||
end
|
||||
|
||||
test 'JS: should serve nested files' do
|
||||
get '/break_escape/js/utils/constants.js'
|
||||
assert_response :success
|
||||
assert_equal 'application/javascript', response.content_type
|
||||
end
|
||||
|
||||
test 'JS: should serve core game module' do
|
||||
get '/break_escape/js/core/game.js'
|
||||
assert_response :success
|
||||
assert_equal 'application/javascript', response.content_type
|
||||
end
|
||||
|
||||
test 'JS: should return 404 for non-existent files' do
|
||||
get '/break_escape/js/non-existent.js'
|
||||
assert_response :not_found
|
||||
end
|
||||
|
||||
# Asset file serving tests
|
||||
test 'Assets: should serve audio with correct MIME type' do
|
||||
get '/break_escape/assets/sounds/lockpick_binding.mp3'
|
||||
assert_response :success
|
||||
assert_equal 'audio/mpeg', response.content_type
|
||||
end
|
||||
|
||||
test 'Assets: should serve PNG tiles with correct MIME type' do
|
||||
get '/break_escape/assets/tiles/door_32.png'
|
||||
assert_response :success
|
||||
assert_equal 'image/png', response.content_type
|
||||
end
|
||||
|
||||
test 'Assets: should serve nested files' do
|
||||
get '/break_escape/assets/tiles/door_32.png'
|
||||
assert_response :success
|
||||
assert_equal 'image/png', response.content_type
|
||||
end
|
||||
|
||||
test 'Assets: should return 404 for non-existent files' do
|
||||
get '/break_escape/assets/sounds/non-existent.mp3'
|
||||
assert_response :not_found
|
||||
end
|
||||
|
||||
# HTML test page serving tests
|
||||
test 'HTML: should serve test files with correct MIME type' do
|
||||
get '/break_escape/test-assets.html'
|
||||
assert_response :success
|
||||
assert_equal 'text/html', response.content_type
|
||||
end
|
||||
|
||||
test 'HTML: should return 404 for non-existent files' do
|
||||
get '/break_escape/non-existent.html'
|
||||
assert_response :not_found
|
||||
end
|
||||
|
||||
# Route parameter capture tests
|
||||
test 'Routes: should capture full filename with extension' do
|
||||
get '/break_escape/css/hud.css'
|
||||
assert_response :success
|
||||
end
|
||||
|
||||
test 'Routes: should capture complex paths with segments' do
|
||||
get '/break_escape/js/utils/constants.js'
|
||||
assert_response :success
|
||||
end
|
||||
|
||||
test 'Routes: should handle files with multiple dots' do
|
||||
get '/break_escape/assets/tiles/door_sheet_32.png'
|
||||
assert_response :success
|
||||
assert_equal 'image/png', response.content_type
|
||||
end
|
||||
|
||||
# Security tests - directory traversal
|
||||
test 'Security: should prevent directory traversal in CSS' do
|
||||
get '/break_escape/css/../../config/database.yml'
|
||||
assert_response :not_found
|
||||
end
|
||||
|
||||
test 'Security: should prevent directory traversal in JS' do
|
||||
get '/break_escape/js/../../config/secrets.yml'
|
||||
assert_response :not_found
|
||||
end
|
||||
|
||||
test 'Security: should prevent directory traversal in assets' do
|
||||
get '/break_escape/assets/../../config/database.yml'
|
||||
assert_response :not_found
|
||||
end
|
||||
|
||||
# Phaser asset configuration
|
||||
test 'Phaser: main JS imports GAME_CONFIG' do
|
||||
get '/break_escape/js/main.js'
|
||||
assert_response :success
|
||||
assert_includes response.body, 'GAME_CONFIG'
|
||||
end
|
||||
|
||||
test 'Phaser: constants define GAME_CONFIG with baseURL' do
|
||||
get '/break_escape/js/utils/constants.js'
|
||||
assert_response :success
|
||||
content = response.body
|
||||
assert_includes content, 'GAME_CONFIG'
|
||||
assert_includes content, 'baseURL'
|
||||
assert_includes content, '/break_escape/assets'
|
||||
end
|
||||
|
||||
test 'Phaser: game.js has asset references without prefix' do
|
||||
get '/break_escape/js/core/game.js'
|
||||
assert_response :success
|
||||
content = response.body
|
||||
assert_includes content, 'this.load.audio'
|
||||
assert content.include?('sounds/'), "Should reference sounds without assets/ prefix"
|
||||
end
|
||||
|
||||
# File integrity tests
|
||||
test 'Integrity: CSS files are non-empty' do
|
||||
get '/break_escape/css/hud.css'
|
||||
assert_response :success
|
||||
assert response.body.length > 0
|
||||
end
|
||||
|
||||
test 'Integrity: JavaScript files are non-empty' do
|
||||
get '/break_escape/js/main.js'
|
||||
assert_response :success
|
||||
assert response.body.length > 0
|
||||
end
|
||||
|
||||
test 'Integrity: audio files are non-empty' do
|
||||
get '/break_escape/assets/sounds/lockpick_binding.mp3'
|
||||
assert_response :success
|
||||
assert response.body.length > 0
|
||||
end
|
||||
|
||||
test 'Integrity: image files are non-empty' do
|
||||
get '/break_escape/assets/tiles/door_32.png'
|
||||
assert_response :success
|
||||
assert response.body.length > 0
|
||||
end
|
||||
|
||||
# Response header tests
|
||||
test 'Headers: should include Cache-Control' do
|
||||
get '/break_escape/css/hud.css'
|
||||
assert_response :success
|
||||
assert response.headers['Cache-Control']
|
||||
end
|
||||
|
||||
test 'Headers: should set Content-Disposition to inline' do
|
||||
get '/break_escape/css/hud.css'
|
||||
assert_response :success
|
||||
assert_match /inline/, response.headers['Content-Disposition']
|
||||
end
|
||||
|
||||
test 'Headers: should include Content-Length' do
|
||||
get '/break_escape/css/hud.css'
|
||||
assert_response :success
|
||||
assert response.headers['Content-Length']
|
||||
end
|
||||
|
||||
# Minigame asset loading tests
|
||||
test 'Minigame: should serve lockpicking script' do
|
||||
get '/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js'
|
||||
assert_response :success
|
||||
assert_equal 'application/javascript', response.content_type
|
||||
end
|
||||
|
||||
test 'Minigame: should serve lockpicking sounds' do
|
||||
sounds = ['lockpick_binding.mp3', 'lockpick_click.mp3', 'lockpick_success.mp3']
|
||||
sounds.each do |sound|
|
||||
get "/break_escape/assets/sounds/#{sound}"
|
||||
assert_response :success, "Failed to serve #{sound}"
|
||||
assert_equal 'audio/mpeg', response.content_type
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
142
test/integration/asset_loading_integration_test.rb
Normal file
142
test/integration/asset_loading_integration_test.rb
Normal file
@@ -0,0 +1,142 @@
|
||||
require 'test_helper'
|
||||
|
||||
module BreakEscape
|
||||
class AssetLoadingIntegrationTest < ActionDispatch::IntegrationTest
|
||||
include Engine.routes.url_helpers
|
||||
|
||||
test 'should load all required game files in correct order' do
|
||||
get '/break_escape/js/main.js'
|
||||
assert_response :success
|
||||
assert_includes response.body, 'GAME_CONFIG'
|
||||
end
|
||||
|
||||
test 'should load GAME_CONFIG with proper baseURL' do
|
||||
get '/break_escape/js/utils/constants.js'
|
||||
assert_response :success
|
||||
content = response.body
|
||||
assert_match /export const GAME_CONFIG/, content
|
||||
assert_match /baseURL/, content
|
||||
assert_match /\/break_escape\/assets/, content
|
||||
end
|
||||
|
||||
test 'CSS files should be accessible from main game' do
|
||||
get '/break_escape/css/hud.css'
|
||||
assert_response :success
|
||||
assert_equal 'text/css', response.content_type
|
||||
end
|
||||
|
||||
test 'should serve game core with asset references' do
|
||||
get '/break_escape/js/core/game.js'
|
||||
assert_response :success
|
||||
content = response.body
|
||||
assert_includes content, 'preload'
|
||||
assert_includes content, 'this.load'
|
||||
end
|
||||
|
||||
test 'should serve sound manager module' do
|
||||
get '/break_escape/js/systems/sound-manager.js'
|
||||
assert_response :success
|
||||
assert_equal 'application/javascript', response.content_type
|
||||
end
|
||||
|
||||
test 'should serve minigame starters' do
|
||||
get '/break_escape/js/systems/minigame-starters.js'
|
||||
assert_response :success
|
||||
assert_equal 'application/javascript', response.content_type
|
||||
end
|
||||
|
||||
test 'should serve lockpicking minigame' do
|
||||
get '/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js'
|
||||
assert_response :success
|
||||
assert_equal 'application/javascript', response.content_type
|
||||
content = response.body
|
||||
assert_match /baseURL/, content
|
||||
end
|
||||
|
||||
test 'complete asset loading path for lockpicking' do
|
||||
get '/break_escape/js/minigames/lockpicking/lockpicking-game-phaser.js'
|
||||
assert_response :success
|
||||
|
||||
lockpick_sounds = [
|
||||
'lockpick_binding.mp3',
|
||||
'lockpick_click.mp3',
|
||||
'lockpick_overtension.mp3',
|
||||
'lockpick_reset.mp3',
|
||||
'lockpick_set.mp3',
|
||||
'lockpick_success.mp3',
|
||||
'lockpick_tension.mp3',
|
||||
'lockpick_wrong.mp3'
|
||||
]
|
||||
|
||||
lockpick_sounds.each do |sound|
|
||||
get "/break_escape/assets/sounds/#{sound}"
|
||||
assert_response :success, "Lockpick sound not found: #{sound}"
|
||||
assert_equal 'audio/mpeg', response.content_type
|
||||
end
|
||||
|
||||
get '/break_escape/assets/tiles/door_32.png'
|
||||
assert_response :success
|
||||
assert_equal 'image/png', response.content_type
|
||||
end
|
||||
|
||||
test 'route constraints correctly capture file extensions' do
|
||||
files_to_test = [
|
||||
'/break_escape/css/hud.css',
|
||||
'/break_escape/js/main.js',
|
||||
'/break_escape/assets/tiles/door_32.png',
|
||||
'/break_escape/assets/sounds/lockpick_binding.mp3'
|
||||
]
|
||||
|
||||
files_to_test.each do |file_path|
|
||||
get file_path
|
||||
assert_response :success, "Failed to load file with extension: #{file_path}"
|
||||
end
|
||||
end
|
||||
|
||||
test 'baseURL prevents duplicate asset paths' do
|
||||
get '/break_escape/js/utils/constants.js'
|
||||
assert_response :success
|
||||
content = response.body
|
||||
assert !content.include?('assets/assets'), "Should not have duplicate assets/ prefix"
|
||||
end
|
||||
|
||||
test 'asset paths work without assets prefix in load calls' do
|
||||
get '/break_escape/js/core/game.js'
|
||||
assert_response :success
|
||||
content = response.body
|
||||
assert_match /this\.load\.audio\(['"][\w_]+['"],\s*['"]sounds\//, content
|
||||
end
|
||||
|
||||
test 'security: cannot access files outside break_escape directory' do
|
||||
get '/break_escape/css/../../config/secrets.yml'
|
||||
assert_response :not_found
|
||||
|
||||
get '/break_escape/js/../../config/database.yml'
|
||||
assert_response :not_found
|
||||
|
||||
get '/break_escape/assets/../../config/secrets.yml'
|
||||
assert_response :not_found
|
||||
end
|
||||
|
||||
test 'all response headers are correct' do
|
||||
[
|
||||
'/break_escape/css/hud.css',
|
||||
'/break_escape/js/main.js',
|
||||
'/break_escape/assets/sounds/lockpick_binding.mp3'
|
||||
].each do |path|
|
||||
get path
|
||||
assert_response :success
|
||||
assert response.headers['Content-Type'], "Missing Content-Type for #{path}"
|
||||
assert_match /inline/, response.headers['Content-Disposition']
|
||||
assert response.headers['Content-Length']
|
||||
end
|
||||
end
|
||||
|
||||
test 'test asset page loads correctly' do
|
||||
get '/break_escape/test-assets.html'
|
||||
assert_response :success
|
||||
assert_equal 'text/html', response.content_type
|
||||
assert_includes response.body, 'Asset Loading Test'
|
||||
end
|
||||
end
|
||||
end
|
||||
106
test/unit/static_files_controller_unit_test.rb
Normal file
106
test/unit/static_files_controller_unit_test.rb
Normal file
@@ -0,0 +1,106 @@
|
||||
require 'test_helper'
|
||||
|
||||
module BreakEscape
|
||||
class StaticFilesControllerUnitTest < ActiveSupport::TestCase
|
||||
# Test the content type determination logic in isolation
|
||||
|
||||
setup do
|
||||
@controller = StaticFilesController.new
|
||||
end
|
||||
|
||||
test 'determines CSS content type' do
|
||||
content_type = @controller.send(:determine_content_type, '/path/to/file.css')
|
||||
assert_equal 'text/css', content_type
|
||||
end
|
||||
|
||||
test 'determines JavaScript content type' do
|
||||
content_type = @controller.send(:determine_content_type, '/path/to/file.js')
|
||||
assert_equal 'application/javascript', content_type
|
||||
end
|
||||
|
||||
test 'determines HTML content type' do
|
||||
content_type = @controller.send(:determine_content_type, '/path/to/file.html')
|
||||
assert_equal 'text/html', content_type
|
||||
end
|
||||
|
||||
test 'determines JSON content type' do
|
||||
content_type = @controller.send(:determine_content_type, '/path/to/file.json')
|
||||
assert_equal 'application/json', content_type
|
||||
end
|
||||
|
||||
test 'determines PNG content type' do
|
||||
content_type = @controller.send(:determine_content_type, '/path/to/file.png')
|
||||
assert_equal 'image/png', content_type
|
||||
end
|
||||
|
||||
test 'determines JPEG content type' do
|
||||
content_type = @controller.send(:determine_content_type, '/path/to/file.jpg')
|
||||
assert_equal 'image/jpeg', content_type
|
||||
end
|
||||
|
||||
test 'determines GIF content type' do
|
||||
content_type = @controller.send(:determine_content_type, '/path/to/file.gif')
|
||||
assert_equal 'image/gif', content_type
|
||||
end
|
||||
|
||||
test 'determines SVG content type' do
|
||||
content_type = @controller.send(:determine_content_type, '/path/to/file.svg')
|
||||
assert_equal 'image/svg+xml', content_type
|
||||
end
|
||||
|
||||
test 'determines MP3 content type' do
|
||||
content_type = @controller.send(:determine_content_type, '/path/to/file.mp3')
|
||||
assert_equal 'audio/mpeg', content_type
|
||||
end
|
||||
|
||||
test 'determines WAV content type' do
|
||||
content_type = @controller.send(:determine_content_type, '/path/to/file.wav')
|
||||
assert_equal 'audio/wav', content_type
|
||||
end
|
||||
|
||||
test 'determines OGG content type' do
|
||||
content_type = @controller.send(:determine_content_type, '/path/to/file.ogg')
|
||||
assert_equal 'audio/ogg', content_type
|
||||
end
|
||||
|
||||
test 'determines WOFF font content type' do
|
||||
content_type = @controller.send(:determine_content_type, '/path/to/font.woff')
|
||||
assert_equal 'font/woff', content_type
|
||||
end
|
||||
|
||||
test 'determines WOFF2 font content type' do
|
||||
content_type = @controller.send(:determine_content_type, '/path/to/font.woff2')
|
||||
assert_equal 'font/woff2', content_type
|
||||
end
|
||||
|
||||
test 'determines TTF font content type' do
|
||||
content_type = @controller.send(:determine_content_type, '/path/to/font.ttf')
|
||||
assert_equal 'font/ttf', content_type
|
||||
end
|
||||
|
||||
test 'is case insensitive' do
|
||||
content_type = @controller.send(:determine_content_type, '/path/to/FILE.CSS')
|
||||
assert_equal 'text/css', content_type
|
||||
|
||||
content_type = @controller.send(:determine_content_type, '/path/to/FILE.JS')
|
||||
assert_equal 'application/javascript', content_type
|
||||
|
||||
content_type = @controller.send(:determine_content_type, '/path/to/FILE.PNG')
|
||||
assert_equal 'image/png', content_type
|
||||
end
|
||||
|
||||
test 'handles multiple dots in filename' do
|
||||
# Files like door_sheet_32.png should work
|
||||
content_type = @controller.send(:determine_content_type, '/path/to/door_sheet_32.png')
|
||||
assert_equal 'image/png', content_type
|
||||
|
||||
content_type = @controller.send(:determine_content_type, '/path/to/lockpick_binding.mp3')
|
||||
assert_equal 'audio/mpeg', content_type
|
||||
end
|
||||
|
||||
test 'returns octet-stream for unknown extensions' do
|
||||
content_type = @controller.send(:determine_content_type, '/path/to/file.unknown')
|
||||
assert_equal 'application/octet-stream', content_type
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user