Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions qface/idl/listener.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,19 +109,32 @@ def parse_type(self, ctx: ParserRuleContext, type: TypeSymbol):
if not type.module.checkType(type):
log.warning('Unknown type: {0}. Missing import?'.format(type.name))

def validate_keys(self, data, path=""):
if isinstance(data, dict):
for key, value in data.items():
if ":" in key:
error_msg = f"Invalid YAML: Missing space after ':' in key '{path}{key}'"
click.secho(error_msg, fg='red', err=True)
raise ValueError(error_msg)
self.validate_keys(value, path + key + ".")
elif isinstance(data, list):
for item in data:
self.validate_keys(item, path)

def parse_annotations(self, ctx, symbol):
assert ctx and symbol
if ctx.comment:
comment = ctx.comment.text
symbol.comment = comment
if ctx.tagSymbol():
lines = [tag.line.text[1:] for tag in ctx.tagSymbol()]
lines = [re.sub(r':\s*', ': ', line) for line in lines]
try:
data = yaml.load('\n'.join(lines), Loader=Loader)
self.validate_keys(data)
symbol._tags = data
except yaml.YAMLError as exc:
click.secho(str(exc), fg='red')
except (yaml.YAMLError, ValueError) as exc:
click.secho(f"YAML Parsing Error: while parsing {lines}, error: {str(exc)}", fg='red', err=True)
raise

def parse_value(self, ctx, symbol):
self.check_support(EFeature.DEFAULT_VALUES)
Expand Down
6 changes: 6 additions & 0 deletions tests/in/com.pelagicore.four.qface
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module com.pelagicore.two 1.0;

@config: { qml_type: {key:value} }
interface FourService {
StringStruct message;
}
2 changes: 1 addition & 1 deletion tests/in/com.pelagicore.ivi.tuner.qface
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ interface BaseTuner {
/** Service Tuner */
@service: true
@interface: true
@config: {private: true, b: B, c: C, d:D}
@config: {private: true, b: B, c: {C: e}, d: "qrc:/path"}
@data: [1,2,3]
interface Tuner extends BaseTuner {
/** property currentStation */
Expand Down
6 changes: 6 additions & 0 deletions tests/in/com.pelagicore.three.qface
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module com.pelagicore.two 1.0;

@config:{ qml_type: "UiAddressBook" }
interface TwoService {
StringStruct message;
}
6 changes: 6 additions & 0 deletions tests/in/com.pelagicore.two.qface
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module com.pelagicore.two 1.0;

@config: { qml_type:"UiAddressBook" }
interface TwoService {
StringStruct message;
}
4 changes: 2 additions & 2 deletions tests/test_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ def test_error_template_doesnt_exist(mock_stderr):
generator.write(dst_template, 'doesnt_exist.txt', ctx)
path = generator.apply(dst_template, ctx)
assert Path(path).exists() == False
assert mock_stderr.getvalue() == "/doesnt_exist.txt: error: Template not found\n"
assert "/doesnt_exist.txt: error: Template not found\n" in mock_stderr.getvalue()

@patch('sys.stderr', new_callable=StringIO)
def test_error_yaml_doesnt_exist(mock_stderr):
Expand All @@ -155,4 +155,4 @@ def test_error_yaml_doesnt_exist(mock_stderr):
out.mkdir(parents=True, exist_ok=True)
generator = RuleGenerator(search_path='tests/templates', destination=out)
generator.process_rules('doesnt_exist.txt', system)
assert mock_stderr.getvalue() == "yaml document does not exists: doesnt_exist.txt\n"
assert "yaml document does not exists: doesnt_exist.txt\n" in mock_stderr.getvalue()
33 changes: 31 additions & 2 deletions tests/test_tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,10 @@ def test_flag():
assert interface.attribute('config', 'private') is True
assert interface.attribute('config', 'a') == 'a' # use value from yaml
assert interface.attribute('config', 'b') == 'b' # use value from yaml
assert interface.attribute('config', 'c') == 'C' # use value from IDL
assert interface.attribute('config', 'd') == 'D' # use value from IDL, No Space after :
nestedVal = interface.attribute('config', 'c')
assert nestedVal == {'C': 'e'}
assert nestedVal['C'] == 'e'
assert interface.attribute('config', 'd') == 'qrc:/path' # use value from IDL, Value containing :
assert interface.tags['data'] == [1, 2, 3] # array annotatiom

def test_merge_annotation():
Expand Down Expand Up @@ -105,3 +107,30 @@ def test_merge_invalid_annotation(mock_stderr):
expected_error = "Error parsing annotation tests/in/invalid_tuner_annotations.yaml: not able to lookup symbol: Tunerrrrrrrr\n"
actual_output = mock_stderr.getvalue().replace("\\", "/") # Normalize backslashes
assert expected_error in actual_output, f"Expected error not found. Expected: {expected_error}, Actual: {actual_output}"

@patch('sys.stderr', new_callable=StringIO)
def test_broken_annotation(mock_stderr):
path = inputPath / 'com.pelagicore.two.qface'
system = FileSystem.parse_document(path)
assert system is None
expected_error = "Invalid YAML: Missing space after ':' in key 'config.qml_type:\"UiAddressBook\"'"
actual_output = mock_stderr.getvalue().replace("\\", "/") # Normalize backslashes
assert expected_error in actual_output, f"Expected error not found. Expected: {expected_error}, Actual: {actual_output}"

@patch('sys.stderr', new_callable=StringIO)
def test_broken_annotation_1(mock_stderr):
path = inputPath / 'com.pelagicore.three.qface'
system = FileSystem.parse_document(path)
assert system is None
expected_error = "YAML Parsing Error: while parsing [\'config:{ qml_type: \"UiAddressBook\" }\']"
actual_output = mock_stderr.getvalue().replace("\\", "/") # Normalize backslashes
assert expected_error in actual_output, f"Expected error not found. Expected: {expected_error}, Actual: {actual_output}"

@patch('sys.stderr', new_callable=StringIO)
def test_broken_annotation_2(mock_stderr):
path = inputPath / 'com.pelagicore.four.qface'
system = FileSystem.parse_document(path)
assert system is None
expected_error = "Invalid YAML: Missing space after ':' in key 'config.qml_type.key:value'"
actual_output = mock_stderr.getvalue().replace("\\", "/") # Normalize backslashes
assert expected_error in actual_output, f"Expected error not found. Expected: {expected_error}, Actual: {actual_output}"