tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

testFindSCCs.cpp (4839B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      3 */
      4 /* This Source Code Form is subject to the terms of the Mozilla Public
      5 * License, v. 2.0. If a copy of the MPL was not distributed with this
      6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      7 
      8 #include <stdarg.h>
      9 #include <string.h>
     10 
     11 #include "gc/FindSCCs.h"
     12 #include "jsapi-tests/tests.h"
     13 
     14 static const unsigned MaxVertices = 10;
     15 
     16 using js::gc::ComponentFinder;
     17 using js::gc::GraphNodeBase;
     18 
     19 struct TestNode : public GraphNodeBase<TestNode> {
     20  unsigned index;
     21 };
     22 
     23 using TestComponentFinder = ComponentFinder<TestNode>;
     24 
     25 MOZ_RUNINIT static TestNode Vertex[MaxVertices];
     26 
     27 BEGIN_TEST(testFindSCCs) {
     28  // no vertices
     29 
     30  setup(0);
     31  run();
     32  CHECK(end());
     33 
     34  // no edges
     35 
     36  setup(1);
     37  run();
     38  CHECK(group(0, -1));
     39  CHECK(end());
     40 
     41  setup(3);
     42  run();
     43  CHECK(group(2, -1));
     44  CHECK(group(1, -1));
     45  CHECK(group(0, -1));
     46  CHECK(end());
     47 
     48  // linear
     49 
     50  setup(3);
     51  CHECK(edge(0, 1));
     52  CHECK(edge(1, 2));
     53  run();
     54  CHECK(group(0, -1));
     55  CHECK(group(1, -1));
     56  CHECK(group(2, -1));
     57  CHECK(end());
     58 
     59  // tree
     60 
     61  setup(3);
     62  CHECK(edge(0, 1));
     63  CHECK(edge(0, 2));
     64  run();
     65  CHECK(group(0, -1));
     66  if (resultsList && resultsList->index == 1) {
     67    CHECK(group(1, -1));
     68    CHECK(group(2, -1));
     69  } else {
     70    CHECK(group(2, -1));
     71    CHECK(group(1, -1));
     72  }
     73  CHECK(end());
     74 
     75  // cycles
     76 
     77  setup(3);
     78  CHECK(edge(0, 1));
     79  CHECK(edge(1, 2));
     80  CHECK(edge(2, 0));
     81  run();
     82  CHECK(group(0, 1, 2, -1));
     83  CHECK(end());
     84 
     85  setup(4);
     86  CHECK(edge(0, 1));
     87  CHECK(edge(1, 2));
     88  CHECK(edge(2, 1));
     89  CHECK(edge(2, 3));
     90  run();
     91  CHECK(group(0, -1));
     92  CHECK(group(1, 2, -1));
     93  CHECK(group(3, -1));
     94  CHECK(end());
     95 
     96  // remaining
     97 
     98  setup(2);
     99  CHECK(edge(0, 1));
    100  run();
    101  CHECK(remaining(0, 1, -1));
    102  CHECK(end());
    103 
    104  setup(2);
    105  CHECK(edge(0, 1));
    106  run();
    107  CHECK(group(0, -1));
    108  CHECK(remaining(1, -1));
    109  CHECK(end());
    110 
    111  setup(2);
    112  CHECK(edge(0, 1));
    113  run();
    114  CHECK(group(0, -1));
    115  CHECK(group(1, -1));
    116  CHECK(remaining(-1));
    117  CHECK(end());
    118 
    119  return true;
    120 }
    121 
    122 unsigned vertex_count;
    123 TestComponentFinder* finder;
    124 TestNode* resultsList;
    125 
    126 void setup(unsigned count) {
    127  vertex_count = count;
    128  for (unsigned i = 0; i < MaxVertices; ++i) {
    129    TestNode& v = Vertex[i];
    130    v.gcGraphEdges.clear();
    131    v.gcNextGraphNode = nullptr;
    132    v.index = i;
    133  }
    134 }
    135 
    136 bool edge(unsigned src_index, unsigned dest_index) {
    137  return Vertex[src_index].gcGraphEdges.put(&Vertex[dest_index]);
    138 }
    139 
    140 void run() {
    141  finder = new TestComponentFinder(cx);
    142  for (unsigned i = 0; i < vertex_count; ++i) {
    143    finder->addNode(&Vertex[i]);
    144  }
    145  resultsList = finder->getResultsList();
    146 }
    147 
    148 bool group(int vertex, ...) {
    149  TestNode* v = resultsList;
    150 
    151  va_list ap;
    152  va_start(ap, vertex);
    153  while (vertex != -1) {
    154    CHECK(v != nullptr);
    155    CHECK(v->index == unsigned(vertex));
    156    v = v->nextNodeInGroup();
    157    vertex = va_arg(ap, int);
    158  }
    159  va_end(ap);
    160 
    161  CHECK(v == nullptr);
    162  resultsList = resultsList->nextGroup();
    163  return true;
    164 }
    165 
    166 bool remaining(int vertex, ...) {
    167  TestNode* v = resultsList;
    168 
    169  va_list ap;
    170  va_start(ap, vertex);
    171  while (vertex != -1) {
    172    CHECK(v != nullptr);
    173    CHECK(v->index == unsigned(vertex));
    174    v = (TestNode*)v->gcNextGraphNode;
    175    vertex = va_arg(ap, int);
    176  }
    177  va_end(ap);
    178 
    179  CHECK(v == nullptr);
    180  resultsList = nullptr;
    181  return true;
    182 }
    183 
    184 bool end() {
    185  CHECK(resultsList == nullptr);
    186 
    187  delete finder;
    188  finder = nullptr;
    189  return true;
    190 }
    191 END_TEST(testFindSCCs)
    192 
    193 BEGIN_TEST(testFindSCCsStackLimit) {
    194  /*
    195   * Test what happens if recusion causes the stack to become full while
    196   * traversing the graph.
    197   *
    198   * The test case is a large number of vertices, almost all of which are
    199   * arranged in a linear chain.  The last few are left unlinked to exercise
    200   * adding vertices after the stack full condition has already been detected.
    201   *
    202   * Such an arrangement with no cycles would normally result in one group for
    203   * each vertex, but since the stack is exhasted in processing a single group
    204   * is returned containing all the vertices.
    205   */
    206  const unsigned max = 1000000;
    207  const unsigned initial = 10;
    208 
    209  TestNode* vertices = new TestNode[max]();
    210  for (unsigned i = initial; i < (max - 10); ++i) {
    211    CHECK(vertices[i].gcGraphEdges.put(&vertices[i + 1]));
    212  }
    213 
    214  TestComponentFinder finder(cx);
    215  for (unsigned i = 0; i < max; ++i) {
    216    finder.addNode(&vertices[i]);
    217  }
    218 
    219  TestNode* r = finder.getResultsList();
    220  CHECK(r);
    221  TestNode* v = r;
    222 
    223  unsigned count = 0;
    224  while (v) {
    225    ++count;
    226    v = v->nextNodeInGroup();
    227  }
    228  CHECK(count == max - initial);
    229 
    230  count = 0;
    231  v = r->nextGroup();
    232  while (v) {
    233    ++count;
    234    CHECK(!v->nextNodeInGroup());
    235    v = v->nextGroup();
    236  }
    237 
    238  delete[] vertices;
    239  return true;
    240 }
    241 END_TEST(testFindSCCsStackLimit)