@@ -72,3 +72,127 @@ func TestFrameworkCopiesStayInSync(t *testing.T) {
7272 require .Equalf (t , string (repoRaw ), string (coreRaw ), "framework copy mismatch for %s" , entry .Name ())
7373 }
7474}
75+
76+ func TestParseFrameworkBranches (t * testing.T ) {
77+ _ , err := parseFramework ("bad-yaml" , []byte ("framework: [" ))
78+ require .Error (t , err )
79+
80+ _ , err = parseFramework ("missing-id" , []byte (`
81+ framework:
82+ version: "1"
83+ title: Missing ID
84+ controls:
85+ - id: c1
86+ title: Control
87+ required_record_types: [decision]
88+ required_fields: [record_id]
89+ minimum_frequency: continuous
90+ ` ))
91+ require .ErrorContains (t , err , "missing id" )
92+
93+ _ , err = parseFramework ("missing-controls" , []byte (`
94+ framework:
95+ id: test
96+ version: "1"
97+ title: Missing Controls
98+ controls: []
99+ ` ))
100+ require .ErrorContains (t , err , "has no controls" )
101+ }
102+
103+ func TestValidateControlsErrors (t * testing.T ) {
104+ cases := []struct {
105+ name string
106+ in []Control
107+ needle string
108+ }{
109+ {
110+ name : "missing id" ,
111+ in : []Control {{
112+ Title : "Control" ,
113+ RequiredRecordTypes : []string {"decision" },
114+ MinimumFrequency : "continuous" ,
115+ RequiredFields : []string {"record_id" },
116+ }},
117+ needle : "missing id" ,
118+ },
119+ {
120+ name : "missing title" ,
121+ in : []Control {{
122+ ID : "c1" ,
123+ RequiredRecordTypes : []string {"decision" },
124+ MinimumFrequency : "continuous" ,
125+ RequiredFields : []string {"record_id" },
126+ }},
127+ needle : "missing title" ,
128+ },
129+ {
130+ name : "missing required_record_types" ,
131+ in : []Control {{
132+ ID : "c1" ,
133+ Title : "Control" ,
134+ MinimumFrequency : "continuous" ,
135+ RequiredFields : []string {"record_id" },
136+ }},
137+ needle : "missing required_record_types" ,
138+ },
139+ {
140+ name : "missing minimum_frequency" ,
141+ in : []Control {{
142+ ID : "c1" ,
143+ Title : "Control" ,
144+ RequiredRecordTypes : []string {"decision" },
145+ RequiredFields : []string {"record_id" },
146+ }},
147+ needle : "missing minimum_frequency" ,
148+ },
149+ {
150+ name : "blank required_record_types entry" ,
151+ in : []Control {{
152+ ID : "c1" ,
153+ Title : "Control" ,
154+ RequiredRecordTypes : []string {"decision" , " " },
155+ MinimumFrequency : "continuous" ,
156+ RequiredFields : []string {"record_id" },
157+ }},
158+ needle : "blank required_record_types entry" ,
159+ },
160+ {
161+ name : "blank required_fields entry" ,
162+ in : []Control {{
163+ ID : "c1" ,
164+ Title : "Control" ,
165+ RequiredRecordTypes : []string {"decision" },
166+ MinimumFrequency : "continuous" ,
167+ RequiredFields : []string {"record_id" , "" },
168+ }},
169+ needle : "blank required_fields entry" ,
170+ },
171+ {
172+ name : "invalid child control" ,
173+ in : []Control {{
174+ ID : "c1" ,
175+ Title : "Control" ,
176+ RequiredRecordTypes : []string {"decision" },
177+ MinimumFrequency : "continuous" ,
178+ RequiredFields : []string {"record_id" },
179+ Children : []Control {{
180+ ID : "child" ,
181+ Title : "Child" ,
182+ MinimumFrequency : "continuous" ,
183+ RequiredFields : []string {"record_id" },
184+ }},
185+ }},
186+ needle : "missing required_record_types" ,
187+ },
188+ }
189+
190+ for _ , tc := range cases {
191+ tc := tc
192+ t .Run (tc .name , func (t * testing.T ) {
193+ err := validateControls (tc .in , "controls" )
194+ require .Error (t , err )
195+ require .ErrorContains (t , err , tc .needle )
196+ })
197+ }
198+ }
0 commit comments