test_utils.py 10 KB

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