Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More validation #180

Merged
merged 5 commits into from
Nov 8, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 94 additions & 9 deletions src/process.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::input::*;
use crate::region::*;
use crate::time_slice::{TimeSliceInfo, TimeSliceSelection};
use ::log::warn;
use serde::{Deserialize, Deserializer};
use serde_string_enum::{DeserializeLabeledStringEnum, SerializeLabeledStringEnum};
use std::collections::{HashMap, HashSet};
Expand Down Expand Up @@ -117,6 +118,8 @@
))?;
}

self.validate()?;

Ok(ProcessParameter {
process_id: self.process_id,
years: start_year..=end_year,
Expand All @@ -130,6 +133,57 @@
}
}

impl ProcessParameterRaw {
/// Validates the `ProcessParameterRaw` instance.
///
/// # Errors
///
/// Returns an error if:
/// - `lifetime` is 0.
/// - `discount_rate` is present and less than 0.0.
/// - `cap2act` is present and less than 0.0.
///
/// # Warnings
///
/// Logs a warning if:
/// - `discount_rate` is present and greater than 1.0.
///
/// # Returns
///
/// Returns `Ok(())` if all validations pass.
fn validate(&self) -> Result<(), Box<dyn Error>> {
if self.lifetime == 0 {
Err(format!(
"Error in parameter for process {}: Lifetime must be greater than 0",
self.process_id
))?;
}
if let Some(dr) = self.discount_rate {
if dr < 0.0 {
Err(format!(

Check warning on line 163 in src/process.rs

View check run for this annotation

Codecov / codecov/patch

src/process.rs#L163

Added line #L163 was not covered by tests
"Error in parameter for process {}: Discount rate must be positive",
self.process_id
))?;
}
if dr > 1.0 {
warn!(

Check warning on line 169 in src/process.rs

View check run for this annotation

Codecov / codecov/patch

src/process.rs#L169

Added line #L169 was not covered by tests
"Warning in parameter for process {}: Discount rate is greater than 1",
self.process_id
);
}
}
if let Some(c2a) = self.cap2act {
if c2a < 0.0 {
Err(format!(

Check warning on line 177 in src/process.rs

View check run for this annotation

Codecov / codecov/patch

src/process.rs#L177

Added line #L177 was not covered by tests
"Error in parameter for process {}: Cap2act must be positive",
self.process_id
))?;
}
}
Ok(())
}
}

#[derive(PartialEq, Debug, Deserialize)]
pub struct ProcessParameter {
pub process_id: String,
Expand Down Expand Up @@ -325,6 +379,7 @@
fn create_param_raw(
start_year: Option<u32>,
end_year: Option<u32>,
lifetime: u32,
discount_rate: Option<f64>,
cap2act: Option<f64>,
) -> ProcessParameterRaw {
Expand All @@ -335,7 +390,7 @@
capital_cost: 0.0,
fixed_operating_cost: 0.0,
variable_operating_cost: 0.0,
lifetime: 1,
lifetime,
discount_rate,
cap2act,
}
Expand Down Expand Up @@ -363,28 +418,28 @@
let year_range = 2000..=2100;

// No missing values
let raw = create_param_raw(Some(2010), Some(2020), Some(1.0), Some(0.0));
let raw = create_param_raw(Some(2010), Some(2020), 1, Some(1.0), Some(0.0));
assert_eq!(
raw.into_parameter(&year_range).unwrap(),
create_param(2010..=2020, 1.0, 0.0)
);

// Missing years
let raw = create_param_raw(None, None, Some(1.0), Some(0.0));
let raw = create_param_raw(None, None, 1, Some(1.0), Some(0.0));
assert_eq!(
raw.into_parameter(&year_range).unwrap(),
create_param(2000..=2100, 1.0, 0.0)
);

// Missing discount_rate
let raw = create_param_raw(Some(2010), Some(2020), None, Some(0.0));
let raw = create_param_raw(Some(2010), Some(2020), 1, None, Some(0.0));
assert_eq!(
raw.into_parameter(&year_range).unwrap(),
create_param(2010..=2020, 0.0, 0.0)
);

// Missing cap2act
let raw = create_param_raw(Some(2010), Some(2020), Some(1.0), None);
let raw = create_param_raw(Some(2010), Some(2020), 1, Some(1.0), None);
assert_eq!(
raw.into_parameter(&year_range).unwrap(),
create_param(2010..=2020, 1.0, 1.0)
Expand All @@ -397,21 +452,21 @@

// Normal case
assert!(
create_param_raw(Some(2000), Some(2100), Some(1.0), Some(0.0))
create_param_raw(Some(2000), Some(2100), 1, Some(1.0), Some(0.0))
.into_parameter(&year_range)
.is_ok()
);

// start_year out of range - this is permitted
assert!(
create_param_raw(Some(1999), Some(2100), Some(1.0), Some(0.0))
create_param_raw(Some(1999), Some(2100), 1, Some(1.0), Some(0.0))
.into_parameter(&year_range)
.is_ok()
);

// end_year out of range - this is permitted
assert!(
create_param_raw(Some(2000), Some(2101), Some(1.0), Some(0.0))
create_param_raw(Some(2000), Some(2101), 1, Some(1.0), Some(0.0))
.into_parameter(&year_range)
.is_ok()
);
Expand All @@ -424,12 +479,42 @@

// start_year after end_year
assert!(
create_param_raw(Some(2001), Some(2000), Some(1.0), Some(0.0))
create_param_raw(Some(2001), Some(2000), 1, Some(1.0), Some(0.0))
.into_parameter(&year_range)
.is_ok()
);
}

#[test]
fn test_param_raw_validate_bad_lifetime() {
// lifetime = 0
assert!(
create_param_raw(Some(2000), Some(2100), 0, Some(1.0), Some(0.0))
.validate()
.is_err()
);
}

#[test]
fn test_param_raw_validate_bad_discount_rate() {
// discount rate = -1
assert!(
create_param_raw(Some(2000), Some(2100), 0, Some(-1.0), Some(0.0))
.validate()
.is_err()
);
}

#[test]
fn test_param_raw_validate_bad_capt2act() {
// capt2act = -1
assert!(
create_param_raw(Some(2000), Some(2100), 0, Some(1.0), Some(-1.0))
.validate()
.is_err()
);
}

#[test]
fn test_read_process_parameters_from_iter_good() {
let year_range = 2000..=2100;
Expand Down