[4122] | 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 |
---|
[4126] | 7 | return tuple(map(int, vn.split("."))) |
---|
[4122] | 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" |
---|
[4126] | 18 | NOSPACE = " nn_off_idx=1 2 3\n" |
---|
[4122] | 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]) |
---|
[4126] | 30 | self.nospace_text = "\n".join([HEADER, NOSPACE, FOOTER]) |
---|
[4122] | 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 | |
---|
[4126] | 65 | def test_nospace_data(self): |
---|
| 66 | data = nml.variables(self.nospace_text) |
---|
[4122] | 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): |
---|
[4126] | 86 | FIXTURE = " x = 'y' ! comment \n" |
---|
| 87 | RESULT = " x = 'z' ! comment \n" |
---|
[4122] | 88 | text = nml.replace(FIXTURE, {"x": "z"}) |
---|
| 89 | self.assertEqual(text, RESULT) |
---|
| 90 | |
---|
| 91 | def test_replace_variable_no_comment(self): |
---|
[4126] | 92 | FIXTURE = " x = 'y' \n" |
---|
| 93 | RESULT = " x = 'z' \n" |
---|
[4122] | 94 | text = nml.replace(FIXTURE, {"x": "z"}) |
---|
| 95 | self.assertEqual(text, RESULT) |
---|
| 96 | |
---|
[4126] | 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 | |
---|
[4122] | 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 |
---|
[4126] | 174 | self.mixed_list = ["foo.nc", -1, True] |
---|
[4128] | 175 | self.mixed_str_list = map(nml.quote, ["foo.nc", "-1", ".TRUE."]) |
---|
[4122] | 176 | |
---|
[4126] | 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 | |
---|
[4122] | 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) |
---|
[4128] | 189 | result = "'a.nc', 'b.nc', 'c.nc'" |
---|
[4122] | 190 | self.assertEqual(data, result) |
---|
| 191 | |
---|
| 192 | def test_should_format_strings(self): |
---|
| 193 | data = nml.tostring(self.char) |
---|
[4126] | 194 | result = "'%s'" % (self.char,) |
---|
[4122] | 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 | |
---|
[4126] | 202 | def test_should_not_format_numeric_string(self): |
---|
| 203 | input = "3.14159" |
---|
| 204 | self.assertEqual(nml.tostring(input), input) |
---|
| 205 | |
---|
[4122] | 206 | def test_should_format_logicals(self): |
---|
| 207 | data = nml.tostring(True) |
---|
| 208 | result = ".TRUE." |
---|
| 209 | self.assertEqual(data.upper(), result) |
---|
| 210 | |
---|
[4126] | 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 | |
---|
[4128] | 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 | |
---|
[4122] | 221 | class TestUpdateNamelist(unittest.TestCase): |
---|
| 222 | def setUp(self): |
---|
| 223 | self.empty = """ |
---|
| 224 | &namone |
---|
| 225 | / |
---|
| 226 | """ |
---|
| 227 | self.single = """ |
---|
| 228 | &namone |
---|
[4126] | 229 | x = 'y' |
---|
[4122] | 230 | / |
---|
| 231 | """ |
---|
| 232 | self.single_update = """ |
---|
| 233 | &namone |
---|
[4126] | 234 | x = 'z' |
---|
[4122] | 235 | / |
---|
| 236 | """ |
---|
| 237 | |
---|
| 238 | def test_should_append_new_variable_to_namelist(self): |
---|
[4126] | 239 | trial = nml.update("namone", self.empty, {"x": "'y'"}) |
---|
[4122] | 240 | self.assertEqual(trial, self.single) |
---|
| 241 | |
---|
| 242 | def test_should_update_existing_variables(self): |
---|
[4126] | 243 | trial = nml.update("namone", self.single, {"x": "'z'"}) |
---|
[4122] | 244 | self.assertEqual(trial, self.single_update) |
---|
| 245 | |
---|
| 246 | if __name__ == '__main__': |
---|
| 247 | unittest.main() |
---|
| 248 | |
---|