Add basic unit tests (#7)
* Unit tests for components, state, and utils
This commit is contained in:
parent
7d91a9db68
commit
29e37350e5
@ -1,5 +1,6 @@
|
|||||||
"""Welcome to Pynecone! This file outlines the steps to create a basic app."""
|
"""Welcome to Pynecone! This file outlines the steps to create a basic app."""
|
||||||
import pcconfig
|
import pcconfig
|
||||||
|
|
||||||
import pynecone as pc
|
import pynecone as pc
|
||||||
|
|
||||||
docs_url = "https://pynecone.io/docs/getting-started/introduction"
|
docs_url = "https://pynecone.io/docs/getting-started/introduction"
|
||||||
@ -8,6 +9,7 @@ filename = f"{pcconfig.APP_NAME}/{pcconfig.APP_NAME}.py"
|
|||||||
|
|
||||||
class State(pc.State):
|
class State(pc.State):
|
||||||
"""The app state."""
|
"""The app state."""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@ -21,10 +23,10 @@ def index():
|
|||||||
href=docs_url,
|
href=docs_url,
|
||||||
border="0.1em solid",
|
border="0.1em solid",
|
||||||
padding="0.5em",
|
padding="0.5em",
|
||||||
border_radius="0.5em"
|
border_radius="0.5em",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
padding="5em"
|
padding="5em",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -32,4 +34,3 @@ def index():
|
|||||||
app = pc.App(state=State)
|
app = pc.App(state=State)
|
||||||
app.add_page(index)
|
app.add_page(index)
|
||||||
app.compile()
|
app.compile()
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
"""The main Pynecone app."""
|
"""The main Pynecone app."""
|
||||||
|
|
||||||
|
import os
|
||||||
import re
|
import re
|
||||||
from typing import Any, Callable, Coroutine, Dict, List, Optional, Tuple, Type, Union
|
from typing import Any, Callable, Coroutine, Dict, List, Optional, Tuple, Type, Union
|
||||||
|
|
||||||
@ -12,7 +13,7 @@ from pynecone.compiler import compiler
|
|||||||
from pynecone.compiler import utils as compiler_utils
|
from pynecone.compiler import utils as compiler_utils
|
||||||
from pynecone.components.component import Component, ComponentStyle
|
from pynecone.components.component import Component, ComponentStyle
|
||||||
from pynecone.event import Event
|
from pynecone.event import Event
|
||||||
from pynecone.middleware import HydrateMiddleware, LoggingMiddleware, Middleware
|
from pynecone.middleware import HydrateMiddleware, Middleware
|
||||||
from pynecone.model import Model
|
from pynecone.model import Model
|
||||||
from pynecone.state import DefaultState, Delta, State, StateManager, StateUpdate
|
from pynecone.state import DefaultState, Delta, State, StateManager, StateUpdate
|
||||||
|
|
||||||
@ -56,7 +57,6 @@ class App(Base):
|
|||||||
|
|
||||||
# Add middleware.
|
# Add middleware.
|
||||||
self.middleware.append(HydrateMiddleware())
|
self.middleware.append(HydrateMiddleware())
|
||||||
self.middleware.append(LoggingMiddleware())
|
|
||||||
|
|
||||||
# Set up the state manager.
|
# Set up the state manager.
|
||||||
self.state_manager.set(state=self.state)
|
self.state_manager.set(state=self.state)
|
||||||
@ -187,7 +187,7 @@ class App(Base):
|
|||||||
|
|
||||||
from pynecone.var import BaseVar
|
from pynecone.var import BaseVar
|
||||||
|
|
||||||
parts = path.split("/")
|
parts = os.path.split(path)
|
||||||
check = re.compile(r"^\[(.+)\]$")
|
check = re.compile(r"^\[(.+)\]$")
|
||||||
args = []
|
args = []
|
||||||
for part in parts:
|
for part in parts:
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
"""Templates to use in the pynecone compiler."""
|
"""Templates to use in the pynecone compiler."""
|
||||||
|
|
||||||
from typing import Callable, Optional, Set
|
from typing import Optional, Set
|
||||||
|
|
||||||
from pynecone import constants, utils
|
from pynecone import constants
|
||||||
from pynecone.utils import join
|
from pynecone.utils import join
|
||||||
|
|
||||||
# Template for the Pynecone config file.
|
# Template for the Pynecone config file.
|
||||||
|
@ -327,7 +327,7 @@ class Component(Base, ABC):
|
|||||||
for child in self.children:
|
for child in self.children:
|
||||||
child_code = child.get_custom_code()
|
child_code = child.get_custom_code()
|
||||||
if child_code != "" and child_code not in code:
|
if child_code != "" and child_code not in code:
|
||||||
code += child_code
|
code += "\n" + child_code
|
||||||
return code
|
return code
|
||||||
|
|
||||||
def _get_imports(self) -> ImportDict:
|
def _get_imports(self) -> ImportDict:
|
||||||
|
@ -368,13 +368,16 @@ class State(Base, ABC):
|
|||||||
Returns:
|
Returns:
|
||||||
The delta for the state.
|
The delta for the state.
|
||||||
"""
|
"""
|
||||||
|
delta = {}
|
||||||
|
|
||||||
# Return the dirty vars, as well as all computed vars.
|
# Return the dirty vars, as well as all computed vars.
|
||||||
delta = {
|
subdelta = {
|
||||||
self.get_full_name(): {
|
prop: getattr(self, prop)
|
||||||
prop: getattr(self, prop)
|
for prop in self.dirty_vars | set(self.computed_vars.keys())
|
||||||
for prop in self.dirty_vars | set(self.computed_vars.keys())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if len(subdelta) > 0:
|
||||||
|
delta[self.get_full_name()] = subdelta
|
||||||
|
|
||||||
# Recursively find the substate deltas.
|
# Recursively find the substate deltas.
|
||||||
for substate in self.dirty_substates:
|
for substate in self.dirty_substates:
|
||||||
delta.update(self.substates[substate].get_delta())
|
delta.update(self.substates[substate].get_delta())
|
||||||
|
@ -4,7 +4,7 @@ from __future__ import annotations
|
|||||||
import json
|
import json
|
||||||
from abc import ABC
|
from abc import ABC
|
||||||
from typing import _GenericAlias # type: ignore
|
from typing import _GenericAlias # type: ignore
|
||||||
from typing import TYPE_CHECKING, Any, Callable, List, Optional, Type, Union
|
from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Type, Union
|
||||||
|
|
||||||
from plotly.graph_objects import Figure
|
from plotly.graph_objects import Figure
|
||||||
from plotly.io import to_json
|
from plotly.io import to_json
|
||||||
@ -153,7 +153,7 @@ class Var(ABC):
|
|||||||
type_ = utils.get_args(self.type_)[0]
|
type_ = utils.get_args(self.type_)[0]
|
||||||
else:
|
else:
|
||||||
type_ = Any
|
type_ = Any
|
||||||
elif utils.is_dataframe(self.type_):
|
elif utils._issubclass(self.type_, Dict) or utils.is_dataframe(self.type_):
|
||||||
if isinstance(i, str):
|
if isinstance(i, str):
|
||||||
i = utils.wrap(i, '"')
|
i = utils.wrap(i, '"')
|
||||||
if isinstance(self.type_, _GenericAlias):
|
if isinstance(self.type_, _GenericAlias):
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "pynecone-io"
|
name = "pynecone-io"
|
||||||
version = "0.1.2"
|
version = "0.1.3"
|
||||||
description = ""
|
description = ""
|
||||||
authors = [
|
authors = [
|
||||||
"Nikhil Rao <nikhil@pynecone.io>",
|
"Nikhil Rao <nikhil@pynecone.io>",
|
||||||
|
1
tests/__init__.py
Normal file
1
tests/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
"""Root directory for tests."""
|
1
tests/compiler/__init__.py
Normal file
1
tests/compiler/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
"""Compiler tests."""
|
72
tests/compiler/test_compiler.py
Normal file
72
tests/compiler/test_compiler.py
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
from typing import Set
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from pynecone.compiler import utils
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"lib,fields,output",
|
||||||
|
[
|
||||||
|
("axios", {"axios"}, 'import axios from "axios"'),
|
||||||
|
("axios", {"foo", "bar"}, 'import {bar, foo} from "axios"'),
|
||||||
|
("axios", {"axios", "foo", "bar"}, 'import axios, {bar, foo} from "axios"'),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_compile_import_statement(lib: str, fields: Set[str], output: str):
|
||||||
|
"""Test the compile_import_statement function.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
lib: The library name.
|
||||||
|
fields: The fields to import.
|
||||||
|
output: The expected output.
|
||||||
|
"""
|
||||||
|
assert utils.compile_import_statement(lib, fields) == output
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"import_dict,output",
|
||||||
|
[
|
||||||
|
({}, ""),
|
||||||
|
({"axios": {"axios"}}, 'import axios from "axios"'),
|
||||||
|
({"axios": {"foo", "bar"}}, 'import {bar, foo} from "axios"'),
|
||||||
|
(
|
||||||
|
{"axios": {"axios", "foo", "bar"}, "react": {"react"}},
|
||||||
|
'import axios, {bar, foo} from "axios"\nimport react from "react"',
|
||||||
|
),
|
||||||
|
({"": {"lib1.js", "lib2.js"}}, 'import "lib1.js"\nimport "lib2.js"'),
|
||||||
|
(
|
||||||
|
{"": {"lib1.js", "lib2.js"}, "axios": {"axios"}},
|
||||||
|
'import "lib1.js"\nimport "lib2.js"\nimport axios from "axios"',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_compile_imports(import_dict: utils.ImportDict, output: str):
|
||||||
|
"""Test the compile_imports function.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
import_dict: The import dictionary.
|
||||||
|
output: The expected output.
|
||||||
|
"""
|
||||||
|
assert utils.compile_imports(import_dict) == output
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"name,value,output",
|
||||||
|
[
|
||||||
|
("foo", "bar", 'const foo = "bar"'),
|
||||||
|
("num", 1, "const num = 1"),
|
||||||
|
("check", False, "const check = false"),
|
||||||
|
("arr", [1, 2, 3], "const arr = [1, 2, 3]"),
|
||||||
|
("obj", {"foo": "bar"}, 'const obj = {"foo": "bar"}'),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_compile_constant_declaration(name: str, value: str, output: str):
|
||||||
|
"""Test the compile_constant_declaration function.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name: The name of the constant.
|
||||||
|
value: The value of the constant.
|
||||||
|
output: The expected output.
|
||||||
|
"""
|
||||||
|
assert utils.compile_constant_declaration(name, value) == output
|
1
tests/components/__init__.py
Normal file
1
tests/components/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
"""Component tests."""
|
152
tests/components/test_component.py
Normal file
152
tests/components/test_component.py
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
from typing import Type
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from pynecone.components.component import Component, ImportDict
|
||||||
|
from pynecone.event import EventHandler
|
||||||
|
from pynecone.style import Style
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def component1() -> Type[Component]:
|
||||||
|
"""A test component.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A test component.
|
||||||
|
"""
|
||||||
|
|
||||||
|
class TestComponent1(Component):
|
||||||
|
def _get_imports(self) -> ImportDict:
|
||||||
|
return {"react": {"Component"}}
|
||||||
|
|
||||||
|
def _get_custom_code(self) -> str:
|
||||||
|
return "console.log('component1')"
|
||||||
|
|
||||||
|
return TestComponent1
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def component2() -> Type[Component]:
|
||||||
|
"""A test component.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A test component.
|
||||||
|
"""
|
||||||
|
|
||||||
|
class TestComponent2(Component):
|
||||||
|
def _get_imports(self) -> ImportDict:
|
||||||
|
return {"react-redux": {"connect"}}
|
||||||
|
|
||||||
|
def _get_custom_code(self) -> str:
|
||||||
|
return "console.log('component2')"
|
||||||
|
|
||||||
|
return TestComponent2
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def on_click1() -> EventHandler:
|
||||||
|
"""A sample on click function.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A sample on click function.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def on_click1():
|
||||||
|
pass
|
||||||
|
|
||||||
|
return EventHandler(fn=on_click1)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def on_click2() -> EventHandler:
|
||||||
|
"""A sample on click function.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A sample on click function.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def on_click2():
|
||||||
|
pass
|
||||||
|
|
||||||
|
return EventHandler(fn=on_click2)
|
||||||
|
|
||||||
|
|
||||||
|
def test_set_style_attrs(component1: Type[Component]):
|
||||||
|
"""Test that style attributes are set in the dict.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
component1: A test component.
|
||||||
|
"""
|
||||||
|
component = component1(color="white", text_align="center")
|
||||||
|
assert component.style["color"] == "white"
|
||||||
|
assert component.style["textAlign"] == "center"
|
||||||
|
|
||||||
|
|
||||||
|
def test_create_component(component1: Type[Component]):
|
||||||
|
"""Test that the component is created correctly.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
component1: A test component.
|
||||||
|
"""
|
||||||
|
children = [component1() for _ in range(3)]
|
||||||
|
attrs = {"color": "white", "text_align": "center"}
|
||||||
|
c = component1.create(*children, **attrs)
|
||||||
|
assert isinstance(c, component1)
|
||||||
|
assert c.children == children
|
||||||
|
assert c.style == {"color": "white", "textAlign": "center"}
|
||||||
|
|
||||||
|
|
||||||
|
def test_add_style(component1: Type[Component], component2: Type[Component]):
|
||||||
|
"""Test adding a style to a component.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
component1: A test component.
|
||||||
|
component2: A test component.
|
||||||
|
"""
|
||||||
|
style = {
|
||||||
|
component1: Style({"color": "white"}),
|
||||||
|
component2: Style({"color": "black"}),
|
||||||
|
}
|
||||||
|
c1 = component1().add_style(style) # type: ignore
|
||||||
|
c2 = component2().add_style(style) # type: ignore
|
||||||
|
assert c1.style["color"] == "white"
|
||||||
|
assert c2.style["color"] == "black"
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_imports(component1: Type[Component], component2: Type[Component]):
|
||||||
|
"""Test getting the imports of a component.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
component1: A test component.
|
||||||
|
component2: A test component.
|
||||||
|
"""
|
||||||
|
c1 = component1.create()
|
||||||
|
c2 = component2.create(c1)
|
||||||
|
assert c1.get_imports() == {"react": {"Component"}}
|
||||||
|
assert c2.get_imports() == {"react-redux": {"connect"}, "react": {"Component"}}
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_custom_code(component1: Type[Component], component2: Type[Component]):
|
||||||
|
"""Test getting the custom code of a component.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
component1: A test component.
|
||||||
|
component2: A test component.
|
||||||
|
"""
|
||||||
|
# Check that the code gets compiled correctly.
|
||||||
|
c1 = component1.create()
|
||||||
|
c2 = component2.create()
|
||||||
|
assert c1.get_custom_code() == "console.log('component1')"
|
||||||
|
assert c2.get_custom_code() == "console.log('component2')"
|
||||||
|
|
||||||
|
# Check that nesting components compiles both codes.
|
||||||
|
c1 = component1.create(c2)
|
||||||
|
assert (
|
||||||
|
c1.get_custom_code() == "console.log('component1')\nconsole.log('component2')"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Check that code is not duplicated.
|
||||||
|
c1 = component1.create(c2, c2, c1, c1)
|
||||||
|
assert (
|
||||||
|
c1.get_custom_code() == "console.log('component1')\nconsole.log('component2')"
|
||||||
|
)
|
@ -1,9 +1,9 @@
|
|||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
|
||||||
import pydantic
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from pynecone.components.tags import CondTag, Tag
|
from pynecone.components import Box
|
||||||
|
from pynecone.components.tags import CondTag, IterTag, Tag
|
||||||
from pynecone.event import EventHandler, EventSpec, EventChain
|
from pynecone.event import EventHandler, EventSpec, EventChain
|
||||||
from pynecone.var import BaseVar, Var
|
from pynecone.var import BaseVar, Var
|
||||||
|
|
||||||
@ -13,29 +13,7 @@ def mock_event(arg):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"cond,valid",
|
"prop,formatted",
|
||||||
[
|
|
||||||
(BaseVar(name="p", type_=bool), True),
|
|
||||||
(BaseVar(name="p", type_=int), False),
|
|
||||||
(BaseVar(name="p", type_=str), False),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
def test_validate_cond(cond: BaseVar, valid: bool):
|
|
||||||
"""Test that the cond is a boolean.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
cond: The cond to test.
|
|
||||||
valid: The expected validity of the cond.
|
|
||||||
"""
|
|
||||||
if not valid:
|
|
||||||
with pytest.raises(pydantic.ValidationError):
|
|
||||||
Tag(cond=cond)
|
|
||||||
else:
|
|
||||||
assert cond == Tag(cond=cond).cond
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
|
||||||
"attr,formatted",
|
|
||||||
[
|
[
|
||||||
("string", '"string"'),
|
("string", '"string"'),
|
||||||
("{wrapped_string}", "{wrapped_string}"),
|
("{wrapped_string}", "{wrapped_string}"),
|
||||||
@ -47,31 +25,35 @@ def test_validate_cond(cond: BaseVar, valid: bool):
|
|||||||
(["a", "b", "c"], '{["a", "b", "c"]}'),
|
(["a", "b", "c"], '{["a", "b", "c"]}'),
|
||||||
({"a": 1, "b": 2, "c": 3}, '{{"a": 1, "b": 2, "c": 3}}'),
|
({"a": 1, "b": 2, "c": 3}, '{{"a": 1, "b": 2, "c": 3}}'),
|
||||||
(
|
(
|
||||||
EventSpec(handler=EventHandler(fn=mock_event)),
|
EventChain(events=[EventSpec(handler=EventHandler(fn=mock_event))]),
|
||||||
'{() => Event([E("mock_event", {})])}',
|
'{() => Event([E("mock_event", {})])}',
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
EventSpec(
|
EventChain(
|
||||||
handler=EventHandler(fn=mock_event),
|
events=[
|
||||||
local_args=("e",),
|
EventSpec(
|
||||||
args=(("arg", "e.target.value"),),
|
handler=EventHandler(fn=mock_event),
|
||||||
|
local_args=("e",),
|
||||||
|
args=(("arg", "e.target.value"),),
|
||||||
|
)
|
||||||
|
]
|
||||||
),
|
),
|
||||||
'{(e) => Event([E("mock_event", {arg:e.target.value})])}',
|
'{(e) => Event([E("mock_event", {arg:e.target.value})])}',
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_format_value(attr: Var, formatted: str):
|
def test_format_value(prop: Var, formatted: str):
|
||||||
"""Test that the formatted value of an attribute is correct.
|
"""Test that the formatted value of an prop is correct.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
attr: The attribute to test.
|
prop: The prop to test.
|
||||||
formatted: The expected formatted value.
|
formatted: The expected formatted value.
|
||||||
"""
|
"""
|
||||||
assert Tag.format_attr_value(attr) == formatted
|
assert Tag.format_prop(prop) == formatted
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"attrs,formatted",
|
"props,formatted",
|
||||||
[
|
[
|
||||||
({}, ""),
|
({}, ""),
|
||||||
({"key": 1}, "key={1}"),
|
({"key": 1}, "key={1}"),
|
||||||
@ -79,18 +61,18 @@ def test_format_value(attr: Var, formatted: str):
|
|||||||
({"key": True, "key2": "value2"}, 'key={true}\nkey2="value2"'),
|
({"key": True, "key2": "value2"}, 'key={true}\nkey2="value2"'),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_format_attrs(attrs: Dict[str, Var], formatted: str):
|
def test_format_props(props: Dict[str, Var], formatted: str):
|
||||||
"""Test that the formatted attributes are correct.
|
"""Test that the formatted props are correct.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
attrs: The attributes to test.
|
props: The props to test.
|
||||||
formatted: The expected formatted attributes.
|
formatted: The expected formatted props.
|
||||||
"""
|
"""
|
||||||
assert Tag(attrs=attrs).format_attrs() == formatted
|
assert Tag(props=props).format_props() == formatted
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"attr,valid",
|
"prop,valid",
|
||||||
[
|
[
|
||||||
(1, True),
|
(1, True),
|
||||||
(3.14, True),
|
(3.14, True),
|
||||||
@ -101,23 +83,23 @@ def test_format_attrs(attrs: Dict[str, Var], formatted: str):
|
|||||||
(None, False),
|
(None, False),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_is_valid_attr(attr: Var, valid: bool):
|
def test_is_valid_prop(prop: Var, valid: bool):
|
||||||
"""Test that the attribute is valid.
|
"""Test that the prop is valid.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
attr: The attribute to test.
|
prop: The prop to test.
|
||||||
valid: The expected validity of the attribute.
|
valid: The expected validity of the prop.
|
||||||
"""
|
"""
|
||||||
assert Tag.is_valid_attr(attr) == valid
|
assert Tag.is_valid_prop(prop) == valid
|
||||||
|
|
||||||
|
|
||||||
def test_add_props():
|
def test_add_props():
|
||||||
"""Test that the attributes are added."""
|
"""Test that the props are added."""
|
||||||
tag = Tag().add_props(key="value", key2=42, invalid=None, invalid2={})
|
tag = Tag().add_props(key="value", key2=42, invalid=None, invalid2={})
|
||||||
assert tag.attrs["key"] == Var.create("value")
|
assert tag.props["key"] == Var.create("value")
|
||||||
assert tag.attrs["key2"] == Var.create(42)
|
assert tag.props["key2"] == Var.create(42)
|
||||||
assert "invalid" not in tag.attrs
|
assert "invalid" not in tag.props
|
||||||
assert "invalid2" not in tag.attrs
|
assert "invalid2" not in tag.props
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
@ -128,25 +110,17 @@ def test_add_props():
|
|||||||
(Tag(contents="hello"), "<>hello</>"),
|
(Tag(contents="hello"), "<>hello</>"),
|
||||||
(Tag(name="h1", contents="hello"), "<h1>hello</h1>"),
|
(Tag(name="h1", contents="hello"), "<h1>hello</h1>"),
|
||||||
(
|
(
|
||||||
Tag(name="box", attrs={"color": "red", "textAlign": "center"}),
|
Tag(name="box", props={"color": "red", "textAlign": "center"}),
|
||||||
'<box color="red"\ntextAlign="center"/>',
|
'<box color="red"\ntextAlign="center"/>',
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
Tag(
|
Tag(
|
||||||
name="box",
|
name="box",
|
||||||
attrs={"color": "red", "textAlign": "center"},
|
props={"color": "red", "textAlign": "center"},
|
||||||
contents="text",
|
contents="text",
|
||||||
),
|
),
|
||||||
'<box color="red"\ntextAlign="center">text</box>',
|
'<box color="red"\ntextAlign="center">text</box>',
|
||||||
),
|
),
|
||||||
(
|
|
||||||
Tag(
|
|
||||||
name="h1",
|
|
||||||
contents="hello",
|
|
||||||
cond=BaseVar(name="logged_in", type_=bool),
|
|
||||||
),
|
|
||||||
'{logged_in ? <h1>hello</h1> : ""}',
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_format_tag(tag: Tag, expected: str):
|
def test_format_tag(tag: Tag, expected: str):
|
||||||
@ -167,15 +141,3 @@ def test_format_cond_tag():
|
|||||||
cond=BaseVar(name="logged_in", type_=bool),
|
cond=BaseVar(name="logged_in", type_=bool),
|
||||||
)
|
)
|
||||||
assert str(tag) == "{logged_in ? <h1>True content</h1> : <h2>False content</h2>}"
|
assert str(tag) == "{logged_in ? <h1>True content</h1> : <h2>False content</h2>}"
|
||||||
|
|
||||||
|
|
||||||
def test_format_iter_tag():
|
|
||||||
"""Test that the formatted iter tag is correct."""
|
|
||||||
# def render_todo(todo: str):
|
|
||||||
# return Tag(name="Text", contents=todo)
|
|
||||||
|
|
||||||
# tag = IterTag(
|
|
||||||
# iterable=BaseVar(name="todos", type_=list),
|
|
||||||
# render_fn=render_todo
|
|
||||||
# )
|
|
||||||
# assert str(tag) == '{state.todos.map(render_todo)}'
|
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
|
from typing import Type
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from pynecone.base import Base
|
|
||||||
from pynecone.app import App, DefaultState
|
from pynecone.app import App, DefaultState
|
||||||
from pynecone.middleware import HydrateMiddleware
|
from pynecone.middleware import HydrateMiddleware
|
||||||
from pynecone.components import Box
|
from pynecone.components import Box
|
||||||
|
from pynecone.state import State
|
||||||
|
from pynecone.style import Style
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@ -36,25 +39,32 @@ def about_page():
|
|||||||
return about
|
return about
|
||||||
|
|
||||||
|
|
||||||
def test_default_state(app: App) -> None:
|
@pytest.fixture()
|
||||||
"""Test creating an app with no state.
|
def TestState() -> Type[State]:
|
||||||
|
"""A default state.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A default state.
|
||||||
|
"""
|
||||||
|
|
||||||
|
class TestState(State):
|
||||||
|
var: int
|
||||||
|
|
||||||
|
return TestState
|
||||||
|
|
||||||
|
|
||||||
|
def test_default_app(app: App):
|
||||||
|
"""Test creating an app with no args.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
app: The app to test.
|
app: The app to test.
|
||||||
"""
|
"""
|
||||||
assert app.state() == DefaultState()
|
assert app.state() == DefaultState()
|
||||||
|
|
||||||
|
|
||||||
def test_default_middleware(app: App) -> None:
|
|
||||||
"""Test creating an app with no middleware.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
app: The app to test.
|
|
||||||
"""
|
|
||||||
assert app.middleware == [HydrateMiddleware()]
|
assert app.middleware == [HydrateMiddleware()]
|
||||||
|
assert app.style == Style()
|
||||||
|
|
||||||
|
|
||||||
def test_add_page_default_route(app: App, index_page, about_page) -> None:
|
def test_add_page_default_route(app: App, index_page, about_page):
|
||||||
"""Test adding a page to an app.
|
"""Test adding a page to an app.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -69,7 +79,7 @@ def test_add_page_default_route(app: App, index_page, about_page) -> None:
|
|||||||
assert set(app.pages.keys()) == {"index", "about"}
|
assert set(app.pages.keys()) == {"index", "about"}
|
||||||
|
|
||||||
|
|
||||||
def test_add_page_set_route(app: App, index_page) -> None:
|
def test_add_page_set_route(app: App, index_page):
|
||||||
"""Test adding a page to an app.
|
"""Test adding a page to an app.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -79,3 +89,62 @@ def test_add_page_set_route(app: App, index_page) -> None:
|
|||||||
assert app.pages == {}
|
assert app.pages == {}
|
||||||
app.add_page(index_page, path="/test")
|
app.add_page(index_page, path="/test")
|
||||||
assert set(app.pages.keys()) == {"test"}
|
assert set(app.pages.keys()) == {"test"}
|
||||||
|
|
||||||
|
|
||||||
|
def test_add_page_set_route_nested(app: App, index_page):
|
||||||
|
"""Test adding a page to an app.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
app: The app to test.
|
||||||
|
index_page: The index page.
|
||||||
|
"""
|
||||||
|
assert app.pages == {}
|
||||||
|
app.add_page(index_page, path="/test/nested")
|
||||||
|
assert set(app.pages.keys()) == {"test/nested"}
|
||||||
|
|
||||||
|
|
||||||
|
def test_initialize_with_state(TestState: Type[State]):
|
||||||
|
"""Test setting the state of an app.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
DefaultState: The default state.
|
||||||
|
"""
|
||||||
|
app = App(state=TestState)
|
||||||
|
assert app.state == TestState
|
||||||
|
|
||||||
|
# Get a state for a given token.
|
||||||
|
token = "token"
|
||||||
|
state = app.get_state(token)
|
||||||
|
assert isinstance(state, TestState)
|
||||||
|
assert state.var == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_set_and_get_state(TestState: Type[State]):
|
||||||
|
"""Test setting and getting the state of an app with different tokens.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
DefaultState: The default state.
|
||||||
|
"""
|
||||||
|
app = App(state=TestState)
|
||||||
|
|
||||||
|
# Create two tokens.
|
||||||
|
token1 = "token1"
|
||||||
|
token2 = "token2"
|
||||||
|
|
||||||
|
# Get the default state for each token.
|
||||||
|
state1 = app.get_state(token1)
|
||||||
|
state2 = app.get_state(token2)
|
||||||
|
assert state1.var == 0
|
||||||
|
assert state2.var == 0
|
||||||
|
|
||||||
|
# Set the vars to different values.
|
||||||
|
state1.var = 1
|
||||||
|
state2.var = 2
|
||||||
|
app.set_state(token1, state1)
|
||||||
|
app.set_state(token2, state2)
|
||||||
|
|
||||||
|
# Get the states again and check the values.
|
||||||
|
state1 = app.get_state(token1)
|
||||||
|
state2 = app.get_state(token2)
|
||||||
|
assert state1.var == 1
|
||||||
|
assert state2.var == 2
|
||||||
|
47
tests/test_base.py
Normal file
47
tests/test_base.py
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from pynecone.base import Base
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def child() -> Base:
|
||||||
|
"""A child class.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A child class.
|
||||||
|
"""
|
||||||
|
|
||||||
|
class Child(Base):
|
||||||
|
num: float
|
||||||
|
key: str
|
||||||
|
|
||||||
|
return Child(num=3.14, key="pi")
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_fields(child):
|
||||||
|
"""Test that the fields are set correctly.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
child: A child class.
|
||||||
|
"""
|
||||||
|
assert child.get_fields().keys() == {"num", "key"}
|
||||||
|
|
||||||
|
|
||||||
|
def test_set(child):
|
||||||
|
"""Test setting fields.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
child: A child class.
|
||||||
|
"""
|
||||||
|
child.set(num=1, key="a")
|
||||||
|
assert child.num == 1
|
||||||
|
assert child.key == "a"
|
||||||
|
|
||||||
|
|
||||||
|
def test_json(child):
|
||||||
|
"""Test converting to json.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
child: A child class.
|
||||||
|
"""
|
||||||
|
assert child.json().replace(" ", "") == '{"num":3.14,"key":"pi"}'
|
@ -1,15 +1,35 @@
|
|||||||
from datetime import datetime
|
import pytest
|
||||||
|
|
||||||
from pynecone.event import Event
|
from pynecone.event import Event, EventHandler, EventSpec
|
||||||
|
|
||||||
|
|
||||||
# def test_event_default_date():
|
def test_create_event():
|
||||||
# """Test that that the default date is set."""
|
"""Test creating an event."""
|
||||||
# t1 = datetime.now()
|
event = Event(token="token", name="state.do_thing", payload={"arg": "value"})
|
||||||
|
assert event.token == "token"
|
||||||
|
assert event.name == "state.do_thing"
|
||||||
|
assert event.payload == {"arg": "value"}
|
||||||
|
|
||||||
# e1 = Event(token="t", name="e1")
|
|
||||||
# e2 = Event(token="t", name="e2")
|
|
||||||
|
|
||||||
# t2 = datetime.now()
|
def test_call_event_handler():
|
||||||
|
"""Test that calling an event handler creates an event spec."""
|
||||||
|
|
||||||
# assert t1 < e1.date < e2.date < t2
|
def test_fn():
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_fn_with_args(_, arg1, arg2):
|
||||||
|
pass
|
||||||
|
|
||||||
|
handler = EventHandler(fn=test_fn)
|
||||||
|
event_spec = handler()
|
||||||
|
|
||||||
|
assert event_spec.handler == handler
|
||||||
|
assert event_spec.local_args == ()
|
||||||
|
assert event_spec.args == ()
|
||||||
|
|
||||||
|
handler = EventHandler(fn=test_fn_with_args)
|
||||||
|
event_spec = handler("first", "second")
|
||||||
|
|
||||||
|
assert event_spec.handler == handler
|
||||||
|
assert event_spec.local_args == ()
|
||||||
|
assert event_spec.args == (("arg1", "first"), ("arg2", "second"))
|
||||||
|
@ -643,14 +643,15 @@ async def test_process_event_simple(TestState):
|
|||||||
test_state = TestState()
|
test_state = TestState()
|
||||||
assert test_state.num1 == 0
|
assert test_state.num1 == 0
|
||||||
|
|
||||||
event = Event(token="t", name="set_num1", payload={"num1": 69})
|
event = Event(token="t", name="set_num1", payload={"value": 69})
|
||||||
delta = await test_state.process(event)
|
update = await test_state.process(event)
|
||||||
|
|
||||||
# The event should update the value.
|
# The event should update the value.
|
||||||
assert test_state.num1 == 69
|
assert test_state.num1 == 69
|
||||||
|
|
||||||
# The delta should contain the changes, including computed vars.
|
# The delta should contain the changes, including computed vars.
|
||||||
assert delta == {"test_state": {"num1": 69, "sum": 72.14, "upper": ""}}
|
assert update.delta == {"test_state": {"num1": 69, "sum": 72.14, "upper": ""}}
|
||||||
|
assert update.events == []
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
@ -672,10 +673,13 @@ async def test_process_event_substate(TestState, ChildState, GrandchildState):
|
|||||||
event = Event(
|
event = Event(
|
||||||
token="t", name="child_state.change_both", payload={"value": "hi", "count": 12}
|
token="t", name="child_state.change_both", payload={"value": "hi", "count": 12}
|
||||||
)
|
)
|
||||||
delta = await test_state.process(event)
|
update = await test_state.process(event)
|
||||||
assert child_state.value == "HI"
|
assert child_state.value == "HI"
|
||||||
assert child_state.count == 24
|
assert child_state.count == 24
|
||||||
assert delta == {"test_state.child_state": {"value": "HI", "count": 24}}
|
assert update.delta == {
|
||||||
|
"test_state.child_state": {"value": "HI", "count": 24},
|
||||||
|
"test_state": {"sum": 3.14, "upper": ""},
|
||||||
|
}
|
||||||
test_state.clean()
|
test_state.clean()
|
||||||
|
|
||||||
# Test with the granchild state.
|
# Test with the granchild state.
|
||||||
@ -683,11 +687,14 @@ async def test_process_event_substate(TestState, ChildState, GrandchildState):
|
|||||||
event = Event(
|
event = Event(
|
||||||
token="t",
|
token="t",
|
||||||
name="child_state.grandchild_state.set_value2",
|
name="child_state.grandchild_state.set_value2",
|
||||||
payload={"value2": "new"},
|
payload={"value": "new"},
|
||||||
)
|
)
|
||||||
delta = await test_state.process(event)
|
update = await test_state.process(event)
|
||||||
assert grandchild_state.value2 == "new"
|
assert grandchild_state.value2 == "new"
|
||||||
assert delta == {"test_state.child_state.grandchild_state": {"value2": "new"}}
|
assert update.delta == {
|
||||||
|
"test_state.child_state.grandchild_state": {"value2": "new"},
|
||||||
|
"test_state": {"sum": 3.14, "upper": ""},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
@ -699,7 +706,7 @@ async def test_process_event_substate_set_parent_state(TestState, ChildState):
|
|||||||
ChildState: The child state class.
|
ChildState: The child state class.
|
||||||
"""
|
"""
|
||||||
test_state = TestState()
|
test_state = TestState()
|
||||||
event = Event(token="t", name="child_state.set_num1", payload={"num1": 69})
|
event = Event(token="t", name="child_state.set_num1", payload={"value": 69})
|
||||||
delta = await test_state.process(event)
|
update = await test_state.process(event)
|
||||||
assert test_state.num1 == 69
|
assert test_state.num1 == 69
|
||||||
assert delta == {"test_state": {"num1": 69, "sum": 72.14, "upper": ""}}
|
assert update.delta == {"test_state": {"num1": 69, "sum": 72.14, "upper": ""}}
|
||||||
|
@ -11,6 +11,8 @@ from pynecone import utils
|
|||||||
("Hello", "hello"),
|
("Hello", "hello"),
|
||||||
("camelCase", "camel_case"),
|
("camelCase", "camel_case"),
|
||||||
("camelTwoHumps", "camel_two_humps"),
|
("camelTwoHumps", "camel_two_humps"),
|
||||||
|
("_start_with_underscore", "_start_with_underscore"),
|
||||||
|
("__start_with_double_underscore", "__start_with_double_underscore"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_to_snake_case(input: str, output: str):
|
def test_to_snake_case(input: str, output: str):
|
||||||
@ -169,3 +171,13 @@ def test_format_cond(condition: str, true_value: str, false_value: str, expected
|
|||||||
expected: The expected output string.
|
expected: The expected output string.
|
||||||
"""
|
"""
|
||||||
assert utils.format_cond(condition, true_value, false_value) == expected
|
assert utils.format_cond(condition, true_value, false_value) == expected
|
||||||
|
|
||||||
|
|
||||||
|
def test_merge_imports():
|
||||||
|
"""Test that imports are merged correctly."""
|
||||||
|
d1 = {"react": {"Component"}}
|
||||||
|
d2 = {"react": {"Component"}, "react-dom": {"render"}}
|
||||||
|
d = utils.merge_imports(d1, d2)
|
||||||
|
assert set(d.keys()) == {"react", "react-dom"}
|
||||||
|
assert set(d["react"]) == {"Component"}
|
||||||
|
assert set(d["react-dom"]) == {"render"}
|
||||||
|
169
tests/test_var.py
Normal file
169
tests/test_var.py
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from pynecone.base import Base
|
||||||
|
from pynecone.var import BaseVar, Var
|
||||||
|
|
||||||
|
test_vars = [
|
||||||
|
BaseVar(name="prop1", type_=int),
|
||||||
|
BaseVar(name="key", type_=str),
|
||||||
|
BaseVar(name="value", type_=str, state="state"),
|
||||||
|
BaseVar(name="local", type_=str, state="state", is_local=True),
|
||||||
|
BaseVar(name="local2", type_=str, is_local=True),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def TestObj():
|
||||||
|
class TestObj(Base):
|
||||||
|
foo: int
|
||||||
|
bar: str
|
||||||
|
|
||||||
|
return TestObj
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"prop,expected",
|
||||||
|
zip(
|
||||||
|
test_vars,
|
||||||
|
[
|
||||||
|
"prop1",
|
||||||
|
"key",
|
||||||
|
"state.value",
|
||||||
|
"state.local",
|
||||||
|
"local2",
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
def test_full_name(prop, expected):
|
||||||
|
"""Test that the full name of a var is correct.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
prop: The var to test.
|
||||||
|
expected: The expected full name.
|
||||||
|
"""
|
||||||
|
assert prop.full_name == expected
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"prop,expected",
|
||||||
|
zip(
|
||||||
|
test_vars,
|
||||||
|
["{prop1}", "{key}", "{state.value}", "state.local", "local2"],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
def test_str(prop, expected):
|
||||||
|
"""Test that the string representation of a var is correct.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
prop: The var to test.
|
||||||
|
expected: The expected string representation.
|
||||||
|
"""
|
||||||
|
assert str(prop) == expected
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"prop,expected",
|
||||||
|
[
|
||||||
|
(BaseVar(name="p", type_=int), 0),
|
||||||
|
(BaseVar(name="p", type_=float), 0.0),
|
||||||
|
(BaseVar(name="p", type_=str), ""),
|
||||||
|
(BaseVar(name="p", type_=bool), False),
|
||||||
|
(BaseVar(name="p", type_=list), []),
|
||||||
|
(BaseVar(name="p", type_=dict), {}),
|
||||||
|
(BaseVar(name="p", type_=tuple), ()),
|
||||||
|
(BaseVar(name="p", type_=set), set()),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_default_value(prop, expected):
|
||||||
|
"""Test that the default value of a var is correct.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
prop: The var to test.
|
||||||
|
expected: The expected default value.
|
||||||
|
"""
|
||||||
|
assert prop.get_default_value() == expected
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"prop,expected",
|
||||||
|
zip(
|
||||||
|
test_vars,
|
||||||
|
[
|
||||||
|
"set_prop1",
|
||||||
|
"set_key",
|
||||||
|
"state.set_value",
|
||||||
|
"state.set_local",
|
||||||
|
"set_local2",
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
def test_get_setter(prop, expected):
|
||||||
|
"""Test that the name of the setter function of a var is correct.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
prop: The var to test.
|
||||||
|
expected: The expected name of the setter function.
|
||||||
|
"""
|
||||||
|
assert prop.get_setter_name() == expected
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"value,expected",
|
||||||
|
[
|
||||||
|
(None, None),
|
||||||
|
(1, BaseVar(name="1", type_=int, is_local=True)),
|
||||||
|
("key", BaseVar(name="key", type_=str, is_local=True)),
|
||||||
|
(3.14, BaseVar(name="3.14", type_=float, is_local=True)),
|
||||||
|
([1, 2, 3], BaseVar(name="[1, 2, 3]", type_=list, is_local=True)),
|
||||||
|
(
|
||||||
|
{"a": 1, "b": 2},
|
||||||
|
BaseVar(name='{"a": 1, "b": 2}', type_=dict, is_local=True),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_create(value, expected):
|
||||||
|
"""Test the var create function.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
value: The value to create a var from.
|
||||||
|
expected: The expected name of the setter function.
|
||||||
|
"""
|
||||||
|
prop = Var.create(value)
|
||||||
|
if value is None:
|
||||||
|
assert prop == expected
|
||||||
|
else:
|
||||||
|
assert prop.equals(expected) # type: ignore
|
||||||
|
|
||||||
|
|
||||||
|
def test_basic_operations(TestObj):
|
||||||
|
"""Test the var operations.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
TestObj: The test object.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def v(value) -> Var:
|
||||||
|
val = Var.create(value)
|
||||||
|
assert val is not None
|
||||||
|
return val
|
||||||
|
|
||||||
|
assert str(v(1) == v(2)) == "{(1 == 2)}"
|
||||||
|
assert str(v(1) != v(2)) == "{(1 != 2)}"
|
||||||
|
assert str(v(1) < v(2)) == "{(1 < 2)}"
|
||||||
|
assert str(v(1) <= v(2)) == "{(1 <= 2)}"
|
||||||
|
assert str(v(1) > v(2)) == "{(1 > 2)}"
|
||||||
|
assert str(v(1) >= v(2)) == "{(1 >= 2)}"
|
||||||
|
assert str(v(1) + v(2)) == "{(1 + 2)}"
|
||||||
|
assert str(v(1) - v(2)) == "{(1 - 2)}"
|
||||||
|
assert str(v(1) * v(2)) == "{(1 * 2)}"
|
||||||
|
assert str(v(1) / v(2)) == "{(1 / 2)}"
|
||||||
|
assert str(v(1) // v(2)) == "{Math.floor(1 / 2)}"
|
||||||
|
assert str(v(1) % v(2)) == "{(1 % 2)}"
|
||||||
|
assert str(v(1) ** v(2)) == "{Math.pow(1 , 2)}"
|
||||||
|
assert str(v(1) & v(2)) == "{(1 && 2)}"
|
||||||
|
assert str(v(1) | v(2)) == "{(1 || 2)}"
|
||||||
|
assert str(v([1, 2, 3])[v(0)]) == "{[1, 2, 3][0]}"
|
||||||
|
assert str(v({"a": 1, "b": 2})["a"]) == '{{"a": 1, "b": 2}["a"]}'
|
||||||
|
assert (
|
||||||
|
str(BaseVar(name="foo", state="state", type_=TestObj).bar) == "{state.foo.bar}"
|
||||||
|
)
|
Loading…
Reference in New Issue
Block a user