@@ -47,7 +47,7 @@ enum TemplateVariantKind {
47
47
}
48
48
49
49
/// The variant mode in which a template should be run.
50
- #[ derive( Clone , Debug , Eq , PartialEq ) ]
50
+ #[ derive( Clone , Debug ) ]
51
51
pub enum TemplateVariantInfo {
52
52
/// Create a new application from the template.
53
53
NewApplication ,
@@ -111,6 +111,8 @@ pub(crate) struct Conditional {
111
111
#[ derive( Clone , Debug ) ]
112
112
pub ( crate ) enum Condition {
113
113
ManifestEntryExists ( Vec < String > ) ,
114
+ #[ cfg( test) ]
115
+ Always ( bool ) ,
114
116
}
115
117
116
118
#[ derive( Clone , Debug , Eq , PartialEq , Hash ) ]
@@ -601,9 +603,11 @@ impl Condition {
601
603
let Ok ( table) = toml:: from_str :: < toml:: Value > ( & toml_text) else {
602
604
return false ;
603
605
} ;
604
- get_at ( table, path) . is_some ( )
606
+ crate :: toml :: get_at ( table, path) . is_some ( )
605
607
}
606
608
} ,
609
+ #[ cfg( test) ]
610
+ Self :: Always ( b) => * b,
607
611
}
608
612
}
609
613
}
@@ -638,19 +642,127 @@ fn validate_v1_manifest(raw: &RawTemplateManifestV1) -> anyhow::Result<()> {
638
642
Ok ( ( ) )
639
643
}
640
644
641
- fn get_at ( value : toml:: Value , path : & [ String ] ) -> Option < toml:: Value > {
642
- match path. split_first ( ) {
643
- None => Some ( value) , // we are at the end of the path and we have a thing
644
- Some ( ( first, rest) ) => {
645
- match value. as_table ( ) {
646
- None => None , // we need to key into it and we can't
647
- Some ( t) => {
648
- match t. get ( first) {
649
- None => None , // we tried to key into it and no match
650
- Some ( v) => get_at ( v. clone ( ) , rest) , // we pathed into it! keep pathing
651
- }
652
- }
653
- }
645
+ #[ cfg( test) ]
646
+ mod test {
647
+ use super :: * ;
648
+
649
+ struct TempFile ( tempfile:: TempDir , PathBuf ) ;
650
+
651
+ impl TempFile {
652
+ fn path ( & self ) -> PathBuf {
653
+ self . 1 . clone ( )
654
654
}
655
655
}
656
+
657
+ fn make_temp_manifest ( content : & str ) -> TempFile {
658
+ let temp_dir = tempfile:: tempdir ( ) . unwrap ( ) ;
659
+ let temp_file = temp_dir. path ( ) . join ( "spin.toml" ) ;
660
+ std:: fs:: write ( & temp_file, content) . unwrap ( ) ;
661
+ TempFile ( temp_dir, temp_file)
662
+ }
663
+
664
+ #[ test]
665
+ fn manifest_entry_exists_condition_is_false_for_new_app ( ) {
666
+ let condition = Template :: parse_condition ( RawCondition :: ManifestEntryExists (
667
+ "application.trigger.redis" . to_owned ( ) ,
668
+ ) ) ;
669
+ assert ! ( !condition. is_true( & TemplateVariantInfo :: NewApplication ) ) ;
670
+ }
671
+
672
+ #[ test]
673
+ fn manifest_entry_exists_condition_is_false_if_not_present_in_existing_manifest ( ) {
674
+ let temp_file =
675
+ make_temp_manifest ( "name = \" hello\" \n [application.trigger.http]\n base = \" /\" " ) ;
676
+ let condition = Template :: parse_condition ( RawCondition :: ManifestEntryExists (
677
+ "application.trigger.redis" . to_owned ( ) ,
678
+ ) ) ;
679
+ assert ! ( !condition. is_true( & TemplateVariantInfo :: AddComponent {
680
+ manifest_path: temp_file. path( )
681
+ } ) ) ;
682
+ }
683
+
684
+ #[ test]
685
+ fn manifest_entry_exists_condition_is_true_if_present_in_existing_manifest ( ) {
686
+ let temp_file = make_temp_manifest (
687
+ "name = \" hello\" \n [application.trigger.redis]\n channel = \" HELLO\" " ,
688
+ ) ;
689
+ let condition = Template :: parse_condition ( RawCondition :: ManifestEntryExists (
690
+ "application.trigger.redis" . to_owned ( ) ,
691
+ ) ) ;
692
+ assert ! ( condition. is_true( & TemplateVariantInfo :: AddComponent {
693
+ manifest_path: temp_file. path( )
694
+ } ) ) ;
695
+ }
696
+
697
+ #[ test]
698
+ fn manifest_entry_exists_condition_is_false_if_path_does_not_exist ( ) {
699
+ let condition = Template :: parse_condition ( RawCondition :: ManifestEntryExists (
700
+ "application.trigger.redis" . to_owned ( ) ,
701
+ ) ) ;
702
+ assert ! ( !condition. is_true( & TemplateVariantInfo :: AddComponent {
703
+ manifest_path: PathBuf :: from( "this/file/does/not.exist" )
704
+ } ) ) ;
705
+ }
706
+
707
+ #[ test]
708
+ fn selected_variant_respects_target ( ) {
709
+ let add_component_vt = TemplateVariant {
710
+ conditions : vec ! [ Conditional {
711
+ condition: Condition :: Always ( true ) ,
712
+ skip_files: vec![ "test2" . to_owned( ) ] ,
713
+ skip_parameters: vec![ "p1" . to_owned( ) ] ,
714
+ skip_snippets: vec![ "s1" . to_owned( ) ] ,
715
+ } ] ,
716
+ skip_files : vec ! [ "test1" . to_owned( ) ] ,
717
+ snippets : [
718
+ ( "s1" . to_owned ( ) , "s1val" . to_owned ( ) ) ,
719
+ ( "s2" . to_owned ( ) , "s2val" . to_owned ( ) ) ,
720
+ ]
721
+ . into_iter ( )
722
+ . collect ( ) ,
723
+ ..Default :: default ( )
724
+ } ;
725
+ let variants = [
726
+ (
727
+ TemplateVariantKind :: NewApplication ,
728
+ TemplateVariant :: default ( ) ,
729
+ ) ,
730
+ ( TemplateVariantKind :: AddComponent , add_component_vt) ,
731
+ ]
732
+ . into_iter ( )
733
+ . collect ( ) ;
734
+ let template = Template {
735
+ id : "test" . to_owned ( ) ,
736
+ tags : HashSet :: new ( ) ,
737
+ description : None ,
738
+ installed_from : InstalledFrom :: Unknown ,
739
+ trigger : TemplateTriggerCompatibility :: Any ,
740
+ variants,
741
+ parameters : vec ! [ ] ,
742
+ extra_outputs : vec ! [ ] ,
743
+ snippets_dir : None ,
744
+ content_dir : None ,
745
+ } ;
746
+
747
+ let variant_info = TemplateVariantInfo :: NewApplication ;
748
+ let variant = template. variant ( & variant_info) . unwrap ( ) ;
749
+ assert ! ( variant. skip_files. is_empty( ) ) ;
750
+ assert ! ( variant. skip_parameters. is_empty( ) ) ;
751
+ assert ! ( variant. snippets. is_empty( ) ) ;
752
+
753
+ let add_variant_info = TemplateVariantInfo :: AddComponent {
754
+ manifest_path : PathBuf :: from ( "dummy" ) ,
755
+ } ;
756
+ let add_variant = template. variant ( & add_variant_info) . unwrap ( ) ;
757
+ // the conditional skip_files and skip_parameters are added to the variant's skip lists
758
+ assert_eq ! ( 2 , add_variant. skip_files. len( ) ) ;
759
+ assert ! ( add_variant. skip_files. contains( & "test1" . to_owned( ) ) ) ;
760
+ assert ! ( add_variant. skip_files. contains( & "test2" . to_owned( ) ) ) ;
761
+ assert_eq ! ( 1 , add_variant. skip_parameters. len( ) ) ;
762
+ assert ! ( add_variant. skip_parameters. contains( & "p1" . to_owned( ) ) ) ;
763
+ // the conditional skip_snippets are *removed from* the variant's snippets list
764
+ assert_eq ! ( 1 , add_variant. snippets. len( ) ) ;
765
+ assert ! ( !add_variant. snippets. contains_key( "s1" ) ) ;
766
+ assert ! ( add_variant. snippets. contains_key( "s2" ) ) ;
767
+ }
656
768
}
0 commit comments