test_nml.py 7.5 KB

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