@@ -8,6 +8,7 @@ use crate::asset::{Asset, AssetPool, AssetRef};
88use crate :: commodity:: {
99 Commodity , CommodityID , CommodityLevyMap , CommodityType , DemandMap , PricingStrategy ,
1010} ;
11+ use crate :: patch:: { FilePatch , ModelPatch } ;
1112use crate :: process:: {
1213 ActivityLimits , Process , ProcessActivityLimitsMap , ProcessFlow , ProcessFlowsMap ,
1314 ProcessInvestmentConstraintsMap , ProcessMap , ProcessParameter , ProcessParameterMap ,
@@ -21,6 +22,7 @@ use crate::units::{
2122 Activity , ActivityPerCapacity , Capacity , Dimensionless , Flow , MoneyPerActivity ,
2223 MoneyPerCapacity , MoneyPerCapacityPerYear , MoneyPerFlow , Year ,
2324} ;
25+ use anyhow:: Result ;
2426use indexmap:: indexmap;
2527use indexmap:: { IndexMap , IndexSet } ;
2628use itertools:: Itertools ;
@@ -40,6 +42,44 @@ macro_rules! assert_error {
4042}
4143pub ( crate ) use assert_error;
4244
45+ /// Build a patched copy of `examples/simple` to a temporary directory and return the `TempDir`.
46+ ///
47+ /// If the patched model cannot be built, for whatever reason, this function will panic.
48+ pub ( crate ) fn build_patched_simple_tempdir ( file_patches : Vec < FilePatch > ) -> tempfile:: TempDir {
49+ ModelPatch :: from_example ( "simple" )
50+ . with_file_patches ( file_patches)
51+ . build_to_tempdir ( )
52+ . unwrap ( )
53+ }
54+
55+ /// Check whether the simple example passes or fails validation after applying file patches
56+ macro_rules! patch_and_validate_simple {
57+ ( $file_patches: expr) => { {
58+ ( || -> Result <( ) > {
59+ let tmp = crate :: fixture:: build_patched_simple_tempdir( $file_patches) ;
60+ crate :: input:: load_model( tmp. path( ) ) ?;
61+ Ok ( ( ) )
62+ } ) ( )
63+ } } ;
64+ }
65+ pub ( crate ) use patch_and_validate_simple;
66+
67+ /// Check whether the simple example runs successfully after applying file patches
68+ macro_rules! patch_and_run_simple {
69+ ( $file_patches: expr) => { {
70+ ( || -> Result <( ) > {
71+ let tmp = crate :: fixture:: build_patched_simple_tempdir( $file_patches) ;
72+ let ( model, assets) = crate :: input:: load_model( tmp. path( ) ) ?;
73+ let output_path = tmp. path( ) . join( "output" ) ;
74+ std:: fs:: create_dir_all( & output_path) ?;
75+
76+ crate :: simulation:: run( & model, assets, & output_path, false ) ?;
77+ Ok ( ( ) )
78+ } ) ( )
79+ } } ;
80+ }
81+ pub ( crate ) use patch_and_run_simple;
82+
4383#[ fixture]
4484pub fn region_id ( ) -> RegionID {
4585 "GBR" . into ( )
@@ -320,3 +360,34 @@ pub fn appraisal_output(asset: Asset, time_slice: TimeSliceID) -> AppraisalOutpu
320360 metric : 4.14 ,
321361 }
322362}
363+
364+ #[ cfg( test) ]
365+ mod tests {
366+ use super :: * ;
367+
368+ #[ test]
369+ fn patch_and_validate_simple_smoke ( ) {
370+ let patches = Vec :: new ( ) ;
371+ assert ! ( patch_and_validate_simple!( patches) . is_ok( ) ) ;
372+ }
373+
374+ #[ test]
375+ fn patch_and_run_simple_smoke ( ) {
376+ let patches = Vec :: new ( ) ;
377+ assert ! ( patch_and_run_simple!( patches) . is_ok( ) ) ;
378+ }
379+
380+ #[ test]
381+ fn test_patch_and_validate_simple_fail ( ) {
382+ let patch = FilePatch :: new ( "commodities.csv" )
383+ . with_deletion ( "RSHEAT,Residential heating,svd,daynight" ) ;
384+ assert ! ( patch_and_validate_simple!( vec![ patch] ) . is_err( ) ) ;
385+ }
386+
387+ #[ test]
388+ fn test_patch_and_run_simple_fail ( ) {
389+ let patch = FilePatch :: new ( "commodities.csv" )
390+ . with_deletion ( "RSHEAT,Residential heating,svd,daynight" ) ;
391+ assert ! ( patch_and_run_simple!( vec![ patch] ) . is_err( ) ) ;
392+ }
393+ }
0 commit comments