use rs_teststand_sys::{Dispatch, Value};
use crate::Error;
use crate::dispids::property_object_file;
use crate::types::TypeUsageList;
#[derive(Debug)]
pub struct PropertyObjectFile {
dispatch: Box<dyn Dispatch>,
}
impl PropertyObjectFile {
pub(crate) fn new(dispatch: Box<dyn Dispatch>) -> Self {
Self { dispatch }
}
pub fn save_file_if_modified(&self, prompt: bool) -> Result<bool, Error> {
Ok(self
.dispatch
.call(
property_object_file::SAVE_FILE_IF_MODIFIED,
&[Value::Bool(prompt)],
)?
.as_bool()?)
}
pub fn type_usage_list(&self) -> Result<TypeUsageList, Error> {
Ok(TypeUsageList::new(
self.dispatch
.get(property_object_file::TYPE_USAGE_LIST)?
.into_object()?,
))
}
pub fn inc_change_count(&self) -> Result<(), Error> {
self.dispatch
.call(property_object_file::INC_CHANGE_COUNT, &[])?;
Ok(())
}
pub fn change_count(&self) -> Result<i32, Error> {
Ok(self
.dispatch
.get(property_object_file::CHANGE_COUNT)?
.as_i32()?)
}
pub fn set_change_count(&self, count: i32) -> Result<(), Error> {
self.dispatch
.put(property_object_file::CHANGE_COUNT, Value::I32(count))?;
Ok(())
}
pub fn is_modified(&self) -> Result<bool, Error> {
Ok(self
.dispatch
.get(property_object_file::IS_MODIFIED)?
.as_bool()?)
}
pub fn data(&self) -> Result<crate::property::PropertyObject, Error> {
Ok(crate::property::PropertyObject::new(
self.dispatch
.get(property_object_file::DATA)?
.into_object()?,
))
}
pub fn path(&self) -> Result<String, Error> {
Ok(self
.dispatch
.get(property_object_file::PATH)?
.into_string()?)
}
pub fn set_path(&self, path: &str) -> Result<(), Error> {
self.dispatch
.put(property_object_file::PATH, Value::Str(path.to_owned()))?;
Ok(())
}
pub fn is_disk_file_modified(&self) -> Result<i32, Error> {
Ok(self
.dispatch
.get(property_object_file::IS_DISK_FILE_MODIFIED)?
.as_i32()?)
}
pub fn is_disk_file_read_only(&self) -> Result<bool, Error> {
Ok(self
.dispatch
.get(property_object_file::IS_DISK_FILE_READ_ONLY)?
.as_bool()?)
}
pub fn version(&self) -> Result<String, Error> {
Ok(self
.dispatch
.get(property_object_file::VERSION)?
.into_string()?)
}
pub fn set_version(&self, version: &str) -> Result<(), Error> {
self.dispatch.put(
property_object_file::VERSION,
Value::Str(version.to_owned()),
)?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::PropertyObjectFile;
use crate::Error;
use crate::dispids::property_object_file;
use rs_teststand_sys::{ComError, Dispatch, Value};
use std::collections::HashMap;
#[derive(Debug)]
struct FakeDispatch {
reads: HashMap<i32, Value>,
}
impl Dispatch for FakeDispatch {
fn get(&self, dispid: i32) -> Result<Value, ComError> {
match self.reads.get(&dispid) {
Some(Value::I32(value)) => Ok(Value::I32(*value)),
Some(Value::Bool(value)) => Ok(Value::Bool(*value)),
Some(Value::Str(value)) => Ok(Value::Str(value.clone())),
_ => Err(ComError::hresult(0, "fake: unscripted property")),
}
}
fn put(&self, _dispid: i32, _value: Value) -> Result<(), ComError> {
Ok(())
}
fn call(&self, _dispid: i32, _args: &[Value]) -> Result<Value, ComError> {
Err(ComError::hresult(0, "fake: unscripted method"))
}
}
fn file(reads: Vec<(i32, Value)>) -> PropertyObjectFile {
PropertyObjectFile::new(Box::new(FakeDispatch {
reads: reads.into_iter().collect(),
}))
}
#[test]
fn file_state_reads_use_their_typed_dispatch_properties() -> Result<(), Error> {
let subject = file(vec![
(property_object_file::CHANGE_COUNT, Value::I32(4)),
(property_object_file::IS_MODIFIED, Value::Bool(true)),
(property_object_file::IS_DISK_FILE_MODIFIED, Value::I32(-1)),
(
property_object_file::IS_DISK_FILE_READ_ONLY,
Value::Bool(false),
),
(
property_object_file::VERSION,
Value::Str("1.2.3.4".to_owned()),
),
]);
assert_eq!(subject.change_count()?, 4);
assert!(subject.is_modified()?);
assert_eq!(subject.is_disk_file_modified()?, -1);
assert!(!subject.is_disk_file_read_only()?);
assert_eq!(subject.version()?, "1.2.3.4");
Ok(())
}
#[test]
fn file_state_writes_accept_typed_values() -> Result<(), Error> {
let subject = file(Vec::new());
subject.set_change_count(9)?;
subject.set_version("2.0.0.0")?;
Ok(())
}
}