• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The Tint Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <unordered_set>
16 
17 #include "gtest/gtest-spi.h"
18 #include "src/program_builder.h"
19 
20 namespace tint {
21 namespace {
22 
23 struct Allocator {
24   template <typename T, typename... ARGS>
Createtint::__anonc203a2060111::Allocator25   T* Create(ARGS&&... args) {
26     return alloc.Create<T>(this, std::forward<ARGS>(args)...);
27   }
28 
29  private:
30   BlockAllocator<Cloneable> alloc;
31 };
32 
33 struct Node : public Castable<Node, Cloneable> {
Nodetint::__anonc203a2060111::Node34   Node(Allocator* alloc,
35        Symbol n,
36        const Node* node_a = nullptr,
37        const Node* node_b = nullptr,
38        const Node* node_c = nullptr)
39       : allocator(alloc), name(n), a(node_a), b(node_b), c(node_c) {}
40   Allocator* const allocator;
41   Symbol name;
42   const Node* a = nullptr;
43   const Node* b = nullptr;
44   const Node* c = nullptr;
45   std::vector<const Node*> vec;
46 
Clonetint::__anonc203a2060111::Node47   Node* Clone(CloneContext* ctx) const override {
48     auto* out = allocator->Create<Node>(ctx->Clone(name));
49     out->a = ctx->Clone(a);
50     out->b = ctx->Clone(b);
51     out->c = ctx->Clone(c);
52     out->vec = ctx->Clone(vec);
53     return out;
54   }
55 };
56 
57 struct Replaceable : public Castable<Replaceable, Node> {
Replaceabletint::__anonc203a2060111::Replaceable58   Replaceable(Allocator* alloc,
59               Symbol n,
60               const Node* node_a = nullptr,
61               const Node* node_b = nullptr,
62               const Node* node_c = nullptr)
63       : Base(alloc, n, node_a, node_b, node_c) {}
64 };
65 
66 struct Replacement : public Castable<Replacement, Replaceable> {
Replacementtint::__anonc203a2060111::Replacement67   Replacement(Allocator* alloc, Symbol n) : Base(alloc, n) {}
68 };
69 
70 struct NotANode : public Castable<NotANode, Cloneable> {
NotANodetint::__anonc203a2060111::NotANode71   explicit NotANode(Allocator* alloc) : allocator(alloc) {}
72 
73   Allocator* const allocator;
Clonetint::__anonc203a2060111::NotANode74   NotANode* Clone(CloneContext*) const override {
75     return allocator->Create<NotANode>();
76   }
77 };
78 
79 struct ProgramNode : public Castable<ProgramNode, Cloneable> {
ProgramNodetint::__anonc203a2060111::ProgramNode80   ProgramNode(Allocator* alloc, ProgramID id, ProgramID cloned_id)
81       : allocator(alloc), program_id(id), cloned_program_id(cloned_id) {}
82 
83   Allocator* const allocator;
84   const ProgramID program_id;
85   const ProgramID cloned_program_id;
86 
Clonetint::__anonc203a2060111::ProgramNode87   ProgramNode* Clone(CloneContext*) const override {
88     return allocator->Create<ProgramNode>(cloned_program_id, cloned_program_id);
89   }
90 };
91 
ProgramIDOf(const ProgramNode * node)92 ProgramID ProgramIDOf(const ProgramNode* node) {
93   return node->program_id;
94 }
95 
96 using CloneContextNodeTest = ::testing::Test;
97 
TEST_F(CloneContextNodeTest,Clone)98 TEST_F(CloneContextNodeTest, Clone) {
99   Allocator alloc;
100 
101   ProgramBuilder builder;
102   Node* original_root;
103   {
104     auto* a_b = alloc.Create<Node>(builder.Symbols().New("a->b"));
105     auto* a = alloc.Create<Node>(builder.Symbols().New("a"), nullptr, a_b);
106     auto* b_a = a;  // Aliased
107     auto* b_b = alloc.Create<Node>(builder.Symbols().New("b->b"));
108     auto* b = alloc.Create<Node>(builder.Symbols().New("b"), b_a, b_b);
109     auto* c = b;  // Aliased
110     original_root = alloc.Create<Node>(builder.Symbols().New("root"), a, b, c);
111   }
112   Program original(std::move(builder));
113 
114   //                          root
115   //        ╭──────────────────┼──────────────────╮
116   //       (a)                (b)                (c)
117   //        N  <──────┐        N  <───────────────┘
118   //   ╭────┼────╮    │   ╭────┼────╮
119   //  (a)  (b)  (c)   │  (a)  (b)  (c)
120   //        N         └───┘    N
121   //
122   // N: Node
123 
124   ProgramBuilder cloned;
125   auto* cloned_root = CloneContext(&cloned, &original).Clone(original_root);
126 
127   EXPECT_NE(cloned_root->a, nullptr);
128   EXPECT_EQ(cloned_root->a->a, nullptr);
129   EXPECT_NE(cloned_root->a->b, nullptr);
130   EXPECT_EQ(cloned_root->a->c, nullptr);
131   EXPECT_NE(cloned_root->b, nullptr);
132   EXPECT_NE(cloned_root->b->a, nullptr);
133   EXPECT_NE(cloned_root->b->b, nullptr);
134   EXPECT_EQ(cloned_root->b->c, nullptr);
135   EXPECT_NE(cloned_root->c, nullptr);
136 
137   EXPECT_NE(cloned_root->a, original_root->a);
138   EXPECT_NE(cloned_root->a->b, original_root->a->b);
139   EXPECT_NE(cloned_root->b, original_root->b);
140   EXPECT_NE(cloned_root->b->a, original_root->b->a);
141   EXPECT_NE(cloned_root->b->b, original_root->b->b);
142   EXPECT_NE(cloned_root->c, original_root->c);
143 
144   EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
145   EXPECT_EQ(cloned_root->a->name, cloned.Symbols().Get("a"));
146   EXPECT_EQ(cloned_root->a->b->name, cloned.Symbols().Get("a->b"));
147   EXPECT_EQ(cloned_root->b->name, cloned.Symbols().Get("b"));
148   EXPECT_EQ(cloned_root->b->b->name, cloned.Symbols().Get("b->b"));
149 
150   EXPECT_NE(cloned_root->b->a, cloned_root->a);  // De-aliased
151   EXPECT_NE(cloned_root->c, cloned_root->b);     // De-aliased
152 
153   EXPECT_EQ(cloned_root->b->a->name, cloned_root->a->name);
154   EXPECT_EQ(cloned_root->c->name, cloned_root->b->name);
155 }
156 
TEST_F(CloneContextNodeTest,CloneWithReplaceAll_Cloneable)157 TEST_F(CloneContextNodeTest, CloneWithReplaceAll_Cloneable) {
158   Allocator alloc;
159 
160   ProgramBuilder builder;
161   Node* original_root;
162   {
163     auto* a_b = alloc.Create<Replaceable>(builder.Symbols().New("a->b"));
164     auto* a = alloc.Create<Node>(builder.Symbols().New("a"), nullptr, a_b);
165     auto* b_a = a;  // Aliased
166     auto* b =
167         alloc.Create<Replaceable>(builder.Symbols().New("b"), b_a, nullptr);
168     auto* c = b;  // Aliased
169     original_root = alloc.Create<Node>(builder.Symbols().New("root"), a, b, c);
170   }
171   Program original(std::move(builder));
172 
173   //                          root
174   //        ╭──────────────────┼──────────────────╮
175   //       (a)                (b)                (c)
176   //        N  <──────┐        R  <───────────────┘
177   //   ╭────┼────╮    │   ╭────┼────╮
178   //  (a)  (b)  (c)   │  (a)  (b)  (c)
179   //        R         └───┘
180   //
181   // N: Node
182   // R: Replaceable
183 
184   ProgramBuilder cloned;
185 
186   CloneContext ctx(&cloned, &original);
187   ctx.ReplaceAll([&](const Replaceable* in) {
188     auto out_name = cloned.Symbols().Register(
189         "replacement:" + original.Symbols().NameFor(in->name));
190     auto b_name = cloned.Symbols().Register(
191         "replacement-child:" + original.Symbols().NameFor(in->name));
192     auto* out = alloc.Create<Replacement>(out_name);
193     out->b = alloc.Create<Node>(b_name);
194     out->c = ctx.Clone(in->a);
195     return out;
196   });
197   auto* cloned_root = ctx.Clone(original_root);
198 
199   //                         root
200   //        ╭─────────────────┼──────────────────╮
201   //       (a)               (b)                (c)
202   //        N  <──────┐       R  <───────────────┘
203   //   ╭────┼────╮    │  ╭────┼────╮
204   //  (a)  (b)  (c)   │ (a)  (b)  (c)
205   //        R         │       N    |
206   //   ╭────┼────╮    └────────────┘
207   //  (a)  (b)  (c)
208   //        N
209   //
210   // N: Node
211   // R: Replacement
212 
213   EXPECT_NE(cloned_root->a, nullptr);
214   EXPECT_EQ(cloned_root->a->a, nullptr);
215   EXPECT_NE(cloned_root->a->b, nullptr);     // Replaced
216   EXPECT_EQ(cloned_root->a->b->a, nullptr);  // From replacement
217   EXPECT_NE(cloned_root->a->b->b, nullptr);  // From replacement
218   EXPECT_EQ(cloned_root->a->b->c, nullptr);  // From replacement
219   EXPECT_EQ(cloned_root->a->c, nullptr);
220   EXPECT_NE(cloned_root->b, nullptr);
221   EXPECT_EQ(cloned_root->b->a, nullptr);  // From replacement
222   EXPECT_NE(cloned_root->b->b, nullptr);  // From replacement
223   EXPECT_NE(cloned_root->b->c, nullptr);  // From replacement
224   EXPECT_NE(cloned_root->c, nullptr);
225 
226   EXPECT_NE(cloned_root->a, original_root->a);
227   EXPECT_NE(cloned_root->a->b, original_root->a->b);
228   EXPECT_NE(cloned_root->b, original_root->b);
229   EXPECT_NE(cloned_root->b->a, original_root->b->a);
230   EXPECT_NE(cloned_root->c, original_root->c);
231 
232   EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
233   EXPECT_EQ(cloned_root->a->name, cloned.Symbols().Get("a"));
234   EXPECT_EQ(cloned_root->a->b->name, cloned.Symbols().Get("replacement:a->b"));
235   EXPECT_EQ(cloned_root->a->b->b->name,
236             cloned.Symbols().Get("replacement-child:a->b"));
237   EXPECT_EQ(cloned_root->b->name, cloned.Symbols().Get("replacement:b"));
238   EXPECT_EQ(cloned_root->b->b->name,
239             cloned.Symbols().Get("replacement-child:b"));
240 
241   EXPECT_NE(cloned_root->b->c, cloned_root->a);  // De-aliased
242   EXPECT_NE(cloned_root->c, cloned_root->b);     // De-aliased
243 
244   EXPECT_EQ(cloned_root->b->c->name, cloned_root->a->name);
245   EXPECT_EQ(cloned_root->c->name, cloned_root->b->name);
246 
247   EXPECT_FALSE(Is<Replacement>(cloned_root->a));
248   EXPECT_TRUE(Is<Replacement>(cloned_root->a->b));
249   EXPECT_FALSE(Is<Replacement>(cloned_root->a->b->b));
250   EXPECT_TRUE(Is<Replacement>(cloned_root->b));
251   EXPECT_FALSE(Is<Replacement>(cloned_root->b->b));
252 }
253 
TEST_F(CloneContextNodeTest,CloneWithReplaceAll_Symbols)254 TEST_F(CloneContextNodeTest, CloneWithReplaceAll_Symbols) {
255   Allocator alloc;
256 
257   ProgramBuilder builder;
258   Node* original_root;
259   {
260     auto* a_b = alloc.Create<Node>(builder.Symbols().New("a->b"));
261     auto* a = alloc.Create<Node>(builder.Symbols().New("a"), nullptr, a_b);
262     auto* b_a = a;  // Aliased
263     auto* b_b = alloc.Create<Node>(builder.Symbols().New("b->b"));
264     auto* b = alloc.Create<Node>(builder.Symbols().New("b"), b_a, b_b);
265     auto* c = b;  // Aliased
266     original_root = alloc.Create<Node>(builder.Symbols().New("root"), a, b, c);
267   }
268   Program original(std::move(builder));
269 
270   //                          root
271   //        ╭──────────────────┼──────────────────╮
272   //       (a)                (b)                (c)
273   //        N  <──────┐        N  <───────────────┘
274   //   ╭────┼────╮    │   ╭────┼────╮
275   //  (a)  (b)  (c)   │  (a)  (b)  (c)
276   //        N         └───┘    N
277   //
278   // N: Node
279 
280   ProgramBuilder cloned;
281   auto* cloned_root = CloneContext(&cloned, &original, false)
282                           .ReplaceAll([&](Symbol sym) {
283                             auto in = original.Symbols().NameFor(sym);
284                             auto out = "transformed<" + in + ">";
285                             return cloned.Symbols().New(out);
286                           })
287                           .Clone(original_root);
288 
289   EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("transformed<root>"));
290   EXPECT_EQ(cloned_root->a->name, cloned.Symbols().Get("transformed<a>"));
291   EXPECT_EQ(cloned_root->a->b->name, cloned.Symbols().Get("transformed<a->b>"));
292   EXPECT_EQ(cloned_root->b->name, cloned.Symbols().Get("transformed<b>"));
293   EXPECT_EQ(cloned_root->b->b->name, cloned.Symbols().Get("transformed<b->b>"));
294 }
295 
TEST_F(CloneContextNodeTest,CloneWithoutTransform)296 TEST_F(CloneContextNodeTest, CloneWithoutTransform) {
297   Allocator a;
298 
299   ProgramBuilder builder;
300   auto* original_node = a.Create<Node>(builder.Symbols().New("root"));
301   Program original(std::move(builder));
302 
303   ProgramBuilder cloned;
304   CloneContext ctx(&cloned, &original);
305   ctx.ReplaceAll([&](const Node*) {
306     return a.Create<Replacement>(builder.Symbols().New("<unexpected-node>"));
307   });
308 
309   auto* cloned_node = ctx.CloneWithoutTransform(original_node);
310   EXPECT_NE(cloned_node, original_node);
311   EXPECT_EQ(cloned_node->name, cloned.Symbols().Get("root"));
312 }
313 
TEST_F(CloneContextNodeTest,CloneWithReplacePointer)314 TEST_F(CloneContextNodeTest, CloneWithReplacePointer) {
315   Allocator a;
316 
317   ProgramBuilder builder;
318   auto* original_root = a.Create<Node>(builder.Symbols().New("root"));
319   original_root->a = a.Create<Node>(builder.Symbols().New("a"));
320   original_root->b = a.Create<Node>(builder.Symbols().New("b"));
321   original_root->c = a.Create<Node>(builder.Symbols().New("c"));
322   Program original(std::move(builder));
323 
324   //                          root
325   //        ╭──────────────────┼──────────────────╮
326   //       (a)                (b)                (c)
327   //                        Replaced
328 
329   ProgramBuilder cloned;
330   auto* replacement = a.Create<Node>(cloned.Symbols().New("replacement"));
331 
332   auto* cloned_root = CloneContext(&cloned, &original)
333                           .Replace(original_root->b, replacement)
334                           .Clone(original_root);
335 
336   EXPECT_NE(cloned_root->a, replacement);
337   EXPECT_EQ(cloned_root->b, replacement);
338   EXPECT_NE(cloned_root->c, replacement);
339 
340   EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
341   EXPECT_EQ(cloned_root->a->name, cloned.Symbols().Get("a"));
342   EXPECT_EQ(cloned_root->b->name, cloned.Symbols().Get("replacement"));
343   EXPECT_EQ(cloned_root->c->name, cloned.Symbols().Get("c"));
344 }
345 
TEST_F(CloneContextNodeTest,CloneWithReplaceFunction)346 TEST_F(CloneContextNodeTest, CloneWithReplaceFunction) {
347   Allocator a;
348 
349   ProgramBuilder builder;
350   auto* original_root = a.Create<Node>(builder.Symbols().New("root"));
351   original_root->a = a.Create<Node>(builder.Symbols().New("a"));
352   original_root->b = a.Create<Node>(builder.Symbols().New("b"));
353   original_root->c = a.Create<Node>(builder.Symbols().New("c"));
354   Program original(std::move(builder));
355 
356   //                          root
357   //        ╭──────────────────┼──────────────────╮
358   //       (a)                (b)                (c)
359   //                        Replaced
360 
361   ProgramBuilder cloned;
362   auto* replacement = a.Create<Node>(cloned.Symbols().New("replacement"));
363 
364   auto* cloned_root =
365       CloneContext(&cloned, &original)
366           .Replace(original_root->b, [=] { return replacement; })
367           .Clone(original_root);
368 
369   EXPECT_NE(cloned_root->a, replacement);
370   EXPECT_EQ(cloned_root->b, replacement);
371   EXPECT_NE(cloned_root->c, replacement);
372 
373   EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
374   EXPECT_EQ(cloned_root->a->name, cloned.Symbols().Get("a"));
375   EXPECT_EQ(cloned_root->b->name, cloned.Symbols().Get("replacement"));
376   EXPECT_EQ(cloned_root->c->name, cloned.Symbols().Get("c"));
377 }
378 
TEST_F(CloneContextNodeTest,CloneWithRemove)379 TEST_F(CloneContextNodeTest, CloneWithRemove) {
380   Allocator a;
381 
382   ProgramBuilder builder;
383   auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
384   original_root->a = a.Create<Node>(builder.Symbols().Register("a"));
385   original_root->b = a.Create<Node>(builder.Symbols().Register("b"));
386   original_root->c = a.Create<Node>(builder.Symbols().Register("c"));
387   original_root->vec = {original_root->a, original_root->b, original_root->c};
388   Program original(std::move(builder));
389 
390   ProgramBuilder cloned;
391   auto* cloned_root = CloneContext(&cloned, &original)
392                           .Remove(original_root->vec, original_root->b)
393                           .Clone(original_root);
394 
395   EXPECT_EQ(cloned_root->vec.size(), 2u);
396 
397   EXPECT_NE(cloned_root->vec[0], cloned_root->a);
398   EXPECT_NE(cloned_root->vec[1], cloned_root->c);
399 
400   EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
401   EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a"));
402   EXPECT_EQ(cloned_root->vec[1]->name, cloned.Symbols().Get("c"));
403 }
404 
TEST_F(CloneContextNodeTest,CloneWithInsertFront)405 TEST_F(CloneContextNodeTest, CloneWithInsertFront) {
406   Allocator a;
407 
408   ProgramBuilder builder;
409   auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
410   original_root->a = a.Create<Node>(builder.Symbols().Register("a"));
411   original_root->b = a.Create<Node>(builder.Symbols().Register("b"));
412   original_root->c = a.Create<Node>(builder.Symbols().Register("c"));
413   original_root->vec = {original_root->a, original_root->b, original_root->c};
414   Program original(std::move(builder));
415 
416   ProgramBuilder cloned;
417   auto* insertion = a.Create<Node>(cloned.Symbols().New("insertion"));
418 
419   auto* cloned_root = CloneContext(&cloned, &original)
420                           .InsertFront(original_root->vec, insertion)
421                           .Clone(original_root);
422 
423   EXPECT_EQ(cloned_root->vec.size(), 4u);
424 
425   EXPECT_NE(cloned_root->vec[0], cloned_root->a);
426   EXPECT_NE(cloned_root->vec[1], cloned_root->b);
427   EXPECT_NE(cloned_root->vec[2], cloned_root->c);
428 
429   EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
430   EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("insertion"));
431   EXPECT_EQ(cloned_root->vec[1]->name, cloned.Symbols().Get("a"));
432   EXPECT_EQ(cloned_root->vec[2]->name, cloned.Symbols().Get("b"));
433   EXPECT_EQ(cloned_root->vec[3]->name, cloned.Symbols().Get("c"));
434 }
435 
TEST_F(CloneContextNodeTest,CloneWithInsertFront_Empty)436 TEST_F(CloneContextNodeTest, CloneWithInsertFront_Empty) {
437   Allocator a;
438 
439   ProgramBuilder builder;
440   auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
441   original_root->vec = {};
442   Program original(std::move(builder));
443 
444   ProgramBuilder cloned;
445   auto* insertion = a.Create<Node>(cloned.Symbols().New("insertion"));
446 
447   auto* cloned_root = CloneContext(&cloned, &original)
448                           .InsertFront(original_root->vec, insertion)
449                           .Clone(original_root);
450 
451   EXPECT_EQ(cloned_root->vec.size(), 1u);
452 
453   EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
454   EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("insertion"));
455 }
456 
TEST_F(CloneContextNodeTest,CloneWithInsertBack)457 TEST_F(CloneContextNodeTest, CloneWithInsertBack) {
458   Allocator a;
459 
460   ProgramBuilder builder;
461   auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
462   original_root->a = a.Create<Node>(builder.Symbols().Register("a"));
463   original_root->b = a.Create<Node>(builder.Symbols().Register("b"));
464   original_root->c = a.Create<Node>(builder.Symbols().Register("c"));
465   original_root->vec = {original_root->a, original_root->b, original_root->c};
466   Program original(std::move(builder));
467 
468   ProgramBuilder cloned;
469   auto* insertion = a.Create<Node>(cloned.Symbols().New("insertion"));
470 
471   auto* cloned_root = CloneContext(&cloned, &original)
472                           .InsertBack(original_root->vec, insertion)
473                           .Clone(original_root);
474 
475   EXPECT_EQ(cloned_root->vec.size(), 4u);
476 
477   EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
478   EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a"));
479   EXPECT_EQ(cloned_root->vec[1]->name, cloned.Symbols().Get("b"));
480   EXPECT_EQ(cloned_root->vec[2]->name, cloned.Symbols().Get("c"));
481   EXPECT_EQ(cloned_root->vec[3]->name, cloned.Symbols().Get("insertion"));
482 }
483 
TEST_F(CloneContextNodeTest,CloneWithInsertBack_Empty)484 TEST_F(CloneContextNodeTest, CloneWithInsertBack_Empty) {
485   Allocator a;
486 
487   ProgramBuilder builder;
488   auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
489   original_root->vec = {};
490   Program original(std::move(builder));
491 
492   ProgramBuilder cloned;
493   auto* insertion = a.Create<Node>(cloned.Symbols().New("insertion"));
494 
495   auto* cloned_root = CloneContext(&cloned, &original)
496                           .InsertBack(original_root->vec, insertion)
497                           .Clone(original_root);
498 
499   EXPECT_EQ(cloned_root->vec.size(), 1u);
500 
501   EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
502   EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("insertion"));
503 }
504 
TEST_F(CloneContextNodeTest,CloneWithInsertFrontAndBack_Empty)505 TEST_F(CloneContextNodeTest, CloneWithInsertFrontAndBack_Empty) {
506   Allocator a;
507 
508   ProgramBuilder builder;
509   auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
510   original_root->vec = {};
511   Program original(std::move(builder));
512 
513   ProgramBuilder cloned;
514   auto* insertion_front =
515       a.Create<Node>(cloned.Symbols().New("insertion_front"));
516   auto* insertion_back = a.Create<Node>(cloned.Symbols().New("insertion_back"));
517 
518   auto* cloned_root = CloneContext(&cloned, &original)
519                           .InsertBack(original_root->vec, insertion_back)
520                           .InsertFront(original_root->vec, insertion_front)
521                           .Clone(original_root);
522 
523   EXPECT_EQ(cloned_root->vec.size(), 2u);
524 
525   EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
526   EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("insertion_front"));
527   EXPECT_EQ(cloned_root->vec[1]->name, cloned.Symbols().Get("insertion_back"));
528 }
529 
TEST_F(CloneContextNodeTest,CloneWithInsertBefore)530 TEST_F(CloneContextNodeTest, CloneWithInsertBefore) {
531   Allocator a;
532 
533   ProgramBuilder builder;
534   auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
535   original_root->a = a.Create<Node>(builder.Symbols().Register("a"));
536   original_root->b = a.Create<Node>(builder.Symbols().Register("b"));
537   original_root->c = a.Create<Node>(builder.Symbols().Register("c"));
538   original_root->vec = {original_root->a, original_root->b, original_root->c};
539   Program original(std::move(builder));
540 
541   ProgramBuilder cloned;
542   auto* insertion = a.Create<Node>(cloned.Symbols().New("insertion"));
543 
544   auto* cloned_root =
545       CloneContext(&cloned, &original)
546           .InsertBefore(original_root->vec, original_root->b, insertion)
547           .Clone(original_root);
548 
549   EXPECT_EQ(cloned_root->vec.size(), 4u);
550 
551   EXPECT_NE(cloned_root->vec[0], cloned_root->a);
552   EXPECT_NE(cloned_root->vec[2], cloned_root->b);
553   EXPECT_NE(cloned_root->vec[3], cloned_root->c);
554 
555   EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
556   EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a"));
557   EXPECT_EQ(cloned_root->vec[1]->name, cloned.Symbols().Get("insertion"));
558   EXPECT_EQ(cloned_root->vec[2]->name, cloned.Symbols().Get("b"));
559   EXPECT_EQ(cloned_root->vec[3]->name, cloned.Symbols().Get("c"));
560 }
561 
TEST_F(CloneContextNodeTest,CloneWithInsertAfter)562 TEST_F(CloneContextNodeTest, CloneWithInsertAfter) {
563   Allocator a;
564 
565   ProgramBuilder builder;
566   auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
567   original_root->a = a.Create<Node>(builder.Symbols().Register("a"));
568   original_root->b = a.Create<Node>(builder.Symbols().Register("b"));
569   original_root->c = a.Create<Node>(builder.Symbols().Register("c"));
570   original_root->vec = {original_root->a, original_root->b, original_root->c};
571   Program original(std::move(builder));
572 
573   ProgramBuilder cloned;
574   auto* insertion = a.Create<Node>(cloned.Symbols().New("insertion"));
575 
576   auto* cloned_root =
577       CloneContext(&cloned, &original)
578           .InsertAfter(original_root->vec, original_root->b, insertion)
579           .Clone(original_root);
580 
581   EXPECT_EQ(cloned_root->vec.size(), 4u);
582 
583   EXPECT_NE(cloned_root->vec[0], cloned_root->a);
584   EXPECT_NE(cloned_root->vec[1], cloned_root->b);
585   EXPECT_NE(cloned_root->vec[3], cloned_root->c);
586 
587   EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
588   EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a"));
589   EXPECT_EQ(cloned_root->vec[1]->name, cloned.Symbols().Get("b"));
590   EXPECT_EQ(cloned_root->vec[2]->name, cloned.Symbols().Get("insertion"));
591   EXPECT_EQ(cloned_root->vec[3]->name, cloned.Symbols().Get("c"));
592 }
593 
TEST_F(CloneContextNodeTest,CloneWithInsertBeforeAndAfterRemoved)594 TEST_F(CloneContextNodeTest, CloneWithInsertBeforeAndAfterRemoved) {
595   Allocator a;
596 
597   ProgramBuilder builder;
598   auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
599   original_root->a = a.Create<Node>(builder.Symbols().Register("a"));
600   original_root->b = a.Create<Node>(builder.Symbols().Register("b"));
601   original_root->c = a.Create<Node>(builder.Symbols().Register("c"));
602   original_root->vec = {original_root->a, original_root->b, original_root->c};
603   Program original(std::move(builder));
604 
605   ProgramBuilder cloned;
606   auto* insertion_before =
607       a.Create<Node>(cloned.Symbols().New("insertion_before"));
608   auto* insertion_after =
609       a.Create<Node>(cloned.Symbols().New("insertion_after"));
610 
611   auto* cloned_root =
612       CloneContext(&cloned, &original)
613           .InsertBefore(original_root->vec, original_root->b, insertion_before)
614           .InsertAfter(original_root->vec, original_root->b, insertion_after)
615           .Remove(original_root->vec, original_root->b)
616           .Clone(original_root);
617 
618   EXPECT_EQ(cloned_root->vec.size(), 4u);
619 
620   EXPECT_NE(cloned_root->vec[0], cloned_root->a);
621   EXPECT_NE(cloned_root->vec[3], cloned_root->c);
622 
623   EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
624   EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a"));
625   EXPECT_EQ(cloned_root->vec[1]->name,
626             cloned.Symbols().Get("insertion_before"));
627   EXPECT_EQ(cloned_root->vec[2]->name, cloned.Symbols().Get("insertion_after"));
628   EXPECT_EQ(cloned_root->vec[3]->name, cloned.Symbols().Get("c"));
629 }
630 
TEST_F(CloneContextNodeTest,CloneIntoSameBuilder)631 TEST_F(CloneContextNodeTest, CloneIntoSameBuilder) {
632   ProgramBuilder builder;
633   CloneContext ctx(&builder);
634   Allocator allocator;
635   auto* original = allocator.Create<Node>(builder.Symbols().New());
636   auto* cloned_a = ctx.Clone(original);
637   auto* cloned_b = ctx.Clone(original);
638   EXPECT_NE(original, cloned_a);
639   EXPECT_NE(original, cloned_b);
640 
641   EXPECT_NE(cloned_a, cloned_b);
642 }
643 
TEST_F(CloneContextNodeTest,CloneWithReplaceAll_SameTypeTwice)644 TEST_F(CloneContextNodeTest, CloneWithReplaceAll_SameTypeTwice) {
645   std::string node_name = TypeInfo::Of<Node>().name;
646 
647   EXPECT_FATAL_FAILURE(
648       {
649         ProgramBuilder cloned;
650         Program original;
651         CloneContext ctx(&cloned, &original);
652         ctx.ReplaceAll([](const Node*) { return nullptr; });
653         ctx.ReplaceAll([](const Node*) { return nullptr; });
654       },
655       "internal compiler error: ReplaceAll() called with a handler for type " +
656           node_name + " that is already handled by a handler for type " +
657           node_name);
658 }
659 
TEST_F(CloneContextNodeTest,CloneWithReplaceAll_BaseThenDerived)660 TEST_F(CloneContextNodeTest, CloneWithReplaceAll_BaseThenDerived) {
661   std::string node_name = TypeInfo::Of<Node>().name;
662   std::string replaceable_name = TypeInfo::Of<Replaceable>().name;
663 
664   EXPECT_FATAL_FAILURE(
665       {
666         ProgramBuilder cloned;
667         Program original;
668         CloneContext ctx(&cloned, &original);
669         ctx.ReplaceAll([](const Node*) { return nullptr; });
670         ctx.ReplaceAll([](const Replaceable*) { return nullptr; });
671       },
672       "internal compiler error: ReplaceAll() called with a handler for type " +
673           replaceable_name + " that is already handled by a handler for type " +
674           node_name);
675 }
676 
TEST_F(CloneContextNodeTest,CloneWithReplaceAll_DerivedThenBase)677 TEST_F(CloneContextNodeTest, CloneWithReplaceAll_DerivedThenBase) {
678   std::string node_name = TypeInfo::Of<Node>().name;
679   std::string replaceable_name = TypeInfo::Of<Replaceable>().name;
680 
681   EXPECT_FATAL_FAILURE(
682       {
683         ProgramBuilder cloned;
684         Program original;
685         CloneContext ctx(&cloned, &original);
686         ctx.ReplaceAll([](const Replaceable*) { return nullptr; });
687         ctx.ReplaceAll([](const Node*) { return nullptr; });
688       },
689       "internal compiler error: ReplaceAll() called with a handler for type " +
690           node_name + " that is already handled by a handler for type " +
691           replaceable_name);
692 }
693 
TEST_F(CloneContextNodeTest,CloneWithReplacePointer_WithNotANode)694 TEST_F(CloneContextNodeTest, CloneWithReplacePointer_WithNotANode) {
695   EXPECT_FATAL_FAILURE(
696       {
697         Allocator allocator;
698         ProgramBuilder builder;
699         auto* original_root =
700             allocator.Create<Node>(builder.Symbols().New("root"));
701         original_root->a = allocator.Create<Node>(builder.Symbols().New("a"));
702         original_root->b = allocator.Create<Node>(builder.Symbols().New("b"));
703         original_root->c = allocator.Create<Node>(builder.Symbols().New("c"));
704         Program original(std::move(builder));
705 
706         //                          root
707         //        ╭──────────────────┼──────────────────╮
708         //       (a)                (b)                (c)
709         //                        Replaced
710 
711         ProgramBuilder cloned;
712         auto* replacement = allocator.Create<NotANode>();
713 
714         CloneContext ctx(&cloned, &original);
715         ctx.Replace(original_root->b, replacement);
716 
717         ctx.Clone(original_root);
718       },
719       "internal compiler error");
720 }
721 
TEST_F(CloneContextNodeTest,CloneWithReplaceFunction_WithNotANode)722 TEST_F(CloneContextNodeTest, CloneWithReplaceFunction_WithNotANode) {
723   EXPECT_FATAL_FAILURE(
724       {
725         Allocator allocator;
726         ProgramBuilder builder;
727         auto* original_root =
728             allocator.Create<Node>(builder.Symbols().New("root"));
729         original_root->a = allocator.Create<Node>(builder.Symbols().New("a"));
730         original_root->b = allocator.Create<Node>(builder.Symbols().New("b"));
731         original_root->c = allocator.Create<Node>(builder.Symbols().New("c"));
732         Program original(std::move(builder));
733 
734         //                          root
735         //        ╭──────────────────┼──────────────────╮
736         //       (a)                (b)                (c)
737         //                        Replaced
738 
739         ProgramBuilder cloned;
740         auto* replacement = allocator.Create<NotANode>();
741 
742         CloneContext ctx(&cloned, &original);
743         ctx.Replace(original_root->b, [=] { return replacement; });
744 
745         ctx.Clone(original_root);
746       },
747       "internal compiler error");
748 }
749 
750 using CloneContextTest = ::testing::Test;
751 
TEST_F(CloneContextTest,CloneWithReplaceAll_SymbolsTwice)752 TEST_F(CloneContextTest, CloneWithReplaceAll_SymbolsTwice) {
753   EXPECT_FATAL_FAILURE(
754       {
755         ProgramBuilder cloned;
756         Program original;
757         CloneContext ctx(&cloned, &original);
758         ctx.ReplaceAll([](const Symbol s) { return s; });
759         ctx.ReplaceAll([](const Symbol s) { return s; });
760       },
761       "internal compiler error: ReplaceAll(const SymbolTransform&) called "
762       "multiple times on the same CloneContext");
763 }
764 
TEST_F(CloneContextTest,CloneNewUnnamedSymbols)765 TEST_F(CloneContextTest, CloneNewUnnamedSymbols) {
766   ProgramBuilder builder;
767   Symbol old_a = builder.Symbols().New();
768   Symbol old_b = builder.Symbols().New();
769   Symbol old_c = builder.Symbols().New();
770   EXPECT_EQ(builder.Symbols().NameFor(old_a), "tint_symbol");
771   EXPECT_EQ(builder.Symbols().NameFor(old_b), "tint_symbol_1");
772   EXPECT_EQ(builder.Symbols().NameFor(old_c), "tint_symbol_2");
773 
774   Program original(std::move(builder));
775 
776   ProgramBuilder cloned;
777   CloneContext ctx(&cloned, &original, false);
778   Symbol new_x = cloned.Symbols().New();
779   Symbol new_a = ctx.Clone(old_a);
780   Symbol new_y = cloned.Symbols().New();
781   Symbol new_b = ctx.Clone(old_b);
782   Symbol new_z = cloned.Symbols().New();
783   Symbol new_c = ctx.Clone(old_c);
784 
785   EXPECT_EQ(cloned.Symbols().NameFor(new_x), "tint_symbol");
786   EXPECT_EQ(cloned.Symbols().NameFor(new_a), "tint_symbol_1");
787   EXPECT_EQ(cloned.Symbols().NameFor(new_y), "tint_symbol_2");
788   EXPECT_EQ(cloned.Symbols().NameFor(new_b), "tint_symbol_1_1");
789   EXPECT_EQ(cloned.Symbols().NameFor(new_z), "tint_symbol_3");
790   EXPECT_EQ(cloned.Symbols().NameFor(new_c), "tint_symbol_2_1");
791 }
792 
TEST_F(CloneContextTest,CloneNewSymbols)793 TEST_F(CloneContextTest, CloneNewSymbols) {
794   ProgramBuilder builder;
795   Symbol old_a = builder.Symbols().New("a");
796   Symbol old_b = builder.Symbols().New("b");
797   Symbol old_c = builder.Symbols().New("c");
798   EXPECT_EQ(builder.Symbols().NameFor(old_a), "a");
799   EXPECT_EQ(builder.Symbols().NameFor(old_b), "b");
800   EXPECT_EQ(builder.Symbols().NameFor(old_c), "c");
801 
802   Program original(std::move(builder));
803 
804   ProgramBuilder cloned;
805   CloneContext ctx(&cloned, &original, false);
806   Symbol new_x = cloned.Symbols().New("a");
807   Symbol new_a = ctx.Clone(old_a);
808   Symbol new_y = cloned.Symbols().New("b");
809   Symbol new_b = ctx.Clone(old_b);
810   Symbol new_z = cloned.Symbols().New("c");
811   Symbol new_c = ctx.Clone(old_c);
812 
813   EXPECT_EQ(cloned.Symbols().NameFor(new_x), "a");
814   EXPECT_EQ(cloned.Symbols().NameFor(new_a), "a_1");
815   EXPECT_EQ(cloned.Symbols().NameFor(new_y), "b");
816   EXPECT_EQ(cloned.Symbols().NameFor(new_b), "b_1");
817   EXPECT_EQ(cloned.Symbols().NameFor(new_z), "c");
818   EXPECT_EQ(cloned.Symbols().NameFor(new_c), "c_1");
819 }
820 
TEST_F(CloneContextTest,CloneNewSymbols_AfterCloneSymbols)821 TEST_F(CloneContextTest, CloneNewSymbols_AfterCloneSymbols) {
822   ProgramBuilder builder;
823   Symbol old_a = builder.Symbols().New("a");
824   Symbol old_b = builder.Symbols().New("b");
825   Symbol old_c = builder.Symbols().New("c");
826   EXPECT_EQ(builder.Symbols().NameFor(old_a), "a");
827   EXPECT_EQ(builder.Symbols().NameFor(old_b), "b");
828   EXPECT_EQ(builder.Symbols().NameFor(old_c), "c");
829 
830   Program original(std::move(builder));
831 
832   ProgramBuilder cloned;
833   CloneContext ctx(&cloned, &original);
834   Symbol new_x = cloned.Symbols().New("a");
835   Symbol new_a = ctx.Clone(old_a);
836   Symbol new_y = cloned.Symbols().New("b");
837   Symbol new_b = ctx.Clone(old_b);
838   Symbol new_z = cloned.Symbols().New("c");
839   Symbol new_c = ctx.Clone(old_c);
840 
841   EXPECT_EQ(cloned.Symbols().NameFor(new_x), "a_1");
842   EXPECT_EQ(cloned.Symbols().NameFor(new_a), "a");
843   EXPECT_EQ(cloned.Symbols().NameFor(new_y), "b_1");
844   EXPECT_EQ(cloned.Symbols().NameFor(new_b), "b");
845   EXPECT_EQ(cloned.Symbols().NameFor(new_z), "c_1");
846   EXPECT_EQ(cloned.Symbols().NameFor(new_c), "c");
847 }
848 
TEST_F(CloneContextTest,ProgramIDs)849 TEST_F(CloneContextTest, ProgramIDs) {
850   ProgramBuilder dst;
851   Program src(ProgramBuilder{});
852   CloneContext ctx(&dst, &src);
853   Allocator allocator;
854   auto* cloned = ctx.Clone(allocator.Create<ProgramNode>(src.ID(), dst.ID()));
855   EXPECT_EQ(cloned->program_id, dst.ID());
856 }
857 
TEST_F(CloneContextTest,ProgramIDs_Clone_ObjectNotOwnedBySrc)858 TEST_F(CloneContextTest, ProgramIDs_Clone_ObjectNotOwnedBySrc) {
859   EXPECT_FATAL_FAILURE(
860       {
861         ProgramBuilder dst;
862         Program src(ProgramBuilder{});
863         CloneContext ctx(&dst, &src);
864         Allocator allocator;
865         ctx.Clone(allocator.Create<ProgramNode>(ProgramID::New(), dst.ID()));
866       },
867       R"(internal compiler error: TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, src, object))");
868 }
869 
TEST_F(CloneContextTest,ProgramIDs_Clone_ObjectNotOwnedByDst)870 TEST_F(CloneContextTest, ProgramIDs_Clone_ObjectNotOwnedByDst) {
871   EXPECT_FATAL_FAILURE(
872       {
873         ProgramBuilder dst;
874         Program src(ProgramBuilder{});
875         CloneContext ctx(&dst, &src);
876         Allocator allocator;
877         ctx.Clone(allocator.Create<ProgramNode>(src.ID(), ProgramID::New()));
878       },
879       R"(internal compiler error: TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, dst, out))");
880 }
881 
882 }  // namespace
883 
884 TINT_INSTANTIATE_TYPEINFO(Node);
885 TINT_INSTANTIATE_TYPEINFO(Replaceable);
886 TINT_INSTANTIATE_TYPEINFO(Replacement);
887 TINT_INSTANTIATE_TYPEINFO(NotANode);
888 TINT_INSTANTIATE_TYPEINFO(ProgramNode);
889 
890 }  // namespace tint
891