use neurodoom::engine::ClassicEngine;
use neurodoom::math::*;
use neurodoom::render::SemanticClass;
use neurodoom::rules::PlayerAction;
use neurodoom::world::PeerId;
fn load_wad() -> Vec<u8> {
let path = std::env::var("DOOM_WAD")
.unwrap_or_else(|_| "doom1.wad".to_string());
std::fs::read(&path).unwrap_or_else(|e| panic!("failed to read WAD at {path}: {e}"))
}
#[test]
fn engine_initializes() {
let wad_data = load_wad();
let engine = ClassicEngine::new(&wad_data, "E1M1").unwrap();
assert_eq!(engine.buffer_size(), (SCREENWIDTH, SCREENHEIGHT));
}
#[test]
fn tick_empty_input() {
let wad_data = load_wad();
let mut engine = ClassicEngine::new(&wad_data, "E1M1").unwrap();
engine.tick_single(PeerId(0), PlayerAction::default());
let nonzero = engine.framebuffer().iter().filter(|&&b| b != 0).count();
assert!(nonzero > 1000, "framebuffer mostly empty after tick");
}
#[test]
fn tick_350_no_panic() {
let wad_data = load_wad();
let mut engine = ClassicEngine::new(&wad_data, "E1M1").unwrap();
for _ in 0..350 {
engine.tick_single(PeerId(0), PlayerAction::default());
}
assert_eq!(engine.world().tick, 350);
}
#[test]
fn forward_input_moves_player() {
let wad_data = load_wad();
let mut engine = ClassicEngine::new(&wad_data, "E1M1").unwrap();
let initial_pos = engine.world().iter()
.find(|e| engine.world().is_controlled(e.id))
.map(|e| (e.x, e.y))
.unwrap();
for _ in 0..35 {
engine.tick_single(PeerId(0), PlayerAction {
forward_move: 25,
..PlayerAction::default()
});
}
let final_pos = engine.world().iter()
.find(|e| engine.world().is_controlled(e.id))
.map(|e| (e.x, e.y))
.unwrap();
let dx = (final_pos.0 - initial_pos.0).abs();
let dy = (final_pos.1 - initial_pos.1).abs();
assert!(dx > FRACUNIT || dy > FRACUNIT, "player should have moved: dx={dx} dy={dy}");
}
#[test]
fn turn_changes_angle() {
let wad_data = load_wad();
let mut engine = ClassicEngine::new(&wad_data, "E1M1").unwrap();
let initial_angle = engine.world().iter()
.find(|e| engine.world().is_controlled(e.id))
.map(|e| e.angle)
.unwrap();
engine.tick_single(PeerId(0), PlayerAction {
angle_turn: 512,
..PlayerAction::default()
});
let new_angle = engine.world().iter()
.find(|e| engine.world().is_controlled(e.id))
.map(|e| e.angle)
.unwrap();
assert_ne!(initial_angle, new_angle, "angle should change on turn input");
}
#[test]
fn semantic_buffer_has_content() {
let wad_data = load_wad();
let mut engine = ClassicEngine::new(&wad_data, "E1M1").unwrap();
engine.tick_single(PeerId(0), PlayerAction::default());
let semantic = engine.semantic_buffer();
assert!(semantic.iter().any(|&c| c == SemanticClass::Wall as u8), "no Wall pixels");
assert!(semantic.iter().any(|&c| c == SemanticClass::Floor as u8), "no Floor pixels");
assert!(semantic.iter().any(|&c| c == SemanticClass::Ceiling as u8), "no Ceiling pixels");
}
#[test]
fn depth_buffer_has_content() {
let wad_data = load_wad();
let mut engine = ClassicEngine::new(&wad_data, "E1M1").unwrap();
engine.tick_single(PeerId(0), PlayerAction::default());
assert!(engine.depth_buffer().iter().any(|&d| d != 0), "depth buffer all zeros");
}