use carla::client::{ActorBase, Client};
use std::{thread, time::Duration};
type TestResult = Result<(), Box<dyn std::error::Error>>;
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("=== World Operations Tests ===\n");
let client = Client::connect("127.0.0.1", 2000, None)?;
let mut world = client.world()?;
println!("Connected to CARLA server\n");
let mut passed = 0;
let mut failed = 0;
println!("--- Traffic Light Operations ---");
run_test(
"test_get_traffic_lights",
|| test_get_traffic_lights(&world),
&mut passed,
&mut failed,
);
run_test(
"test_traffic_light_state_change",
|| test_traffic_light_state_change(&world),
&mut passed,
&mut failed,
);
run_test(
"test_traffic_light_timing",
|| test_traffic_light_timing(&world),
&mut passed,
&mut failed,
);
run_test(
"test_traffic_light_freeze",
|| test_traffic_light_freeze(&mut world),
&mut passed,
&mut failed,
);
run_test(
"test_reset_all_traffic_lights",
|| test_reset_all_traffic_lights(&mut world),
&mut passed,
&mut failed,
);
println!("\n--- Landmark Operations ---");
run_test(
"test_get_landmarks",
|| test_get_landmarks(&world),
&mut passed,
&mut failed,
);
run_test(
"test_landmarks_by_type",
|| test_landmarks_by_type(&world),
&mut passed,
&mut failed,
);
run_test(
"test_landmark_waypoints",
|| test_landmark_waypoints(&world),
&mut passed,
&mut failed,
);
println!("\n--- Environment Object Operations ---");
run_test(
"test_environment_objects_query",
|| test_environment_objects_query(&world),
&mut passed,
&mut failed,
);
run_test(
"test_environment_object_enable_disable",
|| test_environment_object_enable_disable(&world),
&mut passed,
&mut failed,
);
println!("\n--- World Operations ---");
run_test(
"test_world_tick_timeout",
|| test_world_tick_timeout(&mut world),
&mut passed,
&mut failed,
);
println!("\n=== Results ===");
println!("Passed: {}", passed);
println!("Failed: {}", failed);
std::process::exit(if failed > 0 { 1 } else { 0 });
}
fn run_test<F>(name: &str, test_fn: F, passed: &mut i32, failed: &mut i32)
where
F: FnOnce() -> TestResult,
{
print!("Testing {}... ", name);
match test_fn() {
Ok(_) => {
println!("✓ PASS");
*passed += 1;
}
Err(e) => {
println!("✗ FAIL: {}", e);
*failed += 1;
}
}
}
fn test_get_traffic_lights(world: &carla::client::World) -> TestResult {
let actors = world.actors()?;
let mut traffic_light_count = 0;
for actor in actors.iter() {
let type_id = actor.type_id();
if type_id.starts_with("traffic.traffic_light") {
traffic_light_count += 1;
}
}
println!(" Found {} traffic lights", traffic_light_count);
Ok(())
}
fn test_traffic_light_state_change(world: &carla::client::World) -> TestResult {
let actors = world.actors()?;
let traffic_lights: Vec<_> = actors
.iter()
.filter(|a| a.type_id().starts_with("traffic.traffic_light"))
.collect();
if !traffic_lights.is_empty() {
println!(
" Can identify {} traffic lights via actors",
traffic_lights.len()
);
if let Some(tl) = traffic_lights.first() {
let location = tl.location()?;
println!(
" Traffic light location: ({:.1}, {:.1}, {:.1})",
location.x, location.y, location.z
);
}
}
Ok(())
}
fn test_traffic_light_timing(world: &carla::client::World) -> TestResult {
let actors = world.actors()?;
let traffic_light_count = actors
.iter()
.filter(|a| a.type_id().starts_with("traffic.traffic_light"))
.count();
println!(
" Timing API not yet available for {} traffic lights",
traffic_light_count
);
Ok(())
}
fn test_traffic_light_freeze(world: &mut carla::client::World) -> TestResult {
println!(" Freezing all traffic lights");
world.freeze_all_traffic_lights(true)?;
thread::sleep(Duration::from_millis(100));
println!(" Unfreezing all traffic lights");
world.freeze_all_traffic_lights(false)?;
thread::sleep(Duration::from_millis(100));
Ok(())
}
fn test_reset_all_traffic_lights(world: &mut carla::client::World) -> TestResult {
println!(" Resetting all traffic lights to default");
world.reset_all_traffic_lights()?;
thread::sleep(Duration::from_millis(100));
Ok(())
}
fn test_get_landmarks(world: &carla::client::World) -> TestResult {
let map = world.map()?;
let name = map.name();
println!(" Current map: {}", name);
println!(" Landmark query API not yet available");
assert!(!name.is_empty(), "Map name should not be empty");
Ok(())
}
fn test_landmarks_by_type(world: &carla::client::World) -> TestResult {
let map = world.map()?;
let waypoints = map.generate_waypoints(10.0)?;
println!(
" Generated {} waypoints (landmarks would be nearby)",
waypoints.len()
);
println!(" Landmark type filtering API not yet available");
Ok(())
}
fn test_landmark_waypoints(world: &carla::client::World) -> TestResult {
let map = world.map()?;
let waypoints = map.generate_waypoints(10.0)?;
if !waypoints.is_empty()
&& let Some(wp) = waypoints.get(0)
{
println!(
" Waypoint at ({:.1}, {:.1}, {:.1})",
wp.transform().location.x,
wp.transform().location.y,
wp.transform().location.z
);
println!(" Landmark waypoint association API not yet available");
}
Ok(())
}
fn test_environment_objects_query(world: &carla::client::World) -> TestResult {
let objects = world.environment_objects(0xFF)?;
println!(" Found {} environment objects", objects.len());
assert!(
!objects.is_empty(),
"Most maps should have environment objects"
);
let sample_count = 3.min(objects.len());
for i in 0..sample_count {
if let Some(obj) = objects.get(i) {
let location = obj.transform().location;
println!(
" Object {}: ID={}, location=({:.1}, {:.1}, {:.1})",
i + 1,
obj.id(),
location.x,
location.y,
location.z
);
}
}
Ok(())
}
fn test_environment_object_enable_disable(world: &carla::client::World) -> TestResult {
let objects = world.environment_objects(0xFF)?;
if objects.is_empty() {
println!(" No environment objects to toggle");
return Ok(());
}
let toggle_count = 5.min(objects.len());
let mut ids_to_toggle = Vec::new();
for i in 0..toggle_count {
if let Some(obj) = objects.get(i) {
ids_to_toggle.push(obj.id());
}
}
if !ids_to_toggle.is_empty() {
println!(" Disabling {} environment objects", ids_to_toggle.len());
world.enable_environment_objects(&ids_to_toggle, false)?;
thread::sleep(Duration::from_millis(200));
println!(" Re-enabling {} environment objects", ids_to_toggle.len());
world.enable_environment_objects(&ids_to_toggle, true)?;
thread::sleep(Duration::from_millis(200));
}
Ok(())
}
fn test_world_tick_timeout(world: &mut carla::client::World) -> TestResult {
println!(" Performing world tick");
let tick_result = world.tick()?;
println!(" Tick completed, frame: {}", tick_result);
assert!(tick_result > 0, "Tick should return valid frame number");
let tick2 = world.tick()?;
println!(" Second tick completed, frame: {}", tick2);
assert!(
tick2 > tick_result,
"Frame number should increment on each tick"
);
Ok(())
}