fs-watcher: Switch code to use ndn-cxx

Implementation moved to ndn::chronoshare namespace

Change-Id: I78a7f08dc2aafe7a2d578f78d99c72db7ea414b6
diff --git a/tests/unit-tests/fs-watcher.t.cpp b/tests/integrated-tests/fs-watcher.t.cpp
similarity index 62%
rename from tests/unit-tests/fs-watcher.t.cpp
rename to tests/integrated-tests/fs-watcher.t.cpp
index 22b1838..05f9764 100644
--- a/tests/unit-tests/fs-watcher.t.cpp
+++ b/tests/integrated-tests/fs-watcher.t.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2013-2016, Regents of the University of California.
+ * Copyright (c) 2013-2017, Regents of the University of California.
  *
  * This file is part of ChronoShare, a decentralized file sharing application over NDN.
  *
@@ -17,79 +17,129 @@
  *
  * See AUTHORS.md for complete list of ChronoShare authors and contributors.
  */
+
 #include "fs-watcher.hpp"
+#include "test-common.hpp"
+
 #include <boost/bind.hpp>
 #include <boost/filesystem.hpp>
+#include <boost/filesystem/fstream.hpp>
 #include <boost/lexical_cast.hpp>
 #include <boost/make_shared.hpp>
 #include <boost/test/unit_test.hpp>
 #include <boost/thread/thread.hpp>
-#include <QtGui>
 #include <fstream>
+#include <iostream>
+#include <thread>
 #include <set>
 
+#include "fs-watcher.t.hpp"
+
 using namespace std;
-using namespace boost;
 namespace fs = boost::filesystem;
 
-BOOST_AUTO_TEST_SUITE(TestFsWatcher)
+_LOG_INIT(Test.FSWatcher);
 
-void
-onChange(set<string>& files, const fs::path& file)
+namespace ndn {
+namespace chronoshare {
+namespace tests {
+
+fsWatcherApp::fsWatcherApp(int& argc, char** argv)
+  : QCoreApplication(argc, argv)
 {
-  cerr << "onChange called" << endl;
-  files.insert(file.string());
+  connect(this, SIGNAL(stopApp()), this, SLOT(quit()), Qt::QueuedConnection);
 }
 
-void
-onDelete(set<string>& files, const fs::path& file)
-{
-  files.erase(file.string());
-}
+fsWatcherApp::~fsWatcherApp() = default;
 
-void
-create_file(const fs::path& ph, const std::string& contents)
+class TestFSWatcherFixture : public IdentityManagementFixture
 {
-  std::ofstream f(ph.string().c_str());
-  if (!f) {
-    abort();
+public:
+  TestFSWatcherFixture()
+    : dir(fs::path(UNIT_TEST_CONFIG_PATH) / "TestFsWatcher")
+    , argc(0)
+  {
+    if (fs::exists(dir)) {
+      fs::remove_all(dir);
+    }
+
+    fs::create_directory(dir);
   }
-  if (!contents.empty()) {
-    f << contents;
-  }
-}
 
-void
-run(fs::path dir, FsWatcher::LocalFile_Change_Callback c, FsWatcher::LocalFile_Change_Callback d)
-{
-  int x = 0;
-  QCoreApplication app(x, 0);
-  FsWatcher watcher(dir.string().c_str(), c, d);
-  app.exec();
-  sleep(100);
-}
+  ~TestFSWatcherFixture(){
+    // cleanup
+    if (fs::exists(dir)) {
+      _LOG_DEBUG("clean all");
+      fs::remove_all(dir);
+    }
+  }
+
+  void
+  advanceClocks(std::chrono::seconds delay)
+  {
+    std::chrono::milliseconds step = delay;
+    step /= 50;
+    for (int i = 0; i < 50; ++i) {
+      std::this_thread::sleep_for(step);
+      m_io.poll();
+      m_io.reset();
+    }
+  }
+
+  void
+  onChange(set<string>& files, const fs::path& file)
+  {
+    _LOG_DEBUG("on change, file: " << file);
+    files.insert(file.string());
+  }
+
+  void
+  onDelete(set<string>& files, const fs::path& file)
+  {
+    _LOG_DEBUG("on delete, file: " << file);
+    files.erase(file.string());
+  }
+
+  void
+  create_file(const fs::path& ph, const std::string& contents)
+  {
+    std::ofstream f(ph.string().c_str());
+    if (!f) {
+      abort();
+    }
+    if (!contents.empty()) {
+      f << contents;
+    }
+  }
+
+  void
+  run()
+  {
+    app = new fsWatcherApp(argc, nullptr);
+    new FsWatcher(m_io, dir.string().c_str(),
+                  std::bind(&TestFSWatcherFixture::onChange, this, std::ref(files), _1),
+                  std::bind(&TestFSWatcherFixture::onDelete, this, std::ref(files), _1),
+                  app);
+    app->exec();
+  }
+
+public:
+  fs::path dir;
+  set<string> files;
+  int argc;
+  fsWatcherApp* app;
+};
+
+BOOST_FIXTURE_TEST_SUITE(TestFsWatcher, TestFSWatcherFixture)
 
 BOOST_AUTO_TEST_CASE(TestFsWatcher)
 {
-  fs::path dir = fs::absolute(fs::path("TestFsWatcher"));
-  if (fs::exists(dir)) {
-    fs::remove_all(dir);
-  }
-
-  fs::create_directory(dir);
-
-  set<string> files;
-
-  FsWatcher::LocalFile_Change_Callback fileChange = boost::bind(onChange, ref(files), _1);
-  FsWatcher::LocalFile_Change_Callback fileDelete = boost::bind(onDelete, ref(files), _1);
-
-  thread workThread(run, dir, fileChange, fileDelete);
-  //FsWatcher watcher (dir.string().c_str(), fileChange, fileDelete);
+  std::thread workThread(boost::bind(&TestFSWatcherFixture::run, this));
+  this->advanceClocks(std::chrono::seconds(2));
 
   // ============ check create file detection ================
   create_file(dir / "test.txt", "hello");
-  // have to at least wait 0.5 seconds
-  usleep(1000000);
+  this->advanceClocks(std::chrono::seconds(2));
   // test.txt
   BOOST_CHECK_EQUAL(files.size(), 1);
   BOOST_CHECK(files.find("test.txt") != files.end());
@@ -101,8 +151,7 @@
     string filename = boost::lexical_cast<string>(i);
     create_file(subdir / filename.c_str(), boost::lexical_cast<string>(i));
   }
-  // have to at least wait 0.5 * 2 seconds
-  usleep(1100000);
+  this->advanceClocks(std::chrono::seconds(2));
   // test.txt
   // sub/0..9
   BOOST_CHECK_EQUAL(files.size(), 11);
@@ -117,10 +166,9 @@
   fs::copy_directory(subdir, subdir1);
   for (int i = 0; i < 5; i++) {
     string filename = boost::lexical_cast<string>(i);
-    fs::copy_file(subdir / filename.c_str(), subdir1 / filename.c_str());
+    fs::copy(subdir / filename.c_str(), subdir1 / filename.c_str());
   }
-  // have to at least wait 0.5 * 2 seconds
-  usleep(1100000);
+  this->advanceClocks(std::chrono::seconds(2));
   // test.txt
   // sub/0..9
   // sub1/sub2/0..4
@@ -135,7 +183,7 @@
     string filename = boost::lexical_cast<string>(i);
     fs::remove(subdir / filename.c_str());
   }
-  usleep(1100000);
+  this->advanceClocks(std::chrono::seconds(2));
   // test.txt
   // sub/7..9
   // sub1/sub2/0..4
@@ -148,14 +196,15 @@
       BOOST_CHECK(files.find("sub/" + filename) != files.end());
   }
 
-  // =================== check remove files again, remove the whole dir this time ===================
+  // =================== check remove files again, remove the whole dir this time
+  // ===================
   // before remove check
   for (int i = 0; i < 5; i++) {
     string filename = boost::lexical_cast<string>(i);
     BOOST_CHECK(files.find("sub1/sub2/" + filename) != files.end());
   }
   fs::remove_all(subdir1);
-  usleep(1100000);
+  this->advanceClocks(std::chrono::seconds(2));
   BOOST_CHECK_EQUAL(files.size(), 4);
   // test.txt
   // sub/7..9
@@ -169,7 +218,7 @@
     string filename = boost::lexical_cast<string>(i);
     fs::rename(subdir / filename.c_str(), dir / filename.c_str());
   }
-  usleep(1100000);
+  this->advanceClocks(std::chrono::seconds(2));
   // test.txt
   // 7
   // 8
@@ -183,33 +232,36 @@
   }
 
   create_file(dir / "add-removal-check.txt", "add-removal-check");
-  usleep(1200000);
+  this->advanceClocks(std::chrono::seconds(2));
   BOOST_CHECK(files.find("add-removal-check.txt") != files.end());
 
   fs::remove(dir / "add-removal-check.txt");
-  usleep(1200000);
+  this->advanceClocks(std::chrono::seconds(2));
   BOOST_CHECK(files.find("add-removal-check.txt") == files.end());
 
   create_file(dir / "add-removal-check.txt", "add-removal-check");
-  usleep(1200000);
+  this->advanceClocks(std::chrono::seconds(2));
   BOOST_CHECK(files.find("add-removal-check.txt") != files.end());
 
   fs::remove(dir / "add-removal-check.txt");
-  usleep(1200000);
+  this->advanceClocks(std::chrono::seconds(2));
   BOOST_CHECK(files.find("add-removal-check.txt") == files.end());
 
   create_file(dir / "add-removal-check.txt", "add-removal-check");
-  usleep(1200000);
+  this->advanceClocks(std::chrono::seconds(2));
   BOOST_CHECK(files.find("add-removal-check.txt") != files.end());
 
   fs::remove(dir / "add-removal-check.txt");
-  usleep(1200000);
+  this->advanceClocks(std::chrono::seconds(2));
   BOOST_CHECK(files.find("add-removal-check.txt") == files.end());
 
-  // cleanup
-  if (fs::exists(dir)) {
-    fs::remove_all(dir);
-  }
+  emit app->stopApp();
+
+  workThread.join();
 }
 
 BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace tests
+} // namespace chronoshare
+} // namespace ndn
diff --git a/tests/integrated-tests/fs-watcher.t.hpp b/tests/integrated-tests/fs-watcher.t.hpp
new file mode 100644
index 0000000..40c524b
--- /dev/null
+++ b/tests/integrated-tests/fs-watcher.t.hpp
@@ -0,0 +1,42 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2017, Regents of the University of California.
+ *
+ * This file is part of ChronoShare, a decentralized file sharing application over NDN.
+ *
+ * ChronoShare 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 of the License, or (at your option) any later version.
+ *
+ * ChronoShare 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 copies of the GNU General Public License along with
+ * ChronoShare, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ChronoShare authors and contributors.
+ */
+
+#include <QtWidgets>
+
+namespace ndn {
+namespace chronoshare {
+namespace tests {
+
+class fsWatcherApp : public QCoreApplication
+{
+Q_OBJECT
+
+signals:
+  void
+  stopApp();
+
+public:
+  fsWatcherApp(int& argc, char** argv);
+  ~fsWatcherApp();
+};
+
+} // namespace tests
+} // namespace chronoshare
+} // namespace ndn
diff --git a/tests/unit-tests/fs-watcher-delay.t.cpp b/tests/unit-tests/fs-watcher-delay.t.cpp
deleted file mode 100644
index 0ccd5cc..0000000
--- a/tests/unit-tests/fs-watcher-delay.t.cpp
+++ /dev/null
@@ -1,102 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2013-2016, Regents of the University of California.
- *
- * This file is part of ChronoShare, a decentralized file sharing application over NDN.
- *
- * ChronoShare 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 of the License, or (at your option) any later version.
- *
- * ChronoShare 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 copies of the GNU General Public License along with
- * ChronoShare, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
- *
- * See AUTHORS.md for complete list of ChronoShare authors and contributors.
- */
-
-#include "fs-watcher.h"
-#include <boost/bind.hpp>
-#include <boost/filesystem.hpp>
-#include <boost/filesystem/fstream.hpp>
-#include <boost/lexical_cast.hpp>
-#include <boost/make_shared.hpp>
-#include <boost/test/unit_test.hpp>
-#include <boost/thread/thread.hpp>
-#include <QtGui>
-#include <fstream>
-#include <iostream>
-#include <set>
-
-using namespace std;
-using namespace boost;
-namespace fs = boost::filesystem;
-
-BOOST_AUTO_TEST_SUITE(TestFsWatcherDelay)
-
-void
-onChange(const fs::path& file)
-{
-  cerr << "onChange called" << endl;
-}
-
-void
-onDelete(const fs::path& file)
-{
-  cerr << "onDelete called" << endl;
-}
-
-void
-run(fs::path dir, FsWatcher::LocalFile_Change_Callback c, FsWatcher::LocalFile_Change_Callback d)
-{
-  int x = 0;
-  QCoreApplication app(x, 0);
-  FsWatcher watcher(dir.string().c_str(), c, d);
-  app.exec();
-  sleep(100);
-}
-
-void
-SlowWrite(fs::path& file)
-{
-  fs::ofstream off(file, std::ios::out);
-
-  for (int i = 0; i < 10; i++) {
-    off << i << endl;
-    usleep(200000);
-  }
-}
-
-BOOST_AUTO_TEST_CASE(TestFsWatcherDelay)
-{
-  fs::path dir = fs::absolute(fs::path("TestFsWatcher"));
-  if (fs::exists(dir)) {
-    fs::remove_all(dir);
-  }
-
-  fs::create_directory(dir);
-
-  FsWatcher::LocalFile_Change_Callback fileChange = boost::bind(onChange, _1);
-  FsWatcher::LocalFile_Change_Callback fileDelete = boost::bind(onDelete, _1);
-
-  fs::path file = dir / "test.text";
-
-  thread watcherThread(run, dir, fileChange, fileDelete);
-
-  thread writeThread(SlowWrite, file);
-
-
-  usleep(10000000);
-
-  // cleanup
-  if (fs::exists(dir)) {
-    fs::remove_all(dir);
-  }
-
-  usleep(1000000);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/tests/wscript b/tests/wscript
index 3cb795b..e900761 100644
--- a/tests/wscript
+++ b/tests/wscript
@@ -8,32 +8,32 @@
     if not bld.env['WITH_TESTS']:
         return
 
-    Logs.error("Many unit tests are temporary disabled")
-
     bld(features='cxx',
-        target='unit-tests-main',
-        name='unit-tests-main',
-        source='main.cpp',
-        use='BOOST',
+        target='tests-base',
+        name='tests-base',
+        source=bld.path.ant_glob(['*.cpp'], excl='main.cpp'),
+        use='core-objects',
         includes='.. .',
-        defines=['BOOST_TEST_MODULE=ChronoShare Unit Tests'])
+        defines='UNIT_TEST_CONFIG_PATH=\"%s/tmp-files/\"' % (bld.bldnode)
+      )
 
-    unit_tests = bld.program(
-            target='../unit-tests',
-            features='cxx cxxprogram',
-            source=bld.path.ant_glob(['*.cpp',
-                                      'unit-tests/dummy-forwarder.cpp',
-                                      'unit-tests/sync-*.t.cpp',
-                                      'unit-tests/action-log.t.cpp',
-                                      'unit-tests/object-*.t.cpp',
-                                      'unit-tests/fetch*.t.cpp',
-                                      'unit-tests/serve-and-fetch.t.cpp',
-                                      'unit-tests/content-server.t.cpp',
-                                      'unit-tests/dispatcher.t.cpp',
-                                      ],
-                                     excl=['main.cpp']),
-            use='chronoshare core-objects unit-tests-main',
+    for module, name in {"unit": "Unit Tests",
+                         "integrated": "Integrated Tests"}.items():
+        bld(target='%s-tests-main' % module,
+            name='%s-tests-main' % module,
+            features='cxx',
+            use='core-objects BOOST',
+            source='main.cpp',
+            defines=['BOOST_TEST_MODULE=%s' % name]
+        )
+
+        tests = bld.program(
+            target='../%s-tests' % module,
+            features='qt5 cxx cxxprogram',
+            moc='' if module == 'unit' else 'integrated-tests/fs-watcher.t.hpp',
+            source=bld.path.ant_glob(['%s-tests/*.cpp' % module]),
+            use='chronoshare core-objects fs-watcher tests-base %s-tests-main QT5CORE QT5WIDGETS' % module,
             install_path=None,
-            defines='UNIT_TEST_CONFIG_PATH=\"%s/tmp-files/\"' % (bld.bldnode),
+            defines=['UNIT_TEST_CONFIG_PATH=\"%s/tmp-files/\"' % (bld.bldnode)],
             includes='.. ../src .',
-          )
+        )