// $Id$
//
//  Copyright (C) 2003-2006 Rational Discovery LLC
//
//   @@ All Rights Reserved @@
//  This file is part of the RDKit.
//  The contents are covered by the terms of the BSD license
//  which is included in the file license.txt, found at the root
//  of the RDKit source tree.
//
#include <RDGeneral/test.h>
#include <GraphMol/RDKitBase.h>
#include <GraphMol/Subgraphs/Subgraphs.h>
#include <GraphMol/SmilesParse/SmilesParse.h>

#include <iostream>
using namespace std;
using namespace RDKit;

void testSubgraphs() {
  std::cout << "-----------------------\n Subgraph retrieval" << std::endl;
  // build: CCC(C)CC
  RWMol mol;
  bool updateLabel = true;
  bool takeOwnership = true;
  mol.addAtom(new Atom(6), updateLabel, takeOwnership);
  mol.addAtom(new Atom(6), updateLabel, takeOwnership);
  mol.addAtom(new Atom(6), updateLabel, takeOwnership);
  mol.addAtom(new Atom(6), updateLabel, takeOwnership);
  mol.addAtom(new Atom(6), updateLabel, takeOwnership);
  mol.addAtom(new Atom(6), updateLabel, takeOwnership);
  mol.addBond(0, 1, Bond::SINGLE);
  mol.addBond(1, 2, Bond::SINGLE);
  mol.addBond(2, 3, Bond::SINGLE);
  mol.addBond(2, 4, Bond::SINGLE);
  mol.addBond(3, 5, Bond::SINGLE);

  PATH_LIST tmp;
  PATH_LIST::iterator i;

  int totPs = 0;
  tmp = findAllSubgraphsOfLengthN(mol, 1);
  CHECK_INVARIANT(tmp.size() == 5, "");
  totPs += tmp.size();
  tmp = findAllSubgraphsOfLengthN(mol, 2);
  CHECK_INVARIANT(tmp.size() == 5, "");
  totPs += tmp.size();
  tmp = findAllSubgraphsOfLengthN(mol, 3);
  CHECK_INVARIANT(tmp.size() == 5, "");
  totPs += tmp.size();
  tmp = findAllSubgraphsOfLengthN(mol, 4);
  CHECK_INVARIANT(tmp.size() == 3, "");
  totPs += tmp.size();
  tmp = findAllSubgraphsOfLengthN(mol, 5);
  CHECK_INVARIANT(tmp.size() == 1, "");
  totPs += tmp.size();
  tmp = findAllSubgraphsOfLengthN(mol, 6);
  CHECK_INVARIANT(tmp.empty(), "");
  totPs += tmp.size();

  // now use the direct range function and check that we get the
  // same answer
  INT_PATH_LIST_MAP tmpm;
  tmpm = findAllSubgraphsOfLengthsMtoN(mol, 1, 6);
  int newTot, idx;
  newTot = 0;
  for (idx = 1; idx <= 6; idx++) {
    newTot += tmpm[idx].size();
  }
  CHECK_INVARIANT(totPs == newTot, "");

  // add an H and make sure things don't change:
  mol.addAtom(new Atom(1), updateLabel, takeOwnership);
  mol.addBond(5, 6, Bond::SINGLE);

  tmp = findAllSubgraphsOfLengthN(mol, 1);

  CHECK_INVARIANT(tmp.size() == 5, "");
  tmp = findAllSubgraphsOfLengthN(mol, 2);
  CHECK_INVARIANT(tmp.size() == 5, "");
  tmp = findAllSubgraphsOfLengthN(mol, 3);
  CHECK_INVARIANT(tmp.size() == 5, "");
  tmp = findAllSubgraphsOfLengthN(mol, 4);
  CHECK_INVARIANT(tmp.size() == 3, "");
  tmp = findAllSubgraphsOfLengthN(mol, 5);
  CHECK_INVARIANT(tmp.size() == 1, "");
  tmp = findAllSubgraphsOfLengthN(mol, 6);
  CHECK_INVARIANT(tmp.empty(), "");

  std::cout << "Finished" << std::endl;
}

void testSubgraphs2a() {
  // these have been moved here from test2.cpp
  std::cout << "-----------------------\n testSubgraphs2a" << std::endl;
  RWMol *mol = SmilesToMol("C1CC2C1N2");
  CHECK_INVARIANT(mol, "");
  int nAll = 0;
  int nUnique = 0;
  for (unsigned int i = 1; i < 7; ++i) {
    PATH_LIST tmp;
    tmp = findAllSubgraphsOfLengthN(*mol, i);
    nAll += tmp.size();
    tmp = findUniqueSubgraphsOfLengthN(*mol, i);
    nUnique += tmp.size();
  }

  CHECK_INVARIANT(nAll == 49, "");
  CHECK_INVARIANT(nUnique == 21, "");
  delete mol;

  std::cout << "Finished" << std::endl;
}

void testSubgraphs2() {
  // these have been moved here from test2.cpp
  std::cout << "-----------------------\n testSubgraphs2" << std::endl;
  RWMol *mol = SmilesToMol("C12C3C4C1C1C2C3N41");
  CHECK_INVARIANT(mol, "");

  int nAll = 0;
  int nUnique = 0;
  int i;
  for (i = 1; i < 13; i++) {
    PATH_LIST tmp;
    tmp = findAllSubgraphsOfLengthN(*mol, i);
    nAll += tmp.size();
    tmp = findUniqueSubgraphsOfLengthN(*mol, i);
    nUnique += tmp.size();
  }

  delete mol;
  CHECK_INVARIANT(nAll == 2433, "");
  CHECK_INVARIANT(nUnique == 300, "");

  mol = SmilesToMol("CCC(O)C(c1ccccc1)CC(C)N(C)C");
  CHECK_INVARIANT(mol, "");

  nAll = 0;
  nUnique = 0;
  for (i = 1; i < 18; i++) {
    PATH_LIST tmp;
    tmp = findAllSubgraphsOfLengthN(*mol, i);
    nAll += tmp.size();
    tmp = findUniqueSubgraphsOfLengthN(*mol, i);
    nUnique += tmp.size();
  }

  delete mol;
  CHECK_INVARIANT(nAll == 1990, "");
  CHECK_INVARIANT(nUnique == 907, "");

  std::cout << "Finished" << std::endl;
}

void dumpVIV(PATH_LIST v) {
  PATH_LIST::iterator i;
  PATH_TYPE::iterator j;
  for (i = v.begin(); i != v.end(); i++) {
    for (j = i->begin(); j != i->end(); j++) {
      std::cout << *j << " ";
    }
    std::cout << std::endl;
  }
}

void testPaths() {
  std::cout << "-----------------------\n Path retrieval" << std::endl;
  // build: CCC(C)CC
  RWMol mol;
  bool updateLabel = true;
  bool takeOwnership = true;
  mol.addAtom(new Atom(6), updateLabel, takeOwnership);
  mol.addAtom(new Atom(6), updateLabel, takeOwnership);
  mol.addAtom(new Atom(6), updateLabel, takeOwnership);
  mol.addAtom(new Atom(6), updateLabel, takeOwnership);
  mol.addAtom(new Atom(6), updateLabel, takeOwnership);
  mol.addAtom(new Atom(6), updateLabel, takeOwnership);
  mol.addBond(0, 1, Bond::SINGLE);
  mol.addBond(1, 2, Bond::SINGLE);
  mol.addBond(2, 3, Bond::SINGLE);
  mol.addBond(2, 4, Bond::SINGLE);
  mol.addBond(3, 5, Bond::SINGLE);

  PATH_LIST tmp;

  //
  //  Retrieve using bonds
  //
  tmp = findAllPathsOfLengthN(mol, 1);
  CHECK_INVARIANT(tmp.size() == 5, "");
  tmp = findAllPathsOfLengthN(mol, 2);
  CHECK_INVARIANT(tmp.size() == 5, "");
  tmp = findAllPathsOfLengthN(mol, 3);
  CHECK_INVARIANT(tmp.size() == 4, "");
  tmp = findAllPathsOfLengthN(mol, 4);
  CHECK_INVARIANT(tmp.size() == 1, "");
  tmp = findAllPathsOfLengthN(mol, 5);
  CHECK_INVARIANT(tmp.empty(), "");
  tmp = findAllPathsOfLengthN(mol, 6);
  CHECK_INVARIANT(tmp.empty(), "");

  //
  //  Retrieve using atoms, which gives the results shifted by
  //  one (it takes two atoms to make one bond)
  //
  tmp = findAllPathsOfLengthN(mol, 1, false);
  CHECK_INVARIANT(tmp.size() == 6, "");
  tmp = findAllPathsOfLengthN(mol, 2, false);
  CHECK_INVARIANT(tmp.size() == 5, "");
  tmp = findAllPathsOfLengthN(mol, 3, false);
  CHECK_INVARIANT(tmp.size() == 5, "");
  tmp = findAllPathsOfLengthN(mol, 4, false);
  CHECK_INVARIANT(tmp.size() == 4, "");
  tmp = findAllPathsOfLengthN(mol, 5, false);
  CHECK_INVARIANT(tmp.size() == 1, "");
  tmp = findAllPathsOfLengthN(mol, 6, false);
  CHECK_INVARIANT(tmp.empty(), "");

  //
  //  try m->n
  //
  INT_PATH_LIST_MAP pths;
  pths = findAllPathsOfLengthsMtoN(mol, 1, 6);
  CHECK_INVARIANT(pths[1].size() == 5, "");
  CHECK_INVARIANT(pths[2].size() == 5, "");
  CHECK_INVARIANT(pths[3].size() == 4, "");
  CHECK_INVARIANT(pths[4].size() == 1, "");
  CHECK_INVARIANT(pths[5].empty(), "");
  CHECK_INVARIANT(pths[6].empty(), "");

  pths = findAllPathsOfLengthsMtoN(mol, 1, 6, false);
  CHECK_INVARIANT(pths[1].size() == 6, "");
  CHECK_INVARIANT(pths[2].size() == 5, "");
  CHECK_INVARIANT(pths[3].size() == 5, "");
  CHECK_INVARIANT(pths[4].size() == 4, "");
  CHECK_INVARIANT(pths[5].size() == 1, "");
  CHECK_INVARIANT(pths[6].empty(), "");

  //
  //  add an atom, close the ring and re-check a couple indices:
  //   (leaves us with CC1CCCCC1)
  //
  mol.addAtom(new Atom(6), updateLabel, takeOwnership);
  mol.addBond(5, 6, Bond::SINGLE);
  mol.addBond(0, 6, Bond::SINGLE);
  tmp = findAllPathsOfLengthN(mol, 4);
  CHECK_INVARIANT(tmp.size() == 8, "");
  tmp = findAllPathsOfLengthN(mol, 5, false);
  CHECK_INVARIANT(tmp.size() == 8, "");

  std::cout << "Finished" << std::endl;
}

void testPaths2() {
  std::cout << "-----------------------\n Path retrieval2" << std::endl;
  // build: CCC(C)CC
  RWMol mol;
  bool updateLabel = true;
  bool takeOwnership = true;
  mol.addAtom(new Atom(6), updateLabel, takeOwnership);
  mol.addAtom(new Atom(6), updateLabel, takeOwnership);
  mol.addAtom(new Atom(6), updateLabel, takeOwnership);
  mol.addAtom(new Atom(6), updateLabel, takeOwnership);
  mol.addBond(0, 1, Bond::SINGLE);
  mol.addBond(1, 2, Bond::SINGLE);
  mol.addBond(2, 3, Bond::SINGLE);
  mol.addBond(2, 0, Bond::SINGLE);

  //
  //  Retrieve using bonds
  //
  PATH_LIST tmp = findAllPathsOfLengthN(mol, 3);
  // std::cout << "\n3:" << std::endl;
  // dumpVIV(tmp);
  CHECK_INVARIANT(tmp.size() == 3, "");

  std::cout << "Finished" << std::endl;
}

void testUniqueSubgraphs() {
  std::cout << "-----------------------\n Unique Subgraph retrieval"
            << std::endl;
  // build: CCC(C)CC
  RWMol mol;
  bool updateLabel = true;
  bool takeOwnership = true;
  mol.addAtom(new Atom(6), updateLabel, takeOwnership);
  mol.addAtom(new Atom(6), updateLabel, takeOwnership);
  mol.addAtom(new Atom(6), updateLabel, takeOwnership);
  mol.addAtom(new Atom(6), updateLabel, takeOwnership);
  mol.addAtom(new Atom(6), updateLabel, takeOwnership);
  mol.addAtom(new Atom(6), updateLabel, takeOwnership);
  mol.addBond(0, 1, Bond::SINGLE);
  mol.addBond(1, 2, Bond::SINGLE);
  mol.addBond(2, 3, Bond::SINGLE);
  mol.addBond(2, 4, Bond::SINGLE);
  mol.addBond(3, 5, Bond::SINGLE);

  PATH_LIST tmp;
  PATH_LIST::iterator i;

  tmp = findAllSubgraphsOfLengthN(mol, 1);
  CHECK_INVARIANT(tmp.size() == 5, "");

  tmp = findAllSubgraphsOfLengthN(mol, 2);
  CHECK_INVARIANT(tmp.size() == 5, "");
  tmp = findUniqueSubgraphsOfLengthN(mol, 2);
  CHECK_INVARIANT(tmp.size() == 1, "");

  tmp = findAllSubgraphsOfLengthN(mol, 3);
  CHECK_INVARIANT(tmp.size() == 5, "");
  tmp = findUniqueSubgraphsOfLengthN(mol, 3);
  CHECK_INVARIANT(tmp.size() == 2, "");

  tmp = findAllSubgraphsOfLengthN(mol, 4);
  CHECK_INVARIANT(tmp.size() == 3, "");
  tmp = findUniqueSubgraphsOfLengthN(mol, 4);
  CHECK_INVARIANT(tmp.size() == 2, "");

  tmp = findAllSubgraphsOfLengthN(mol, 5);
  CHECK_INVARIANT(tmp.size() == 1, "");
  tmp = findUniqueSubgraphsOfLengthN(mol, 5);
  CHECK_INVARIANT(tmp.size() == 1, "");

  tmp = findAllSubgraphsOfLengthN(mol, 6);
  CHECK_INVARIANT(tmp.empty(), "");
  tmp = findUniqueSubgraphsOfLengthN(mol, 6);
  CHECK_INVARIANT(tmp.empty(), "");

  // add an H and make sure things don't change:
  mol.addAtom(new Atom(1), updateLabel, takeOwnership);
  mol.addBond(5, 6, Bond::SINGLE);

  tmp = findAllSubgraphsOfLengthN(mol, 2);
  CHECK_INVARIANT(tmp.size() == 5, "");
  tmp = findUniqueSubgraphsOfLengthN(mol, 2);
  CHECK_INVARIANT(tmp.size() == 1, "");

  tmp = findAllSubgraphsOfLengthN(mol, 3);
  CHECK_INVARIANT(tmp.size() == 5, "");
  tmp = findUniqueSubgraphsOfLengthN(mol, 3);
  CHECK_INVARIANT(tmp.size() == 2, "");

  tmp = findAllSubgraphsOfLengthN(mol, 4);
  CHECK_INVARIANT(tmp.size() == 3, "");
  tmp = findUniqueSubgraphsOfLengthN(mol, 4);
  CHECK_INVARIANT(tmp.size() == 2, "");

  tmp = findAllSubgraphsOfLengthN(mol, 5);
  CHECK_INVARIANT(tmp.size() == 1, "");
  tmp = findUniqueSubgraphsOfLengthN(mol, 5);
  CHECK_INVARIANT(tmp.size() == 1, "");

  tmp = findAllSubgraphsOfLengthN(mol, 6);
  CHECK_INVARIANT(tmp.empty(), "");
  tmp = findUniqueSubgraphsOfLengthN(mol, 6);
  CHECK_INVARIANT(tmp.empty(), "");

  std::cout << "Finished" << std::endl;
}

void testUniqueSubgraphs2() {
  // moved here from test2.cpp
  std::cout << "-----------------------\n testUniqueSubgraphs2" << std::endl;
  RWMol *mol = SmilesToMol("O=C(O)CCCC=CC(C1C(O)CC(O)C1(C=CC(O)CCCCC))");
  CHECK_INVARIANT(mol, "");

  int nAll = 0;
  int nUnique = 0;
  for (int i = 1; i < 26; i++) {
    PATH_LIST tmp;
    tmp = findAllSubgraphsOfLengthN(*mol, i);
    // std::cout << i << "\t" << tmp.size();
    nAll += tmp.size();
    tmp = findUniqueSubgraphsOfLengthN(*mol, i);
    // std::cout << "\t" << tmp.size() << std::endl;;
    nUnique += tmp.size();
  }

  CHECK_INVARIANT(nAll == 6435, "");
  CHECK_INVARIANT(nUnique == 5618, "");
  delete mol;
  std::cout << "Finished" << std::endl;
}

void testLeak() {
  // moved here from test2.cpp
  std::cout << "-----------------------\n testing for a core leak (Issue 42) "
            << std::endl;
  RWMol *mol = SmilesToMol("O=C(O)CCCC=CC(C1C(O)CC(O)C1(C=CC(O)CCCCC))");
  CHECK_INVARIANT(mol, "");

  for (int rep = 0; rep < 100; rep++) {
    int nAll = 0;
    int nUnique = 0;
    for (int i = 1; i < 26; i++) {
      PATH_LIST tmp;
      tmp = findAllSubgraphsOfLengthN(*mol, i);
      // std::cout << i << "\t" << tmp.size();
      nAll += tmp.size();
      tmp = findUniqueSubgraphsOfLengthN(*mol, i);
      // std::cout << "\t" << tmp.size() << std::endl;;
      nUnique += tmp.size();
    }
    CHECK_INVARIANT(nAll == 6435, "");
    CHECK_INVARIANT(nUnique == 5618, "");
  }
  delete mol;
  std::cout << "Finished" << std::endl;
}

void testRootedSubgraphs() {
  std::cout << "-----------------------\n testRootedSubgraphs" << std::endl;
  {
    RWMol *mol = SmilesToMol("CC1CC1");
    TEST_ASSERT(mol);

    PATH_LIST tmp;
    tmp = findAllSubgraphsOfLengthN(*mol, 1, false, 0);
    TEST_ASSERT(tmp.size() == 1);
    tmp = findAllSubgraphsOfLengthN(*mol, 2, false, 0);
    TEST_ASSERT(tmp.size() == 2);
    tmp = findAllSubgraphsOfLengthN(*mol, 3, false, 0);
    TEST_ASSERT(tmp.size() == 3);
    tmp = findUniqueSubgraphsOfLengthN(*mol, 2, false, false, 0);
    TEST_ASSERT(tmp.size() == 1);
    tmp = findUniqueSubgraphsOfLengthN(*mol, 3, false, false, 0);
    TEST_ASSERT(tmp.size() == 2);

    INT_PATH_LIST_MAP tmpm;
    tmpm = findAllSubgraphsOfLengthsMtoN(*mol, 1, 3, false, 0);
    TEST_ASSERT(tmpm[1].size() == 1);
    TEST_ASSERT(tmpm[2].size() == 2);
    TEST_ASSERT(tmpm[3].size() == 3);

    // edge case:
    tmp = findAllSubgraphsOfLengthN(*mol, 1, false, 10);
    TEST_ASSERT(tmp.empty());

    delete mol;
  }

  {  // tests for sf.net issue 250
    RWMol *mol = SmilesToMol("C1CC1C");
    TEST_ASSERT(mol);

    PATH_LIST tmp;
    tmp = findAllSubgraphsOfLengthN(*mol, 1, false, 3);
    TEST_ASSERT(tmp.size() == 1);
    tmp = findAllSubgraphsOfLengthN(*mol, 2, false, 3);
    TEST_ASSERT(tmp.size() == 2);
    tmp = findAllSubgraphsOfLengthN(*mol, 3, false, 3);
    TEST_ASSERT(tmp.size() == 3);
    tmp = findUniqueSubgraphsOfLengthN(*mol, 2, false, false, 3);
    TEST_ASSERT(tmp.size() == 1);
    tmp = findUniqueSubgraphsOfLengthN(*mol, 3, false, false, 3);
    TEST_ASSERT(tmp.size() == 2);

    INT_PATH_LIST_MAP tmpm;
    tmpm = findAllSubgraphsOfLengthsMtoN(*mol, 1, 3, false, 3);
    TEST_ASSERT(tmpm[1].size() == 1);
    TEST_ASSERT(tmpm[2].size() == 2);
    TEST_ASSERT(tmpm[3].size() == 3);

    // edge case:
    tmp = findAllSubgraphsOfLengthN(*mol, 1, false, 10);
    TEST_ASSERT(tmp.empty());

    delete mol;
  }

  {
    RWMol *mol = SmilesToMol("CC1CC1");
    TEST_ASSERT(mol);

    INT_PATH_LIST_MAP tmpm;
    tmpm = findAllSubgraphsOfLengthsMtoN(*mol, 1, 2, false, 0);
    TEST_ASSERT(tmpm[1].size() == 1);
    TEST_ASSERT(tmpm[2].size() == 2);
    TEST_ASSERT(tmpm[3].empty());
    tmpm = findAllSubgraphsOfLengthsMtoN(*mol, 1, 3, false, 0);
    TEST_ASSERT(tmpm[1].size() == 1);
    TEST_ASSERT(tmpm[2].size() == 2);
    TEST_ASSERT(tmpm[3].size() == 3);
    delete mol;
  }
  {  // tests for sf.net issue 250
    RWMol *mol = SmilesToMol("C1CC1C");
    TEST_ASSERT(mol);

    INT_PATH_LIST_MAP tmpm;
    tmpm = findAllSubgraphsOfLengthsMtoN(*mol, 1, 2, false, 3);
    TEST_ASSERT(tmpm[1].size() == 1);
    TEST_ASSERT(tmpm[2].size() == 2);
    TEST_ASSERT(tmpm[3].empty());
    tmpm = findAllSubgraphsOfLengthsMtoN(*mol, 1, 3, false, 3);
    TEST_ASSERT(tmpm[1].size() == 1);
    TEST_ASSERT(tmpm[2].size() == 2);
    TEST_ASSERT(tmpm[3].size() == 3);
    delete mol;
  }

  std::cout << "Finished" << std::endl;
}

void testRootedPaths() {
  std::cout << "-----------------------\n testRootedPaths" << std::endl;
  {
    RWMol *mol = SmilesToMol("CC1CC1");
    TEST_ASSERT(mol);

    PATH_LIST tmp;

    // bond paths:
    tmp = findAllPathsOfLengthN(*mol, 1, true, false, 0);
    TEST_ASSERT(tmp.size() == 1);
    tmp = findAllPathsOfLengthN(*mol, 2, true, false, 0);
    TEST_ASSERT(tmp.size() == 2);
    tmp = findAllPathsOfLengthN(*mol, 3, true, false, 0);
    TEST_ASSERT(tmp.size() == 2);

    // edge case:
    tmp = findAllPathsOfLengthN(*mol, 1, true, false, 10);
    TEST_ASSERT(tmp.empty());

    // atom paths:
    tmp = findAllPathsOfLengthN(*mol, 1, false, false, 0);
    TEST_ASSERT(tmp.size() == 1);
    tmp = findAllPathsOfLengthN(*mol, 2, false, false, 0);
    TEST_ASSERT(tmp.size() == 1);
    tmp = findAllPathsOfLengthN(*mol, 3, false, false, 0);
    TEST_ASSERT(tmp.size() == 2);
    tmp = findAllPathsOfLengthN(*mol, 4, false, false, 0);
    TEST_ASSERT(tmp.size() == 2);

    delete mol;
  }

  {  // tests for sf.net issue 250
    RWMol *mol = SmilesToMol("C1CC1C");
    TEST_ASSERT(mol);

    PATH_LIST tmp;

    // bond paths:
    tmp = findAllPathsOfLengthN(*mol, 1, true, false, 3);
    TEST_ASSERT(tmp.size() == 1);
    tmp = findAllPathsOfLengthN(*mol, 2, true, false, 3);
    TEST_ASSERT(tmp.size() == 2);
    tmp = findAllPathsOfLengthN(*mol, 3, true, false, 3);
    TEST_ASSERT(tmp.size() == 2);

    // edge case:
    tmp = findAllPathsOfLengthN(*mol, 1, true, false, 10);
    TEST_ASSERT(tmp.empty());

    // atom paths:
    tmp = findAllPathsOfLengthN(*mol, 1, false, false, 3);
    TEST_ASSERT(tmp.size() == 1);
    tmp = findAllPathsOfLengthN(*mol, 2, false, false, 3);
    TEST_ASSERT(tmp.size() == 1);
    tmp = findAllPathsOfLengthN(*mol, 3, false, false, 3);
    TEST_ASSERT(tmp.size() == 2);
    tmp = findAllPathsOfLengthN(*mol, 4, false, false, 3);
    TEST_ASSERT(tmp.size() == 2);

    delete mol;
  }

  {
    RWMol *mol = SmilesToMol("CC1CC1");
    TEST_ASSERT(mol);

    INT_PATH_LIST_MAP tmpm;
    tmpm = findAllPathsOfLengthsMtoN(*mol, 1, 2, false, false, 0);
    TEST_ASSERT(tmpm[1].size() == 1);
    TEST_ASSERT(tmpm[2].size() == 1);
    TEST_ASSERT(tmpm[3].empty());
    tmpm = findAllPathsOfLengthsMtoN(*mol, 1, 3, false, false, 0);
    TEST_ASSERT(tmpm[1].size() == 1);
    TEST_ASSERT(tmpm[2].size() == 1);
    TEST_ASSERT(tmpm[3].size() == 2);
    delete mol;
  }
  {  // tests for sf.net issue 250
    RWMol *mol = SmilesToMol("C1CC1C");
    TEST_ASSERT(mol);

    INT_PATH_LIST_MAP tmpm;
    tmpm = findAllPathsOfLengthsMtoN(*mol, 1, 2, false, false, 3);
    TEST_ASSERT(tmpm[1].size() == 1);
    TEST_ASSERT(tmpm[2].size() == 1);
    TEST_ASSERT(tmpm[3].empty());
    tmpm = findAllPathsOfLengthsMtoN(*mol, 1, 3, false, false, 3);
    TEST_ASSERT(tmpm[1].size() == 1);
    TEST_ASSERT(tmpm[2].size() == 1);
    TEST_ASSERT(tmpm[3].size() == 2);
    delete mol;
  }

  std::cout << "Finished" << std::endl;
}

// -------------------------------------------------------------------
int main() {
#if 1
  testSubgraphs();
  testSubgraphs2a();
  testSubgraphs2();
  testPaths();
  testPaths2();
  testUniqueSubgraphs();
  testUniqueSubgraphs2();
  testRootedSubgraphs();
  testRootedPaths();
#endif
  // testLeak();
  return 0;
}
