1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2021 Google, Inc. 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 10bf215546Sopenharmony_ci * 11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 13bf215546Sopenharmony_ci * Software. 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21bf215546Sopenharmony_ci * IN THE SOFTWARE. 22bf215546Sopenharmony_ci */ 23bf215546Sopenharmony_ci 24bf215546Sopenharmony_ci#include <gtest/gtest.h> 25bf215546Sopenharmony_ci#include "util/dag.h" 26bf215546Sopenharmony_ci 27bf215546Sopenharmony_ciclass dag_test : public ::testing::Test { 28bf215546Sopenharmony_ciprotected: 29bf215546Sopenharmony_ci dag_test(); 30bf215546Sopenharmony_ci ~dag_test(); 31bf215546Sopenharmony_ci 32bf215546Sopenharmony_ci void *mem_ctx; 33bf215546Sopenharmony_ci struct util_dynarray expect, actual; 34bf215546Sopenharmony_ci struct dag *dag; 35bf215546Sopenharmony_ci}; 36bf215546Sopenharmony_ci 37bf215546Sopenharmony_cidag_test::dag_test() 38bf215546Sopenharmony_ci{ 39bf215546Sopenharmony_ci mem_ctx = ralloc_context(NULL); 40bf215546Sopenharmony_ci util_dynarray_init(&expect, mem_ctx); 41bf215546Sopenharmony_ci util_dynarray_init(&actual, mem_ctx); 42bf215546Sopenharmony_ci dag = dag_create(mem_ctx); 43bf215546Sopenharmony_ci} 44bf215546Sopenharmony_ci 45bf215546Sopenharmony_cidag_test::~dag_test() 46bf215546Sopenharmony_ci{ 47bf215546Sopenharmony_ci ralloc_free(mem_ctx); 48bf215546Sopenharmony_ci} 49bf215546Sopenharmony_ci 50bf215546Sopenharmony_cistruct node: public dag_node { 51bf215546Sopenharmony_ci int val; 52bf215546Sopenharmony_ci 53bf215546Sopenharmony_ci /* Overload >> to make describing our test case graphs easier to read */ 54bf215546Sopenharmony_ci struct node &operator>>(struct node &child) { 55bf215546Sopenharmony_ci dag_add_edge(static_cast<struct dag_node *>(this), 56bf215546Sopenharmony_ci static_cast<struct dag_node *>(&child), 0); 57bf215546Sopenharmony_ci return child; 58bf215546Sopenharmony_ci } 59bf215546Sopenharmony_ci 60bf215546Sopenharmony_ci void add_edge(struct node &child, uintptr_t data) { 61bf215546Sopenharmony_ci dag_add_edge(static_cast<struct dag_node *>(this), 62bf215546Sopenharmony_ci static_cast<struct dag_node *>(&child), data); 63bf215546Sopenharmony_ci } 64bf215546Sopenharmony_ci 65bf215546Sopenharmony_ci void add_edge_max_data(struct node &child, uintptr_t data) { 66bf215546Sopenharmony_ci dag_add_edge_max_data(static_cast<struct dag_node *>(this), 67bf215546Sopenharmony_ci static_cast<struct dag_node *>(&child), data); 68bf215546Sopenharmony_ci } 69bf215546Sopenharmony_ci}; 70bf215546Sopenharmony_ci 71bf215546Sopenharmony_cistatic void output_cb(struct dag_node *dag_node, void *data) 72bf215546Sopenharmony_ci{ 73bf215546Sopenharmony_ci struct node *node = static_cast<struct node *>(dag_node); 74bf215546Sopenharmony_ci struct util_dynarray *output = (struct util_dynarray *)data; 75bf215546Sopenharmony_ci util_dynarray_append(output, int, node->val); 76bf215546Sopenharmony_ci} 77bf215546Sopenharmony_ci 78bf215546Sopenharmony_cistatic void 79bf215546Sopenharmony_ciinit_nodes(struct dag *dag, struct node *nodes, unsigned num_nodes) 80bf215546Sopenharmony_ci{ 81bf215546Sopenharmony_ci for (unsigned i = 0; i < num_nodes; i++) { 82bf215546Sopenharmony_ci dag_init_node(dag, static_cast<struct dag_node *>(&nodes[i])); 83bf215546Sopenharmony_ci nodes[i].val = i; 84bf215546Sopenharmony_ci } 85bf215546Sopenharmony_ci} 86bf215546Sopenharmony_ci 87bf215546Sopenharmony_ci#define INIT_NODES(num_nodes) \ 88bf215546Sopenharmony_ci typedef struct { int order[num_nodes]; } result_type; \ 89bf215546Sopenharmony_ci struct node node[(num_nodes)]; \ 90bf215546Sopenharmony_ci init_nodes(dag, node, (num_nodes)) 91bf215546Sopenharmony_ci 92bf215546Sopenharmony_ci#define SET_EXPECTED(...) do { \ 93bf215546Sopenharmony_ci result_type res = {{ __VA_ARGS__ }}; \ 94bf215546Sopenharmony_ci util_dynarray_append(&expect, result_type, res); \ 95bf215546Sopenharmony_ci} while (0) 96bf215546Sopenharmony_ci 97bf215546Sopenharmony_cistatic bool 98bf215546Sopenharmony_ciint_dynarrays_equal(struct util_dynarray *a, struct util_dynarray *b) 99bf215546Sopenharmony_ci{ 100bf215546Sopenharmony_ci if (util_dynarray_num_elements(a, int) != util_dynarray_num_elements(b, int)) 101bf215546Sopenharmony_ci return false; 102bf215546Sopenharmony_ci 103bf215546Sopenharmony_ci for (unsigned i = 0; i < util_dynarray_num_elements(a, int); i++) { 104bf215546Sopenharmony_ci if (*util_dynarray_element(a, int, i) != 105bf215546Sopenharmony_ci *util_dynarray_element(b, int, i)) { 106bf215546Sopenharmony_ci return false; 107bf215546Sopenharmony_ci } 108bf215546Sopenharmony_ci } 109bf215546Sopenharmony_ci return true; 110bf215546Sopenharmony_ci} 111bf215546Sopenharmony_ci 112bf215546Sopenharmony_cistatic testing::AssertionResult 113bf215546Sopenharmony_ciint_dynarrays_equal_pred(const char *a_expr, 114bf215546Sopenharmony_ci const char *b_expr, 115bf215546Sopenharmony_ci struct util_dynarray *a, 116bf215546Sopenharmony_ci struct util_dynarray *b) 117bf215546Sopenharmony_ci{ 118bf215546Sopenharmony_ci if (int_dynarrays_equal(a, b)) return testing::AssertionSuccess(); 119bf215546Sopenharmony_ci 120bf215546Sopenharmony_ci testing::AssertionResult result = testing::AssertionFailure(); 121bf215546Sopenharmony_ci 122bf215546Sopenharmony_ci result << a_expr << " != " << b_expr; 123bf215546Sopenharmony_ci 124bf215546Sopenharmony_ci result << ", ("; 125bf215546Sopenharmony_ci for (unsigned i = 0; i < util_dynarray_num_elements(a, int); i++) { 126bf215546Sopenharmony_ci if (i != 0) 127bf215546Sopenharmony_ci result << ", "; 128bf215546Sopenharmony_ci result << *util_dynarray_element(a, int, i); 129bf215546Sopenharmony_ci } 130bf215546Sopenharmony_ci 131bf215546Sopenharmony_ci result << ") != ("; 132bf215546Sopenharmony_ci for (unsigned i = 0; i < util_dynarray_num_elements(b, int); i++) { 133bf215546Sopenharmony_ci if (i != 0) 134bf215546Sopenharmony_ci result << ", "; 135bf215546Sopenharmony_ci result << *util_dynarray_element(b, int, i); 136bf215546Sopenharmony_ci } 137bf215546Sopenharmony_ci 138bf215546Sopenharmony_ci result << ")"; 139bf215546Sopenharmony_ci 140bf215546Sopenharmony_ci return result; 141bf215546Sopenharmony_ci} 142bf215546Sopenharmony_ci 143bf215546Sopenharmony_ci#define TEST_CHECK() EXPECT_PRED_FORMAT2(int_dynarrays_equal_pred, &expect, &actual) 144bf215546Sopenharmony_ci 145bf215546Sopenharmony_ciTEST_F(dag_test, simple) 146bf215546Sopenharmony_ci{ 147bf215546Sopenharmony_ci INIT_NODES(3); 148bf215546Sopenharmony_ci 149bf215546Sopenharmony_ci /* 0 150bf215546Sopenharmony_ci * / \ 151bf215546Sopenharmony_ci * 1 2 152bf215546Sopenharmony_ci */ 153bf215546Sopenharmony_ci node[0] >> node[1]; 154bf215546Sopenharmony_ci node[0] >> node[2]; 155bf215546Sopenharmony_ci 156bf215546Sopenharmony_ci /* Expected traversal order: [1, 2, 0] */ 157bf215546Sopenharmony_ci SET_EXPECTED(1, 2, 0); 158bf215546Sopenharmony_ci 159bf215546Sopenharmony_ci dag_traverse_bottom_up(dag, output_cb, &actual); 160bf215546Sopenharmony_ci 161bf215546Sopenharmony_ci TEST_CHECK(); 162bf215546Sopenharmony_ci} 163bf215546Sopenharmony_ci 164bf215546Sopenharmony_ciTEST_F(dag_test, duplicate_edge) 165bf215546Sopenharmony_ci{ 166bf215546Sopenharmony_ci INIT_NODES(3); 167bf215546Sopenharmony_ci 168bf215546Sopenharmony_ci node[0].add_edge(node[1], 0); 169bf215546Sopenharmony_ci node[0].add_edge(node[1], 1); 170bf215546Sopenharmony_ci node[0].add_edge(node[2], 0); 171bf215546Sopenharmony_ci 172bf215546Sopenharmony_ci EXPECT_EQ(util_dynarray_num_elements(&node[0].edges, struct dag_edge), 3); 173bf215546Sopenharmony_ci 174bf215546Sopenharmony_ci SET_EXPECTED(1, 2, 0); 175bf215546Sopenharmony_ci 176bf215546Sopenharmony_ci dag_traverse_bottom_up(dag, output_cb, &actual); 177bf215546Sopenharmony_ci 178bf215546Sopenharmony_ci TEST_CHECK(); 179bf215546Sopenharmony_ci} 180bf215546Sopenharmony_ci 181bf215546Sopenharmony_ciTEST_F(dag_test, duplicate_edge_max_data) 182bf215546Sopenharmony_ci{ 183bf215546Sopenharmony_ci INIT_NODES(3); 184bf215546Sopenharmony_ci 185bf215546Sopenharmony_ci node[0].add_edge_max_data(node[1], 0); 186bf215546Sopenharmony_ci node[0].add_edge_max_data(node[1], 1); 187bf215546Sopenharmony_ci node[0].add_edge_max_data(node[2], 0); 188bf215546Sopenharmony_ci 189bf215546Sopenharmony_ci EXPECT_EQ(util_dynarray_num_elements(&node[0].edges, struct dag_edge), 2); 190bf215546Sopenharmony_ci 191bf215546Sopenharmony_ci util_dynarray_foreach (&node[0].edges, struct dag_edge, edge) { 192bf215546Sopenharmony_ci if (edge->child == &node[1]) { 193bf215546Sopenharmony_ci EXPECT_EQ(edge->data, 1); 194bf215546Sopenharmony_ci } else { 195bf215546Sopenharmony_ci EXPECT_EQ(edge->child, &node[2]); 196bf215546Sopenharmony_ci EXPECT_EQ(edge->data, 0); 197bf215546Sopenharmony_ci } 198bf215546Sopenharmony_ci } 199bf215546Sopenharmony_ci 200bf215546Sopenharmony_ci SET_EXPECTED(1, 2, 0); 201bf215546Sopenharmony_ci 202bf215546Sopenharmony_ci dag_traverse_bottom_up(dag, output_cb, &actual); 203bf215546Sopenharmony_ci 204bf215546Sopenharmony_ci TEST_CHECK(); 205bf215546Sopenharmony_ci} 206bf215546Sopenharmony_ci 207bf215546Sopenharmony_ciTEST_F(dag_test, simple_many_children) 208bf215546Sopenharmony_ci{ 209bf215546Sopenharmony_ci INIT_NODES(6); 210bf215546Sopenharmony_ci 211bf215546Sopenharmony_ci /* _ 0 _ 212bf215546Sopenharmony_ci * / /|\ \ 213bf215546Sopenharmony_ci * / / | \ \ 214bf215546Sopenharmony_ci * | | | | | 215bf215546Sopenharmony_ci * 1 2 3 4 5 216bf215546Sopenharmony_ci */ 217bf215546Sopenharmony_ci node[0] >> node[1]; 218bf215546Sopenharmony_ci node[0] >> node[2]; 219bf215546Sopenharmony_ci node[0] >> node[3]; 220bf215546Sopenharmony_ci node[0] >> node[4]; 221bf215546Sopenharmony_ci node[0] >> node[5]; 222bf215546Sopenharmony_ci 223bf215546Sopenharmony_ci /* Expected traversal order: [1, 2, 3, 4, 5, 0] */ 224bf215546Sopenharmony_ci SET_EXPECTED(1, 2, 3, 4, 5, 0); 225bf215546Sopenharmony_ci 226bf215546Sopenharmony_ci dag_traverse_bottom_up(dag, output_cb, &actual); 227bf215546Sopenharmony_ci 228bf215546Sopenharmony_ci TEST_CHECK(); 229bf215546Sopenharmony_ci} 230bf215546Sopenharmony_ci 231bf215546Sopenharmony_ciTEST_F(dag_test, simple_many_parents) 232bf215546Sopenharmony_ci{ 233bf215546Sopenharmony_ci INIT_NODES(7); 234bf215546Sopenharmony_ci 235bf215546Sopenharmony_ci /* _ 0 _ 236bf215546Sopenharmony_ci * / /|\ \ 237bf215546Sopenharmony_ci * / / | \ \ 238bf215546Sopenharmony_ci * | | | | | 239bf215546Sopenharmony_ci * 1 2 3 4 5 240bf215546Sopenharmony_ci * | | | | | 241bf215546Sopenharmony_ci * \ \ | / / 242bf215546Sopenharmony_ci * \ \|/ / 243bf215546Sopenharmony_ci * ‾ 6 ‾ 244bf215546Sopenharmony_ci */ 245bf215546Sopenharmony_ci node[0] >> node[1] >> node[6]; 246bf215546Sopenharmony_ci node[0] >> node[2] >> node[6]; 247bf215546Sopenharmony_ci node[0] >> node[3] >> node[6]; 248bf215546Sopenharmony_ci node[0] >> node[4] >> node[6]; 249bf215546Sopenharmony_ci node[0] >> node[5] >> node[6]; 250bf215546Sopenharmony_ci 251bf215546Sopenharmony_ci /* Expected traversal order: [6, 1, 2, 3, 4, 5, 0] */ 252bf215546Sopenharmony_ci SET_EXPECTED(6, 1, 2, 3, 4, 5, 0); 253bf215546Sopenharmony_ci 254bf215546Sopenharmony_ci dag_traverse_bottom_up(dag, output_cb, &actual); 255bf215546Sopenharmony_ci 256bf215546Sopenharmony_ci TEST_CHECK(); 257bf215546Sopenharmony_ci} 258bf215546Sopenharmony_ci 259bf215546Sopenharmony_ciTEST_F(dag_test, complex) 260bf215546Sopenharmony_ci{ 261bf215546Sopenharmony_ci INIT_NODES(6); 262bf215546Sopenharmony_ci 263bf215546Sopenharmony_ci /* 0 264bf215546Sopenharmony_ci * / \ 265bf215546Sopenharmony_ci * 1 3 266bf215546Sopenharmony_ci * / \ |\ 267bf215546Sopenharmony_ci * 2 | | \ 268bf215546Sopenharmony_ci * \ / / 5 269bf215546Sopenharmony_ci * 4 ‾ 270bf215546Sopenharmony_ci */ 271bf215546Sopenharmony_ci node[0] >> node[1] >> node[2] >> node[4]; 272bf215546Sopenharmony_ci node[1] >> node[4]; 273bf215546Sopenharmony_ci node[0] >> node[3]; 274bf215546Sopenharmony_ci node[3] >> node[4]; 275bf215546Sopenharmony_ci node[3] >> node[5]; 276bf215546Sopenharmony_ci 277bf215546Sopenharmony_ci /* Expected traversal order: [4, 2, 1, 5, 3, 0] */ 278bf215546Sopenharmony_ci SET_EXPECTED(4, 2, 1, 5, 3, 0); 279bf215546Sopenharmony_ci 280bf215546Sopenharmony_ci dag_traverse_bottom_up(dag, output_cb, &actual); 281bf215546Sopenharmony_ci 282bf215546Sopenharmony_ci TEST_CHECK(); 283bf215546Sopenharmony_ci} 284