use super::*;
use crate::crinex;
fn esbc_rnx() -> String {
let path = concat!(
env!("CARGO_MANIFEST_DIR"),
"/tests/fixtures/obs/ESBC00DNK_R_20201770000_01D_30S_MO_trim.rnx"
);
std::fs::read_to_string(path).unwrap_or_else(|e| panic!("read RINEX fixture {path}: {e}"))
}
fn esbc_crx() -> String {
let path = concat!(
env!("CARGO_MANIFEST_DIR"),
"/tests/fixtures/obs/ESBC00DNK_R_20201770000_01D_30S_MO_trim.crx"
);
std::fs::read_to_string(path).unwrap_or_else(|e| panic!("read CRINEX fixture {path}: {e}"))
}
#[test]
fn parses_header_fields() {
let obs = RinexObs::parse(&esbc_rnx()).expect("parse RINEX OBS");
let h = obs.header();
assert!((h.version - 3.05).abs() < 1e-9);
let pos = h.approx_position_m.expect("approx position present");
assert!((pos[0] - 3582105.2910).abs() < 1e-3);
assert!((pos[1] - 532589.7313).abs() < 1e-3);
assert!((pos[2] - 5232754.8054).abs() < 1e-3);
let delta = h.antenna_delta_hen_m.expect("antenna delta H/E/N present");
assert!((delta[0] - 0.2160).abs() < 1e-9);
assert_eq!(delta[1], 0.0);
assert_eq!(delta[2], 0.0);
assert_eq!(h.marker_name.as_deref(), Some("ESBC00DNK"));
assert_eq!(h.interval_s, Some(30.0));
let (t0, scale) = h.time_of_first_obs.expect("time of first obs");
assert_eq!(t0.year, 2020);
assert_eq!(t0.month, 6);
assert_eq!(t0.day, 25);
assert_eq!(scale, TimeScale::Gpst);
}
#[test]
fn parses_per_system_obs_codes_in_order() {
let obs = RinexObs::parse(&esbc_rnx()).expect("parse RINEX OBS");
let gps = obs.obs_codes(GnssSystem::Gps).expect("GPS codes");
assert_eq!(gps.len(), 18);
assert_eq!(gps[0], "C1C");
let bds = obs.obs_codes(GnssSystem::BeiDou).expect("BeiDou codes");
assert_eq!(bds.len(), 12);
assert_eq!(bds[0], "C2I");
let gal = obs.obs_codes(GnssSystem::Galileo).expect("Galileo codes");
assert_eq!(gal.len(), 20);
assert_eq!(gal[0], "C1C");
}
#[test]
fn parses_two_epochs_with_satellites() {
let obs = RinexObs::parse(&esbc_rnx()).expect("parse RINEX OBS");
assert_eq!(obs.epochs().len(), 2);
let e0 = &obs.epochs()[0];
assert_eq!(e0.flag, 0);
assert_eq!(e0.sats.len(), 43);
let g02 = GnssSatelliteId::new(GnssSystem::Gps, 2);
let g02_vals = e0.sats.get(&g02).expect("G02 present");
assert!(g02_vals[0].value.unwrap() > 2.0e7);
}
#[test]
fn pseudoranges_select_default_gps_code() {
let obs = RinexObs::parse(&esbc_rnx()).expect("parse RINEX OBS");
let policy = SignalPolicy::default_for(obs.header().version);
let prs = pseudoranges(&obs, &obs.epochs()[0], &policy);
assert!(!prs.is_empty());
for (sat, range_m) in &prs {
assert!(
*range_m > 1.9e7 && *range_m < 4.3e7,
"{sat} range {range_m}"
);
}
let gps_only = SignalPolicy {
codes: [(GnssSystem::Gps, vec!["C1C".to_string()])]
.into_iter()
.collect(),
};
let gps_prs = pseudoranges(&obs, &obs.epochs()[0], &gps_only);
assert!(gps_prs.iter().all(|(s, _)| s.system == GnssSystem::Gps));
assert!(gps_prs.len() >= 8);
}
#[test]
fn beidou_default_is_version_aware() {
let v301 = SignalPolicy::default_for(3.01);
assert_eq!(v301.codes[&GnssSystem::BeiDou][0], "C2I");
let v302 = SignalPolicy::default_for(3.02);
assert_eq!(v302.codes[&GnssSystem::BeiDou][0], "C1I");
let v303 = SignalPolicy::default_for(3.03);
assert_eq!(v303.codes[&GnssSystem::BeiDou][0], "C2I");
let v305 = SignalPolicy::default_for(3.05);
assert_eq!(v305.codes[&GnssSystem::BeiDou][0], "C2I");
}
#[test]
fn parses_crinex_decoded_text_identically() {
let decoded = crinex::decode(&esbc_crx()).expect("decode CRINEX");
let from_crx = RinexObs::parse(&decoded).expect("parse decoded");
let from_rnx = RinexObs::parse(&esbc_rnx()).expect("parse reference");
assert_eq!(from_crx, from_rnx);
}
#[test]
fn rejects_non_observation_file() {
let nav = " 3.05 N: GNSS NAV DATA M (MIXED) RINEX VERSION / TYPE\n";
assert!(RinexObs::parse(nav).is_err());
}
#[test]
fn rejects_non_v3_observation_file() {
let v2 = " 2.11 OBSERVATION DATA M (MIXED) RINEX VERSION / TYPE\n";
assert!(RinexObs::parse(v2).is_err());
}