Fix generator consistency checker (#559)
authorEfimov Alexander/AI Tools Lab/./Samsung Electronics <a.efimov@samsung.com>
Tue, 10 Jul 2018 16:15:27 +0000 (19:15 +0300)
committerSergey Vostokov/AI Tools Lab /SRR/Staff Engineer/삼성전자 <s.vostokov@samsung.com>
Tue, 10 Jul 2018 16:15:27 +0000 (01:15 +0900)
Fix generator consistency checker

Fix argument checker in generator and add tests for it

Signed-off-by: Efimov Alexander <a.efimov@samsung.com>
contrib/nnc/libs/backend/soft/CMakeLists.txt
contrib/nnc/libs/backend/soft/src/generator.cpp
contrib/nnc/libs/backend/soft/src/generator.test.cpp [new file with mode: 0644]

index 4ddad1f..67cf563 100644 (file)
@@ -1,6 +1,13 @@
-file(GLOB_RECURSE LANG_BACKEND_SOURCES src/*.cpp)
+file(GLOB_RECURSE SOFT_BACKEND_SOURCES src/*.cpp)
+file(GLOB_RECURSE HEADERS "include/*.h")
+file(GLOB_RECURSE TESTS "src/*.test.cpp")
+list(REMOVE_ITEM SOFT_BACKEND_SOURCES ${TESTS})
 
-add_library(soft_backend SHARED ${LANG_BACKEND_SOURCES})
+add_library(soft_backend SHARED ${SOFT_BACKEND_SOURCES})
+
+add_nncc_test(soft_backend_test ${TESTS})
+nncc_target_link_libraries(soft_backend_test nncc_core nnc_core nnc_plugin_core nncc_foundation soft_backend)
+target_include_directories(soft_backend_test PUBLIC include)
 
 target_link_libraries(soft_backend PRIVATE nncc_core)
 
index 2890d54..12dc0b0 100644 (file)
@@ -36,7 +36,26 @@ bool fillFileStats(const string &path, struct stat &s)
   if (path.empty())
     return false;
   if (stat(path.c_str(), &s))
-    throw PluginException("Can not get info for file: " + path);
+  {
+    if (errno == ENOENT)
+    {
+      // file not found, try to create it
+      ofstream f(path);
+      if (!f.good())
+        throw PluginException("Can not create output file: " + path);
+      // try again
+      int res = stat(path.c_str(), &s);
+      (void) res;
+      // on this step everythink should be fine, since we just created file
+      assert(!res);
+      return true;
+    }
+    else
+      throw PluginException("Can not get info for file: " + path);
+  }
+  // check that selected file is regular or char device(to accept /dev/null, and simular)
+  if (!(s.st_mode & (S_IFREG | S_IFCHR)))
+    throw PluginException("Not a regular file: " + path);
   return true;
 }
 
@@ -53,13 +72,13 @@ void BaseCodeGenerator::checkCorrectness()
   // check that header, code and model file paths refers to different files.
   // Exception: stdout could be common output stream
   struct stat headerStat, codeStat, modelStat;
-  bool skipHeader = fillFileStats(_headerFile, headerStat);
-  bool skipCode = fillFileStats(_codeFile, codeStat);
-  bool skipModel = fillFileStats(_modelFile, modelStat);
+  bool checkHeader = fillFileStats(_headerFile, headerStat);
+  bool checkCode = fillFileStats(_codeFile, codeStat);
+  bool checkModel = fillFileStats(_modelFile, modelStat);
 
-  if ((!skipHeader && !skipCode && areFilesEqual(headerStat, codeStat)) ||
-      (!skipHeader && !skipModel && areFilesEqual(headerStat, modelStat)) ||
-      (!skipCode && !skipModel && areFilesEqual(codeStat, modelStat)))
+  if ((checkHeader && checkCode && areFilesEqual(headerStat, codeStat)) ||
+      (checkHeader && checkModel && areFilesEqual(headerStat, modelStat)) ||
+      (checkCode && checkModel && areFilesEqual(codeStat, modelStat)))
   {
     throw PluginException("output files should not be equal");
   }
diff --git a/contrib/nnc/libs/backend/soft/src/generator.test.cpp b/contrib/nnc/libs/backend/soft/src/generator.test.cpp
new file mode 100644 (file)
index 0000000..ba5c546
--- /dev/null
@@ -0,0 +1,95 @@
+#include "generator.h"
+#include "PluginException.h"
+
+#include <gtest/gtest.h>
+
+#include <fstream>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <cstdio>
+
+using namespace std;
+using namespace nncc::contrib;
+using namespace nncc::contrib::backend::soft;
+
+static bool isFileExists(const string &path)
+{
+  ifstream f(path);
+  return f.good();
+}
+
+static void createFile(const string &path)
+{
+  assert(!isFileExists(path));
+  ofstream f(path);
+  assert(f.good());
+  f << "hello world\n";
+}
+
+static void createDir(const string &path)
+{
+  int res = mkdir(path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
+  assert(!res);
+}
+
+static void deleteFile(const string &path)
+{
+  int res = remove(path.c_str());
+  assert(!res && "failed to remove file");
+}
+
+static void deleteDir(const string &path)
+{
+  int res = rmdir(path.c_str());
+  assert(!res && "failed to remove dir");
+}
+
+TEST(Generator, check_path_consistency)
+{
+  // assume here that c++ and c code generators behave identically in terms of parameters check
+  // test only c++ generator
+  const char *TEST_FILE1 = "test_file1";
+  const char *TEST_FILE2 = "test_file2";
+  const char *TEST_DIR = "test_dir";
+
+  // iterate this arrays to check that all arguments are working equally
+  const char *fileNames1[] = {"", "" , TEST_FILE1, "", ""};
+  const char *fileNames2[] = {TEST_FILE1, TEST_FILE1, "", TEST_FILE1, TEST_FILE1};
+  const char *fileNames3[] = {TEST_FILE1, TEST_FILE2, "", TEST_FILE1, TEST_FILE2};
+  const char *dirNames[] = {"", "" , TEST_DIR, "", ""};
+
+  assert(!isFileExists(TEST_DIR) && "remove test_dir");
+  assert(!isFileExists(TEST_FILE2) && "remove test_file2");
+  createDir(TEST_DIR);
+  for (int i = 0; i < 3; ++i)
+  {
+    // check that test file is created
+    assert(!isFileExists(TEST_FILE1) && "remove test_file1");
+    CPPCodeGenerator::create(fileNames1[i], fileNames1[i + 1], fileNames1[i + 2]);
+    ASSERT_TRUE(isFileExists(TEST_FILE1));
+    // file already exists
+    struct stat s1;
+    int res = stat(TEST_FILE1, &s1);
+    assert(!res);
+    CPPCodeGenerator::create(fileNames1[i], fileNames1[i + 1], fileNames1[i + 2]);
+    struct stat s2;
+    res = stat(TEST_FILE1, &s2);
+    assert(!res);
+    deleteFile(TEST_FILE1);
+    // check that file is not changed at this point
+    ASSERT_EQ(s1.st_ino, s2.st_ino);
+    ASSERT_EQ(s1.st_size, s2.st_size);
+    // check that dir is not valid output
+    EXPECT_THROW(CPPCodeGenerator::create(dirNames[i], dirNames[i + 1], dirNames[i + 2]), PluginException);
+    // check that equal files are not permitted
+    EXPECT_THROW(CPPCodeGenerator::create(fileNames2[i], fileNames2[i + 1], fileNames2[i + 2]), PluginException);
+    // check that different files are ok
+    CPPCodeGenerator::create(fileNames3[i], fileNames3[i + 1], fileNames3[i + 2]);
+    deleteFile(TEST_FILE1);
+  }
+  deleteDir(TEST_DIR);
+  deleteFile(TEST_FILE2);
+}
+