@@ -550,6 +550,149 @@ func TestTargetConfig_BranchValidation(t *testing.T) {
550550 }
551551}
552552
553+ // TestTargetConfig_MappingRequirement tests that targets accept any combination of
554+ // direct mappings or list refs, and reject targets with none.
555+ func TestTargetConfig_MappingRequirement (t * testing.T ) {
556+ tests := []struct {
557+ name string
558+ target TargetConfig
559+ expectErr bool
560+ }{
561+ {
562+ name : "valid - files only" ,
563+ target : TargetConfig {
564+ Repo : "org/target" ,
565+ Files : []FileMapping {{Src : "a.txt" , Dest : "a.txt" }},
566+ },
567+ },
568+ {
569+ name : "valid - directories only" ,
570+ target : TargetConfig {
571+ Repo : "org/target" ,
572+ Directories : []DirectoryMapping {{Src : "src" , Dest : "dest" }},
573+ },
574+ },
575+ {
576+ name : "valid - file list refs only" ,
577+ target : TargetConfig {
578+ Repo : "org/target" ,
579+ FileListRefs : []string {"common-files" },
580+ },
581+ },
582+ {
583+ name : "valid - directory list refs only" ,
584+ target : TargetConfig {
585+ Repo : "org/target" ,
586+ DirectoryListRefs : []string {"github-workflows" },
587+ },
588+ },
589+ {
590+ name : "valid - file list refs and directory list refs" ,
591+ target : TargetConfig {
592+ Repo : "org/target" ,
593+ FileListRefs : []string {"common-files" , "editor-config" },
594+ DirectoryListRefs : []string {"github-workflows" , "vs-code" },
595+ },
596+ },
597+ {
598+ name : "valid - files and directories" ,
599+ target : TargetConfig {
600+ Repo : "org/target" ,
601+ Files : []FileMapping {{Src : "a.txt" , Dest : "a.txt" }},
602+ Directories : []DirectoryMapping {{Src : "src" , Dest : "dest" }},
603+ },
604+ },
605+ {
606+ name : "valid - all four mapping types" ,
607+ target : TargetConfig {
608+ Repo : "org/target" ,
609+ Files : []FileMapping {{Src : "a.txt" , Dest : "a.txt" }},
610+ Directories : []DirectoryMapping {{Src : "src" , Dest : "dest" }},
611+ FileListRefs : []string {"common-files" },
612+ DirectoryListRefs : []string {"github-workflows" },
613+ },
614+ },
615+ {
616+ name : "invalid - no mappings at all" ,
617+ target : TargetConfig {
618+ Repo : "org/target" ,
619+ },
620+ expectErr : true ,
621+ },
622+ {
623+ name : "invalid - empty slices for all mapping types" ,
624+ target : TargetConfig {
625+ Repo : "org/target" ,
626+ Files : []FileMapping {},
627+ Directories : []DirectoryMapping {},
628+ FileListRefs : []string {},
629+ DirectoryListRefs : []string {},
630+ },
631+ expectErr : true ,
632+ },
633+ }
634+
635+ for _ , tt := range tests {
636+ t .Run (tt .name , func (t * testing.T ) {
637+ ctx := context .Background ()
638+ logger := logrus .NewEntry (logrus .StandardLogger ())
639+
640+ err := tt .target .validateWithLogging (ctx , nil , logger )
641+
642+ if tt .expectErr {
643+ require .Error (t , err )
644+ assert .ErrorIs (t , err , ErrNoMappings )
645+ } else {
646+ assert .NoError (t , err )
647+ }
648+ })
649+ }
650+ }
651+
652+ // TestTargetConfig_ListRefsOnlyFullValidation verifies that a target with only list refs
653+ // passes full config-level validation (the real-world scenario that was broken).
654+ func TestTargetConfig_ListRefsOnlyFullValidation (t * testing.T ) {
655+ config := & Config {
656+ Version : 1 ,
657+ FileLists : []FileList {
658+ {
659+ ID : "common-files" ,
660+ Name : "Common Files" ,
661+ Files : []FileMapping {
662+ {Src : ".editorconfig" , Dest : ".editorconfig" },
663+ },
664+ },
665+ },
666+ DirectoryLists : []DirectoryList {
667+ {
668+ ID : "github-workflows" ,
669+ Name : "GitHub Workflows" ,
670+ Directories : []DirectoryMapping {
671+ {Src : ".github/workflows" , Dest : ".github/workflows" },
672+ },
673+ },
674+ },
675+ Groups : []Group {
676+ {
677+ Name : "test-group" ,
678+ ID : "test-group" ,
679+ Source : SourceConfig {Repo : "org/source" , Branch : "main" },
680+ Targets : []TargetConfig {
681+ {
682+ Repo : "org/target" ,
683+ FileListRefs : []string {"common-files" },
684+ DirectoryListRefs : []string {"github-workflows" },
685+ Transform : Transform {RepoName : true },
686+ },
687+ },
688+ },
689+ },
690+ }
691+
692+ err := config .Validate ()
693+ assert .NoError (t , err )
694+ }
695+
553696// TestValidate_DuplicateFileDestinations verifies that duplicate file destinations
554697// within the same target are detected
555698func TestValidate_DuplicateFileDestinations (t * testing.T ) {
0 commit comments