Skip to content
Snippets Groups Projects
Commit 2d8c0fc9 authored by René Paris's avatar René Paris
Browse files

fix(tests): nodeview + propertyview

parent 42fe551b
No related branches found
No related tags found
No related merge requests found
Pipeline #45424 failed
......@@ -54,7 +54,8 @@ private:
[=]() { return ConvertScenarioPosition(environment, trafficSinkAction_->GetPosition()); },
trafficSinkAction_->IsSetTrafficDefinition()
? std::make_optional(ConvertScenarioTrafficDefinition(trafficSinkAction_->GetTrafficDefinition()))
: std::nullopt},
: std::nullopt
},
OpenScenarioEngine::v1_2::TrafficSinkAction::Interfaces{
environment});
}
......
......@@ -21,15 +21,15 @@ class Entity:
@dataclass
class PrimitiveType:
name: str
name: str
@dataclass
@dataclass(frozen=True)
class OscProperty:
name: str
type: Union[str, PrimitiveType]
optional: bool
list: bool
choice: bool
name: str
type: Union[str, PrimitiveType]
optional: bool
list: bool
choice: bool
class OscNode:
PROPAGATED_PROPERTIES = {
......
from typing import List
from open_scenario_tree import OscProperty
from converter import Converter
def feature_decorator(condition, prefix, suffix = ""):
def decorator(func):
def wrapper(self, *args, **kwargs):
prefix_, suffix_ = ("", "")
if condition(self):
prefix_ = prefix if isinstance(prefix, str) else prefix(self)
suffix_ = suffix if isinstance(suffix, str) else suffix(self)
return f'{prefix_}{func(self, *args, **kwargs)}{suffix_}'
return wrapper
return decorator
class PropertyView:
CONVERTER_PREFIX = "ConvertScenario"
def __init__(self, node_name, converter: Converter, properties: List[OscProperty]):
self.node_name = node_name
self.converter = converter
self.properties = properties
@staticmethod
def capitalize_first(s):
return s[0].upper() + s[1:] if s else s
def get_property(self, prop):
prefix = f"{self.node_name}->IsSet{self.capitalize_first(prop.name)}() ? std::make_optional(" if prop.optional else ""
suffix = ") : std::nullopt" if prop.optional else ""
return f"{prefix}{self.node_name}->Get{self.capitalize_first(prop.name)}(){suffix}"
@feature_decorator(condition = lambda self: self.converter and self.converter.runtime,
prefix="[=](){ return ",
suffix="; }")
@feature_decorator(condition = lambda self: self.converter,
prefix=lambda self: f"{self.CONVERTER_PREFIX}{self.capitalize_first(self.converter.name)}(",
suffix=")")
@feature_decorator(condition = lambda self: self.converter and self.converter.dependencies,
prefix=lambda self: f'{", ".join([d.name for d in self.converter.dependencies])}, ')
def __str__(self):
return ", ".join(self.get_property(prop) for prop in self.properties)
......@@ -3,11 +3,8 @@ from open_scenario_tree import OscNode, parse_properties
from converter import Converter, Dependency
from typing import List
import pytest
import dataclasses
#from test_property_view import PropertyView
class PropertyView:
pass
from property_view import PropertyView
def capitalize_first(s):
return s[0].upper() + s[1:] if s else s
......@@ -21,54 +18,28 @@ class NodeView:
def __init__(self, node: OscNode, converter: List[Converter]):
self.node = node
self.member_name = f'{lowercase_first(self.node.name)}{self.MEMBER_SUFFIX}'
self.converter = converter
self.properties_view = self._generate_properties_view()
self._properties = self._generate_properties_view()
self.dependencies = self._generate_dependencies()
self.includes = self._generate_converter_includes()
@property
def name(self):
return f'{lowercase_first(self.node.name)}{self.MEMBER_SUFFIX}'
def _generate_properties_view(self):
properties_view = []
properties = []
unconverted_properties = set(self.node.properties)
for converter in self.converter:
if set(converter.properties).issubset({prop.name for prop in self.node.properties}):
property_view = PropertyView(converter, )
property_view.name=f"{self.CONVERTER_PREFIX}{capitalize_first(converter.name)}"
property_view.members=[f"{self.name}->Get{capitalize_first(prop)}()" for prop in converter.properties]
if converter.keep:
properties_view.extend([
PropertyView(
name=f"{self.name}->Get{capitalize_first(prop)}") for prop in converter.keep
if all(f"{self.name}->Get{capitalize_first(prop)}" != prop_view.name for prop_view in properties_view)])
if converter.dependencies:
property_view.dependencies=[dep.name for dep in converter.dependencies]
if converter.runtime:
property_view.opening="[=](){ return "
property_view.closing="; }"
properties_view.extend(property_view)
optional_props = [prop for prop in self.node.properties if prop.optional]
properties_view.extend([
PropertyView(
name=f"{self.name}->Get{capitalize_first(prop.name)}",
opening=f"{self.name}->IsSet{capitalize_first(prop.name)}() ? std::make_optional(",
closing=") : std::nullopt") for prop in optional_props for prop_view in properties_view])
# Add remaining properties that are not consumed by the converters
consumed_props = [prop for converter in self.converter for prop in converter.properties]
remaining_props = [prop for prop in self.node.properties if prop.name not in consumed_props and not prop.optional]
properties_view.extend([
PropertyView(
name=f"{self.name}->Get{capitalize_first(prop.name)}") for prop in remaining_props])
return properties_view
consumed_properties = [prop for prop in self.node.properties if prop.name in converter.properties]
properties.append(PropertyView(self.member_name, converter, consumed_properties))
unconverted_properties.difference_update(consumed_properties)
unconverted_properties.update([prop for prop in self.node.properties if prop.name in converter.keep])
for prop in unconverted_properties:
properties.append(PropertyView(self.member_name, None, [prop]))
return properties
@property
def new_properties(self):
return sorted([str(prop) for prop in self.properties_view])
def properties(self):
return sorted([str(prop) for prop in self._properties])
def _generate_converter_includes(self):
includes = []
......@@ -97,12 +68,12 @@ def node_with_3_props():
def test__given_node_and_no_converters__relays_name(node_with_3_props):
node_view = NodeView(node_with_3_props, [])
assert node_view.name == "nodeUnderTest_"
assert node_view.member_name == "nodeUnderTest_"
def test__given_node_and_no_converters__generates_property_views_without_converters(node_with_3_props):
node_view = NodeView(node_with_3_props, [])
assert node_view.new_properties == [
assert node_view.properties == [
"nodeUnderTest_->GetPropName1()",
"nodeUnderTest_->GetPropName2()",
"nodeUnderTest_->GetPropName3()" ]
......@@ -114,7 +85,7 @@ def test__given_node_and_no_converters__generates_no_conversion_includes(node_wi
def test__given_node_and_consuming_converter__combines_props_and_consumes_them(node_with_3_props):
node_view = NodeView(node_with_3_props, [Converter([], "customPropName", {'Properties': ['propName1', 'propName3']})])
assert node_view.new_properties == [
assert node_view.properties == [
"ConvertScenarioCustomPropName(nodeUnderTest_->GetPropName1(), nodeUnderTest_->GetPropName3())",
"nodeUnderTest_->GetPropName2()"]
......@@ -129,7 +100,7 @@ def test__given_node_and_keeping_converter__combines_props_and_keeps_prop(node_w
'Keep': ['propName3']
})])
assert node_view.new_properties == [
assert node_view.properties == [
"ConvertScenarioCustomPropName(nodeUnderTest_->GetPropName1(), nodeUnderTest_->GetPropName3())",
"nodeUnderTest_->GetPropName2()",
"nodeUnderTest_->GetPropName3()"]
......@@ -143,7 +114,7 @@ def test__given_node_and_two_keeping_converters__combines_props_and_keeps_prop_o
'Keep': ['propName3']
})])
assert node_view.new_properties == [
assert node_view.properties == [
"ConvertScenarioCustomPropName1(nodeUnderTest_->GetPropName1(), nodeUnderTest_->GetPropName3())",
"ConvertScenarioCustomPropName2(nodeUnderTest_->GetPropName2(), nodeUnderTest_->GetPropName3())",
"nodeUnderTest_->GetPropName3()"]
......@@ -155,21 +126,21 @@ def test__given_node_and_converter_with_deps_and_props__integrates_deps_and_cons
'Dependencies': ['Environment']})
node_view = NodeView(node_with_3_props, [converter])
assert "ConvertScenarioCustomType(environment, nodeUnderTest_->GetPropName1())" in node_view.new_properties
assert "ConvertScenarioCustomType(environment, nodeUnderTest_->GetPropName1())" in node_view.properties
def test__given_node_and_converter_with_deps_and_no_props__integrates_deps_and_consumes_default_prop(node_with_3_props):
fake_deps = {"Environment": Dependency("environment", "std::shared_ptr<mantle_api::IEnvironment>", "<mantle_api/i_environment.h>")}
converter = Converter(fake_deps, "propName1", {'Dependencies': ['Environment']})
node_view = NodeView(node_with_3_props, [converter])
assert "ConvertScenarioPropName1(environment, nodeUnderTest_->GetPropName1())" in node_view.new_properties
assert "ConvertScenarioPropName1(environment, nodeUnderTest_->GetPropName1())" in node_view.properties
def test__given_node_and_non_matching_converter__ignores_converter(node_with_3_props):
fake_deps = {"Environment": Dependency("environment", "std::shared_ptr<mantle_api::IEnvironment>", "<mantle_api/i_environment.h>")}
unused_converter = Converter(fake_deps, "someArbitraryProperty", {'Dependencies': ['Environment']})
node_view = NodeView(node_with_3_props, [unused_converter])
assert node_view.new_properties == [
assert node_view.properties == [
"nodeUnderTest_->GetPropName1()",
"nodeUnderTest_->GetPropName2()",
"nodeUnderTest_->GetPropName3()"]
......@@ -198,7 +169,7 @@ def test__given_node_and_runtime_converter__creates_lambda_wrapper_for_converter
'Type': 'runtime'
})])
assert "[=](){ return ConvertScenarioPropName1(nodeUnderTest_->GetPropName1()); }" in node_view.new_properties
assert "[=](){ return ConvertScenarioPropName1(nodeUnderTest_->GetPropName1()); }" in node_view.properties
def test__given_node_and_runtime_converter_with_deps__creates_lambda_wrapper_for_converter_stage(node_with_3_props):
fake_deps = {"Environment": Dependency("environment", "std::shared_ptr<mantle_api::IEnvironment>", "<mantle_api/i_environment.h>")}
......@@ -206,7 +177,7 @@ def test__given_node_and_runtime_converter_with_deps__creates_lambda_wrapper_for
'Type': 'runtime'
})])
assert "[=](){ return ConvertScenarioPropName1(environment, nodeUnderTest_->GetPropName1()); }" in node_view.new_properties
assert "[=](){ return ConvertScenarioPropName1(environment, nodeUnderTest_->GetPropName1()); }" in node_view.properties
# assert str(PropertyView(
# opening="[=](){ return ",
......@@ -225,7 +196,7 @@ def test__given_node_with_optional_property__generates_ternary_operator():
}))
node_view = NodeView(node_under_test, [])
assert node_view.new_properties == [
assert node_view.properties == [
"nodeUnderTest_->IsSetPropName1() ? std::make_optional(nodeUnderTest_->GetPropName1()) : std::nullopt"]
def test__given_node_with_optional_property_and_converter__generates_ternary_operator():
......@@ -234,8 +205,8 @@ def test__given_node_with_optional_property_and_converter__generates_ternary_ope
}))
node_view = NodeView(node_under_test, [Converter([], "customPropName", {'Properties': ['propName1']})])
assert node_view.new_properties == [
"nodeUnderTest_->IsSetPropName1() ? std::make_optional(ConvertScenarioCustomPropName(nodeUnderTest_->GetPropName1())) : std::nullopt"]
assert node_view.properties == [
"ConvertScenarioCustomPropName(nodeUnderTest_->IsSetPropName1() ? std::make_optional(nodeUnderTest_->GetPropName1()) : std::nullopt)"]
def test__given_node_with_optional_property_and_runtime__generates_ternary_operator():
node_under_test = OscNode("NodeUnderTest", parse_properties({
......@@ -243,5 +214,5 @@ def test__given_node_with_optional_property_and_runtime__generates_ternary_opera
}))
node_view = NodeView(node_under_test, [Converter([], "customPropName", {'Properties': ['propName1'], 'Type': 'runtime'})])
assert node_view.new_properties == [
"[=](){ return nodeUnderTest_->IsSetPropName1() ? std::make_optional(ConvertScenarioCustomPropName(nodeUnderTest_->GetPropName1())) : std::nullopt }"]
assert node_view.properties == [
"[=](){ return ConvertScenarioCustomPropName(nodeUnderTest_->IsSetPropName1() ? std::make_optional(nodeUnderTest_->GetPropName1()) : std::nullopt); }"]
from typing import List
import pytest
from open_scenario_tree import OscProperty
from converter import Converter, Dependency
# def test_my_decorator_used():
# obj = PropertyView("node", "Method", True, False)
# assert str(obj) == "node_->IsSetMethod ? std::make_optional(node_->GetMethod()) : std::nullopt"
# def test_my_decorator_unused():
# obj = PropertyView("node", "Method", False, False)
# assert str(obj) == "node_->GetMethod()"
# def test_my_decorator_used_2():
# obj = PropertyView("node", "Method", False, True)
# assert str(obj) == "[=](){ return node_->GetMethod(); }"
# def test_my_decorator_used_3():
# obj = PropertyView("node", "Method", True, True)
# assert str(obj) == "[=](){ return node_->IsSetMethod ? std::make_optional(node_->GetMethod()) : std::nullopt; }"
def feature_decorator(condition, prefix, suffix = ""):
def decorator(func):
def wrapper(self, *args, **kwargs):
prefix_, suffix_ = ("", "")
if condition(self):
prefix_ = prefix if isinstance(prefix, str) else prefix(self)
suffix_ = suffix if isinstance(suffix, str) else suffix(self)
return f'{prefix_}{func(self, *args, **kwargs)}{suffix_}'
return wrapper
return decorator
class PropertyView:
CONVERTER_PREFIX = "ConvertScenario"
MEMBER_SUFFIX = "_"
def __init__(self, node, converter: Converter, properties: List[OscProperty]):
self.node = f'{node}{self.MEMBER_SUFFIX}'
self.converter = converter
self.properties = properties
@staticmethod
def capitalize_first(s):
return s[0].upper() + s[1:] if s else s
def get_property(self, prop):
prefix = f"{self.node}->IsSet{self.capitalize_first(prop.name)} ? std::make_optional(" if prop.optional else ""
suffix = ") : std::nullopt" if prop.optional else ""
return f"{prefix}{self.node}->Get{self.capitalize_first(prop.name)}(){suffix}"
@feature_decorator(condition = lambda self: self.converter and self.converter.runtime,
prefix="[=](){ return ",
suffix="; }")
@feature_decorator(condition = lambda self: self.converter,
prefix=lambda self: f"{self.CONVERTER_PREFIX}{self.capitalize_first(self.converter.name)}(",
suffix=")")
@feature_decorator(condition = lambda self: self.converter and self.converter.dependencies,
prefix=lambda self: f'{", ".join([d.name for d in self.converter.dependencies])}, ')
def __str__(self):
return ", ".join(self.get_property(prop) for prop in self.properties)
from property_view import PropertyView
from converter import Converter, Dependency
from open_scenario_tree import OscProperty
@pytest.mark.parametrize("node, converter, oscProperty, expected_result", [
("node", Converter([], "propName", {}), [OscProperty("propName", "type", False, False, False)], "ConvertScenarioPropName(node_->GetPropName())"),
("node", Converter([], "propName", {}), [OscProperty("propName", "type", True, False, False)], "ConvertScenarioPropName(node_->IsSetPropName ? std::make_optional(node_->GetPropName()) : std::nullopt)"),
("node", Converter([], "propName", {}), [OscProperty("propName", "type", False, True, False)], "ConvertScenarioPropName(node_->GetPropName())"),
("node", Converter([], "propName", {}), [OscProperty("propName", "type", False, False, True)], "ConvertScenarioPropName(node_->GetPropName())"),
("node", Converter([], "propName", {}), [OscProperty("propName", "type", True, True, False)], "ConvertScenarioPropName(node_->IsSetPropName ? std::make_optional(node_->GetPropName()) : std::nullopt)"),
("node", Converter([], "propName", {}), [OscProperty("propName", "type", True, False, True)], "ConvertScenarioPropName(node_->IsSetPropName ? std::make_optional(node_->GetPropName()) : std::nullopt)"),
("node", Converter([], "propName", {}), [OscProperty("propName", "type", False, True, True)], "ConvertScenarioPropName(node_->GetPropName())"),
("node", Converter([], "propName", {}), [OscProperty("propName", "type", True, True, True)], "ConvertScenarioPropName(node_->IsSetPropName ? std::make_optional(node_->GetPropName()) : std::nullopt)")
("node_", Converter([], "propName", {}), [OscProperty("propName", "type", False, False, False)], "ConvertScenarioPropName(node_->GetPropName())"),
("node_", Converter([], "propName", {}), [OscProperty("propName", "type", True, False, False)], "ConvertScenarioPropName(node_->IsSetPropName() ? std::make_optional(node_->GetPropName()) : std::nullopt)"),
("node_", Converter([], "propName", {}), [OscProperty("propName", "type", False, True, False)], "ConvertScenarioPropName(node_->GetPropName())"),
("node_", Converter([], "propName", {}), [OscProperty("propName", "type", False, False, True)], "ConvertScenarioPropName(node_->GetPropName())"),
("node_", Converter([], "propName", {}), [OscProperty("propName", "type", True, True, False)], "ConvertScenarioPropName(node_->IsSetPropName() ? std::make_optional(node_->GetPropName()) : std::nullopt)"),
("node_", Converter([], "propName", {}), [OscProperty("propName", "type", True, False, True)], "ConvertScenarioPropName(node_->IsSetPropName() ? std::make_optional(node_->GetPropName()) : std::nullopt)"),
("node_", Converter([], "propName", {}), [OscProperty("propName", "type", False, True, True)], "ConvertScenarioPropName(node_->GetPropName())"),
("node_", Converter([], "propName", {}), [OscProperty("propName", "type", True, True, True)], "ConvertScenarioPropName(node_->IsSetPropName() ? std::make_optional(node_->GetPropName()) : std::nullopt)")
])
def test__given_property_with_converter__generates_property_views_with_converters(node, converter, oscProperty, expected_result):
obj = PropertyView(node, converter, oscProperty)
assert str(obj) == expected_result
def test__given_property_and_optional_property_with_converter__generates_property_views_with_ternary_operator():
obj = PropertyView("node", Converter([], "MyConv", {}), [OscProperty("propName1", "type", False, False, False), OscProperty("propName2", "type", True, False, False)])
assert str(obj) == "ConvertScenarioMyConv(node_->GetPropName1(), node_->IsSetPropName2 ? std::make_optional(node_->GetPropName2()) : std::nullopt)"
obj = PropertyView("node_", Converter([], "MyConv", {}), [OscProperty("propName1", "type", False, False, False), OscProperty("propName2", "type", True, False, False)])
assert str(obj) == "ConvertScenarioMyConv(node_->GetPropName1(), node_->IsSetPropName2() ? std::make_optional(node_->GetPropName2()) : std::nullopt)"
def test__given_property_with_no_converters__generates_property_views_without_converters():
obj = PropertyView("node", None, [OscProperty("propName1", "type", False, False, False)])
obj = PropertyView("node_", None, [OscProperty("propName1", "type", False, False, False)])
assert str(obj) == "node_->GetPropName1()"
def test__given_property_and_optional_property_with_converter__generates_property_views_with_ternary_operator213():
dep = {"Environment": Dependency("environment", "", "")}
obj = PropertyView("node", Converter(dep, "MyConv", {'Dependencies': ['Environment']}), [OscProperty("propName1", "type", False, False, False)])
obj = PropertyView("node_", Converter(dep, "MyConv", {'Dependencies': ['Environment']}), [OscProperty("propName1", "type", False, False, False)])
assert str(obj) == "ConvertScenarioMyConv(environment, node_->GetPropName1())"
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment