Skip to content

Commit ccb79cf

Browse files
committed
Add tests and tidy up translation parser
1 parent 2d1d2c7 commit ccb79cf

12 files changed

+218
-15
lines changed

addons/parley/constants.gd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
const VERSION: StringName = &"2.1.0"
99
const AST_VERSION: StringName = &"1.1.0"
1010
const USER_CONFIG_PATH: StringName = &"user://parley_user_config.json"
11+
const DIALOGUE_SEQUENCE_EXTENSION: StringName = &"ds"
1112
#endregion
1213

1314

addons/parley/dialogue_ast_format_saver.gd

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,20 @@
33
@tool
44
class_name ParleyDialogueSequenceAstFormatSaver extends ResourceFormatSaver
55

6+
7+
const ParleyConstants = preload('./constants.gd')
8+
9+
610
## Returns the list of extensions available for saving the resource object,
711
## provided it is recognized (see _recognize).
812
func _recognize(resource: Resource) -> bool:
913
return is_instance_of(resource, ParleyDialogueSequenceAst)
1014

15+
1116
## Returns whether the given resource object can be saved by this saver.
1217
func _get_recognized_extensions(_resource: Resource) -> PackedStringArray:
13-
return PackedStringArray(["ds"])
18+
return PackedStringArray([ParleyConstants.DIALOGUE_SEQUENCE_EXTENSION])
19+
1420

1521
## Saves the given resource object to a file at the target path.
1622
## flags is a bitmask composed with SaverFlags constants.

addons/parley/import_plugin.gd

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ func _get_visible_name() -> String:
3131

3232

3333
func _get_recognized_extensions() -> PackedStringArray:
34-
return ["ds"]
34+
return [ParleyConstants.DIALOGUE_SEQUENCE_EXTENSION]
3535

3636

3737
func _get_save_extension() -> String:

addons/parley/models/dialogue_node_ast.gd

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,12 @@ func to_resolved(resolved_text: String) -> ParleyDialogueNodeAst:
6161

6262
func resolve_character() -> ParleyCharacter:
6363
return ParleyCharacterStore.resolve_character_ref(character)
64+
65+
66+
## Get translation strings for the Dialogue Node
67+
func get_translation_strings() -> Array[PackedStringArray]:
68+
var translation_strings: Array[PackedStringArray] = []
69+
if text:
70+
translation_strings.append(PackedStringArray([text, ParleyUtils.translation.get_msg_ctx(self, 'text_translation_key')]))
71+
return translation_strings
6472
#endregion

addons/parley/models/dialogue_option_node_ast.gd

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,12 @@ func to_resolved(resolved_text: String) -> ParleyDialogueOptionNodeAst:
6161

6262
func resolve_character() -> ParleyCharacter:
6363
return ParleyCharacterStore.resolve_character_ref(character)
64+
65+
66+
## Get translation strings for the Dialogue Option Node
67+
func get_translation_strings() -> Array[PackedStringArray]:
68+
var translation_strings: Array[PackedStringArray] = []
69+
if text:
70+
translation_strings.append(PackedStringArray([text, ParleyUtils.translation.get_msg_ctx(self, 'text_translation_key')]))
71+
return translation_strings
6472
#endregion

addons/parley/models/node_ast.gd

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ func _to_string() -> String:
5757
return "ParleyNodeAst<%s>" % [str(to_dict())]
5858

5959

60+
## Get translation strings for the current node
61+
func get_translation_strings() -> Array[PackedStringArray]:
62+
return []
63+
64+
6065
static func get_colour() -> Color:
6166
return Color("#7a2167")
6267
#endregion

addons/parley/parley_manager.gd

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ func update_localisations(dialogue_sequences_to_register: Array[ParleyDialogueSe
194194
if clean:
195195
for i: int in range(pot_generation_candidates.size() - 1, -1, -1):
196196
var candidate: String = pot_generation_candidates[i]
197-
if candidate.get_extension() == "ds" and not ResourceLoader.exists(candidate):
197+
if candidate.get_extension() == ParleyConstants.DIALOGUE_SEQUENCE_EXTENSION and not ResourceLoader.exists(candidate):
198198
pot_generation_candidates.remove_at(i)
199199
changed = true
200200

addons/parley/translation_parser.gd

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
extends EditorTranslationParserPlugin
33

44

5+
const ParleyConstants = preload("./constants.gd")
6+
7+
58
func _parse_file(path: String) -> Array[PackedStringArray]:
69
if not ResourceLoader.exists(path):
710
return []
@@ -11,14 +14,9 @@ func _parse_file(path: String) -> Array[PackedStringArray]:
1114
for node: ParleyNodeAst in dialogue_sequence.nodes:
1215
if not uid:
1316
continue
14-
# TODO: handle this at the node level to be much more maintainable
15-
var text: Variant = node.get("text")
16-
if is_instance_of(text, TYPE_STRING) and text:
17-
# TODO: add support for nodes to have a custom translation key
18-
ret.append(PackedStringArray([text, ParleyUtils.translation.get_msg_ctx(node, 'text_translation_key')])) # id[,ctx]
17+
ret.append_array(node.get_translation_strings())
1918
return ret
2019

2120

2221
func _get_recognized_extensions() -> PackedStringArray:
23-
# TODO: is there a constant we can use?
24-
return ["ds"]
22+
return [ParleyConstants.DIALOGUE_SEQUENCE_EXTENSION]

tests/dialogue_node_editor_test.gd

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,17 @@ class Test_dialogue_node_editor:
3939

4040

4141
func use_dialogue_node_editor(p_dialogue_node_editor: ParleyDialogueNodeEditor, test_case: Dictionary) -> void:
42-
var _dialogue: Variant = test_case.get('dialogue')
42+
var dialogue_variant: Variant = test_case.get('dialogue')
4343
var selected_character: Variant = test_case.get('selected_character')
44-
if _dialogue and _dialogue is String:
45-
var dialogue: String = _dialogue
44+
var text_translation_key_variant: Variant = test_case.get('text_translation_key')
45+
if dialogue_variant and dialogue_variant is String:
46+
var dialogue: String = dialogue_variant
4647
p_dialogue_node_editor.dialogue_editor.insert_text_at_caret(dialogue)
4748
if is_instance_of(selected_character, TYPE_INT):
4849
p_dialogue_node_editor.character_selector.item_selected.emit(selected_character)
50+
if text_translation_key_variant and text_translation_key_variant is String:
51+
var text_translation_key: String = text_translation_key_variant
52+
p_dialogue_node_editor.text_translation_key_editor.key_changed.emit(text_translation_key)
4953

5054

5155
func test_initial_render(params: Variant = use_parameters([
@@ -137,6 +141,10 @@ class Test_dialogue_node_editor:
137141
"input": {"id": "1", "selected_character": 0},
138142
"expected": {"id": "1", "character_id": "%s::default_character" % ParleyUtils.resource.get_uid(character_store), "selected_character": 0, "dialogue": "", "text_translation_key": ""},
139143
},
144+
{
145+
"input": {"id": "1", "text_translation_key": "some_text_translation_key"},
146+
"expected": {"id": "1", "character_id": "", "selected_character": -1, "dialogue": "", "text_translation_key": "some_text_translation_key"},
147+
},
140148
])) -> void:
141149
# Arrange
142150
var input: Dictionary = params['input']
@@ -155,4 +163,5 @@ class Test_dialogue_node_editor:
155163
assert_eq(dialogue_node_editor.dialogue, str(expected['dialogue']))
156164
assert_eq(dialogue_node_editor.dialogue_editor.text, str(expected['dialogue']))
157165
assert_eq(dialogue_node_editor.character_selector.selected, expected_selected_character)
166+
assert_eq(dialogue_node_editor.text_translation_key, str(expected['text_translation_key']))
158167
assert_signal_emitted_with_parameters(dialogue_node_editor, 'dialogue_node_changed', [expected['id'], expected['character_id'], expected['dialogue'], expected['text_translation_key']])
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
# Copyright 2024-2025 the Bisterix Studio authors. All rights reserved. MIT license.
2+
3+
extends GutTest
4+
5+
# TODO: move test file next to the scene
6+
const DialogueOptionNodeEditorScene: PackedScene = preload('res://addons/parley/components/dialogue_option/dialogue_option_node_editor.tscn')
7+
8+
9+
class Test_dialogue_option_node_editor:
10+
extends GutTest
11+
12+
var dialogue_option_node_editor: ParleyDialogueOptionNodeEditor = null
13+
var character_store: ParleyCharacterStore = null
14+
15+
func before_each() -> void:
16+
dialogue_option_node_editor = DialogueOptionNodeEditorScene.instantiate()
17+
character_store = load('res://tests/fixtures/characters/base_character_store.tres')
18+
character_store.id = "test"
19+
character_store.characters = []
20+
var _result: ParleyCharacter = character_store.add_character("Default Character")
21+
dialogue_option_node_editor.character_store = character_store
22+
add_child_autofree(dialogue_option_node_editor)
23+
24+
func after_each() -> void:
25+
dialogue_option_node_editor = null
26+
27+
func setup_dialogue_option_node_editor(p_dialogue_option_node_editor: ParleyDialogueOptionNodeEditor, test_case: Dictionary) -> void:
28+
var id: Variant = test_case.get('id')
29+
var _character_name: Variant = test_case.get('character_name')
30+
var option: Variant = test_case.get('option')
31+
if id:
32+
p_dialogue_option_node_editor.id = id
33+
if _character_name and _character_name is String:
34+
var character_name: String = _character_name
35+
var _added_character: ParleyCharacter = character_store.add_character(character_name)
36+
p_dialogue_option_node_editor.character = character_store.get_ref_by_index(character_store.characters.size() - 1)
37+
if option:
38+
p_dialogue_option_node_editor.option = option
39+
40+
41+
func use_dialogue_option_node_editor(p_dialogue_option_node_editor: ParleyDialogueOptionNodeEditor, test_case: Dictionary) -> void:
42+
var dialogue_variant: Variant = test_case.get('option')
43+
var selected_character: Variant = test_case.get('selected_character')
44+
var text_translation_key_variant: Variant = test_case.get('text_translation_key')
45+
if dialogue_variant and dialogue_variant is String:
46+
var option: String = dialogue_variant
47+
p_dialogue_option_node_editor.option_editor.insert_text_at_caret(option)
48+
if is_instance_of(selected_character, TYPE_INT):
49+
p_dialogue_option_node_editor.character_selector.item_selected.emit(selected_character)
50+
if text_translation_key_variant and text_translation_key_variant is String:
51+
var text_translation_key: String = text_translation_key_variant
52+
p_dialogue_option_node_editor.text_translation_key_editor.key_changed.emit(text_translation_key)
53+
54+
55+
func test_initial_render(params: Variant = use_parameters([
56+
{
57+
"input": {"id": null, "character_name": null, "option": null},
58+
"expected": {"id": "", "character_id": "", "selected_character": - 1, "option": ""},
59+
},
60+
{
61+
"input": {"id": "1", "character_name": null, "option": null},
62+
"expected": {"id": "1", "character_id": "", "selected_character": - 1, "option": ""},
63+
},
64+
{
65+
"input": {"id": null, "character_name": "Test Character", "option": null},
66+
"expected": {"id": "", "character_id": "%s::test_character" % ParleyUtils.resource.get_uid(character_store), "selected_character": 1, "option": ""},
67+
},
68+
{
69+
"input": {"id": null, "character_name": null, "option": "Some option"},
70+
"expected": {"id": "", "character_id": "", "selected_character": - 1, "option": "Some option"},
71+
},
72+
{
73+
"input": {"id": "1", "character_name": "Test Character", "option": "Some option"},
74+
"expected": {"id": "1", "character_id": "%s::test_character" % ParleyUtils.resource.get_uid(character_store), "selected_character": 1, "option": "Some option"},
75+
},
76+
])) -> void:
77+
# Arrange
78+
var input: Dictionary = params['input']
79+
var expected: Dictionary = params['expected']
80+
var expected_selected_character: int = expected['selected_character']
81+
setup_dialogue_option_node_editor(dialogue_option_node_editor, input)
82+
watch_signals(dialogue_option_node_editor)
83+
84+
# Act
85+
await wait_until(func() -> bool: return dialogue_option_node_editor.is_inside_tree(), .1)
86+
87+
# Assert
88+
assert_true(dialogue_option_node_editor.is_inside_tree())
89+
assert_eq(dialogue_option_node_editor.id, str(expected['id']))
90+
assert_eq(dialogue_option_node_editor.character, str(expected['character_id']))
91+
assert_eq(dialogue_option_node_editor.character_selector.selected, expected_selected_character)
92+
assert_eq(dialogue_option_node_editor.option, str(expected['option']))
93+
assert_eq(dialogue_option_node_editor.option_editor.text, str(expected['option']))
94+
assert_signal_not_emitted(dialogue_option_node_editor, 'dialogue_option_node_changed')
95+
96+
97+
func test_update_render_with_variables(params: Variant = use_parameters([
98+
{
99+
"input": {"id": null, "character_name": null, "option": null},
100+
"expected": {"id": "", "character_id": "", "selected_character": - 1, "option": ""},
101+
},
102+
{
103+
"input": {"id": "1", "character_name": null, "option": null},
104+
"expected": {"id": "1", "character_id": "", "selected_character": - 1, "option": ""},
105+
},
106+
{
107+
"input": {"id": null, "character_name": "Test Character", "option": null},
108+
"expected": {"id": "", "character_id": "%s:test_character" % ParleyUtils.resource.get_uid(character_store), "selected_character": 1, "option": ""},
109+
},
110+
{
111+
"input": {"id": null, "character_name": null, "option": "Some option"},
112+
"expected": {"id": "", "character_id": "", "selected_character": - 1, "option": "Some option"},
113+
},
114+
{
115+
"input": {"id": "1", "character_name": "Test Character", "option": "Some option"},
116+
"expected": {"id": "1", "character_id": "%s:test_character" % ParleyUtils.resource.get_uid(character_store), "selected_character": 1, "option": "Some option"},
117+
},
118+
])) -> void:
119+
# Arrange
120+
var input: Dictionary = params['input']
121+
var expected: Dictionary = params['expected']
122+
watch_signals(dialogue_option_node_editor)
123+
124+
# Act
125+
await wait_until(func() -> bool: return dialogue_option_node_editor.is_inside_tree(), .1)
126+
setup_dialogue_option_node_editor(dialogue_option_node_editor, input)
127+
128+
# Assert
129+
assert_true(dialogue_option_node_editor.is_inside_tree())
130+
assert_eq(dialogue_option_node_editor.id, str(expected['id']))
131+
assert_eq(dialogue_option_node_editor.option, str(expected['option']))
132+
assert_eq(dialogue_option_node_editor.option_editor.text, str(expected['option']))
133+
assert_signal_not_emitted(dialogue_option_node_editor, 'dialogue_option_node_changed')
134+
135+
func test_update_render_with_text_input(params: Variant = use_parameters([
136+
{
137+
"input": {"id": "1", "option": "Some option"},
138+
"expected": {"id": "1", "character_id": "", "selected_character": -1, "option": "Some option", "text_translation_key": ""},
139+
},
140+
{
141+
"input": {"id": "1", "selected_character": 0},
142+
"expected": {"id": "1", "character_id": "%s::default_character" % ParleyUtils.resource.get_uid(character_store), "selected_character": 0, "option": "", "text_translation_key": ""},
143+
},
144+
{
145+
"input": {"id": "1", "text_translation_key": "some_text_translation_key"},
146+
"expected": {"id": "1", "character_id": "", "selected_character": -1, "option": "", "text_translation_key": "some_text_translation_key"},
147+
},
148+
])) -> void:
149+
# Arrange
150+
var input: Dictionary = params['input']
151+
var expected: Dictionary = params['expected']
152+
var expected_selected_character: int = expected['selected_character']
153+
watch_signals(dialogue_option_node_editor)
154+
dialogue_option_node_editor.id = input['id']
155+
156+
# Act
157+
await wait_until(func() -> bool: return dialogue_option_node_editor.is_inside_tree(), .1)
158+
use_dialogue_option_node_editor(dialogue_option_node_editor, input)
159+
await wait_for_signal(dialogue_option_node_editor.dialogue_option_node_changed, .1)
160+
161+
# Assert
162+
assert_true(dialogue_option_node_editor.is_inside_tree())
163+
assert_eq(dialogue_option_node_editor.option, str(expected['option']))
164+
assert_eq(dialogue_option_node_editor.option_editor.text, str(expected['option']))
165+
assert_eq(dialogue_option_node_editor.character_selector.selected, expected_selected_character)
166+
assert_eq(dialogue_option_node_editor.text_translation_key, str(expected['text_translation_key']))
167+
assert_signal_emitted_with_parameters(dialogue_option_node_editor, 'dialogue_option_node_changed', [expected['id'], expected['character_id'], expected['option'], expected['text_translation_key']])

0 commit comments

Comments
 (0)