Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/tests/scene/test_node.cpp
45997 views
1
/**************************************************************************/
2
/* test_node.cpp */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#include "tests/test_macros.h"
32
33
TEST_FORCE_LINK(test_node)
34
35
#include "core/io/file_access.h"
36
#include "core/io/resource_saver.h"
37
#include "core/object/class_db.h"
38
#include "scene/main/node.h"
39
#include "scene/main/scene_tree.h"
40
#include "scene/main/window.h"
41
#include "scene/resources/packed_scene.h"
42
#include "tests/test_utils.h"
43
44
namespace TestNode {
45
46
class TestNode : public Node {
47
GDCLASS(TestNode, Node);
48
49
protected:
50
void _notification(int p_what) {
51
switch (p_what) {
52
case NOTIFICATION_INTERNAL_PROCESS: {
53
internal_process_counter++;
54
push_self();
55
} break;
56
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
57
internal_physics_process_counter++;
58
push_self();
59
} break;
60
case NOTIFICATION_PROCESS: {
61
process_counter++;
62
push_self();
63
} break;
64
case NOTIFICATION_PHYSICS_PROCESS: {
65
physics_process_counter++;
66
push_self();
67
} break;
68
}
69
}
70
71
static void _bind_methods() {
72
ClassDB::bind_method(D_METHOD("set_exported_node", "node"), &TestNode::set_exported_node);
73
ClassDB::bind_method(D_METHOD("get_exported_node"), &TestNode::get_exported_node);
74
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "exported_node", PROPERTY_HINT_NODE_TYPE, "Node"), "set_exported_node", "get_exported_node");
75
76
ClassDB::bind_method(D_METHOD("set_exported_nodes", "node"), &TestNode::set_exported_nodes);
77
ClassDB::bind_method(D_METHOD("get_exported_nodes"), &TestNode::get_exported_nodes);
78
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "exported_nodes", PROPERTY_HINT_TYPE_STRING, "24/34:Node"), "set_exported_nodes", "get_exported_nodes");
79
}
80
81
private:
82
void push_self() {
83
if (callback_list) {
84
callback_list->push_back(this);
85
}
86
}
87
88
public:
89
int internal_process_counter = 0;
90
int internal_physics_process_counter = 0;
91
int process_counter = 0;
92
int physics_process_counter = 0;
93
94
Node *exported_node = nullptr;
95
Array exported_nodes;
96
97
List<Node *> *callback_list = nullptr;
98
99
void set_exported_node(Node *p_node) { exported_node = p_node; }
100
Node *get_exported_node() const { return exported_node; }
101
102
void set_exported_nodes(const Array &p_nodes) { exported_nodes = p_nodes; }
103
Array get_exported_nodes() const { return exported_nodes; }
104
105
TestNode() {
106
Node *internal = memnew(Node);
107
add_child(internal, false, INTERNAL_MODE_FRONT);
108
internal = memnew(Node);
109
add_child(internal, false, INTERNAL_MODE_BACK);
110
}
111
};
112
113
TEST_CASE("[SceneTree][Node] Testing node operations with a very simple scene tree") {
114
Node *node = memnew(Node);
115
116
// Check initial scene tree setup.
117
CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child_count(), 0);
118
CHECK_EQ(SceneTree::get_singleton()->get_node_count(), 1);
119
120
// Check initial node setup.
121
CHECK(node->get_name() == StringName());
122
CHECK_FALSE(node->is_inside_tree());
123
CHECK_EQ(node->get_parent(), nullptr);
124
ERR_PRINT_OFF;
125
CHECK(node->get_path().is_empty());
126
ERR_PRINT_ON;
127
CHECK_EQ(node->get_child_count(), 0);
128
129
SceneTree::get_singleton()->get_root()->add_child(node);
130
131
CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child_count(), 1);
132
CHECK_EQ(SceneTree::get_singleton()->get_node_count(), 2);
133
134
CHECK(node->get_name() != StringName());
135
CHECK(node->is_inside_tree());
136
CHECK_EQ(SceneTree::get_singleton()->get_root(), node->get_parent());
137
CHECK_FALSE(node->get_path().is_empty());
138
CHECK_EQ(node->get_child_count(), 0);
139
140
SUBCASE("Node should be accessible as first child") {
141
Node *child = SceneTree::get_singleton()->get_root()->get_child(0);
142
CHECK_EQ(child, node);
143
}
144
145
SUBCASE("Node should be accessible via the node path") {
146
Node *child_by_path = SceneTree::get_singleton()->get_root()->get_node_or_null(node->get_path());
147
CHECK_EQ(child_by_path, node);
148
149
child_by_path = SceneTree::get_singleton()->get_root()->get_node_or_null(NodePath("Node"));
150
CHECK_EQ(child_by_path, nullptr);
151
152
child_by_path = SceneTree::get_singleton()->get_root()->get_node_or_null(NodePath("/root/Node"));
153
CHECK_EQ(child_by_path, nullptr);
154
155
node->set_name("Node");
156
157
child_by_path = SceneTree::get_singleton()->get_root()->get_node_or_null(node->get_path());
158
CHECK_EQ(child_by_path, node);
159
160
child_by_path = SceneTree::get_singleton()->get_root()->get_node_or_null(NodePath("Node"));
161
CHECK_EQ(child_by_path, node);
162
163
child_by_path = SceneTree::get_singleton()->get_root()->get_node_or_null(NodePath("/root/Node"));
164
CHECK_EQ(child_by_path, node);
165
}
166
167
SUBCASE("Node should be accessible via group") {
168
Vector<Node *> nodes = SceneTree::get_singleton()->get_nodes_in_group("nodes");
169
CHECK(nodes.is_empty());
170
171
node->add_to_group("nodes");
172
173
nodes = SceneTree::get_singleton()->get_nodes_in_group("nodes");
174
CHECK_EQ(nodes.size(), 1);
175
Node *E = nodes.get(0);
176
CHECK_EQ(E, node);
177
}
178
179
SUBCASE("Node should be possible to find") {
180
Node *child = SceneTree::get_singleton()->get_root()->find_child("Node", true, false);
181
CHECK_EQ(child, nullptr);
182
183
node->set_name("Node");
184
185
child = SceneTree::get_singleton()->get_root()->find_child("Node", true, false);
186
CHECK_EQ(child, node);
187
}
188
189
SUBCASE("Node should be possible to remove") {
190
SceneTree::get_singleton()->get_root()->remove_child(node);
191
192
CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child_count(), 0);
193
CHECK_EQ(SceneTree::get_singleton()->get_node_count(), 1);
194
195
CHECK_FALSE(node->is_inside_tree());
196
CHECK_EQ(node->get_parent(), nullptr);
197
ERR_PRINT_OFF;
198
CHECK(node->get_path().is_empty());
199
ERR_PRINT_ON;
200
}
201
202
SUBCASE("Node should be possible to move") {
203
SceneTree::get_singleton()->get_root()->move_child(node, 0);
204
205
Node *child = SceneTree::get_singleton()->get_root()->get_child(0);
206
CHECK_EQ(child, node);
207
CHECK(node->is_inside_tree());
208
}
209
210
SUBCASE("Node should be possible to reparent") {
211
node->reparent(SceneTree::get_singleton()->get_root());
212
213
Node *child = SceneTree::get_singleton()->get_root()->get_child(0);
214
CHECK_EQ(child, node);
215
CHECK(node->is_inside_tree());
216
}
217
218
SUBCASE("Node should be possible to duplicate") {
219
node->set_name("MyName");
220
221
Node *duplicate = node->duplicate();
222
223
CHECK_FALSE(node == duplicate);
224
CHECK_FALSE(duplicate->is_inside_tree());
225
CHECK_EQ(duplicate->get_name(), node->get_name());
226
227
memdelete(duplicate);
228
}
229
230
memdelete(node);
231
}
232
233
TEST_CASE("[SceneTree][Node] Testing node operations with a more complex simple scene tree") {
234
Node *node1 = memnew(Node);
235
Node *node2 = memnew(Node);
236
Node *node1_1 = memnew(Node);
237
238
SceneTree::get_singleton()->get_root()->add_child(node1);
239
SceneTree::get_singleton()->get_root()->add_child(node2);
240
241
node1->add_child(node1_1);
242
243
CHECK(node1_1->is_inside_tree());
244
CHECK_EQ(node1_1->get_parent(), node1);
245
CHECK_EQ(node1->get_child_count(), 1);
246
247
CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child_count(), 2);
248
CHECK_EQ(SceneTree::get_singleton()->get_node_count(), 4);
249
250
SUBCASE("Nodes should be accessible via get_child(..)") {
251
Node *child1 = SceneTree::get_singleton()->get_root()->get_child(0);
252
CHECK_EQ(child1, node1);
253
254
Node *child2 = SceneTree::get_singleton()->get_root()->get_child(1);
255
CHECK_EQ(child2, node2);
256
257
Node *child1_1 = node1->get_child(0);
258
CHECK_EQ(child1_1, node1_1);
259
}
260
261
SUBCASE("Removed nodes should also remove their children from the scene tree") {
262
// Should also remove node1_1 from the scene tree.
263
SceneTree::get_singleton()->get_root()->remove_child(node1);
264
265
CHECK_EQ(node1->get_child_count(), 1);
266
267
CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child_count(), 1);
268
CHECK_EQ(SceneTree::get_singleton()->get_node_count(), 2);
269
270
// First child should now be the second node.
271
Node *child1 = SceneTree::get_singleton()->get_root()->get_child(0);
272
CHECK_EQ(child1, node2);
273
}
274
275
SUBCASE("Removed children nodes should not affect their parent in the scene tree") {
276
node1->remove_child(node1_1);
277
278
CHECK_EQ(node1_1->get_parent(), nullptr);
279
CHECK_EQ(node1->get_child_count(), 0);
280
281
CHECK_EQ(SceneTree::get_singleton()->get_node_count(), 3);
282
}
283
284
SUBCASE("Nodes should be in the expected order when a node is moved to the back") {
285
SceneTree::get_singleton()->get_root()->move_child(node1, 1);
286
287
Node *child1 = SceneTree::get_singleton()->get_root()->get_child(0);
288
CHECK_EQ(child1, node2);
289
290
Node *child2 = SceneTree::get_singleton()->get_root()->get_child(1);
291
CHECK_EQ(child2, node1);
292
}
293
294
SUBCASE("Nodes should be in the expected order when a node is moved to the front") {
295
SceneTree::get_singleton()->get_root()->move_child(node2, 0);
296
297
Node *child1 = SceneTree::get_singleton()->get_root()->get_child(0);
298
CHECK_EQ(child1, node2);
299
300
Node *child2 = SceneTree::get_singleton()->get_root()->get_child(1);
301
CHECK_EQ(child2, node1);
302
}
303
304
SUBCASE("Nodes should be in the expected order when reparented (remove/add)") {
305
CHECK_EQ(node2->get_child_count(), 0);
306
307
node1->remove_child(node1_1);
308
CHECK_EQ(node1->get_child_count(), 0);
309
CHECK_EQ(node1_1->get_parent(), nullptr);
310
311
node2->add_child(node1_1);
312
CHECK_EQ(node2->get_child_count(), 1);
313
CHECK_EQ(node1_1->get_parent(), node2);
314
315
Node *child = node2->get_child(0);
316
CHECK_EQ(child, node1_1);
317
318
CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child_count(), 2);
319
CHECK_EQ(SceneTree::get_singleton()->get_node_count(), 4);
320
}
321
322
SUBCASE("Nodes should be in the expected order when reparented") {
323
CHECK_EQ(node2->get_child_count(), 0);
324
325
node1_1->reparent(node2);
326
327
CHECK_EQ(node1->get_child_count(), 0);
328
CHECK_EQ(node2->get_child_count(), 1);
329
CHECK_EQ(node1_1->get_parent(), node2);
330
331
Node *child = node2->get_child(0);
332
CHECK_EQ(child, node1_1);
333
334
CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child_count(), 2);
335
CHECK_EQ(SceneTree::get_singleton()->get_node_count(), 4);
336
}
337
338
SUBCASE("Nodes should be possible to find") {
339
Node *child = SceneTree::get_singleton()->get_root()->find_child("NestedNode", true, false);
340
CHECK_EQ(child, nullptr);
341
342
TypedArray<Node> children = SceneTree::get_singleton()->get_root()->find_children("NestedNode", "", true, false);
343
CHECK_EQ(children.size(), 0);
344
345
node1->set_name("Node1");
346
node2->set_name("Node2");
347
node1_1->set_name("NestedNode");
348
349
child = SceneTree::get_singleton()->get_root()->find_child("NestedNode", true, false);
350
CHECK_EQ(child, node1_1);
351
352
children = SceneTree::get_singleton()->get_root()->find_children("NestedNode", "", true, false);
353
CHECK_EQ(children.size(), 1);
354
CHECK_EQ(Object::cast_to<Node>(children[0]), node1_1);
355
356
// First node that matches with the name is node1.
357
child = SceneTree::get_singleton()->get_root()->find_child("Node?", true, false);
358
CHECK_EQ(child, node1);
359
360
children = SceneTree::get_singleton()->get_root()->find_children("Node?", "", true, false);
361
CHECK_EQ(children.size(), 2);
362
CHECK_EQ(Object::cast_to<Node>(children[0]), node1);
363
CHECK_EQ(Object::cast_to<Node>(children[1]), node2);
364
365
SceneTree::get_singleton()->get_root()->move_child(node2, 0);
366
367
// It should be node2, as it is now the first one in the tree.
368
child = SceneTree::get_singleton()->get_root()->find_child("Node?", true, false);
369
CHECK_EQ(child, node2);
370
371
children = SceneTree::get_singleton()->get_root()->find_children("Node?", "", true, false);
372
CHECK_EQ(children.size(), 2);
373
CHECK_EQ(Object::cast_to<Node>(children[0]), node2);
374
CHECK_EQ(Object::cast_to<Node>(children[1]), node1);
375
}
376
377
SUBCASE("Nodes should be accessible via their node path") {
378
Node *child_by_path = SceneTree::get_singleton()->get_root()->get_node_or_null(node1->get_path());
379
CHECK_EQ(child_by_path, node1);
380
381
child_by_path = SceneTree::get_singleton()->get_root()->get_node_or_null(node2->get_path());
382
CHECK_EQ(child_by_path, node2);
383
384
child_by_path = SceneTree::get_singleton()->get_root()->get_node_or_null(node1_1->get_path());
385
CHECK_EQ(child_by_path, node1_1);
386
387
node1->set_name("Node1");
388
node1_1->set_name("NestedNode");
389
390
child_by_path = node1->get_node_or_null(NodePath("NestedNode"));
391
CHECK_EQ(child_by_path, node1_1);
392
393
child_by_path = SceneTree::get_singleton()->get_root()->get_node_or_null(NodePath("/root/Node1/NestedNode"));
394
CHECK_EQ(child_by_path, node1_1);
395
396
child_by_path = SceneTree::get_singleton()->get_root()->get_node_or_null(NodePath("Node1/NestedNode"));
397
CHECK_EQ(child_by_path, node1_1);
398
}
399
400
SUBCASE("Nodes should be accessible via their groups") {
401
Vector<Node *> nodes = SceneTree::get_singleton()->get_nodes_in_group("nodes");
402
CHECK(nodes.is_empty());
403
404
nodes = SceneTree::get_singleton()->get_nodes_in_group("other_nodes");
405
CHECK(nodes.is_empty());
406
407
node1->add_to_group("nodes");
408
node2->add_to_group("other_nodes");
409
node1_1->add_to_group("nodes");
410
node1_1->add_to_group("other_nodes");
411
412
nodes = SceneTree::get_singleton()->get_nodes_in_group("nodes");
413
CHECK_EQ(nodes.size(), 2);
414
415
Node *E = nodes.get(0);
416
CHECK_EQ(E, node1);
417
E = nodes.get(1);
418
CHECK_EQ(E, node1_1);
419
420
// Clear and try again with the other group.
421
nodes.clear();
422
423
nodes = SceneTree::get_singleton()->get_nodes_in_group("other_nodes");
424
CHECK_EQ(nodes.size(), 2);
425
426
E = nodes.get(0);
427
CHECK_EQ(E, node1_1);
428
E = nodes.get(1);
429
CHECK_EQ(E, node2);
430
431
// Clear and try again with the other group and one node removed.
432
nodes.clear();
433
434
node1->remove_from_group("nodes");
435
nodes = SceneTree::get_singleton()->get_nodes_in_group("nodes");
436
CHECK_EQ(nodes.size(), 1);
437
438
E = nodes.get(0);
439
CHECK_EQ(E, node1_1);
440
}
441
442
SUBCASE("Nodes added as siblings of another node should be right next to it") {
443
node1->remove_child(node1_1);
444
445
node1->add_sibling(node1_1);
446
447
CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child_count(), 3);
448
CHECK_EQ(SceneTree::get_singleton()->get_node_count(), 4);
449
450
CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child(0), node1);
451
CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child(1), node1_1);
452
CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child(2), node2);
453
}
454
455
SUBCASE("Replaced nodes should be be removed and the replacing node added") {
456
SceneTree::get_singleton()->get_root()->remove_child(node2);
457
458
node1->replace_by(node2);
459
460
CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child_count(), 1);
461
CHECK_EQ(SceneTree::get_singleton()->get_node_count(), 3);
462
463
CHECK_FALSE(node1->is_inside_tree());
464
CHECK(node2->is_inside_tree());
465
466
CHECK_EQ(node1->get_parent(), nullptr);
467
CHECK_EQ(node2->get_parent(), SceneTree::get_singleton()->get_root());
468
CHECK_EQ(node2->get_child_count(), 1);
469
CHECK_EQ(node2->get_child(0), node1_1);
470
}
471
472
SUBCASE("Replacing nodes should keep the groups of the replaced nodes") {
473
SceneTree::get_singleton()->get_root()->remove_child(node2);
474
475
node1->add_to_group("nodes");
476
node1->replace_by(node2, true);
477
478
Vector<Node *> nodes = SceneTree::get_singleton()->get_nodes_in_group("nodes");
479
CHECK_EQ(nodes.size(), 1);
480
481
Node *E = nodes.get(0);
482
CHECK_EQ(E, node2);
483
}
484
485
SUBCASE("Duplicating a node should also duplicate the children") {
486
node1->set_name("MyName1");
487
node1_1->set_name("MyName1_1");
488
Node *duplicate1 = node1->duplicate();
489
490
CHECK_EQ(duplicate1->get_child_count(), node1->get_child_count());
491
Node *duplicate1_1 = duplicate1->get_child(0);
492
493
CHECK_EQ(duplicate1_1->get_child_count(), node1_1->get_child_count());
494
495
CHECK_EQ(duplicate1->get_name(), node1->get_name());
496
CHECK_EQ(duplicate1_1->get_name(), node1_1->get_name());
497
498
CHECK_FALSE(duplicate1->is_inside_tree());
499
CHECK_FALSE(duplicate1_1->is_inside_tree());
500
501
memdelete(duplicate1_1);
502
memdelete(duplicate1);
503
}
504
505
memdelete(node1_1);
506
memdelete(node1);
507
memdelete(node2);
508
}
509
510
TEST_CASE("[SceneTree][Node] Duplicating node with internal children") {
511
GDREGISTER_CLASS(TestNode);
512
513
TestNode *node = memnew(TestNode);
514
Node *child = memnew(Node);
515
child->set_name("Child");
516
node->add_child(child);
517
518
int child_count = node->get_child_count();
519
520
Node *dup = node->duplicate();
521
CHECK(dup->get_child_count() == child_count);
522
CHECK(dup->has_node(String("Child")));
523
524
memdelete(node);
525
memdelete(dup);
526
}
527
528
TEST_CASE("[SceneTree][Node]Exported node checks") {
529
TestNode *node = memnew(TestNode);
530
SceneTree::get_singleton()->get_root()->add_child(node);
531
532
Node *child = memnew(Node);
533
child->set_name("Child");
534
node->add_child(child);
535
child->set_owner(node);
536
537
Node *child2 = memnew(Node);
538
child2->set_name("Child2");
539
node->add_child(child2);
540
child2->set_owner(node);
541
542
Array children;
543
children.append(child);
544
545
node->set("exported_node", child);
546
node->set("exported_nodes", children);
547
548
SUBCASE("Property of duplicated node should point to duplicated child") {
549
GDREGISTER_CLASS(TestNode);
550
551
TestNode *dup = Object::cast_to<TestNode>(node->duplicate());
552
Node *new_exported = Object::cast_to<Node>(dup->get("exported_node"));
553
CHECK(new_exported == dup->get_child(0, false));
554
555
memdelete(dup);
556
}
557
558
#ifdef TOOLS_ENABLED
559
SUBCASE("Saving instance with exported nodes should not store the unchanged property") {
560
Ref<PackedScene> ps;
561
ps.instantiate();
562
ps->pack(node);
563
564
String scene_path = TestUtils::get_temp_path("test_scene.tscn");
565
ps->set_path(scene_path);
566
567
Node *root = memnew(Node);
568
569
Node *sub_child = ps->instantiate(PackedScene::GEN_EDIT_STATE_MAIN);
570
root->add_child(sub_child);
571
sub_child->set_owner(root);
572
573
Ref<PackedScene> ps2;
574
ps2.instantiate();
575
ps2->pack(root);
576
577
scene_path = TestUtils::get_temp_path("new_test_scene.tscn");
578
ResourceSaver::save(ps2, scene_path);
579
memdelete(root);
580
581
bool is_wrong = false;
582
Ref<FileAccess> fa = FileAccess::open(scene_path, FileAccess::READ);
583
while (!fa->eof_reached()) {
584
const String line = fa->get_line();
585
if (line.begins_with("exported_node")) {
586
// The property was saved, while it shouldn't.
587
is_wrong = true;
588
break;
589
}
590
}
591
CHECK_FALSE(is_wrong);
592
}
593
594
SUBCASE("Saving instance with exported nodes should store property if changed") {
595
Ref<PackedScene> ps;
596
ps.instantiate();
597
ps->pack(node);
598
599
String scene_path = TestUtils::get_temp_path("test_scene.tscn");
600
ps->set_path(scene_path);
601
602
Node *root = memnew(Node);
603
604
Node *sub_child = ps->instantiate(PackedScene::GEN_EDIT_STATE_MAIN);
605
root->add_child(sub_child);
606
sub_child->set_owner(root);
607
608
sub_child->set("exported_node", sub_child->get_child(1, false));
609
610
children = Array();
611
children.append(sub_child->get_child(1, false));
612
sub_child->set("exported_nodes", children);
613
614
Ref<PackedScene> ps2;
615
ps2.instantiate();
616
ps2->pack(root);
617
618
scene_path = TestUtils::get_temp_path("new_test_scene2.tscn");
619
ResourceSaver::save(ps2, scene_path);
620
memdelete(root);
621
622
int stored_properties = 0;
623
Ref<FileAccess> fa = FileAccess::open(scene_path, FileAccess::READ);
624
while (!fa->eof_reached()) {
625
const String line = fa->get_line();
626
if (line.begins_with("exported_node")) {
627
stored_properties++;
628
}
629
}
630
CHECK_EQ(stored_properties, 2);
631
}
632
#endif // TOOLS_ENABLED
633
634
memdelete(node);
635
}
636
637
TEST_CASE("[Node] Processing checks") {
638
Node *node = memnew(Node);
639
640
SUBCASE("Processing") {
641
CHECK_FALSE(node->is_processing());
642
643
node->set_process(true);
644
645
CHECK(node->is_processing());
646
647
node->set_process(false);
648
649
CHECK_FALSE(node->is_processing());
650
}
651
652
SUBCASE("Physics processing") {
653
CHECK_FALSE(node->is_physics_processing());
654
655
node->set_physics_process(true);
656
657
CHECK(node->is_physics_processing());
658
659
node->set_physics_process(false);
660
661
CHECK_FALSE(node->is_physics_processing());
662
}
663
664
SUBCASE("Unhandled input processing") {
665
CHECK_FALSE(node->is_processing_unhandled_input());
666
667
node->set_process_unhandled_input(true);
668
669
CHECK(node->is_processing_unhandled_input());
670
671
node->set_process_unhandled_input(false);
672
673
CHECK_FALSE(node->is_processing_unhandled_input());
674
}
675
676
SUBCASE("Input processing") {
677
CHECK_FALSE(node->is_processing_input());
678
679
node->set_process_input(true);
680
681
CHECK(node->is_processing_input());
682
683
node->set_process_input(false);
684
685
CHECK_FALSE(node->is_processing_input());
686
}
687
688
SUBCASE("Unhandled key input processing") {
689
CHECK_FALSE(node->is_processing_unhandled_key_input());
690
691
node->set_process_unhandled_key_input(true);
692
693
CHECK(node->is_processing_unhandled_key_input());
694
695
node->set_process_unhandled_key_input(false);
696
697
CHECK_FALSE(node->is_processing_unhandled_key_input());
698
}
699
700
SUBCASE("Shortcut input processing") {
701
CHECK_FALSE(node->is_processing_shortcut_input());
702
703
node->set_process_shortcut_input(true);
704
705
CHECK(node->is_processing_shortcut_input());
706
707
node->set_process_shortcut_input(false);
708
709
CHECK_FALSE(node->is_processing_shortcut_input());
710
}
711
712
SUBCASE("Internal processing") {
713
CHECK_FALSE(node->is_processing_internal());
714
715
node->set_process_internal(true);
716
717
CHECK(node->is_processing_internal());
718
719
node->set_process_internal(false);
720
721
CHECK_FALSE(node->is_processing_internal());
722
}
723
724
SUBCASE("Process priority") {
725
CHECK_EQ(0, node->get_process_priority());
726
727
node->set_process_priority(1);
728
729
CHECK_EQ(1, node->get_process_priority());
730
}
731
732
SUBCASE("Physics process priority") {
733
CHECK_EQ(0, node->get_physics_process_priority());
734
735
node->set_physics_process_priority(1);
736
737
CHECK_EQ(1, node->get_physics_process_priority());
738
}
739
740
memdelete(node);
741
}
742
743
TEST_CASE("[SceneTree][Node] Test the processing") {
744
TestNode *node = memnew(TestNode);
745
SceneTree::get_singleton()->get_root()->add_child(node);
746
747
SUBCASE("No process") {
748
CHECK_EQ(0, node->process_counter);
749
CHECK_EQ(0, node->physics_process_counter);
750
}
751
752
SUBCASE("Process") {
753
node->set_process(true);
754
SceneTree::get_singleton()->process(0);
755
756
CHECK_EQ(1, node->process_counter);
757
CHECK_EQ(0, node->physics_process_counter);
758
CHECK_EQ(0, node->internal_process_counter);
759
CHECK_EQ(0, node->internal_physics_process_counter);
760
}
761
762
SUBCASE("Physics process") {
763
node->set_physics_process(true);
764
SceneTree::get_singleton()->physics_process(0);
765
766
CHECK_EQ(0, node->process_counter);
767
CHECK_EQ(1, node->physics_process_counter);
768
CHECK_EQ(0, node->internal_process_counter);
769
CHECK_EQ(0, node->internal_physics_process_counter);
770
}
771
772
SUBCASE("Normal and physics process") {
773
node->set_process(true);
774
node->set_physics_process(true);
775
SceneTree::get_singleton()->process(0);
776
SceneTree::get_singleton()->physics_process(0);
777
778
CHECK_EQ(1, node->process_counter);
779
CHECK_EQ(1, node->physics_process_counter);
780
CHECK_EQ(0, node->internal_process_counter);
781
CHECK_EQ(0, node->internal_physics_process_counter);
782
}
783
784
SUBCASE("Internal, normal and physics process") {
785
node->set_process_internal(true);
786
node->set_physics_process_internal(true);
787
SceneTree::get_singleton()->process(0);
788
SceneTree::get_singleton()->physics_process(0);
789
790
CHECK_EQ(0, node->process_counter);
791
CHECK_EQ(0, node->physics_process_counter);
792
CHECK_EQ(1, node->internal_process_counter);
793
CHECK_EQ(1, node->internal_physics_process_counter);
794
}
795
796
SUBCASE("All processing") {
797
node->set_process(true);
798
node->set_physics_process(true);
799
node->set_process_internal(true);
800
node->set_physics_process_internal(true);
801
SceneTree::get_singleton()->process(0);
802
SceneTree::get_singleton()->physics_process(0);
803
804
CHECK_EQ(1, node->process_counter);
805
CHECK_EQ(1, node->physics_process_counter);
806
CHECK_EQ(1, node->internal_process_counter);
807
CHECK_EQ(1, node->internal_physics_process_counter);
808
}
809
810
SUBCASE("All processing twice") {
811
node->set_process(true);
812
node->set_physics_process(true);
813
node->set_process_internal(true);
814
node->set_physics_process_internal(true);
815
SceneTree::get_singleton()->process(0);
816
SceneTree::get_singleton()->physics_process(0);
817
SceneTree::get_singleton()->process(0);
818
SceneTree::get_singleton()->physics_process(0);
819
820
CHECK_EQ(2, node->process_counter);
821
CHECK_EQ(2, node->physics_process_counter);
822
CHECK_EQ(2, node->internal_process_counter);
823
CHECK_EQ(2, node->internal_physics_process_counter);
824
}
825
826
SUBCASE("Enable and disable processing") {
827
node->set_process(true);
828
node->set_physics_process(true);
829
node->set_process_internal(true);
830
node->set_physics_process_internal(true);
831
SceneTree::get_singleton()->process(0);
832
SceneTree::get_singleton()->physics_process(0);
833
834
node->set_process(false);
835
node->set_physics_process(false);
836
node->set_process_internal(false);
837
node->set_physics_process_internal(false);
838
SceneTree::get_singleton()->process(0);
839
SceneTree::get_singleton()->physics_process(0);
840
841
CHECK_EQ(1, node->process_counter);
842
CHECK_EQ(1, node->physics_process_counter);
843
CHECK_EQ(1, node->internal_process_counter);
844
CHECK_EQ(1, node->internal_physics_process_counter);
845
}
846
847
memdelete(node);
848
}
849
850
TEST_CASE("[SceneTree][Node] Test the process priority") {
851
List<Node *> process_order;
852
853
TestNode *node = memnew(TestNode);
854
node->callback_list = &process_order;
855
SceneTree::get_singleton()->get_root()->add_child(node);
856
857
TestNode *node2 = memnew(TestNode);
858
node2->callback_list = &process_order;
859
SceneTree::get_singleton()->get_root()->add_child(node2);
860
861
TestNode *node3 = memnew(TestNode);
862
node3->callback_list = &process_order;
863
SceneTree::get_singleton()->get_root()->add_child(node3);
864
865
TestNode *node4 = memnew(TestNode);
866
node4->callback_list = &process_order;
867
SceneTree::get_singleton()->get_root()->add_child(node4);
868
869
SUBCASE("Process priority") {
870
node->set_process(true);
871
node->set_process_priority(20);
872
node2->set_process(true);
873
node2->set_process_priority(10);
874
node3->set_process(true);
875
node3->set_process_priority(40);
876
node4->set_process(true);
877
node4->set_process_priority(30);
878
879
SceneTree::get_singleton()->process(0);
880
881
CHECK_EQ(4, process_order.size());
882
List<Node *>::Element *E = process_order.front();
883
CHECK_EQ(E->get(), node2);
884
E = E->next();
885
CHECK_EQ(E->get(), node);
886
E = E->next();
887
CHECK_EQ(E->get(), node4);
888
E = E->next();
889
CHECK_EQ(E->get(), node3);
890
}
891
892
SUBCASE("Physics process priority") {
893
node->set_physics_process(true);
894
node->set_physics_process_priority(20);
895
node2->set_physics_process(true);
896
node2->set_physics_process_priority(10);
897
node3->set_physics_process(true);
898
node3->set_physics_process_priority(40);
899
node4->set_physics_process(true);
900
node4->set_physics_process_priority(30);
901
902
SceneTree::get_singleton()->physics_process(0);
903
904
CHECK_EQ(4, process_order.size());
905
List<Node *>::Element *E = process_order.front();
906
CHECK_EQ(E->get(), node2);
907
E = E->next();
908
CHECK_EQ(E->get(), node);
909
E = E->next();
910
CHECK_EQ(E->get(), node4);
911
E = E->next();
912
CHECK_EQ(E->get(), node3);
913
}
914
915
memdelete(node);
916
memdelete(node2);
917
memdelete(node3);
918
memdelete(node4);
919
}
920
921
} // namespace TestNode
922
923