Blender V5.0
node_iterator_tests.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2025 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4#include "testing/testing.h"
5
6#include "CLG_log.h"
7
8/* Allow using `Scene->nodetree` because it's still relevant for backward compatibility. */
9#define DNA_DEPRECATED_ALLOW
10#include "DNA_material_types.h"
11#include "DNA_scene_types.h"
12
13#include "BKE_appdir.hh"
14#include "BKE_context.hh"
15#include "BKE_global.hh"
16#include "BKE_idtype.hh"
17#include "BKE_main.hh"
18#include "BKE_material.hh"
19#include "BKE_node.hh"
20#include "BKE_scene.hh"
21
22#include "IMB_imbuf.hh"
23
24#include "ED_node_c.hh"
25
26#include "RNA_define.hh"
27
28namespace blender::nodes::tests {
29
30class NodeTest : public ::testing::Test {
31
32 protected:
43
44 static void TearDownTestSuite()
45 {
48 RNA_exit();
50 IMB_exit();
51 CLG_exit();
52 }
53
58
60 {
61 IteratorResult iter_result;
62
63 FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
64 iter_result.node_trees.append(ntree);
65 iter_result.ids.append(id);
66 }
68
69 return iter_result;
70 };
71};
72
73class TestData {
74 public:
75 Main *bmain = nullptr;
76 bContext *C = nullptr;
77
79 {
80 if (bmain == nullptr) {
82 G.main = bmain;
83 }
84
85 if (C == nullptr) {
86 C = CTX_create();
88 }
89 }
90
92 {
93 if (bmain != nullptr) {
95 bmain = nullptr;
96 G.main = nullptr;
97 }
98
99 if (C != nullptr) {
100 CTX_free(C);
101 C = nullptr;
102 }
103 }
104};
105
106TEST_F(NodeTest, tree_iterator_empty)
107{
108 TestData context;
109
110 IteratorResult iter_result = this->get_node_trees(context.bmain);
111
112 EXPECT_EQ(iter_result.node_trees.size(), 0);
113 EXPECT_EQ(iter_result.ids.size(), 0);
114}
115
116TEST_F(NodeTest, tree_iterator_1_mat)
117{
118 TestData context;
119
120 Material *material = BKE_material_add(context.bmain, "Material");
121 ED_node_shader_default(context.C, context.bmain, &material->id);
122
123 IteratorResult iter_result = this->get_node_trees(context.bmain);
124
125 ASSERT_EQ(iter_result.node_trees.size(), 1);
126 ASSERT_EQ(iter_result.ids.size(), 1);
127
128 EXPECT_EQ(GS(iter_result.ids[0]->name), ID_MA);
129}
130
131TEST_F(NodeTest, tree_iterator_scene_no_tree)
132{
133 TestData context;
134
135 Material *material = BKE_material_add(context.bmain, "Material");
136 ED_node_shader_default(context.C, context.bmain, &material->id);
137
138 BKE_scene_add(context.bmain, "Scene");
139
140 IteratorResult iter_result = this->get_node_trees(context.bmain);
141
142 ASSERT_EQ(iter_result.node_trees.size(), 1);
143 ASSERT_EQ(iter_result.ids.size(), 1);
144
145 EXPECT_EQ(GS(iter_result.ids[0]->name), ID_MA);
146}
147
148TEST_F(NodeTest, tree_iterator_1mat_1scene)
149{
150 TestData context;
151 const char SCENE_NAME[MAX_ID_NAME] = "Scene for testing";
152
153 Material *material = BKE_material_add(context.bmain, "Material");
154 ED_node_shader_default(context.C, context.bmain, &material->id);
155
156 Scene *scene = BKE_scene_add(context.bmain, SCENE_NAME);
157 /* Embedded compositing trees are deprecated, but still relevant for versioning/backward
158 * compatibility. */
159 scene->nodetree = bke::node_tree_add_tree_embedded(
160 context.bmain, &scene->id, "compositing nodetree", "CompositorNodeTree");
161
162 IteratorResult iter_result = this->get_node_trees(context.bmain);
163
164 ASSERT_EQ(iter_result.node_trees.size(), 2);
165 ASSERT_EQ(iter_result.ids.size(), 2);
166
167 EXPECT_EQ(GS(iter_result.ids[1]->name), ID_MA);
168 EXPECT_EQ(GS(iter_result.ids[0]->name), ID_SCE);
169 EXPECT_STREQ(iter_result.ids[0]->name + 2, SCENE_NAME);
170
171 /* `scene->nodetree` is not managed by the scene anymore, i.e. `scene_free_data()` doesn't free
172 * its embedded node-trees, so we need to free it manually here. */
173 bke::node_tree_free_embedded_tree(scene->nodetree);
174 MEM_freeN(scene->nodetree);
175 scene->nodetree = nullptr;
176}
177
178TEST_F(NodeTest, tree_iterator_1mat_3scenes)
179{
180 TestData context;
181 const char SCENE_NAME_1[MAX_ID_NAME] = "Scene 1";
182 const char SCENE_NAME_2[MAX_ID_NAME] = "Scene 2";
183 const char SCENE_NAME_3[MAX_ID_NAME] = "Scene 3";
184 const char NTREE_NAME[MAX_NAME] = "Test Composisiting Nodetree";
185 /* Name is hard-coded in #ED_node_shader_default(). */
186 const char MATERIAL_NTREE_NAME[MAX_NAME] = "Shader Nodetree";
187
188 Material *material = BKE_material_add(context.bmain, "Material");
189 ED_node_shader_default(context.C, context.bmain, &material->id);
190
191 BKE_scene_add(context.bmain, SCENE_NAME_1);
192 /* Note: no node tree for scene 1. */
193
194 Scene *scene2 = BKE_scene_add(context.bmain, SCENE_NAME_2);
195 scene2->nodetree = bke::node_tree_add_tree_embedded(
196 context.bmain, &scene2->id, NTREE_NAME, "CompositorNodeTree");
197
198 BKE_scene_add(context.bmain, SCENE_NAME_3);
199 /* Also no node tree for scene 3. */
200
201 IteratorResult iter_result = this->get_node_trees(context.bmain);
202
203 ASSERT_EQ(iter_result.node_trees.size(), 2);
204 ASSERT_EQ(iter_result.ids.size(), 2);
205
206 /* Expect that scenes with no node-trees don't have side effects for node trees. */
207 EXPECT_EQ(GS(iter_result.ids[0]->name), ID_SCE);
208 EXPECT_STREQ(iter_result.ids[0]->name + 2, SCENE_NAME_2);
209 EXPECT_STREQ(iter_result.node_trees[0]->id.name + 2, NTREE_NAME);
210
211 EXPECT_EQ(GS(iter_result.ids[1]->name), ID_MA);
212 EXPECT_STREQ(iter_result.node_trees[1]->id.name + 2, MATERIAL_NTREE_NAME);
213
214 /* `scene->nodetree` is not managed by the scene anymore, i.e. `scene_free_data()` doesn't free
215 * its embedded node-trees, so we need to free it manually here. */
216 bke::node_tree_free_embedded_tree(scene2->nodetree);
217 MEM_freeN(scene2->nodetree);
218 scene2->nodetree = nullptr;
219}
220
221TEST_F(NodeTest, tree_iterator_1mat_1scene_2compositing_trees)
222{
223 TestData context;
224 const char SCENE_NAME_1[MAX_ID_NAME - 2] = "Scene 1";
225 const char NTREE_NAME_1[MAX_ID_NAME - 2] = "Test Composisiting Node Tree 1";
226 const char NTREE_NAME_2[MAX_ID_NAME - 2] = "Test Composisiting Node Tree 2";
227 const char MATERIAL_NTREE_NAME[MAX_NAME] = "Shader Nodetree";
228
229 Material *material = BKE_material_add(context.bmain, "Material");
230 ED_node_shader_default(context.C, context.bmain, &material->id);
231
232 BKE_scene_add(context.bmain, SCENE_NAME_1);
233
234 bke::node_tree_add_tree(context.bmain, NTREE_NAME_1, "CompositorNodeTree");
235 bke::node_tree_add_tree(context.bmain, NTREE_NAME_2, "CompositorNodeTree");
236
237 IteratorResult iter_result = this->get_node_trees(context.bmain);
238
239 ASSERT_EQ(iter_result.node_trees.size(), 3);
240 ASSERT_EQ(iter_result.ids.size(), 3);
241
242 /* Iterator should return 2 compositing node trees and no scene node tree. */
243 EXPECT_EQ(GS(iter_result.ids[0]->name), ID_NT);
244 EXPECT_STREQ(iter_result.ids[0]->name + 2, NTREE_NAME_1);
245 EXPECT_FALSE((iter_result.ids[0]->flag & ID_FLAG_EMBEDDED_DATA));
246
247 EXPECT_EQ(GS(iter_result.ids[1]->name), ID_NT);
248 EXPECT_STREQ(iter_result.ids[1]->name + 2, NTREE_NAME_2);
249 EXPECT_FALSE((iter_result.ids[1]->flag & ID_FLAG_EMBEDDED_DATA));
250
251 EXPECT_EQ(GS(iter_result.ids[2]->name), ID_MA);
252 EXPECT_STREQ(iter_result.node_trees[2]->id.name + 2, MATERIAL_NTREE_NAME);
253}
254
255} // namespace blender::nodes::tests
void BKE_appdir_init()
Definition appdir.cc:93
void BKE_appdir_exit()
Definition appdir.cc:101
void CTX_data_main_set(bContext *C, Main *bmain)
void CTX_free(bContext *C)
bContext * CTX_create()
void BKE_idtype_init()
Definition idtype.cc:121
Main * BKE_main_new()
Definition main.cc:89
void BKE_main_free(Main *bmain)
Definition main.cc:192
General operations, lookup, etc. for materials.
void BKE_materials_init()
Material * BKE_material_add(Main *bmain, const char *name)
void BKE_materials_exit()
#define FOREACH_NODETREE_END
Definition BKE_node.hh:881
#define FOREACH_NODETREE_BEGIN(bmain, _nodetree, _id)
Definition BKE_node.hh:871
Scene * BKE_scene_add(Main *bmain, const char *name)
Definition scene.cc:2001
EXPECT_EQ(BLI_expr_pylike_eval(expr, nullptr, 0, &result), EXPR_PYLIKE_INVALID)
void CLG_exit()
Definition clog.cc:880
void CLG_init()
Definition clog.cc:873
#define MAX_ID_NAME
Definition DNA_ID.h:373
@ ID_FLAG_EMBEDDED_DATA
Definition DNA_ID.h:774
@ ID_NT
@ ID_SCE
@ ID_MA
#define MAX_NAME
Definition DNA_defs.h:50
void ED_node_shader_default(const bContext *C, Main *bmain, ID *id)
Definition node_edit.cc:513
void IMB_exit()
Definition module.cc:21
void IMB_init()
Definition module.cc:15
void append(const T &value)
IteratorResult get_node_trees(Main *bmain)
#define GS(x)
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
#define G(x, y, z)
bNodeTree * node_tree_add_tree_embedded(Main *bmain, ID *owner_id, StringRefNull name, StringRefNull idname)
Definition node.cc:4098
void node_system_exit()
Definition node.cc:5431
bNodeTree * node_tree_add_tree(Main *bmain, StringRef name, StringRef idname)
Definition node.cc:4085
void node_system_init()
Definition node.cc:5426
void node_tree_free_embedded_tree(bNodeTree *ntree)
Definition node.cc:4462
TEST_F(BundleTest, DefaultBundle)
void RNA_exit()
void RNA_init()
Definition rna_access.cc:88