use std::collections::HashSet;
use epics_base_rs::server::database::PvDatabase;
use epics_base_rs::server::record::Record;
use epics_base_rs::server::records::ao::AoRecord;
use epics_base_rs::server::records::histogram::HistogramRecord;
use epics_base_rs::server::records::waveform::WaveformRecord;
use epics_base_rs::types::{DbFieldType, EpicsValue};
#[epics_macros_rs::epics_test]
async fn sim_waveform_reads_siol_array_into_val() {
let db = PvDatabase::new();
db.add_record("WFIN_SW", Box::new(AoRecord::new(1.0)))
.await
.unwrap();
let mut src = WaveformRecord::new(8, DbFieldType::Double);
let _ = src.put_field("VAL", EpicsValue::DoubleArray(vec![10.0, 20.0, 30.0]));
db.add_record("WFIN_SRC", Box::new(src)).await.unwrap();
let mut wf = WaveformRecord::new(8, DbFieldType::Double);
wf.siml = "WFIN_SW".to_string();
wf.siol = "WFIN_SRC".to_string();
db.add_record("WFIN", Box::new(wf)).await.unwrap();
let mut v = HashSet::new();
db.process_record_with_links("WFIN", &mut v, 0)
.await
.unwrap();
let val = db.get_pv("WFIN").unwrap();
assert!(
matches!(val, EpicsValue::DoubleArray(ref a) if a.as_slice() == [10.0, 20.0, 30.0]),
"simulated waveform read the SIOL array INTO VAL, got {val:?}"
);
let src = db.get_pv("WFIN_SRC").unwrap();
assert!(
matches!(src, EpicsValue::DoubleArray(ref a) if a.as_slice() == [10.0, 20.0, 30.0]),
"SIOL source untouched (input direction, not VAL->SIOL write), got {src:?}"
);
}
#[epics_macros_rs::epics_test]
async fn sim_histogram_lands_siol_in_sgnl_and_bins_it() {
let db = PvDatabase::new();
db.add_record("HGIN_SW", Box::new(AoRecord::new(1.0)))
.await
.unwrap();
db.add_record("HGIN_SRC", Box::new(AoRecord::new(42.0)))
.await
.unwrap();
let mut hg = HistogramRecord::new(4, 0.0, 100.0);
hg.siml = "HGIN_SW".to_string();
hg.siol = "HGIN_SRC".to_string();
db.add_record("HGIN", Box::new(hg)).await.unwrap();
let mut v = HashSet::new();
db.process_record_with_links("HGIN", &mut v, 0)
.await
.unwrap();
let src = db.get_pv("HGIN_SRC").unwrap();
assert!(
matches!(src, EpicsValue::Double(v) if (v - 42.0).abs() < 1e-10),
"simulated histogram did NOT write VAL out to SIOL (input direction), got {src:?}"
);
assert_eq!(db.get_pv("HGIN.SVAL").unwrap(), EpicsValue::Double(42.0));
assert_eq!(
db.get_pv("HGIN.SGNL").unwrap(),
EpicsValue::Double(42.0),
"C `prec->sgnl = prec->sval` (histogramRecord.c:385)"
);
let val = db.get_pv("HGIN").unwrap();
assert!(
matches!(val, EpicsValue::ULongArray(ref a) if a.as_slice() == [0, 1, 0, 0]),
"the simulated signal is binned exactly once, got {val:?}"
);
}
#[epics_macros_rs::epics_test]
async fn sim_histogram_with_a_failed_siol_read_bins_nothing() {
let db = PvDatabase::new();
db.add_record("HGF_SW", Box::new(AoRecord::new(1.0)))
.await
.unwrap();
let mut hg = HistogramRecord::new(4, 0.0, 100.0);
hg.siml = "HGF_SW".to_string();
hg.siol = "NO:SUCH:RECORD".to_string();
hg.sval = 42.0; db.add_record("HGF", Box::new(hg)).await.unwrap();
let mut v = HashSet::new();
db.process_record_with_links("HGF", &mut v, 0)
.await
.unwrap();
assert_eq!(
db.get_pv("HGF.SGNL").unwrap(),
EpicsValue::Double(0.0),
"C gates `prec->sgnl = prec->sval` on status == 0 — a failed read assigns nothing"
);
let val = db.get_pv("HGF").unwrap();
assert!(
matches!(val, EpicsValue::ULongArray(ref a) if a.as_slice() == [0, 0, 0, 0]),
"add_count is gated on the same status == 0, got {val:?}"
);
}