rrt/crates/rrt-fixtures/src/schema.rs

1432 lines
62 KiB
Rust

use serde::{Deserialize, Serialize};
use serde_json::Value;
use rrt_runtime::{RuntimeState, RuntimeSummary, StepCommand};
pub const FIXTURE_FORMAT_VERSION: u32 = 1;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
pub struct FixtureSource {
pub kind: String,
#[serde(default)]
pub description: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
pub struct ExpectedRuntimeSummary {
#[serde(default)]
pub calendar: Option<rrt_runtime::CalendarPoint>,
#[serde(default)]
pub calendar_projection_source: Option<String>,
#[serde(default)]
pub calendar_projection_is_placeholder: Option<bool>,
#[serde(default)]
pub world_flag_count: Option<usize>,
#[serde(default)]
pub world_restore_selected_year_profile_lane: Option<u8>,
#[serde(default)]
pub world_restore_campaign_scenario_enabled: Option<bool>,
#[serde(default)]
pub world_restore_sandbox_enabled: Option<bool>,
#[serde(default)]
pub world_restore_seed_tuple_written_from_raw_lane: Option<bool>,
#[serde(default)]
pub world_restore_absolute_counter_requires_shell_context: Option<bool>,
#[serde(default)]
pub world_restore_absolute_counter_reconstructible_from_save: Option<bool>,
#[serde(default)]
pub world_restore_disable_cargo_economy_special_condition_slot: Option<u8>,
#[serde(default)]
pub world_restore_disable_cargo_economy_special_condition_reconstructible_from_save:
Option<bool>,
#[serde(default)]
pub world_restore_disable_cargo_economy_special_condition_write_side_grounded: Option<bool>,
#[serde(default)]
pub world_restore_disable_cargo_economy_special_condition_enabled: Option<bool>,
#[serde(default)]
pub world_restore_use_bio_accelerator_cars_enabled: Option<bool>,
#[serde(default)]
pub world_restore_use_wartime_cargos_enabled: Option<bool>,
#[serde(default)]
pub world_restore_disable_train_crashes_enabled: Option<bool>,
#[serde(default)]
pub world_restore_disable_train_crashes_and_breakdowns_enabled: Option<bool>,
#[serde(default)]
pub world_restore_ai_ignore_territories_at_startup_enabled: Option<bool>,
#[serde(default)]
pub world_restore_limited_track_building_amount: Option<i32>,
#[serde(default)]
pub world_restore_economic_status_code: Option<i32>,
#[serde(default)]
pub world_restore_territory_access_cost: Option<u32>,
#[serde(default)]
pub world_restore_issue_37_value: Option<u32>,
#[serde(default)]
pub world_restore_issue_37_multiplier_raw_u32: Option<u32>,
#[serde(default)]
pub world_restore_issue_37_multiplier_value_f32_text: Option<String>,
#[serde(default)]
pub world_restore_economic_tuning_mirror_raw_u32: Option<u32>,
#[serde(default)]
pub world_restore_economic_tuning_mirror_value_f32_text: Option<String>,
#[serde(default)]
pub world_restore_economic_tuning_lane_count: Option<usize>,
#[serde(default)]
pub world_restore_economic_tuning_lane_value_f32_text: Option<Vec<String>>,
#[serde(default)]
pub world_restore_absolute_counter_restore_kind: Option<String>,
#[serde(default)]
pub world_restore_absolute_counter_adjustment_context: Option<String>,
#[serde(default)]
pub metadata_count: Option<usize>,
#[serde(default)]
pub company_count: Option<usize>,
#[serde(default)]
pub active_company_count: Option<usize>,
#[serde(default)]
pub player_count: Option<usize>,
#[serde(default)]
pub chairman_profile_count: Option<usize>,
#[serde(default)]
pub active_chairman_profile_count: Option<usize>,
#[serde(default)]
pub selected_chairman_profile_id: Option<u32>,
#[serde(default)]
pub linked_chairman_company_count: Option<usize>,
#[serde(default)]
pub company_takeover_cooldown_count: Option<usize>,
#[serde(default)]
pub company_merger_cooldown_count: Option<usize>,
#[serde(default)]
pub train_count: Option<usize>,
#[serde(default)]
pub active_train_count: Option<usize>,
#[serde(default)]
pub retired_train_count: Option<usize>,
#[serde(default)]
pub locomotive_catalog_count: Option<usize>,
#[serde(default)]
pub cargo_catalog_count: Option<usize>,
#[serde(default)]
pub territory_count: Option<usize>,
#[serde(default)]
pub company_territory_track_count: Option<usize>,
#[serde(default)]
pub packed_event_collection_present: Option<bool>,
#[serde(default)]
pub packed_event_record_count: Option<usize>,
#[serde(default)]
pub packed_event_decoded_record_count: Option<usize>,
#[serde(default)]
pub packed_event_imported_runtime_record_count: Option<usize>,
#[serde(default)]
pub packed_event_parity_only_record_count: Option<usize>,
#[serde(default)]
pub packed_event_unsupported_record_count: Option<usize>,
#[serde(default)]
pub packed_event_blocked_missing_company_context_count: Option<usize>,
#[serde(default)]
pub packed_event_blocked_missing_selection_context_count: Option<usize>,
#[serde(default)]
pub packed_event_blocked_missing_company_role_context_count: Option<usize>,
#[serde(default)]
pub packed_event_blocked_missing_player_context_count: Option<usize>,
#[serde(default)]
pub packed_event_blocked_missing_player_selection_context_count: Option<usize>,
#[serde(default)]
pub packed_event_blocked_missing_player_role_context_count: Option<usize>,
#[serde(default)]
pub packed_event_blocked_missing_chairman_context_count: Option<usize>,
#[serde(default)]
pub packed_event_blocked_chairman_target_scope_count: Option<usize>,
#[serde(default)]
pub packed_event_blocked_missing_condition_context_count: Option<usize>,
#[serde(default)]
pub packed_event_blocked_missing_player_condition_context_count: Option<usize>,
#[serde(default)]
pub packed_event_blocked_company_condition_scope_disabled_count: Option<usize>,
#[serde(default)]
pub packed_event_blocked_player_condition_scope_count: Option<usize>,
#[serde(default)]
pub packed_event_blocked_territory_condition_scope_count: Option<usize>,
#[serde(default)]
pub packed_event_blocked_missing_territory_context_count: Option<usize>,
#[serde(default)]
pub packed_event_blocked_named_territory_binding_count: Option<usize>,
#[serde(default)]
pub packed_event_blocked_unmapped_ordinary_condition_count: Option<usize>,
#[serde(default)]
pub packed_event_blocked_unmapped_world_condition_count: Option<usize>,
#[serde(default)]
pub packed_event_blocked_missing_compact_control_count: Option<usize>,
#[serde(default)]
pub packed_event_blocked_shell_owned_descriptor_count: Option<usize>,
#[serde(default)]
pub packed_event_blocked_evidence_blocked_descriptor_count: Option<usize>,
#[serde(default)]
pub packed_event_blocked_variant_or_scope_blocked_descriptor_count: Option<usize>,
#[serde(default)]
pub packed_event_blocked_unmapped_real_descriptor_count: Option<usize>,
#[serde(default)]
pub packed_event_blocked_unmapped_world_descriptor_count: Option<usize>,
#[serde(default)]
pub packed_event_blocked_territory_access_variant_count: Option<usize>,
#[serde(default)]
pub packed_event_blocked_territory_access_scope_count: Option<usize>,
#[serde(default)]
pub packed_event_blocked_missing_train_context_count: Option<usize>,
#[serde(default)]
pub packed_event_blocked_missing_train_territory_context_count: Option<usize>,
#[serde(default)]
pub packed_event_blocked_missing_locomotive_catalog_context_count: Option<usize>,
#[serde(default)]
pub packed_event_blocked_confiscation_variant_count: Option<usize>,
#[serde(default)]
pub packed_event_blocked_retire_train_variant_count: Option<usize>,
#[serde(default)]
pub packed_event_blocked_retire_train_scope_count: Option<usize>,
#[serde(default)]
pub packed_event_blocked_structural_only_count: Option<usize>,
#[serde(default)]
pub event_runtime_record_count: Option<usize>,
#[serde(default)]
pub candidate_availability_count: Option<usize>,
#[serde(default)]
pub zero_candidate_availability_count: Option<usize>,
#[serde(default)]
pub named_locomotive_availability_count: Option<usize>,
#[serde(default)]
pub zero_named_locomotive_availability_count: Option<usize>,
#[serde(default)]
pub named_locomotive_cost_count: Option<usize>,
#[serde(default)]
pub cargo_production_override_count: Option<usize>,
#[serde(default)]
pub world_runtime_variable_count: Option<usize>,
#[serde(default)]
pub company_runtime_variable_owner_count: Option<usize>,
#[serde(default)]
pub player_runtime_variable_owner_count: Option<usize>,
#[serde(default)]
pub territory_runtime_variable_owner_count: Option<usize>,
#[serde(default)]
pub world_scalar_override_count: Option<usize>,
#[serde(default)]
pub special_condition_count: Option<usize>,
#[serde(default)]
pub enabled_special_condition_count: Option<usize>,
#[serde(default)]
pub save_profile_kind: Option<String>,
#[serde(default)]
pub save_profile_family: Option<String>,
#[serde(default)]
pub save_profile_map_path: Option<String>,
#[serde(default)]
pub save_profile_display_name: Option<String>,
#[serde(default)]
pub save_profile_selected_year_profile_lane: Option<u8>,
#[serde(default)]
pub save_profile_sandbox_enabled: Option<bool>,
#[serde(default)]
pub save_profile_campaign_scenario_enabled: Option<bool>,
#[serde(default)]
pub save_profile_staged_profile_copy_on_restore: Option<bool>,
#[serde(default)]
pub total_event_record_service_count: Option<u64>,
#[serde(default)]
pub periodic_boundary_call_count: Option<u64>,
#[serde(default)]
pub total_trigger_dispatch_count: Option<u64>,
#[serde(default)]
pub dirty_rerun_count: Option<u64>,
#[serde(default)]
pub total_company_cash: Option<i64>,
}
impl ExpectedRuntimeSummary {
pub fn compare(&self, actual: &RuntimeSummary) -> Vec<String> {
let mut mismatches = Vec::new();
if let Some(calendar) = self.calendar {
if actual.calendar != calendar {
mismatches.push(format!(
"calendar mismatch: expected {:?}, got {:?}",
calendar, actual.calendar
));
}
}
if let Some(source) = &self.calendar_projection_source {
if actual.calendar_projection_source.as_ref() != Some(source) {
mismatches.push(format!(
"calendar_projection_source mismatch: expected {source:?}, got {:?}",
actual.calendar_projection_source
));
}
}
if let Some(is_placeholder) = self.calendar_projection_is_placeholder {
if actual.calendar_projection_is_placeholder != is_placeholder {
mismatches.push(format!(
"calendar_projection_is_placeholder mismatch: expected {is_placeholder}, got {}",
actual.calendar_projection_is_placeholder
));
}
}
if let Some(count) = self.world_flag_count {
if actual.world_flag_count != count {
mismatches.push(format!(
"world_flag_count mismatch: expected {count}, got {}",
actual.world_flag_count
));
}
}
if let Some(lane) = self.world_restore_selected_year_profile_lane {
if actual.world_restore_selected_year_profile_lane != Some(lane) {
mismatches.push(format!(
"world_restore_selected_year_profile_lane mismatch: expected {lane}, got {:?}",
actual.world_restore_selected_year_profile_lane
));
}
}
if let Some(enabled) = self.world_restore_campaign_scenario_enabled {
if actual.world_restore_campaign_scenario_enabled != Some(enabled) {
mismatches.push(format!(
"world_restore_campaign_scenario_enabled mismatch: expected {enabled}, got {:?}",
actual.world_restore_campaign_scenario_enabled
));
}
}
if let Some(enabled) = self.world_restore_sandbox_enabled {
if actual.world_restore_sandbox_enabled != Some(enabled) {
mismatches.push(format!(
"world_restore_sandbox_enabled mismatch: expected {enabled}, got {:?}",
actual.world_restore_sandbox_enabled
));
}
}
if let Some(enabled) = self.world_restore_seed_tuple_written_from_raw_lane {
if actual.world_restore_seed_tuple_written_from_raw_lane != Some(enabled) {
mismatches.push(format!(
"world_restore_seed_tuple_written_from_raw_lane mismatch: expected {enabled}, got {:?}",
actual.world_restore_seed_tuple_written_from_raw_lane
));
}
}
if let Some(enabled) = self.world_restore_absolute_counter_requires_shell_context {
if actual.world_restore_absolute_counter_requires_shell_context != Some(enabled) {
mismatches.push(format!(
"world_restore_absolute_counter_requires_shell_context mismatch: expected {enabled}, got {:?}",
actual.world_restore_absolute_counter_requires_shell_context
));
}
}
if let Some(enabled) = self.world_restore_absolute_counter_reconstructible_from_save {
if actual.world_restore_absolute_counter_reconstructible_from_save != Some(enabled) {
mismatches.push(format!(
"world_restore_absolute_counter_reconstructible_from_save mismatch: expected {enabled}, got {:?}",
actual.world_restore_absolute_counter_reconstructible_from_save
));
}
}
if let Some(slot) = self.world_restore_disable_cargo_economy_special_condition_slot {
if actual.world_restore_disable_cargo_economy_special_condition_slot != Some(slot) {
mismatches.push(format!(
"world_restore_disable_cargo_economy_special_condition_slot mismatch: expected {slot}, got {:?}",
actual.world_restore_disable_cargo_economy_special_condition_slot
));
}
}
if let Some(enabled) =
self.world_restore_disable_cargo_economy_special_condition_reconstructible_from_save
{
if actual
.world_restore_disable_cargo_economy_special_condition_reconstructible_from_save
!= Some(enabled)
{
mismatches.push(format!(
"world_restore_disable_cargo_economy_special_condition_reconstructible_from_save mismatch: expected {enabled}, got {:?}",
actual.world_restore_disable_cargo_economy_special_condition_reconstructible_from_save
));
}
}
if let Some(enabled) =
self.world_restore_disable_cargo_economy_special_condition_write_side_grounded
{
if actual.world_restore_disable_cargo_economy_special_condition_write_side_grounded
!= Some(enabled)
{
mismatches.push(format!(
"world_restore_disable_cargo_economy_special_condition_write_side_grounded mismatch: expected {enabled}, got {:?}",
actual.world_restore_disable_cargo_economy_special_condition_write_side_grounded
));
}
}
if let Some(enabled) = self.world_restore_disable_cargo_economy_special_condition_enabled {
if actual.world_restore_disable_cargo_economy_special_condition_enabled != Some(enabled)
{
mismatches.push(format!(
"world_restore_disable_cargo_economy_special_condition_enabled mismatch: expected {enabled}, got {:?}",
actual.world_restore_disable_cargo_economy_special_condition_enabled
));
}
}
if let Some(enabled) = self.world_restore_use_bio_accelerator_cars_enabled {
if actual.world_restore_use_bio_accelerator_cars_enabled != Some(enabled) {
mismatches.push(format!(
"world_restore_use_bio_accelerator_cars_enabled mismatch: expected {enabled}, got {:?}",
actual.world_restore_use_bio_accelerator_cars_enabled
));
}
}
if let Some(enabled) = self.world_restore_use_wartime_cargos_enabled {
if actual.world_restore_use_wartime_cargos_enabled != Some(enabled) {
mismatches.push(format!(
"world_restore_use_wartime_cargos_enabled mismatch: expected {enabled}, got {:?}",
actual.world_restore_use_wartime_cargos_enabled
));
}
}
if let Some(enabled) = self.world_restore_disable_train_crashes_enabled {
if actual.world_restore_disable_train_crashes_enabled != Some(enabled) {
mismatches.push(format!(
"world_restore_disable_train_crashes_enabled mismatch: expected {enabled}, got {:?}",
actual.world_restore_disable_train_crashes_enabled
));
}
}
if let Some(enabled) = self.world_restore_disable_train_crashes_and_breakdowns_enabled {
if actual.world_restore_disable_train_crashes_and_breakdowns_enabled != Some(enabled) {
mismatches.push(format!(
"world_restore_disable_train_crashes_and_breakdowns_enabled mismatch: expected {enabled}, got {:?}",
actual.world_restore_disable_train_crashes_and_breakdowns_enabled
));
}
}
if let Some(enabled) = self.world_restore_ai_ignore_territories_at_startup_enabled {
if actual.world_restore_ai_ignore_territories_at_startup_enabled != Some(enabled) {
mismatches.push(format!(
"world_restore_ai_ignore_territories_at_startup_enabled mismatch: expected {enabled}, got {:?}",
actual.world_restore_ai_ignore_territories_at_startup_enabled
));
}
}
if let Some(value) = self.world_restore_limited_track_building_amount {
if actual.world_restore_limited_track_building_amount != Some(value) {
mismatches.push(format!(
"world_restore_limited_track_building_amount mismatch: expected {value}, got {:?}",
actual.world_restore_limited_track_building_amount
));
}
}
if let Some(code) = self.world_restore_economic_status_code {
if actual.world_restore_economic_status_code != Some(code) {
mismatches.push(format!(
"world_restore_economic_status_code mismatch: expected {code}, got {:?}",
actual.world_restore_economic_status_code
));
}
}
if let Some(value) = self.world_restore_territory_access_cost {
if actual.world_restore_territory_access_cost != Some(value) {
mismatches.push(format!(
"world_restore_territory_access_cost mismatch: expected {value}, got {:?}",
actual.world_restore_territory_access_cost
));
}
}
if let Some(value) = self.world_restore_issue_37_value {
if actual.world_restore_issue_37_value != Some(value) {
mismatches.push(format!(
"world_restore_issue_37_value mismatch: expected {value}, got {:?}",
actual.world_restore_issue_37_value
));
}
}
if let Some(value) = self.world_restore_issue_37_multiplier_raw_u32 {
if actual.world_restore_issue_37_multiplier_raw_u32 != Some(value) {
mismatches.push(format!(
"world_restore_issue_37_multiplier_raw_u32 mismatch: expected {value}, got {:?}",
actual.world_restore_issue_37_multiplier_raw_u32
));
}
}
if let Some(value) = &self.world_restore_issue_37_multiplier_value_f32_text {
if actual
.world_restore_issue_37_multiplier_value_f32_text
.as_ref()
!= Some(value)
{
mismatches.push(format!(
"world_restore_issue_37_multiplier_value_f32_text mismatch: expected {value:?}, got {:?}",
actual.world_restore_issue_37_multiplier_value_f32_text
));
}
}
if let Some(value) = self.world_restore_economic_tuning_mirror_raw_u32 {
if actual.world_restore_economic_tuning_mirror_raw_u32 != Some(value) {
mismatches.push(format!(
"world_restore_economic_tuning_mirror_raw_u32 mismatch: expected {value}, got {:?}",
actual.world_restore_economic_tuning_mirror_raw_u32
));
}
}
if let Some(value) = &self.world_restore_economic_tuning_mirror_value_f32_text {
if actual
.world_restore_economic_tuning_mirror_value_f32_text
.as_ref()
!= Some(value)
{
mismatches.push(format!(
"world_restore_economic_tuning_mirror_value_f32_text mismatch: expected {value:?}, got {:?}",
actual.world_restore_economic_tuning_mirror_value_f32_text
));
}
}
if let Some(count) = self.world_restore_economic_tuning_lane_count {
if actual.world_restore_economic_tuning_lane_count != count {
mismatches.push(format!(
"world_restore_economic_tuning_lane_count mismatch: expected {count}, got {}",
actual.world_restore_economic_tuning_lane_count
));
}
}
if let Some(values) = &self.world_restore_economic_tuning_lane_value_f32_text {
if &actual.world_restore_economic_tuning_lane_value_f32_text != values {
mismatches.push(format!(
"world_restore_economic_tuning_lane_value_f32_text mismatch: expected {values:?}, got {:?}",
actual.world_restore_economic_tuning_lane_value_f32_text
));
}
}
if let Some(kind) = &self.world_restore_absolute_counter_restore_kind {
if actual.world_restore_absolute_counter_restore_kind.as_ref() != Some(kind) {
mismatches.push(format!(
"world_restore_absolute_counter_restore_kind mismatch: expected {kind:?}, got {:?}",
actual.world_restore_absolute_counter_restore_kind
));
}
}
if let Some(context) = &self.world_restore_absolute_counter_adjustment_context {
if actual
.world_restore_absolute_counter_adjustment_context
.as_ref()
!= Some(context)
{
mismatches.push(format!(
"world_restore_absolute_counter_adjustment_context mismatch: expected {context:?}, got {:?}",
actual.world_restore_absolute_counter_adjustment_context
));
}
}
if let Some(count) = self.metadata_count {
if actual.metadata_count != count {
mismatches.push(format!(
"metadata_count mismatch: expected {count}, got {}",
actual.metadata_count
));
}
}
if let Some(count) = self.company_count {
if actual.company_count != count {
mismatches.push(format!(
"company_count mismatch: expected {count}, got {}",
actual.company_count
));
}
}
if let Some(count) = self.active_company_count {
if actual.active_company_count != count {
mismatches.push(format!(
"active_company_count mismatch: expected {count}, got {}",
actual.active_company_count
));
}
}
if let Some(count) = self.player_count {
if actual.player_count != count {
mismatches.push(format!(
"player_count mismatch: expected {count}, got {}",
actual.player_count
));
}
}
if let Some(count) = self.chairman_profile_count {
if actual.chairman_profile_count != count {
mismatches.push(format!(
"chairman_profile_count mismatch: expected {count}, got {}",
actual.chairman_profile_count
));
}
}
if let Some(count) = self.active_chairman_profile_count {
if actual.active_chairman_profile_count != count {
mismatches.push(format!(
"active_chairman_profile_count mismatch: expected {count}, got {}",
actual.active_chairman_profile_count
));
}
}
if let Some(selected_id) = self.selected_chairman_profile_id {
if actual.selected_chairman_profile_id != Some(selected_id) {
mismatches.push(format!(
"selected_chairman_profile_id mismatch: expected {selected_id:?}, got {:?}",
actual.selected_chairman_profile_id
));
}
}
if let Some(count) = self.linked_chairman_company_count {
if actual.linked_chairman_company_count != count {
mismatches.push(format!(
"linked_chairman_company_count mismatch: expected {count}, got {}",
actual.linked_chairman_company_count
));
}
}
if let Some(count) = self.company_takeover_cooldown_count {
if actual.company_takeover_cooldown_count != count {
mismatches.push(format!(
"company_takeover_cooldown_count mismatch: expected {count}, got {}",
actual.company_takeover_cooldown_count
));
}
}
if let Some(count) = self.company_merger_cooldown_count {
if actual.company_merger_cooldown_count != count {
mismatches.push(format!(
"company_merger_cooldown_count mismatch: expected {count}, got {}",
actual.company_merger_cooldown_count
));
}
}
if let Some(count) = self.train_count {
if actual.train_count != count {
mismatches.push(format!(
"train_count mismatch: expected {count}, got {}",
actual.train_count
));
}
}
if let Some(count) = self.active_train_count {
if actual.active_train_count != count {
mismatches.push(format!(
"active_train_count mismatch: expected {count}, got {}",
actual.active_train_count
));
}
}
if let Some(count) = self.retired_train_count {
if actual.retired_train_count != count {
mismatches.push(format!(
"retired_train_count mismatch: expected {count}, got {}",
actual.retired_train_count
));
}
}
if let Some(count) = self.locomotive_catalog_count {
if actual.locomotive_catalog_count != count {
mismatches.push(format!(
"locomotive_catalog_count mismatch: expected {count}, got {}",
actual.locomotive_catalog_count
));
}
}
if let Some(count) = self.cargo_catalog_count {
if actual.cargo_catalog_count != count {
mismatches.push(format!(
"cargo_catalog_count mismatch: expected {count}, got {}",
actual.cargo_catalog_count
));
}
}
if let Some(count) = self.territory_count {
if actual.territory_count != count {
mismatches.push(format!(
"territory_count mismatch: expected {count}, got {}",
actual.territory_count
));
}
}
if let Some(count) = self.company_territory_track_count {
if actual.company_territory_track_count != count {
mismatches.push(format!(
"company_territory_track_count mismatch: expected {count}, got {}",
actual.company_territory_track_count
));
}
}
if let Some(present) = self.packed_event_collection_present {
if actual.packed_event_collection_present != present {
mismatches.push(format!(
"packed_event_collection_present mismatch: expected {present}, got {}",
actual.packed_event_collection_present
));
}
}
if let Some(count) = self.packed_event_record_count {
if actual.packed_event_record_count != count {
mismatches.push(format!(
"packed_event_record_count mismatch: expected {count}, got {}",
actual.packed_event_record_count
));
}
}
if let Some(count) = self.packed_event_decoded_record_count {
if actual.packed_event_decoded_record_count != count {
mismatches.push(format!(
"packed_event_decoded_record_count mismatch: expected {count}, got {}",
actual.packed_event_decoded_record_count
));
}
}
if let Some(count) = self.packed_event_imported_runtime_record_count {
if actual.packed_event_imported_runtime_record_count != count {
mismatches.push(format!(
"packed_event_imported_runtime_record_count mismatch: expected {count}, got {}",
actual.packed_event_imported_runtime_record_count
));
}
}
if let Some(count) = self.packed_event_parity_only_record_count {
if actual.packed_event_parity_only_record_count != count {
mismatches.push(format!(
"packed_event_parity_only_record_count mismatch: expected {count}, got {}",
actual.packed_event_parity_only_record_count
));
}
}
if let Some(count) = self.packed_event_unsupported_record_count {
if actual.packed_event_unsupported_record_count != count {
mismatches.push(format!(
"packed_event_unsupported_record_count mismatch: expected {count}, got {}",
actual.packed_event_unsupported_record_count
));
}
}
if let Some(count) = self.packed_event_blocked_missing_company_context_count {
if actual.packed_event_blocked_missing_company_context_count != count {
mismatches.push(format!(
"packed_event_blocked_missing_company_context_count mismatch: expected {count}, got {}",
actual.packed_event_blocked_missing_company_context_count
));
}
}
if let Some(count) = self.packed_event_blocked_missing_selection_context_count {
if actual.packed_event_blocked_missing_selection_context_count != count {
mismatches.push(format!(
"packed_event_blocked_missing_selection_context_count mismatch: expected {count}, got {}",
actual.packed_event_blocked_missing_selection_context_count
));
}
}
if let Some(count) = self.packed_event_blocked_missing_company_role_context_count {
if actual.packed_event_blocked_missing_company_role_context_count != count {
mismatches.push(format!(
"packed_event_blocked_missing_company_role_context_count mismatch: expected {count}, got {}",
actual.packed_event_blocked_missing_company_role_context_count
));
}
}
if let Some(count) = self.packed_event_blocked_missing_player_context_count {
if actual.packed_event_blocked_missing_player_context_count != count {
mismatches.push(format!(
"packed_event_blocked_missing_player_context_count mismatch: expected {count}, got {}",
actual.packed_event_blocked_missing_player_context_count
));
}
}
if let Some(count) = self.packed_event_blocked_missing_player_selection_context_count {
if actual.packed_event_blocked_missing_player_selection_context_count != count {
mismatches.push(format!(
"packed_event_blocked_missing_player_selection_context_count mismatch: expected {count}, got {}",
actual.packed_event_blocked_missing_player_selection_context_count
));
}
}
if let Some(count) = self.packed_event_blocked_missing_player_role_context_count {
if actual.packed_event_blocked_missing_player_role_context_count != count {
mismatches.push(format!(
"packed_event_blocked_missing_player_role_context_count mismatch: expected {count}, got {}",
actual.packed_event_blocked_missing_player_role_context_count
));
}
}
if let Some(count) = self.packed_event_blocked_missing_chairman_context_count {
if actual.packed_event_blocked_missing_chairman_context_count != count {
mismatches.push(format!(
"packed_event_blocked_missing_chairman_context_count mismatch: expected {count}, got {}",
actual.packed_event_blocked_missing_chairman_context_count
));
}
}
if let Some(count) = self.packed_event_blocked_chairman_target_scope_count {
if actual.packed_event_blocked_chairman_target_scope_count != count {
mismatches.push(format!(
"packed_event_blocked_chairman_target_scope_count mismatch: expected {count}, got {}",
actual.packed_event_blocked_chairman_target_scope_count
));
}
}
if let Some(count) = self.packed_event_blocked_missing_condition_context_count {
if actual.packed_event_blocked_missing_condition_context_count != count {
mismatches.push(format!(
"packed_event_blocked_missing_condition_context_count mismatch: expected {count}, got {}",
actual.packed_event_blocked_missing_condition_context_count
));
}
}
if let Some(count) = self.packed_event_blocked_missing_player_condition_context_count {
if actual.packed_event_blocked_missing_player_condition_context_count != count {
mismatches.push(format!(
"packed_event_blocked_missing_player_condition_context_count mismatch: expected {count}, got {}",
actual.packed_event_blocked_missing_player_condition_context_count
));
}
}
if let Some(count) = self.packed_event_blocked_company_condition_scope_disabled_count {
if actual.packed_event_blocked_company_condition_scope_disabled_count != count {
mismatches.push(format!(
"packed_event_blocked_company_condition_scope_disabled_count mismatch: expected {count}, got {}",
actual.packed_event_blocked_company_condition_scope_disabled_count
));
}
}
if let Some(count) = self.packed_event_blocked_player_condition_scope_count {
if actual.packed_event_blocked_player_condition_scope_count != count {
mismatches.push(format!(
"packed_event_blocked_player_condition_scope_count mismatch: expected {count}, got {}",
actual.packed_event_blocked_player_condition_scope_count
));
}
}
if let Some(count) = self.packed_event_blocked_territory_condition_scope_count {
if actual.packed_event_blocked_territory_condition_scope_count != count {
mismatches.push(format!(
"packed_event_blocked_territory_condition_scope_count mismatch: expected {count}, got {}",
actual.packed_event_blocked_territory_condition_scope_count
));
}
}
if let Some(count) = self.packed_event_blocked_missing_territory_context_count {
if actual.packed_event_blocked_missing_territory_context_count != count {
mismatches.push(format!(
"packed_event_blocked_missing_territory_context_count mismatch: expected {count}, got {}",
actual.packed_event_blocked_missing_territory_context_count
));
}
}
if let Some(count) = self.packed_event_blocked_named_territory_binding_count {
if actual.packed_event_blocked_named_territory_binding_count != count {
mismatches.push(format!(
"packed_event_blocked_named_territory_binding_count mismatch: expected {count}, got {}",
actual.packed_event_blocked_named_territory_binding_count
));
}
}
if let Some(count) = self.packed_event_blocked_unmapped_ordinary_condition_count {
if actual.packed_event_blocked_unmapped_ordinary_condition_count != count {
mismatches.push(format!(
"packed_event_blocked_unmapped_ordinary_condition_count mismatch: expected {count}, got {}",
actual.packed_event_blocked_unmapped_ordinary_condition_count
));
}
}
if let Some(count) = self.packed_event_blocked_unmapped_world_condition_count {
if actual.packed_event_blocked_unmapped_world_condition_count != count {
mismatches.push(format!(
"packed_event_blocked_unmapped_world_condition_count mismatch: expected {count}, got {}",
actual.packed_event_blocked_unmapped_world_condition_count
));
}
}
if let Some(count) = self.packed_event_blocked_missing_compact_control_count {
if actual.packed_event_blocked_missing_compact_control_count != count {
mismatches.push(format!(
"packed_event_blocked_missing_compact_control_count mismatch: expected {count}, got {}",
actual.packed_event_blocked_missing_compact_control_count
));
}
}
if let Some(count) = self.packed_event_blocked_shell_owned_descriptor_count {
if actual.packed_event_blocked_shell_owned_descriptor_count != count {
mismatches.push(format!(
"packed_event_blocked_shell_owned_descriptor_count mismatch: expected {count}, got {}",
actual.packed_event_blocked_shell_owned_descriptor_count
));
}
}
if let Some(count) = self.packed_event_blocked_evidence_blocked_descriptor_count {
if actual.packed_event_blocked_evidence_blocked_descriptor_count != count {
mismatches.push(format!(
"packed_event_blocked_evidence_blocked_descriptor_count mismatch: expected {count}, got {}",
actual.packed_event_blocked_evidence_blocked_descriptor_count
));
}
}
if let Some(count) = self.packed_event_blocked_variant_or_scope_blocked_descriptor_count {
if actual.packed_event_blocked_variant_or_scope_blocked_descriptor_count != count {
mismatches.push(format!(
"packed_event_blocked_variant_or_scope_blocked_descriptor_count mismatch: expected {count}, got {}",
actual.packed_event_blocked_variant_or_scope_blocked_descriptor_count
));
}
}
if let Some(count) = self.packed_event_blocked_unmapped_real_descriptor_count {
if actual.packed_event_blocked_unmapped_real_descriptor_count != count {
mismatches.push(format!(
"packed_event_blocked_unmapped_real_descriptor_count mismatch: expected {count}, got {}",
actual.packed_event_blocked_unmapped_real_descriptor_count
));
}
}
if let Some(count) = self.packed_event_blocked_unmapped_world_descriptor_count {
if actual.packed_event_blocked_unmapped_world_descriptor_count != count {
mismatches.push(format!(
"packed_event_blocked_unmapped_world_descriptor_count mismatch: expected {count}, got {}",
actual.packed_event_blocked_unmapped_world_descriptor_count
));
}
}
if let Some(count) = self.packed_event_blocked_territory_access_variant_count {
if actual.packed_event_blocked_territory_access_variant_count != count {
mismatches.push(format!(
"packed_event_blocked_territory_access_variant_count mismatch: expected {count}, got {}",
actual.packed_event_blocked_territory_access_variant_count
));
}
}
if let Some(count) = self.packed_event_blocked_territory_access_scope_count {
if actual.packed_event_blocked_territory_access_scope_count != count {
mismatches.push(format!(
"packed_event_blocked_territory_access_scope_count mismatch: expected {count}, got {}",
actual.packed_event_blocked_territory_access_scope_count
));
}
}
if let Some(count) = self.packed_event_blocked_missing_train_context_count {
if actual.packed_event_blocked_missing_train_context_count != count {
mismatches.push(format!(
"packed_event_blocked_missing_train_context_count mismatch: expected {count}, got {}",
actual.packed_event_blocked_missing_train_context_count
));
}
}
if let Some(count) = self.packed_event_blocked_missing_train_territory_context_count {
if actual.packed_event_blocked_missing_train_territory_context_count != count {
mismatches.push(format!(
"packed_event_blocked_missing_train_territory_context_count mismatch: expected {count}, got {}",
actual.packed_event_blocked_missing_train_territory_context_count
));
}
}
if let Some(count) = self.packed_event_blocked_missing_locomotive_catalog_context_count {
if actual.packed_event_blocked_missing_locomotive_catalog_context_count != count {
mismatches.push(format!(
"packed_event_blocked_missing_locomotive_catalog_context_count mismatch: expected {count}, got {}",
actual.packed_event_blocked_missing_locomotive_catalog_context_count
));
}
}
if let Some(count) = self.packed_event_blocked_confiscation_variant_count {
if actual.packed_event_blocked_confiscation_variant_count != count {
mismatches.push(format!(
"packed_event_blocked_confiscation_variant_count mismatch: expected {count}, got {}",
actual.packed_event_blocked_confiscation_variant_count
));
}
}
if let Some(count) = self.packed_event_blocked_retire_train_variant_count {
if actual.packed_event_blocked_retire_train_variant_count != count {
mismatches.push(format!(
"packed_event_blocked_retire_train_variant_count mismatch: expected {count}, got {}",
actual.packed_event_blocked_retire_train_variant_count
));
}
}
if let Some(count) = self.packed_event_blocked_retire_train_scope_count {
if actual.packed_event_blocked_retire_train_scope_count != count {
mismatches.push(format!(
"packed_event_blocked_retire_train_scope_count mismatch: expected {count}, got {}",
actual.packed_event_blocked_retire_train_scope_count
));
}
}
if let Some(count) = self.packed_event_blocked_structural_only_count {
if actual.packed_event_blocked_structural_only_count != count {
mismatches.push(format!(
"packed_event_blocked_structural_only_count mismatch: expected {count}, got {}",
actual.packed_event_blocked_structural_only_count
));
}
}
if let Some(count) = self.event_runtime_record_count {
if actual.event_runtime_record_count != count {
mismatches.push(format!(
"event_runtime_record_count mismatch: expected {count}, got {}",
actual.event_runtime_record_count
));
}
}
if let Some(count) = self.candidate_availability_count {
if actual.candidate_availability_count != count {
mismatches.push(format!(
"candidate_availability_count mismatch: expected {count}, got {}",
actual.candidate_availability_count
));
}
}
if let Some(count) = self.zero_candidate_availability_count {
if actual.zero_candidate_availability_count != count {
mismatches.push(format!(
"zero_candidate_availability_count mismatch: expected {count}, got {}",
actual.zero_candidate_availability_count
));
}
}
if let Some(count) = self.named_locomotive_availability_count {
if actual.named_locomotive_availability_count != count {
mismatches.push(format!(
"named_locomotive_availability_count mismatch: expected {count}, got {}",
actual.named_locomotive_availability_count
));
}
}
if let Some(count) = self.zero_named_locomotive_availability_count {
if actual.zero_named_locomotive_availability_count != count {
mismatches.push(format!(
"zero_named_locomotive_availability_count mismatch: expected {count}, got {}",
actual.zero_named_locomotive_availability_count
));
}
}
if let Some(count) = self.named_locomotive_cost_count {
if actual.named_locomotive_cost_count != count {
mismatches.push(format!(
"named_locomotive_cost_count mismatch: expected {count}, got {}",
actual.named_locomotive_cost_count
));
}
}
if let Some(count) = self.cargo_production_override_count {
if actual.cargo_production_override_count != count {
mismatches.push(format!(
"cargo_production_override_count mismatch: expected {count}, got {}",
actual.cargo_production_override_count
));
}
}
if let Some(count) = self.world_runtime_variable_count {
if actual.world_runtime_variable_count != count {
mismatches.push(format!(
"world_runtime_variable_count mismatch: expected {count}, got {}",
actual.world_runtime_variable_count
));
}
}
if let Some(count) = self.company_runtime_variable_owner_count {
if actual.company_runtime_variable_owner_count != count {
mismatches.push(format!(
"company_runtime_variable_owner_count mismatch: expected {count}, got {}",
actual.company_runtime_variable_owner_count
));
}
}
if let Some(count) = self.player_runtime_variable_owner_count {
if actual.player_runtime_variable_owner_count != count {
mismatches.push(format!(
"player_runtime_variable_owner_count mismatch: expected {count}, got {}",
actual.player_runtime_variable_owner_count
));
}
}
if let Some(count) = self.territory_runtime_variable_owner_count {
if actual.territory_runtime_variable_owner_count != count {
mismatches.push(format!(
"territory_runtime_variable_owner_count mismatch: expected {count}, got {}",
actual.territory_runtime_variable_owner_count
));
}
}
if let Some(count) = self.world_scalar_override_count {
if actual.world_scalar_override_count != count {
mismatches.push(format!(
"world_scalar_override_count mismatch: expected {count}, got {}",
actual.world_scalar_override_count
));
}
}
if let Some(count) = self.special_condition_count {
if actual.special_condition_count != count {
mismatches.push(format!(
"special_condition_count mismatch: expected {count}, got {}",
actual.special_condition_count
));
}
}
if let Some(count) = self.enabled_special_condition_count {
if actual.enabled_special_condition_count != count {
mismatches.push(format!(
"enabled_special_condition_count mismatch: expected {count}, got {}",
actual.enabled_special_condition_count
));
}
}
if let Some(kind) = &self.save_profile_kind {
if actual.save_profile_kind.as_ref() != Some(kind) {
mismatches.push(format!(
"save_profile_kind mismatch: expected {kind:?}, got {:?}",
actual.save_profile_kind
));
}
}
if let Some(family) = &self.save_profile_family {
if actual.save_profile_family.as_ref() != Some(family) {
mismatches.push(format!(
"save_profile_family mismatch: expected {family:?}, got {:?}",
actual.save_profile_family
));
}
}
if let Some(map_path) = &self.save_profile_map_path {
if actual.save_profile_map_path.as_ref() != Some(map_path) {
mismatches.push(format!(
"save_profile_map_path mismatch: expected {map_path:?}, got {:?}",
actual.save_profile_map_path
));
}
}
if let Some(display_name) = &self.save_profile_display_name {
if actual.save_profile_display_name.as_ref() != Some(display_name) {
mismatches.push(format!(
"save_profile_display_name mismatch: expected {display_name:?}, got {:?}",
actual.save_profile_display_name
));
}
}
if let Some(lane) = self.save_profile_selected_year_profile_lane {
if actual.save_profile_selected_year_profile_lane != Some(lane) {
mismatches.push(format!(
"save_profile_selected_year_profile_lane mismatch: expected {lane}, got {:?}",
actual.save_profile_selected_year_profile_lane
));
}
}
if let Some(enabled) = self.save_profile_sandbox_enabled {
if actual.save_profile_sandbox_enabled != Some(enabled) {
mismatches.push(format!(
"save_profile_sandbox_enabled mismatch: expected {enabled}, got {:?}",
actual.save_profile_sandbox_enabled
));
}
}
if let Some(enabled) = self.save_profile_campaign_scenario_enabled {
if actual.save_profile_campaign_scenario_enabled != Some(enabled) {
mismatches.push(format!(
"save_profile_campaign_scenario_enabled mismatch: expected {enabled}, got {:?}",
actual.save_profile_campaign_scenario_enabled
));
}
}
if let Some(enabled) = self.save_profile_staged_profile_copy_on_restore {
if actual.save_profile_staged_profile_copy_on_restore != Some(enabled) {
mismatches.push(format!(
"save_profile_staged_profile_copy_on_restore mismatch: expected {enabled}, got {:?}",
actual.save_profile_staged_profile_copy_on_restore
));
}
}
if let Some(count) = self.total_event_record_service_count {
if actual.total_event_record_service_count != count {
mismatches.push(format!(
"total_event_record_service_count mismatch: expected {count}, got {}",
actual.total_event_record_service_count
));
}
}
if let Some(count) = self.periodic_boundary_call_count {
if actual.periodic_boundary_call_count != count {
mismatches.push(format!(
"periodic_boundary_call_count mismatch: expected {count}, got {}",
actual.periodic_boundary_call_count
));
}
}
if let Some(count) = self.total_trigger_dispatch_count {
if actual.total_trigger_dispatch_count != count {
mismatches.push(format!(
"total_trigger_dispatch_count mismatch: expected {count}, got {}",
actual.total_trigger_dispatch_count
));
}
}
if let Some(count) = self.dirty_rerun_count {
if actual.dirty_rerun_count != count {
mismatches.push(format!(
"dirty_rerun_count mismatch: expected {count}, got {}",
actual.dirty_rerun_count
));
}
}
if let Some(total) = self.total_company_cash {
if actual.total_company_cash != total {
mismatches.push(format!(
"total_company_cash mismatch: expected {total}, got {}",
actual.total_company_cash
));
}
}
mismatches
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct FixtureDocument {
pub format_version: u32,
pub fixture_id: String,
#[serde(default)]
pub source: FixtureSource,
pub state: RuntimeState,
pub state_origin: FixtureStateOrigin,
#[serde(default)]
pub commands: Vec<StepCommand>,
#[serde(default)]
pub expected_summary: ExpectedRuntimeSummary,
#[serde(default)]
pub expected_state_fragment: Option<Value>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum FixtureStateOrigin {
Inline,
SnapshotPath(String),
SaveSlicePath(String),
ImportPath(String),
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct RawFixtureDocument {
pub format_version: u32,
pub fixture_id: String,
#[serde(default)]
pub source: FixtureSource,
#[serde(default)]
pub state: Option<RuntimeState>,
#[serde(default)]
pub state_snapshot_path: Option<String>,
#[serde(default)]
pub state_save_slice_path: Option<String>,
#[serde(default)]
pub state_import_path: Option<String>,
#[serde(default)]
pub commands: Vec<StepCommand>,
#[serde(default)]
pub expected_summary: ExpectedRuntimeSummary,
#[serde(default)]
pub expected_state_fragment: Option<Value>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct FixtureValidationReport {
pub fixture_id: String,
pub valid: bool,
pub issue_count: usize,
pub issues: Vec<String>,
}
pub fn compare_expected_state_fragment(expected: &Value, actual: &Value) -> Vec<String> {
let mut mismatches = Vec::new();
compare_expected_state_fragment_at_path("$", expected, actual, &mut mismatches);
mismatches
}
fn compare_expected_state_fragment_at_path(
path: &str,
expected: &Value,
actual: &Value,
mismatches: &mut Vec<String>,
) {
match (expected, actual) {
(Value::Object(expected_map), Value::Object(actual_map)) => {
for (key, expected_value) in expected_map {
let next_path = format!("{path}.{key}");
match actual_map.get(key) {
Some(actual_value) => compare_expected_state_fragment_at_path(
&next_path,
expected_value,
actual_value,
mismatches,
),
None => mismatches.push(format!("{next_path} missing in actual state")),
}
}
}
(Value::Array(expected_items), Value::Array(actual_items)) => {
for (index, expected_item) in expected_items.iter().enumerate() {
let next_path = format!("{path}[{index}]");
match actual_items.get(index) {
Some(actual_item) => compare_expected_state_fragment_at_path(
&next_path,
expected_item,
actual_item,
mismatches,
),
None => mismatches.push(format!("{next_path} missing in actual state")),
}
}
}
_ if expected != actual => mismatches.push(format!(
"{path} mismatch: expected {expected:?}, got {actual:?}"
)),
_ => {}
}
}
pub fn validate_fixture_document(document: &FixtureDocument) -> FixtureValidationReport {
let mut issues = Vec::new();
if document.format_version != FIXTURE_FORMAT_VERSION {
issues.push(format!(
"unsupported format_version {} (expected {})",
document.format_version, FIXTURE_FORMAT_VERSION
));
}
if document.fixture_id.trim().is_empty() {
issues.push("fixture_id must not be empty".to_string());
}
if document.source.kind.trim().is_empty() {
issues.push("source.kind must not be empty".to_string());
}
if document.commands.is_empty() {
issues.push("fixture must contain at least one command".to_string());
}
if let Err(err) = document.state.validate() {
issues.push(format!("invalid runtime state: {err}"));
}
for (index, command) in document.commands.iter().enumerate() {
if let Err(err) = command.validate() {
issues.push(format!("invalid command at index {index}: {err}"));
}
}
FixtureValidationReport {
fixture_id: document.fixture_id.clone(),
valid: issues.is_empty(),
issue_count: issues.len(),
issues,
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::load_fixture_document_from_str;
const FIXTURE_JSON: &str = r#"
{
"format_version": 1,
"fixture_id": "minimal-world-step-smoke",
"source": {
"kind": "synthetic",
"description": "basic milestone parser smoke fixture"
},
"state": {
"calendar": {
"year": 1830,
"month_slot": 0,
"phase_slot": 0,
"tick_slot": 0
},
"world_flags": {
"sandbox": false
},
"companies": [
{
"company_id": 1,
"current_cash": 250000,
"debt": 0
}
],
"event_runtime_records": [],
"service_state": {
"periodic_boundary_calls": 0,
"trigger_dispatch_counts": {},
"total_event_record_services": 0,
"dirty_rerun_count": 0
}
},
"commands": [
{
"kind": "advance_to",
"calendar": {
"year": 1830,
"month_slot": 0,
"phase_slot": 0,
"tick_slot": 2
}
}
],
"expected_summary": {
"calendar": {
"year": 1830,
"month_slot": 0,
"phase_slot": 0,
"tick_slot": 2
},
"world_flag_count": 1,
"company_count": 1,
"event_runtime_record_count": 0,
"world_restore_economic_tuning_lane_count": 0,
"total_company_cash": 250000
}
}
"#;
#[test]
fn parses_and_validates_fixture() {
let fixture = load_fixture_document_from_str(FIXTURE_JSON).expect("fixture should parse");
let report = validate_fixture_document(&fixture);
assert!(report.valid, "report should be valid: {:?}", report.issues);
assert_eq!(fixture.state_origin, FixtureStateOrigin::Inline);
}
#[test]
fn compares_expected_summary() {
let fixture = load_fixture_document_from_str(FIXTURE_JSON).expect("fixture should parse");
let summary = RuntimeSummary::from_state(&fixture.state);
let mismatches = fixture.expected_summary.compare(&summary);
assert_eq!(mismatches.len(), 1);
assert!(mismatches[0].contains("calendar mismatch"));
}
#[test]
fn compares_expected_state_fragment_recursively() {
let expected = serde_json::json!({
"world_flags": {
"sandbox": false
},
"companies": [
{
"company_id": 1
}
]
});
let actual = serde_json::json!({
"world_flags": {
"sandbox": false,
"runtime.effect_fired": true
},
"companies": [
{
"company_id": 1,
"current_cash": 250000
}
]
});
let mismatches = compare_expected_state_fragment(&expected, &actual);
assert!(
mismatches.is_empty(),
"unexpected mismatches: {mismatches:?}"
);
}
}