test_utils.py 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. from typing import Any, List, Union
  2. import pytest
  3. from pynecone.utils import build, format, imports, prerequisites, types
  4. from pynecone.var import Var
  5. @pytest.mark.parametrize(
  6. "input,output",
  7. [
  8. ("", ""),
  9. ("hello", "hello"),
  10. ("Hello", "hello"),
  11. ("camelCase", "camel_case"),
  12. ("camelTwoHumps", "camel_two_humps"),
  13. ("_start_with_underscore", "_start_with_underscore"),
  14. ("__start_with_double_underscore", "__start_with_double_underscore"),
  15. ],
  16. )
  17. def test_to_snake_case(input: str, output: str):
  18. """Test converting strings to snake case.
  19. Args:
  20. input: The input string.
  21. output: The expected output string.
  22. """
  23. assert format.to_snake_case(input) == output
  24. @pytest.mark.parametrize(
  25. "input,output",
  26. [
  27. ("", ""),
  28. ("hello", "hello"),
  29. ("Hello", "Hello"),
  30. ("snake_case", "snakeCase"),
  31. ("snake_case_two", "snakeCaseTwo"),
  32. ],
  33. )
  34. def test_to_camel_case(input: str, output: str):
  35. """Test converting strings to camel case.
  36. Args:
  37. input: The input string.
  38. output: The expected output string.
  39. """
  40. assert format.to_camel_case(input) == output
  41. @pytest.mark.parametrize(
  42. "input,output",
  43. [
  44. ("", ""),
  45. ("hello", "Hello"),
  46. ("Hello", "Hello"),
  47. ("snake_case", "SnakeCase"),
  48. ("snake_case_two", "SnakeCaseTwo"),
  49. ],
  50. )
  51. def test_to_title_case(input: str, output: str):
  52. """Test converting strings to title case.
  53. Args:
  54. input: The input string.
  55. output: The expected output string.
  56. """
  57. assert format.to_title_case(input) == output
  58. @pytest.mark.parametrize(
  59. "input,output",
  60. [
  61. ("{", "}"),
  62. ("(", ")"),
  63. ("[", "]"),
  64. ("<", ">"),
  65. ('"', '"'),
  66. ("'", "'"),
  67. ],
  68. )
  69. def test_get_close_char(input: str, output: str):
  70. """Test getting the close character for a given open character.
  71. Args:
  72. input: The open character.
  73. output: The expected close character.
  74. """
  75. assert format.get_close_char(input) == output
  76. @pytest.mark.parametrize(
  77. "text,open,expected",
  78. [
  79. ("", "{", False),
  80. ("{wrap}", "{", True),
  81. ("{wrap", "{", False),
  82. ("{wrap}", "(", False),
  83. ("(wrap)", "(", True),
  84. ],
  85. )
  86. def test_is_wrapped(text: str, open: str, expected: bool):
  87. """Test checking if a string is wrapped in the given open and close characters.
  88. Args:
  89. text: The text to check.
  90. open: The open character.
  91. expected: Whether the text is wrapped.
  92. """
  93. assert format.is_wrapped(text, open) == expected
  94. @pytest.mark.parametrize(
  95. "text,open,check_first,num,expected",
  96. [
  97. ("", "{", True, 1, "{}"),
  98. ("wrap", "{", True, 1, "{wrap}"),
  99. ("wrap", "(", True, 1, "(wrap)"),
  100. ("wrap", "(", True, 2, "((wrap))"),
  101. ("(wrap)", "(", True, 1, "(wrap)"),
  102. ("{wrap}", "{", True, 2, "{wrap}"),
  103. ("(wrap)", "{", True, 1, "{(wrap)}"),
  104. ("(wrap)", "(", False, 1, "((wrap))"),
  105. ],
  106. )
  107. def test_wrap(text: str, open: str, expected: str, check_first: bool, num: int):
  108. """Test wrapping a string.
  109. Args:
  110. text: The text to wrap.
  111. open: The open character.
  112. expected: The expected output string.
  113. check_first: Whether to check if the text is already wrapped.
  114. num: The number of times to wrap the text.
  115. """
  116. assert format.wrap(text, open, check_first=check_first, num=num) == expected
  117. @pytest.mark.parametrize(
  118. "text,indent_level,expected",
  119. [
  120. ("", 2, ""),
  121. ("hello", 2, "hello"),
  122. ("hello\nworld", 2, " hello\n world\n"),
  123. ("hello\nworld", 4, " hello\n world\n"),
  124. (" hello\n world", 2, " hello\n world\n"),
  125. ],
  126. )
  127. def test_indent(text: str, indent_level: int, expected: str, windows_platform: bool):
  128. """Test indenting a string.
  129. Args:
  130. text: The text to indent.
  131. indent_level: The number of spaces to indent by.
  132. expected: The expected output string.
  133. windows_platform: Whether the system is windows.
  134. """
  135. assert format.indent(text, indent_level) == (
  136. expected.replace("\n", "\r\n") if windows_platform else expected
  137. )
  138. @pytest.mark.parametrize(
  139. "condition,true_value,false_value,expected",
  140. [
  141. ("cond", "<C1>", '""', '{cond ? <C1> : ""}'),
  142. ("cond", "<C1>", "<C2>", "{cond ? <C1> : <C2>}"),
  143. ],
  144. )
  145. def test_format_cond(condition: str, true_value: str, false_value: str, expected: str):
  146. """Test formatting a cond.
  147. Args:
  148. condition: The condition to check.
  149. true_value: The value to return if the condition is true.
  150. false_value: The value to return if the condition is false.
  151. expected: The expected output string.
  152. """
  153. assert format.format_cond(condition, true_value, false_value) == expected
  154. def test_merge_imports():
  155. """Test that imports are merged correctly."""
  156. d1 = {"react": {"Component"}}
  157. d2 = {"react": {"Component"}, "react-dom": {"render"}}
  158. d = imports.merge_imports(d1, d2)
  159. assert set(d.keys()) == {"react", "react-dom"}
  160. assert set(d["react"]) == {"Component"}
  161. assert set(d["react-dom"]) == {"render"}
  162. @pytest.mark.parametrize(
  163. "cls,expected",
  164. [
  165. (str, False),
  166. (int, False),
  167. (float, False),
  168. (bool, False),
  169. (List, True),
  170. (List[int], True),
  171. ],
  172. )
  173. def test_is_generic_alias(cls: type, expected: bool):
  174. """Test checking if a class is a GenericAlias.
  175. Args:
  176. cls: The class to check.
  177. expected: Whether the class is a GenericAlias.
  178. """
  179. assert types.is_generic_alias(cls) == expected
  180. @pytest.mark.parametrize(
  181. "route,expected",
  182. [
  183. ("", "index"),
  184. ("/", "index"),
  185. ("custom-route", "custom-route"),
  186. ("custom-route/", "custom-route"),
  187. ("/custom-route", "custom-route"),
  188. ],
  189. )
  190. def test_format_route(route: str, expected: bool):
  191. """Test formatting a route.
  192. Args:
  193. route: The route to format.
  194. expected: The expected formatted route.
  195. """
  196. assert format.format_route(route) == expected
  197. def test_setup_frontend(tmp_path, mocker):
  198. """Test checking if assets content have been
  199. copied into the .web/public folder.
  200. Args:
  201. tmp_path: root path of test case data directory
  202. mocker: mocker object to allow mocking
  203. """
  204. web_folder = tmp_path / ".web"
  205. web_public_folder = web_folder / "public"
  206. assets = tmp_path / "assets"
  207. assets.mkdir()
  208. (assets / "favicon.ico").touch()
  209. assert str(web_folder) == prerequisites.create_web_directory(tmp_path)
  210. mocker.patch("pynecone.utils.prerequisites.install_frontend_packages")
  211. build.setup_frontend(tmp_path)
  212. assert web_folder.exists()
  213. assert web_public_folder.exists()
  214. assert (web_public_folder / "favicon.ico").exists()
  215. @pytest.mark.parametrize(
  216. "input, output",
  217. [
  218. ("_hidden", True),
  219. ("not_hidden", False),
  220. ("__dundermethod__", False),
  221. ],
  222. )
  223. def test_is_backend_variable(input, output):
  224. assert types.is_backend_variable(input) == output
  225. @pytest.mark.parametrize(
  226. "cls, cls_check, expected",
  227. [
  228. (int, int, True),
  229. (int, float, False),
  230. (int, Union[int, float], True),
  231. (float, Union[int, float], True),
  232. (str, Union[int, float], False),
  233. (List[int], List[int], True),
  234. (List[int], List[float], True),
  235. (Union[int, float], Union[int, float], False),
  236. (Union[int, Var[int]], Var[int], False),
  237. (int, Any, True),
  238. (Any, Any, True),
  239. (Union[int, float], Any, True),
  240. ],
  241. )
  242. def test_issubclass(cls: type, cls_check: type, expected: bool):
  243. assert types._issubclass(cls, cls_check) == expected
  244. def test_format_sub_state_event(upload_sub_state_event_spec):
  245. """Test formatting an upload event spec of substate.
  246. Args:
  247. upload_sub_state_event_spec: The event spec fixture.
  248. """
  249. assert (
  250. format.format_upload_event(upload_sub_state_event_spec)
  251. == "uploadFiles(base_state, result, setResult, base_state.files, "
  252. '"base_state.sub_upload_state.handle_upload",UPLOAD)'
  253. )
  254. def test_format_upload_event(upload_event_spec):
  255. """Test formatting an upload event spec.
  256. Args:
  257. upload_event_spec: The event spec fixture.
  258. """
  259. assert (
  260. format.format_upload_event(upload_event_spec)
  261. == "uploadFiles(upload_state, result, setResult, "
  262. 'upload_state.files, "upload_state.handle_upload1",'
  263. "UPLOAD)"
  264. )
  265. @pytest.mark.parametrize(
  266. "app_name,expected_config_name",
  267. [
  268. ("appname", "AppnameConfig"),
  269. ("app_name", "AppnameConfig"),
  270. ("app-name", "AppnameConfig"),
  271. ("appname2.io", "AppnameioConfig"),
  272. ],
  273. )
  274. def test_create_config(app_name, expected_config_name, mocker):
  275. """Test templates.PCCONFIG is formatted with correct app name and config class name.
  276. Args:
  277. app_name: App name.
  278. expected_config_name: Expected config name.
  279. mocker: Mocker object.
  280. """
  281. mocker.patch("builtins.open")
  282. tmpl_mock = mocker.patch("pynecone.compiler.templates.PCCONFIG")
  283. prerequisites.create_config(app_name)
  284. tmpl_mock.format.assert_called_with(
  285. app_name=app_name, config_name=expected_config_name
  286. )