use super::*;
#[test]
fn civil_frames_match_independent_calendar_vectors() {
for (hundredths, year, month, day, weekday) in [
(-220_898_880_000, 0, 1, 1, 1), (0, 70, 1, 1, 4), (501_120_000, 70, 2, 28, 6),
(509_760_000, 70, 3, 1, 7),
(94_659_840_000, 99, 12, 31, 5),
(94_668_480_000, 100, 1, 1, 6),
(95_178_240_000, 100, 2, 29, 2), (95_186_880_000, 100, 3, 1, 3),
(410_745_600_000, 200, 2, 28, 7),
(410_754_240_000, 200, 3, 1, 1), (583_796_160_000, 254, 12, 31, 2),
] {
let frame = frame_from_utc_hundredths(hundredths, ClockConfig::default()).unwrap();
assert_eq!(
frame.local_date,
Date {
year,
month,
day,
day_of_week: weekday
}
);
assert_eq!(
frame.local_time,
Time {
hour: 0,
minute: 0,
second: 0,
hundredths: 0
}
);
assert!(frame.is_valid_actual_datetime());
}
}
#[test]
fn civil_frames_enforce_concrete_year_limits_after_local_adjustment() {
const FIRST: i128 = -220_898_880_000;
const AFTER_LAST: i128 = 583_804_800_000;
assert!(frame_from_utc_hundredths(FIRST - 1, ClockConfig::default()).is_none());
assert!(frame_from_utc_hundredths(AFTER_LAST, ClockConfig::default()).is_none());
let last = frame_from_utc_hundredths(AFTER_LAST - 1, ClockConfig::default()).unwrap();
assert_eq!(
last.local_date,
Date {
year: 254,
month: 12,
day: 31,
day_of_week: 2
}
);
assert_eq!(
last.local_time,
Time {
hour: 23,
minute: 59,
second: 59,
hundredths: 99
}
);
assert!(frame_from_utc_hundredths(FIRST, ClockConfig::new(60, false).unwrap()).is_none());
assert!(
frame_from_utc_hundredths(AFTER_LAST - 1, ClockConfig::new(0, true).unwrap()).is_none()
);
let repaired = frame_from_utc_hundredths(FIRST, ClockConfig::new(60, true).unwrap()).unwrap();
assert_eq!(repaired.local_date.year, 0);
assert!(repaired.is_valid_actual_datetime());
}
#[tokio::test]
async fn ordinary_trend_poll_uses_synchronized_offset_and_dst_frame() {
use bacnet_objects::analog::AnalogValueObject;
use bacnet_objects::traits::BACnetObject;
use bacnet_objects::trend::TrendLogObject;
use bacnet_types::constructed::BACnetDeviceObjectPropertyReference;
use bacnet_types::enums::EngineeringUnits;
use bacnet_types::enums::PropertyIdentifier;
use bacnet_types::primitives::PropertyValue;
use std::sync::Arc;
struct CapturingClock {
clock: ServerClock,
captured: Mutex<Option<ClockFrame>>,
}
impl ClockReader for CapturingClock {
fn read_clock(&self) -> Option<ClockFrame> {
let frame = self.clock.read_clock();
*self.captured.lock().unwrap() = frame;
frame
}
}
let clock = Arc::new(CapturingClock {
clock: ServerClock::new(ClockConfig::new(300, true).unwrap()),
captured: Mutex::new(None),
});
clock
.clock
.synchronize(
Date {
year: 124,
month: 7,
day: 4,
day_of_week: 4,
},
Time {
hour: 13,
minute: 15,
second: 0,
hundredths: 47,
},
true,
)
.unwrap();
let mut db = ObjectDatabase::new();
let target = AnalogValueObject::new(1, "AV", EngineeringUnits::NO_UNITS).unwrap();
let mut trend = TrendLogObject::new(1, "Trend", 8).unwrap();
trend
.set_log_device_object_property(Some(BACnetDeviceObjectPropertyReference {
object_identifier: target.object_identifier(),
property_identifier: PropertyIdentifier::PRESENT_VALUE.to_raw(),
property_array_index: None,
device_identifier: None,
}))
.unwrap();
trend
.write_property(
PropertyIdentifier::LOG_INTERVAL,
None,
PropertyValue::Unsigned(60),
None,
)
.unwrap();
let oid = trend.object_identifier();
db.add(Box::new(target)).unwrap();
db.add(Box::new(trend)).unwrap();
db.set_clock_reader(Some(clock.clone()));
db.set_monotonic_clock_internal(Some(Arc::new(|| Duration::ZERO)));
let db = Arc::new(tokio::sync::RwLock::new(db));
crate::trend_log::poll_trend_logs(&db).await;
let frame = clock.captured.lock().unwrap().unwrap();
assert_eq!(
frame.local_date,
Date {
year: 124,
month: 7,
day: 4,
day_of_week: 4
}
);
assert_eq!((frame.local_time.hour, frame.local_time.minute), (9, 15));
assert_eq!(
(frame.utc_offset, frame.daylight_savings_status),
(300, true)
);
let guard = db.read().await;
let identities = guard
.get(&oid)
.unwrap()
.log_record_identities_internal()
.unwrap();
assert_eq!(identities.len(), 1);
assert_eq!(identities[0].date(), frame.local_date);
assert_eq!(identities[0].time(), frame.local_time);
}