/* Template classes for directed graphs.
   Copyright (C) 2019-2020 Free Software Foundation, Inc.
   Contributed by David Malcolm <dmalcolm@redhat.com>.

This file is part of GCC.

GCC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.

GCC is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */

#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "diagnostic.h"
#include "graphviz.h"
#include "digraph.h"
#include "shortest-paths.h"
#include "selftest.h"

#if CHECKING_P

namespace selftest {

/* A family of digraph classes for writing selftests.  */

struct test_node;
struct test_edge;
struct test_graph;
struct test_dump_args_t {};
struct test_cluster;

struct test_graph_traits
{
  typedef test_node node_t;
  typedef test_edge edge_t;
  typedef test_graph graph_t;
  typedef test_dump_args_t dump_args_t;
  typedef test_cluster cluster_t;
};

struct test_node : public dnode<test_graph_traits>
{
  test_node (const char *name, int index) : m_name (name), m_index (index) {}
  void dump_dot (graphviz_out *, const dump_args_t &) const OVERRIDE
  {
  }

  const char *m_name;
  int m_index;
};

struct test_edge : public dedge<test_graph_traits>
{
  test_edge (node_t *src, node_t *dest)
  : dedge<test_graph_traits> (src, dest)
  {}

  void dump_dot (graphviz_out *gv, const dump_args_t &) const OVERRIDE
  {
    gv->println ("%s -> %s;", m_src->m_name, m_dest->m_name);
  }
};

struct test_graph : public digraph<test_graph_traits>
{
  test_node *add_test_node (const char *name)
  {
    test_node *result = new test_node (name, m_nodes.length ());
    add_node (result);
    return result;
  }

  test_edge *add_test_edge (test_node *src, test_node *dst)
  {
    test_edge *result = new test_edge (src, dst);
    add_edge (result);
    return result;
  }
};

struct test_cluster : public cluster<test_graph_traits>
{
};

struct test_path
{
  auto_vec<const test_edge *> m_edges;
};

/* Smoketest of digraph dumping.  */

static void
test_dump_to_dot ()
{
  test_graph g;
  test_node *a = g.add_test_node ("a");
  test_node *b = g.add_test_node ("b");
  g.add_test_edge (a, b);

  pretty_printer pp;
  pp.buffer->stream = NULL;
  test_dump_args_t dump_args;
  g.dump_dot_to_pp (&pp, NULL, dump_args);

  ASSERT_STR_CONTAINS (pp_formatted_text (&pp),
		       "a -> b;\n");
}

/* Test shortest paths from A in this digraph,
   where edges run top-to-bottom if not otherwise labeled:

      A
     / \
    B   C-->D
    |   |
    E   |
     \ /
      F.  */

static void
test_shortest_paths ()
{
  test_graph g;
  test_node *a = g.add_test_node ("a");
  test_node *b = g.add_test_node ("b");
  test_node *c = g.add_test_node ("d");
  test_node *d = g.add_test_node ("d");
  test_node *e = g.add_test_node ("e");
  test_node *f = g.add_test_node ("f");

  test_edge *ab = g.add_test_edge (a, b);
  test_edge *ac = g.add_test_edge (a, c);
  test_edge *cd = g.add_test_edge (c, d);
  test_edge *be = g.add_test_edge (b, e);
  g.add_test_edge (e, f);
  test_edge *cf = g.add_test_edge (c, f);

  shortest_paths<test_graph_traits, test_path> sp (g, a);

  test_path path_to_a = sp.get_shortest_path (a);
  ASSERT_EQ (path_to_a.m_edges.length (), 0);

  test_path path_to_b = sp.get_shortest_path (b);
  ASSERT_EQ (path_to_b.m_edges.length (), 1);
  ASSERT_EQ (path_to_b.m_edges[0], ab);

  test_path path_to_c = sp.get_shortest_path (c);
  ASSERT_EQ (path_to_c.m_edges.length (), 1);
  ASSERT_EQ (path_to_c.m_edges[0], ac);

  test_path path_to_d = sp.get_shortest_path (d);
  ASSERT_EQ (path_to_d.m_edges.length (), 2);
  ASSERT_EQ (path_to_d.m_edges[0], ac);
  ASSERT_EQ (path_to_d.m_edges[1], cd);

  test_path path_to_e = sp.get_shortest_path (e);
  ASSERT_EQ (path_to_e.m_edges.length (), 2);
  ASSERT_EQ (path_to_e.m_edges[0], ab);
  ASSERT_EQ (path_to_e.m_edges[1], be);

  test_path path_to_f = sp.get_shortest_path (f);
  ASSERT_EQ (path_to_f.m_edges.length (), 2);
  ASSERT_EQ (path_to_f.m_edges[0], ac);
  ASSERT_EQ (path_to_f.m_edges[1], cf);
}

/* Run all of the selftests within this file.  */

void
digraph_cc_tests ()
{
  test_dump_to_dot ();
  test_shortest_paths ();
}

} // namespace selftest

#endif /* #if CHECKING_P */
