33
44import xarray as xr
55
6- from xrlint .config import Config
7- from xrlint .constants import CORE_PLUGIN_NAME
6+ from xrlint .config import Config , ConfigList
7+ from xrlint .constants import CORE_PLUGIN_NAME , NODE_ROOT_NAME
88from xrlint .linter import Linter , new_linter
99from xrlint .node import AttrNode , AttrsNode , DataArrayNode , DatasetNode
1010from xrlint .plugin import new_plugin
1616class LinterTest (TestCase ):
1717 def test_default_config_is_empty (self ):
1818 linter = Linter ()
19- self .assertEqual (Config (), linter .config )
19+ self .assertEqual (ConfigList (), linter .config )
2020
2121 def test_new_linter (self ):
22- import xrlint .all as xrl
23-
2422 linter = new_linter ()
25- self .assertIsInstance (linter , xrl .Linter )
26- self .assertIsInstance (linter .config .plugins , dict )
27- self .assertEqual ({CORE_PLUGIN_NAME }, set (linter .config .plugins .keys ()))
28- self .assertEqual (None , linter .config .rules )
29-
30- linter = new_linter (config_name = None )
31- self .assertIsInstance (linter , xrl .Linter )
32- self .assertIsInstance (linter .config .plugins , dict )
33- self .assertEqual ({CORE_PLUGIN_NAME }, set (linter .config .plugins .keys ()))
34- self .assertEqual (None , linter .config .rules )
23+ self .assertIsInstance (linter , Linter )
24+ self .assertEqual (1 , len (linter .config .configs ))
25+ config = linter .config .configs [0 ]
26+ self .assertIsInstance (config .plugins , dict )
27+ self .assertEqual ({CORE_PLUGIN_NAME }, set (config .plugins .keys ()))
28+ self .assertEqual (None , config .rules )
3529
30+ def test_new_linter_recommended (self ):
3631 linter = new_linter ("recommended" )
37- self .assertIsInstance (linter , xrl .Linter )
38- self .assertIsInstance (linter .config .plugins , dict )
39- self .assertEqual ({CORE_PLUGIN_NAME }, set (linter .config .plugins .keys ()))
40- self .assertIsInstance (linter .config .rules , dict )
41- self .assertIn ("coords-for-dims" , linter .config .rules )
32+ self .assertIsInstance (linter , Linter )
33+ self .assertEqual (2 , len (linter .config .configs ))
34+ config0 = linter .config .configs [0 ]
35+ config1 = linter .config .configs [1 ]
36+ self .assertIsInstance (config0 .plugins , dict )
37+ self .assertEqual ({CORE_PLUGIN_NAME }, set (config0 .plugins .keys ()))
38+ self .assertIsInstance (config1 .rules , dict )
39+ self .assertIn ("coords-for-dims" , config1 .rules )
4240
41+ def test_new_linter_all (self ):
4342 linter = new_linter ("all" )
44- self .assertIsInstance (linter , xrl .Linter )
45- self .assertIsInstance (linter .config .plugins , dict )
46- self .assertEqual ({CORE_PLUGIN_NAME }, set (linter .config .plugins .keys ()))
47- self .assertIsInstance (linter .config .rules , dict )
48- self .assertIn ("coords-for-dims" , linter .config .rules )
43+ self .assertIsInstance (linter , Linter )
44+ self .assertEqual (2 , len (linter .config .configs ))
45+ config0 = linter .config .configs [0 ]
46+ config1 = linter .config .configs [1 ]
47+ self .assertIsInstance (config0 .plugins , dict )
48+ self .assertEqual ({CORE_PLUGIN_NAME }, set (config0 .plugins .keys ()))
49+ self .assertIsInstance (config1 .rules , dict )
50+ self .assertIn ("coords-for-dims" , config1 .rules )
51+
52+
53+ class LinterVerifyConfigTest (TestCase ):
54+ def test_config_with_config_list (self ):
55+ linter = new_linter ()
56+ result = linter .verify_dataset (
57+ xr .Dataset (),
58+ config = ConfigList .from_value ([{"rules" : {"no-empty-attrs" : 2 }}]),
59+ )
60+ self .assert_result_ok (result , "Missing metadata, attributes are empty." )
61+
62+ def test_config_with_list_of_config (self ):
63+ linter = new_linter ()
64+ result = linter .verify_dataset (
65+ xr .Dataset (),
66+ config = [{"rules" : {"no-empty-attrs" : 2 }}],
67+ )
68+ self .assert_result_ok (result , "Missing metadata, attributes are empty." )
69+
70+ def test_config_with_config_obj (self ):
71+ linter = new_linter ()
72+ result = linter .verify_dataset (
73+ xr .Dataset (),
74+ config = {"rules" : {"no-empty-attrs" : 2 }},
75+ )
76+ self .assert_result_ok (result , "Missing metadata, attributes are empty." )
77+
78+ def test_no_config (self ):
79+ linter = Linter ()
80+ result = linter .verify_dataset (
81+ xr .Dataset (),
82+ )
83+ self .assert_result_ok (result , "No configuration given or matches '<dataset>'." )
84+
85+ def assert_result_ok (self , result : Result , expected_message : str ):
86+ self .assertIsInstance (result , Result )
87+ self .assertEqual (1 , len (result .messages ))
88+ self .assertEqual (2 , result .messages [0 ].severity )
89+ self .assertEqual (expected_message , result .messages [0 ].message )
4990
5091
5192class LinterVerifyTest (TestCase ):
@@ -88,6 +129,8 @@ class MultiLevelDataset(ProcessorOp):
88129 def preprocess (
89130 self , file_path : str , _opener_options : dict [str , Any ]
90131 ) -> list [tuple [xr .Dataset , str ]]:
132+ if file_path == "bad.levels" :
133+ raise OSError ("bad checksum" )
91134 return [
92135 (xr .Dataset (attrs = {"title" : "Level 0" }), file_path + "/0.zarr" ),
93136 (xr .Dataset (attrs = {"title" : "Level 1" }), file_path + "/1.zarr" ),
@@ -99,7 +142,7 @@ def postprocess(
99142 return messages [0 ] + messages [1 ]
100143
101144 config = Config (plugins = {"test" : plugin })
102- self .linter = Linter (config = config )
145+ self .linter = Linter (config )
103146 super ().setUp ()
104147
105148 def test_rules_are_ok (self ):
@@ -110,7 +153,7 @@ def test_rules_are_ok(self):
110153 "data-var-dim-must-have-coord" ,
111154 "dataset-without-data-vars" ,
112155 ],
113- list (self .linter ._config .plugins ["test" ].rules .keys ()),
156+ list (self .linter .config . configs [ 0 ] .plugins ["test" ].rules .keys ()),
114157 )
115158
116159 def test_linter_respects_rule_severity_error (self ):
@@ -181,6 +224,23 @@ def test_linter_respects_rule_severity_off(self):
181224 result ,
182225 )
183226
227+ def test_linter_recognized_unknown_rule (self ):
228+ result = self .linter .verify_dataset (
229+ xr .Dataset (), rules = {"test/dataset-is-fast" : 2 }
230+ )
231+ self .assertEqual (
232+ [
233+ Message (
234+ message = "unknown rule 'test/dataset-is-fast'" ,
235+ rule_id = "test/dataset-is-fast" ,
236+ node_path = NODE_ROOT_NAME ,
237+ severity = 2 ,
238+ fatal = True ,
239+ )
240+ ],
241+ result .messages ,
242+ )
243+
184244 def test_linter_real_life_scenario (self ):
185245 dataset = xr .Dataset (
186246 attrs = {
@@ -208,11 +268,13 @@ def test_linter_real_life_scenario(self):
208268
209269 result = self .linter .verify_dataset (
210270 dataset ,
211- rules = {
212- "test/no-space-in-attr-name" : "error" ,
213- "test/no-empty-attrs" : "warn" ,
214- "test/data-var-dim-must-have-coord" : "error" ,
215- "test/dataset-without-data-vars" : "warn" ,
271+ config = {
272+ "rules" : {
273+ "test/no-space-in-attr-name" : "error" ,
274+ "test/no-empty-attrs" : "warn" ,
275+ "test/data-var-dim-must-have-coord" : "error" ,
276+ "test/dataset-without-data-vars" : "warn" ,
277+ },
216278 },
217279 )
218280 self .assertEqual (
@@ -262,15 +324,13 @@ def test_linter_real_life_scenario(self):
262324 result ,
263325 )
264326
265- def test_processor (self ):
327+ def test_processor_ok (self ):
266328 result = self .linter .verify_dataset (
267329 "test.levels" ,
268- config = Config .from_value (
269- {
270- "processor" : "test/multi-level-dataset" ,
271- "rules" : {"test/dataset-without-data-vars" : "warn" },
272- }
273- ),
330+ config = {
331+ "processor" : "test/multi-level-dataset" ,
332+ "rules" : {"test/dataset-without-data-vars" : "warn" },
333+ },
274334 )
275335
276336 self .assertEqual (
@@ -290,3 +350,24 @@ def test_processor(self):
290350 ],
291351 result .messages ,
292352 )
353+
354+ def test_processor_fail (self ):
355+ result = self .linter .verify_dataset (
356+ "bad.levels" ,
357+ config = {
358+ "processor" : "test/multi-level-dataset" ,
359+ "rules" : {"test/dataset-without-data-vars" : "warn" },
360+ },
361+ )
362+
363+ self .assertEqual (
364+ [
365+ Message (
366+ message = "bad checksum" ,
367+ severity = 2 ,
368+ fatal = True ,
369+ node_path = NODE_ROOT_NAME ,
370+ )
371+ ],
372+ result .messages ,
373+ )
0 commit comments