@@ -135,3 +135,146 @@ def test_get_datastream_uri():
135135 uri = t ._get_datastream_uri ()
136136 assert uri .startswith ("file://" )
137137 assert "relative/path/to/ds.xml" in uri
138+
139+
140+ def test_datastream_validator ():
141+ """Test that DataStreamValidator properly validates IDs."""
142+ ds_path = pathlib .Path (__file__ ).parent .joinpath ("data_stream.xml" )
143+ validator = autotailor .DataStreamValidator (str (ds_path ))
144+
145+ # Test valid profile validation
146+ validator .validate_profile ("xccdf_com.example.www_profile_P1" )
147+
148+ # Test valid value validation
149+ validator .validate_value ("xccdf_com.example.www_value_V1" )
150+ validator .validate_value ("xccdf_com.example.www_value_V2" )
151+
152+ # Test valid rule validation
153+ validator .validate_rule ("xccdf_com.example.www_rule_R1" )
154+ validator .validate_rule ("xccdf_com.example.www_rule_R2" )
155+ validator .validate_rule ("xccdf_com.example.www_rule_R3" )
156+ validator .validate_rule ("xccdf_com.example.www_rule_R4" )
157+
158+ # Test valid group validation
159+ validator .validate_group ("xccdf_com.example.www_group_G34" )
160+
161+ # Test invalid profile
162+ with pytest .raises (ValueError ) as e :
163+ validator .validate_profile ("xccdf_com.example.www_profile_INVALID" )
164+ assert "Profile ID 'xccdf_com.example.www_profile_INVALID' does not exist" in str (e .value )
165+
166+ # Test invalid value with suggestion
167+ with pytest .raises (ValueError ) as e :
168+ validator .validate_value ("xccdf_com.example.www_value_V3" )
169+ assert "Value ID 'xccdf_com.example.www_value_V3' does not exist" in str (e .value )
170+
171+ # Test invalid rule with suggestion
172+ with pytest .raises (ValueError ) as e :
173+ validator .validate_rule ("xccdf_com.example.www_rule_R5" )
174+ assert "Rule ID 'xccdf_com.example.www_rule_R5' does not exist" in str (e .value )
175+
176+ # Test invalid group
177+ with pytest .raises (ValueError ) as e :
178+ validator .validate_group ("xccdf_com.example.www_group_INVALID" )
179+ assert "Group ID 'xccdf_com.example.www_group_INVALID' does not exist" in str (e .value )
180+
181+
182+ def test_profile_with_validator ():
183+ """Test that Profile uses validator to check IDs."""
184+ ds_path = pathlib .Path (__file__ ).parent .joinpath ("data_stream.xml" )
185+ validator = autotailor .DataStreamValidator (str (ds_path ))
186+
187+ p = autotailor .Profile (validator = validator )
188+ p .reverse_dns = "com.example.www"
189+
190+ # Test valid variable change works
191+ p .add_value_change ("V1" , "30" )
192+
193+ # Test invalid variable name fails
194+ with pytest .raises (ValueError ) as e :
195+ p .add_value_change ("INVALID_VAR" , "test" )
196+ assert "Value ID 'xccdf_com.example.www_value_INVALID_VAR' does not exist" in str (e .value )
197+
198+ # Test valid rule selection works
199+ p .select_rule ("R1" )
200+
201+ # Test invalid rule selection fails
202+ with pytest .raises (ValueError ) as e :
203+ p .select_rule ("INVALID_RULE" )
204+ assert "Rule ID 'xccdf_com.example.www_rule_INVALID_RULE' does not exist" in str (e .value )
205+
206+ # Test valid base profile validation
207+ p .validate_base_profile ("P1" )
208+
209+ # Test invalid base profile fails
210+ with pytest .raises (ValueError ) as e :
211+ p .validate_base_profile ("INVALID_PROFILE" )
212+ assert "Profile ID 'xccdf_com.example.www_profile_INVALID_PROFILE' does not exist" in str (e .value )
213+
214+
215+ def test_validator_suggestions ():
216+ """Test that validator provides helpful suggestions for typos."""
217+ ds_path = pathlib .Path (__file__ ).parent .joinpath ("data_stream.xml" )
218+ validator = autotailor .DataStreamValidator (str (ds_path ))
219+
220+ # Test suggestion for value with typo (V11 instead of V1)
221+ with pytest .raises (ValueError ) as e :
222+ validator .validate_value ("xccdf_com.example.www_value_V11" )
223+ error_msg = str (e .value )
224+ assert "Did you mean one of these?" in error_msg
225+ assert "xccdf_com.example.www_value_V1" in error_msg
226+
227+ # Test suggestion for rule with typo (R11 instead of R1)
228+ with pytest .raises (ValueError ) as e :
229+ validator .validate_rule ("xccdf_com.example.www_rule_R11" )
230+ error_msg = str (e .value )
231+ assert "Did you mean one of these?" in error_msg
232+ assert "xccdf_com.example.www_rule_R1" in error_msg
233+
234+
235+ def test_validate_selector ():
236+ """Test that validate_selector rejects selectors not present in the data stream."""
237+ ds_path = pathlib .Path (__file__ ).parent .joinpath ("data_stream.xml" )
238+ validator = autotailor .DataStreamValidator (str (ds_path ))
239+
240+ # V1 has selector "thirty"; V2 has "some" and "other"
241+ validator .validate_selector ("xccdf_com.example.www_value_V1" , "thirty" )
242+ validator .validate_selector ("xccdf_com.example.www_value_V2" , "some" )
243+ validator .validate_selector ("xccdf_com.example.www_value_V2" , "other" )
244+
245+ # Invalid selector for V1
246+ with pytest .raises (ValueError ) as e :
247+ validator .validate_selector ("xccdf_com.example.www_value_V1" , "invalid" )
248+ error_msg = str (e .value )
249+ assert "Selector 'invalid' does not exist for Value 'xccdf_com.example.www_value_V1'" in error_msg
250+ assert "thirty" in error_msg
251+
252+ # Invalid selector for V2 with a close-enough typo triggers a suggestion
253+ with pytest .raises (ValueError ) as e :
254+ validator .validate_selector ("xccdf_com.example.www_value_V2" , "ther" )
255+ error_msg = str (e .value )
256+ assert "Selector 'ther' does not exist for Value 'xccdf_com.example.www_value_V2'" in error_msg
257+ assert "other" in error_msg
258+
259+
260+ def test_profile_selector_validation ():
261+ """Test that Profile validates selectors via -V/--var-select through refine_value."""
262+ ds_path = pathlib .Path (__file__ ).parent .joinpath ("data_stream.xml" )
263+ validator = autotailor .DataStreamValidator (str (ds_path ))
264+
265+ p = autotailor .Profile (validator = validator )
266+ p .reverse_dns = "com.example.www"
267+
268+ # Valid selector passes
269+ p .change_selectors (["V1=thirty" ])
270+ p .change_selectors (["V2=some" ])
271+
272+ # Invalid selector raises
273+ with pytest .raises (ValueError ) as e :
274+ p .change_selectors (["V1=invalid" ])
275+ assert "Selector 'invalid' does not exist for Value 'xccdf_com.example.www_value_V1'" in str (e .value )
276+
277+ # Invalid value ID still raises before reaching selector check
278+ with pytest .raises (ValueError ) as e :
279+ p .change_selectors (["NONEXISTENT=thirty" ])
280+ assert "Value ID 'xccdf_com.example.www_value_NONEXISTENT' does not exist" in str (e .value )
0 commit comments