1 | #!/usr/bin/env python2.7 |
---|
2 | import unittest |
---|
3 | import nml |
---|
4 | |
---|
5 | def version(vn): |
---|
6 | # Converts module version string to int tuple as PEP-440 |
---|
7 | return tuple(map(int, vn.split("."))) |
---|
8 | |
---|
9 | HEADER = """ |
---|
10 | !! ===================================== |
---|
11 | !! An example FORTRAN 90 namelist |
---|
12 | !! ===================================== |
---|
13 | &namex |
---|
14 | """ |
---|
15 | NOHEADER = "&namex\n" |
---|
16 | LOGIC = " ln_test = .TRUE. ! Comment\n" |
---|
17 | NUMERIC = " nn_off_idx = 1 2 3\n" |
---|
18 | NOSPACE = " nn_off_idx=1 2 3\n" |
---|
19 | NEGATIVE = " nn_off_idx = -1 -2 -3\n" |
---|
20 | LIST = " off_files = 'a.nc' 'b.nc' 'c.nc' ! Comment\n" |
---|
21 | STRING = ' contact = "example@nowhere.com" ! Comment\n' |
---|
22 | COMMENT = ' ! x = y ' |
---|
23 | FOOTER = "/\n" |
---|
24 | NOFOOTER = "/" |
---|
25 | |
---|
26 | class TestNamelist(unittest.TestCase): |
---|
27 | def setUp(self): |
---|
28 | self.logic_text = "\n".join([HEADER, LOGIC, FOOTER]) |
---|
29 | self.numeric_text = "\n".join([HEADER, NUMERIC, FOOTER]) |
---|
30 | self.nospace_text = "\n".join([HEADER, NOSPACE, FOOTER]) |
---|
31 | self.neg_numeric_text = "\n".join([HEADER, NEGATIVE, FOOTER]) |
---|
32 | self.list_text = "\n".join([HEADER, LIST, FOOTER]) |
---|
33 | self.mix_text = "\n".join([HEADER, LIST, NUMERIC, FOOTER]) |
---|
34 | self.string_text = "\n".join([HEADER, STRING, FOOTER]) |
---|
35 | self.comment_text = "\n".join([HEADER, COMMENT, FOOTER]) |
---|
36 | self.no_trail_text = "\n".join([HEADER, NUMERIC, LIST, NOFOOTER]) |
---|
37 | |
---|
38 | def test_should_handle_footer(self): |
---|
39 | data = nml.variables(self.no_trail_text) |
---|
40 | truth = {"nn_off_idx": "1 2 3", |
---|
41 | "off_files": "'a.nc' 'b.nc' 'c.nc'"} |
---|
42 | self.assertDictEqual(data, truth) |
---|
43 | |
---|
44 | def test_mix_data(self): |
---|
45 | data = nml.variables(self.mix_text) |
---|
46 | truth = {"nn_off_idx": "1 2 3", |
---|
47 | "off_files": "'a.nc' 'b.nc' 'c.nc'"} |
---|
48 | self.assertDictEqual(data, truth) |
---|
49 | |
---|
50 | def test_comment_data(self): |
---|
51 | data = nml.variables(self.comment_text) |
---|
52 | truth = {} |
---|
53 | self.assertDictEqual(data, truth) |
---|
54 | |
---|
55 | def test_logical_data(self): |
---|
56 | data = nml.variables(self.logic_text) |
---|
57 | truth = {"ln_test": ".TRUE."} |
---|
58 | self.assertDictEqual(data, truth) |
---|
59 | |
---|
60 | def test_numeric_data(self): |
---|
61 | data = nml.variables(self.numeric_text) |
---|
62 | truth = {"nn_off_idx": "1 2 3"} |
---|
63 | self.assertDictEqual(data, truth) |
---|
64 | |
---|
65 | def test_nospace_data(self): |
---|
66 | data = nml.variables(self.nospace_text) |
---|
67 | truth = {"nn_off_idx": "1 2 3"} |
---|
68 | self.assertDictEqual(data, truth) |
---|
69 | |
---|
70 | def test_negative_numeric_data(self): |
---|
71 | data = nml.variables(self.neg_numeric_text) |
---|
72 | truth = {"nn_off_idx": "-1 -2 -3"} |
---|
73 | self.assertDictEqual(data, truth) |
---|
74 | |
---|
75 | def test_string_data(self): |
---|
76 | data = nml.variables(self.string_text) |
---|
77 | truth = {"contact": '"example@nowhere.com"'} |
---|
78 | self.assertDictEqual(data, truth) |
---|
79 | |
---|
80 | def test_list_data(self): |
---|
81 | data = nml.variables(self.list_text) |
---|
82 | truth = {"off_files": "'a.nc' 'b.nc' 'c.nc'"} |
---|
83 | self.assertDictEqual(data, truth) |
---|
84 | |
---|
85 | def test_replace_variable_comment(self): |
---|
86 | FIXTURE = " x = 'y' ! comment \n" |
---|
87 | RESULT = " x = 'z' ! comment \n" |
---|
88 | text = nml.replace(FIXTURE, {"x": "z"}) |
---|
89 | self.assertEqual(text, RESULT) |
---|
90 | |
---|
91 | def test_replace_variable_no_comment(self): |
---|
92 | FIXTURE = " x = 'y' \n" |
---|
93 | RESULT = " x = 'z' \n" |
---|
94 | text = nml.replace(FIXTURE, {"x": "z"}) |
---|
95 | self.assertEqual(text, RESULT) |
---|
96 | |
---|
97 | def test_replace_variable_no_space(self): |
---|
98 | FIXTURE = " x='y' \n" |
---|
99 | RESULT = " x='z' \n" |
---|
100 | text = nml.replace(FIXTURE, {"x": "z"}) |
---|
101 | self.assertEqual(text, RESULT) |
---|
102 | |
---|
103 | def test_replace_variable_no_space_comment(self): |
---|
104 | FIXTURE = " x='y' ! comment \n" |
---|
105 | RESULT = " x='z' ! comment \n" |
---|
106 | text = nml.replace(FIXTURE, {"x": "z"}) |
---|
107 | self.assertEqual(text, RESULT) |
---|
108 | |
---|
109 | @unittest.skipIf(version(nml.__version__) < (1, 0), |
---|
110 | "Not implemented in this version") |
---|
111 | def test_multiline_variable_replace(self): |
---|
112 | # As a result of a code review |
---|
113 | FIXTURE = " x = 1, \n 2" |
---|
114 | RESULT = " x = 3, \n 4" |
---|
115 | text = nml.replace(FIXTURE, {"x": [3,4]}) |
---|
116 | self.assertEqual(text, RESULT) |
---|
117 | |
---|
118 | class TestCombinedNamelists(unittest.TestCase): |
---|
119 | def setUp(self): |
---|
120 | self.minimal = """&namone |
---|
121 | /""" |
---|
122 | self.blanks = """ |
---|
123 | &namone |
---|
124 | / |
---|
125 | &namtwo |
---|
126 | / |
---|
127 | """ |
---|
128 | self.contents = """ |
---|
129 | &namone |
---|
130 | Content 1 |
---|
131 | / |
---|
132 | &namtwo |
---|
133 | Content 2 |
---|
134 | / |
---|
135 | """ |
---|
136 | self.contents_slash = """ |
---|
137 | &namone |
---|
138 | Content 1 ! Y/N |
---|
139 | / |
---|
140 | &namtwo |
---|
141 | Content 2 |
---|
142 | / |
---|
143 | """ |
---|
144 | def test_should_select_name_from_minimal_namelist(self): |
---|
145 | data = nml.namelists(self.minimal) |
---|
146 | result = {"namone": "&namone\n/"} |
---|
147 | self.assertDictEqual(data, result) |
---|
148 | |
---|
149 | def test_should_select_names(self): |
---|
150 | data = nml.namelists(self.blanks) |
---|
151 | result = {"namone": "&namone\n/", |
---|
152 | "namtwo": "&namtwo\n/"} |
---|
153 | self.assertDictEqual(data, result) |
---|
154 | |
---|
155 | def test_should_select_contents(self): |
---|
156 | data = nml.namelists(self.contents) |
---|
157 | result = {"namone": "&namone\nContent 1\n/", |
---|
158 | "namtwo": "&namtwo\nContent 2\n/"} |
---|
159 | self.assertDictEqual(data, result) |
---|
160 | |
---|
161 | def test_should_select_contents_with_forward_slash(self): |
---|
162 | data = nml.namelists(self.contents_slash) |
---|
163 | result = {"namone": "&namone\nContent 1 ! Y/N\n/", |
---|
164 | "namtwo": "&namtwo\nContent 2\n/"} |
---|
165 | self.assertDictEqual(data, result) |
---|
166 | |
---|
167 | |
---|
168 | class TestToString(unittest.TestCase): |
---|
169 | def setUp(self): |
---|
170 | self.char_list = ["a.nc", "b.nc", "c.nc"] |
---|
171 | self.num_list = [1, 3, 7] |
---|
172 | self.char = "foo@bar.com" |
---|
173 | self.num = 10 |
---|
174 | self.mixed_list = ["foo.nc", -1, True] |
---|
175 | self.mixed_str_list = map(nml.quote, ["foo.nc", "-1", ".TRUE."]) |
---|
176 | |
---|
177 | def test_should_format_mixed_list(self): |
---|
178 | data = nml.tostring(self.mixed_list) |
---|
179 | result = "'foo.nc', -1, .TRUE." |
---|
180 | self.assertEqual(data, result) |
---|
181 | |
---|
182 | def test_should_format_numeric_list(self): |
---|
183 | data = nml.tostring(self.num_list) |
---|
184 | result = "1 3 7" |
---|
185 | self.assertEqual(data, result) |
---|
186 | |
---|
187 | def test_should_format_character_list(self): |
---|
188 | data = nml.tostring(self.char_list) |
---|
189 | result = "'a.nc', 'b.nc', 'c.nc'" |
---|
190 | self.assertEqual(data, result) |
---|
191 | |
---|
192 | def test_should_format_strings(self): |
---|
193 | data = nml.tostring(self.char) |
---|
194 | result = "'%s'" % (self.char,) |
---|
195 | self.assertEqual(data, result) |
---|
196 | |
---|
197 | def test_should_format_numbers(self): |
---|
198 | data = nml.tostring(self.num) |
---|
199 | result = str(self.num) |
---|
200 | self.assertEqual(data, result) |
---|
201 | |
---|
202 | def test_should_not_format_numeric_string(self): |
---|
203 | input = "3.14159" |
---|
204 | self.assertEqual(nml.tostring(input), input) |
---|
205 | |
---|
206 | def test_should_format_logicals(self): |
---|
207 | data = nml.tostring(True) |
---|
208 | result = ".TRUE." |
---|
209 | self.assertEqual(data.upper(), result) |
---|
210 | |
---|
211 | def test_should_not_format_string_of_list_data(self): |
---|
212 | for input in ["1 2 3", "1, 2, 3", ".TRUE. .FALSE."]: |
---|
213 | case = nml.tostring(input) |
---|
214 | self.assertEqual(case, input) |
---|
215 | |
---|
216 | def test_should_treat_mixed_numeric_character_data_as_character(self): |
---|
217 | case = nml.tostring(self.mixed_str_list) |
---|
218 | result = "'foo.nc', '-1', '.TRUE.'" |
---|
219 | self.assertEqual(case, result) |
---|
220 | |
---|
221 | class TestUpdateNamelist(unittest.TestCase): |
---|
222 | def setUp(self): |
---|
223 | self.empty = """ |
---|
224 | &namone |
---|
225 | / |
---|
226 | """ |
---|
227 | self.single = """ |
---|
228 | &namone |
---|
229 | x = 'y' |
---|
230 | / |
---|
231 | """ |
---|
232 | self.single_update = """ |
---|
233 | &namone |
---|
234 | x = 'z' |
---|
235 | / |
---|
236 | """ |
---|
237 | |
---|
238 | def test_should_append_new_variable_to_namelist(self): |
---|
239 | trial = nml.update("namone", self.empty, {"x": "'y'"}) |
---|
240 | self.assertEqual(trial, self.single) |
---|
241 | |
---|
242 | def test_should_update_existing_variables(self): |
---|
243 | trial = nml.update("namone", self.single, {"x": "'z'"}) |
---|
244 | self.assertEqual(trial, self.single_update) |
---|
245 | |
---|
246 | if __name__ == '__main__': |
---|
247 | unittest.main() |
---|
248 | |
---|