[Props] Add Name validator and unittest
authorJihoon Lee <jhoon.it.lee@samsung.com>
Fri, 14 May 2021 09:13:14 +0000 (18:13 +0900)
committerJijoong Moon <jijoong.moon@samsung.com>
Mon, 24 May 2021 10:01:43 +0000 (19:01 +0900)
**Changes proposed in this PR:**
- Add name validator
- Add source file for `common_properties`
- Change name of `unittest_properties.cpp` ->
`unittest_base_properties.cpp`
- Add `unittest_common_properties.cpp`

**Self evaluation:**
1. Build test: [X]Passed [ ]Failed [ ]Skipped
2. Run test: [X]Passed [ ]Failed [ ]Skipped

Signed-off-by: Jihoon Lee <jhoon.it.lee@samsung.com>
jni/Android.mk
nntrainer/layers/common_properties.cpp [new file with mode: 0644]
nntrainer/layers/common_properties.h
nntrainer/layers/meson.build
test/unittest/meson.build
test/unittest/unittest_base_properties.cpp [new file with mode: 0644]
test/unittest/unittest_common_properties.cpp [new file with mode: 0644]
test/unittest/unittest_properties.cpp [deleted file]

index 59a710c00f416b4e8d85cd7b3d199376278676a5..3f5ef9f03f61a2d725911c055e4b880e789a1bc0 100644 (file)
@@ -122,6 +122,7 @@ NNTRAINER_SRCS := $(NNTRAINER_ROOT)/nntrainer/models/neuralnet.cpp \
                   $(NNTRAINER_ROOT)/nntrainer/layers/lstm.cpp \
                   $(NNTRAINER_ROOT)/nntrainer/layers/time_dist.cpp \
                   $(NNTRAINER_ROOT)/nntrainer/layers/acti_func.cpp \
+                  $(NNTRAINER_ROOT)/nntrainer/layers/common_properties.cpp \
                   $(NNTRAINER_ROOT)/nntrainer/graph/network_graph.cpp \
                   $(NNTRAINER_ROOT)/nntrainer/optimizers/optimizer_devel.cpp \
                   $(NNTRAINER_ROOT)/nntrainer/optimizers/optimizer_impl.cpp \
diff --git a/nntrainer/layers/common_properties.cpp b/nntrainer/layers/common_properties.cpp
new file mode 100644 (file)
index 0000000..d0b8369
--- /dev/null
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: Apache-2.0
+/**
+ * Copyright (C) 2021 Jihoon Lee <jhoon.it.lee@samsung.com>
+ *
+ * @file   common_properties.cpp
+ * @date   14 May 2021
+ * @brief  This file contains implementation of common properties widely used
+ * across layers
+ * @see           https://github.com/nnstreamer/nntrainer
+ * @author Jihoon Lee <jhoon.it.lee@samsung.com>
+ * @bug    No known bugs except for NYI items
+ */
+#include <common_properties.h>
+
+#include <nntrainer_error.h>
+#include <parse_util.h>
+
+#include <regex>
+#include <vector>
+
+namespace nntrainer {
+namespace props {
+bool Name::isValid(const std::string &v) const {
+
+  static std::regex allowed("[a-zA-Z0-9][-_./a-zA-Z0-9]*");
+  return std::regex_match(v, allowed);
+}
+
+} // namespace props
+
+} // namespace nntrainer
index 220a7cd53884924fb72189831d6ca16239307302..9146c5231c96e35a5113334d358c52c25c723d5b 100644 (file)
@@ -2,12 +2,13 @@
 /**
  * Copyright (C) 2021 Jihoon Lee <jhoon.it.lee@samsung.com>
  *
- * @file common_properties.h
- * @date 09 April 2021
- * @brief This file contains list of common properties widely used across layers
- * @see        https://github.com/nnstreamer/nntrainer
+ * @file   common_properties.h
+ * @date   09 April 2021
+ * @brief  This file contains list of common properties widely used across
+ * layers
+ * @see           https://github.com/nnstreamer/nntrainer
  * @author Jihoon Lee <jhoon.it.lee@samsung.com>
- * @bug No known bugs except for NYI items
+ * @bug    No known bugs except for NYI items
  */
 
 #include <string>
@@ -30,6 +31,15 @@ public:
     nntrainer::Property<std::string>(value) {} /**< default value if any */
   static constexpr const char *key = "name";   /**< unique key to access */
   using prop_tag = str_prop_tag;               /**< property type */
+
+  /**
+   * @brief name validator
+   *
+   * @param v string to validate
+   * @return true if it contains alphanumeric and/or '-', '_', '/'
+   * @return false if it is empty or contains non-valid character
+   */
+  bool isValid(const std::string &v) const override;
 };
 
 /**
index 21416f49ed18c633e54354aa23c4cc253eb9d69d..30397054483261ba3335ec7be6abb70532cde3bc 100644 (file)
@@ -20,7 +20,8 @@ layer_sources = [
   'rnn.cpp',
   'acti_func.cpp',
   'lstm.cpp',
-  'time_dist.cpp'
+  'time_dist.cpp',
+  'common_properties.cpp'
 ]
 
 layer_headers = [
index b476c461b28c15b394c42051349f25fe8834bea8..e7f426a78c2a45b739fc3373f5c15bec5686b2d7 100644 (file)
@@ -35,7 +35,8 @@ test_target = [
   'unittest_nntrainer_models',
   'unittest_nntrainer_graph',
   'unittest_nntrainer_appcontext',
-  'unittest_properties',
+  'unittest_base_properties',
+  'unittest_common_properties'
 ]
 
 if get_option('enable-profile')
diff --git a/test/unittest/unittest_base_properties.cpp b/test/unittest/unittest_base_properties.cpp
new file mode 100644 (file)
index 0000000..1d565ed
--- /dev/null
@@ -0,0 +1,354 @@
+// SPDX-License-Identifier: Apache-2.0
+/**
+ * Copyright (C) 2021 Jihoon Lee <jhoon.it.lee@samsung.com>
+ *
+ * @file unittest_base_properties.h
+ * @date 09 April 2021
+ * @brief This file contains test and specification of properties and exporter
+ * @see        https://github.com/nnstreamer/nntrainer
+ * @author Jihoon Lee <jhoon.it.lee@samsung.com>
+ * @bug No known bugs except for NYI items
+ */
+#include <gtest/gtest.h>
+
+#include <array>
+#include <utility>
+#include <vector>
+
+#include <base_properties.h>
+#include <fc_layer.h>
+#include <nntrainer_error.h>
+#include <node_exporter.h>
+#include <util_func.h>
+
+namespace { /**< define a property for testing */
+
+/**
+ * @brief banana property tag for example
+ *
+ */
+struct banana_prop_tag : nntrainer::int_prop_tag {};
+
+/**
+ * @brief Number of banana property
+ *
+ */
+class NumBanana : public nntrainer::Property<int> {
+public:
+  NumBanana(int num = 1) : Property<int>(num) {}   /**< default value if any */
+  static constexpr const char *key = "num_banana"; /**< unique key to access */
+  using prop_tag = banana_prop_tag;                /**< property type */
+
+  bool isValid(const int &v) const override { return v >= 0; }
+};
+
+/**
+ * @brief QualityOfBanana property for example, this has to end with "good"
+ *
+ */
+class QualityOfBanana : public nntrainer::Property<std::string> {
+public:
+  QualityOfBanana(const char *value = "") : Property<std::string>(value) {}
+  static constexpr const char *key = "quality_banana";
+  using prop_tag = nntrainer::str_prop_tag;
+
+  bool isValid(const std::string &v) const override {
+    /// assuming quality of banana property must ends with word "good";
+    return nntrainer::endswith(v, "good");
+  }
+};
+
+/**
+ * @brief DimensionOfBanana property for example, this has to have batch size of
+ * 1
+ *
+ */
+class DimensionOfBanana : public nntrainer::Property<nntrainer::TensorDim> {
+public:
+  static constexpr const char *key = "banana_size";
+  using prop_tag = nntrainer::dimension_prop_tag;
+
+  bool isValid(const nntrainer::TensorDim &dim) const override {
+    std::cerr << dim;
+    return dim.batch() == 1;
+  }
+};
+} // namespace
+
+TEST(BasicProperty, tagCast) {
+  EXPECT_EQ(1, 1); /**< this is to prevent no assert tc from TCM */
+
+  { /**< tag_cast simple cast */
+    using T =
+      nntrainer::tag_cast<banana_prop_tag, nntrainer::int_prop_tag>::type;
+    ::testing::StaticAssertTypeEq<T, nntrainer::int_prop_tag>();
+  }
+
+  { /**< tag_cast ranged cast */
+    using T = nntrainer::tag_cast<banana_prop_tag, nntrainer::float_prop_tag,
+                                  nntrainer::int_prop_tag>::type;
+    ::testing::StaticAssertTypeEq<T, nntrainer::int_prop_tag>();
+  }
+
+  { /**< tag_cast does not have appropriate candidates */
+    using T = nntrainer::tag_cast<banana_prop_tag, int, std::string>::type;
+    ::testing::StaticAssertTypeEq<T, banana_prop_tag>();
+  }
+}
+
+/// @todo convert this to typed param test
+TEST(BasicProperty, valid_p) {
+  { /** set -> get / to_string, int*/
+    NumBanana b;
+    b.set(123);
+    int ib = b;
+    EXPECT_EQ(ib, 123);
+    EXPECT_EQ(b.get(), 123);
+    EXPECT_EQ(nntrainer::to_string(b), "123");
+  }
+
+  { /**< from_string -> get / to_string, int*/
+    NumBanana b;
+    nntrainer::from_string("3", b);
+    EXPECT_EQ(b.get(), 3);
+    EXPECT_EQ(nntrainer::to_string(b), "3");
+  }
+
+  { /** set -> get / to_string, string*/
+    QualityOfBanana q;
+    q.set("this is good");
+    std::string sq = q;
+    EXPECT_EQ(sq, "this is good");
+    EXPECT_EQ(q.get(), "this is good");
+    EXPECT_EQ(nntrainer::to_string(q), "this is good");
+  }
+
+  { /**< from_string -> get / to_string, string prop */
+    QualityOfBanana q;
+    nntrainer::from_string("this is good", q);
+    EXPECT_EQ(q.get(), "this is good");
+    EXPECT_EQ(nntrainer::to_string(q), "this is good");
+  }
+
+  { /** set -> get / to_string, dimension*/
+    DimensionOfBanana q;
+    q.set({1, 2, 3, 4});
+    EXPECT_EQ(q.get(), nntrainer::TensorDim(1, 2, 3, 4));
+    EXPECT_EQ(nntrainer::to_string(q), "1:2:3:4");
+  }
+
+  { /**< from_string -> get / to_string, dimension */
+    DimensionOfBanana q;
+    nntrainer::from_string("1:2:3:4", q);
+    EXPECT_EQ(q.get(), nntrainer::TensorDim(1, 2, 3, 4));
+    EXPECT_EQ(nntrainer::to_string(q), "1:2:3:4");
+  }
+
+  { /**< from_string -> get / to_string, dimension */
+    DimensionOfBanana q;
+    nntrainer::from_string("3:4", q);
+    EXPECT_EQ(q.get(), nntrainer::TensorDim(1, 1, 3, 4));
+    EXPECT_EQ(nntrainer::to_string(q), "1:1:3:4");
+  }
+
+  { /**< from_string -> get / to_string, uint vector prop */
+    std::vector<NumBanana> bananas;
+    EXPECT_EQ(nntrainer::getPropKey(bananas), "num_banana");
+    nntrainer::from_string("1, 2,3, 4, 5", bananas);
+    auto expected = std::vector<NumBanana>({1, 2, 3, 4, 5});
+    EXPECT_EQ(bananas, expected);
+    EXPECT_EQ(nntrainer::to_string(bananas), "1,2,3,4,5");
+  }
+
+  { /**< from_string -> get / to_string, uint array prop */
+    std::array<NumBanana, 4> bananas;
+    EXPECT_EQ(nntrainer::getPropKey(bananas), "num_banana");
+    nntrainer::from_string("1, 2,3, 4", bananas);
+    auto expected = std::array<NumBanana, 4>({1, 2, 3, 4});
+    EXPECT_EQ(bananas, expected);
+    EXPECT_EQ(nntrainer::to_string(bananas), "1,2,3,4");
+  }
+
+  { /**< exporter test */
+    auto props = std::make_tuple(NumBanana(), QualityOfBanana());
+
+    nntrainer::Exporter e;
+    e.save_result(props, nntrainer::ExportMethods::METHOD_STRINGVECTOR);
+
+    auto result = e.get_result<nntrainer::ExportMethods::METHOD_STRINGVECTOR>();
+
+    auto pair = std::pair<std::string, std::string>("num_banana", "1");
+    EXPECT_EQ(result[0], pair);
+
+    auto pair2 = std::pair<std::string, std::string>("quality_banana", "");
+    EXPECT_EQ(result[1], pair2);
+  }
+
+  { /**< export from layer */
+    auto layer = nntrainer::FullyConnectedLayer(1);
+    nntrainer::Exporter e;
+    layer.export_to(e);
+
+    auto result = e.get_result<nntrainer::ExportMethods::METHOD_STRINGVECTOR>();
+    auto pair0 = std::pair<std::string, std::string>("name", "");
+    EXPECT_EQ(result[0], pair0);
+    auto pair1 = std::pair<std::string, std::string>("unit", "1");
+    EXPECT_EQ(result[1], pair1);
+  }
+
+  { /**< load from layer */
+    auto props =
+      std::make_tuple(NumBanana(), QualityOfBanana(), DimensionOfBanana());
+
+    auto v = nntrainer::loadProperties(
+      {"num_banana=2", "quality_banana=thisisgood", "num_banana=42",
+       "banana_size=2:2:3", "not_used=key"},
+      props);
+
+    EXPECT_EQ(v, std::vector<std::string>{"not_used=key"});
+    EXPECT_EQ(std::get<0>(props).get(), 42);
+    EXPECT_EQ(std::get<1>(props).get(), "thisisgood");
+  }
+
+  { /**< load from layer */
+    std::tuple<std::array<NumBanana, 4>, std::vector<QualityOfBanana>> props;
+
+    auto v = nntrainer::loadProperties(
+      {"num_banana=1,2, 3 ,4", "quality_banana=thisisgood, thisisverygood",
+       "not_used=key"},
+      props);
+
+    EXPECT_EQ(v, std::vector<std::string>{"not_used=key"});
+    auto expected = std::array<NumBanana, 4>({1, 2, 3, 4});
+    EXPECT_EQ(std::get<0>(props), expected);
+    auto expected2 =
+      std::vector<QualityOfBanana>({"thisisgood", "thisisverygood"});
+    EXPECT_EQ(std::get<1>(props), expected2);
+  }
+}
+
+TEST(BasicProperty, setNotValid_01_n) {
+  NumBanana b;
+  EXPECT_THROW(b.set(-1), std::invalid_argument);
+}
+
+TEST(BasicProperty, setNotValid_02_n) {
+  QualityOfBanana q;
+  EXPECT_THROW(q.set("invalid_str"), std::invalid_argument);
+}
+
+TEST(BasicProperty, setNotValid_03_n) {
+  DimensionOfBanana d;
+  EXPECT_THROW(d.set({3, 3, 2, 4}), std::invalid_argument);
+}
+
+TEST(BasicProperty, fromStringNotValid_01_n) {
+  NumBanana b;
+  EXPECT_THROW(nntrainer::from_string("not integer", b), std::invalid_argument);
+}
+
+TEST(BasicProperty, fromStringNotValid_02_n) {
+  NumBanana b;
+  EXPECT_THROW(nntrainer::from_string("-1", b), std::invalid_argument);
+}
+
+TEST(BasicProperty, fromStringNotValid_03_n) {
+  QualityOfBanana q;
+  EXPECT_THROW(nntrainer::from_string("invalid_str", q), std::invalid_argument);
+}
+
+TEST(BasicProperty, fromStringNotValid_04_n) {
+  DimensionOfBanana d;
+  EXPECT_THROW(nntrainer::from_string("1:1:2:3:5", d), std::invalid_argument);
+}
+
+TEST(BasicProperty, fromStringNotValid_05_n) {
+  DimensionOfBanana d;
+  EXPECT_THROW(nntrainer::from_string("2:2:3:5", d), std::invalid_argument);
+}
+
+TEST(BasicProperty, fromStringNotValid_06_n) {
+  DimensionOfBanana d;
+  EXPECT_THROW(nntrainer::from_string("", d), std::invalid_argument);
+}
+
+TEST(BasicProperty, fromStringNotValid_07_n) {
+  DimensionOfBanana d;
+  EXPECT_THROW(nntrainer::from_string(":2:3:5", d), std::invalid_argument);
+}
+
+TEST(BasicProperty, fromStringVectorElementContainNotValidString_n) {
+  std::vector<NumBanana> bs;
+  EXPECT_THROW(nntrainer::from_string("1, 2, 3, not_valid", bs),
+               std::invalid_argument);
+}
+
+TEST(BasicProperty, fromStringVectorElementContainNotValidProp_n) {
+  std::vector<NumBanana> bs;
+  EXPECT_THROW(nntrainer::from_string("1, 2, 3, -1", bs),
+               std::invalid_argument);
+}
+
+TEST(BasicProperty, fromStringLessArrayElementSize_n) {
+  std::array<NumBanana, 4> bs;
+  EXPECT_THROW(nntrainer::from_string("1, 2, 3", bs), std::invalid_argument);
+}
+
+TEST(BasicProperty, fromStringOverArrayElementSize_n) {
+  std::array<NumBanana, 4> bs;
+  EXPECT_THROW(nntrainer::from_string("1, 2, 3,4,5", bs),
+               std::invalid_argument);
+}
+
+TEST(BasicProperty, fromStringArrayNotValidString_n) {
+  std::array<NumBanana, 4> bs;
+  EXPECT_THROW(nntrainer::from_string("1, 2, invalid, 4", bs),
+               std::invalid_argument);
+}
+
+TEST(BasicProperty, fromStringArrayNotValidProp_n) {
+  std::array<NumBanana, 4> bs;
+  EXPECT_THROW(nntrainer::from_string("1, 2, -1, 4", bs),
+               std::invalid_argument);
+}
+
+TEST(Exporter, invalidMethods_n) {
+  auto props = std::make_tuple(NumBanana(), QualityOfBanana());
+
+  nntrainer::Exporter e;
+  EXPECT_THROW(e.save_result(props, nntrainer::ExportMethods::METHOD_UNDEFINED),
+               nntrainer::exception::not_supported);
+}
+
+TEST(Exporter, notExported_n) {
+  auto props = std::make_tuple(NumBanana(), QualityOfBanana());
+
+  nntrainer::Exporter e;
+  /// intended comment
+  // e.save_result(props, nntrainer::ExportMethods::METHOD_STRINGVECTOR);
+
+  EXPECT_THROW(e.get_result<nntrainer::ExportMethods::METHOD_STRINGVECTOR>(),
+               std::invalid_argument);
+}
+
+/**
+ * @brief Main gtest
+ */
+int main(int argc, char **argv) {
+  int result = -1;
+
+  try {
+    testing::InitGoogleTest(&argc, argv);
+  } catch (...) {
+    std::cerr << "Error duing IniGoogleTest" << std::endl;
+    return 0;
+  }
+
+  try {
+    result = RUN_ALL_TESTS();
+  } catch (...) {
+    std::cerr << "Error duing RUN_ALL_TESTS()" << std::endl;
+  }
+
+  return result;
+}
diff --git a/test/unittest/unittest_common_properties.cpp b/test/unittest/unittest_common_properties.cpp
new file mode 100644 (file)
index 0000000..170c2d9
--- /dev/null
@@ -0,0 +1,121 @@
+// SPDX-License-Identifier: Apache-2.0
+/**
+ * Copyright (C) 2021 Jihoon Lee <jhoon.it.lee@samsung.com>
+ *
+ * @file unittest_common_properties.h
+ * @date 15 May 2021
+ * @brief This file contains test and specification of properties and exporter
+ * @see        https://github.com/nnstreamer/nntrainer
+ * @author Jihoon Lee <jhoon.it.lee@samsung.com>
+ * @bug No known bugs except for NYI items
+ */
+#include <gtest/gtest.h>
+
+#include <common_properties.h>
+
+/// @todo change this to typed param test
+/// <type, list of string, value pair, list of invalid string, value pair>
+TEST(NameProperty, setPropertyValid_p) {
+  nntrainer::props::Name n;
+  EXPECT_NO_THROW(n.set("layer"));
+  EXPECT_EQ(n.get(), "layer");
+
+  EXPECT_NO_THROW(n.set("layer-"));
+  EXPECT_EQ(n.get(), "layer-");
+
+  EXPECT_NO_THROW(n.set("laye-r"));
+  EXPECT_EQ(n.get(), "laye-r");
+
+  EXPECT_NO_THROW(n.set("layer/a"));
+  EXPECT_EQ(n.get(), "layer/a");
+
+  EXPECT_NO_THROW(n.set("laye__r"));
+  EXPECT_EQ(n.get(), "laye__r");
+}
+
+TEST(NameProperty, forbiddenString_01_n) {
+  nntrainer::props::Name n;
+  EXPECT_THROW(n.set("layer "), std::invalid_argument);
+}
+
+TEST(NameProperty, forbiddenString_02_n) {
+  nntrainer::props::Name n;
+  EXPECT_THROW(n.set("layer layer"), std::invalid_argument);
+}
+
+TEST(NameProperty, forbiddenString_03_n) {
+  nntrainer::props::Name n;
+  EXPECT_THROW(n.set(" layer"), std::invalid_argument);
+}
+
+TEST(NameProperty, forbiddenString_04_n) {
+  nntrainer::props::Name n;
+  EXPECT_THROW(n.set("layer,"), std::invalid_argument);
+}
+
+TEST(NameProperty, forbiddenString_05_n) {
+  nntrainer::props::Name n;
+  EXPECT_THROW(n.set("lay,er"), std::invalid_argument);
+}
+
+TEST(NameProperty, forbiddenString_06_n) {
+  nntrainer::props::Name n;
+  EXPECT_THROW(n.set("lay, er"), std::invalid_argument);
+}
+
+TEST(NameProperty, forbiddenString_07_n) {
+  nntrainer::props::Name n;
+  EXPECT_THROW(n.set(",layer"), std::invalid_argument);
+}
+
+TEST(NameProperty, forbiddenString_08_n) {
+  nntrainer::props::Name n;
+  EXPECT_THROW(n.set("layer+"), std::invalid_argument);
+}
+
+TEST(NameProperty, forbiddenString_09_n) {
+  nntrainer::props::Name n;
+  EXPECT_THROW(n.set("la+ yer"), std::invalid_argument);
+}
+
+TEST(NameProperty, forbiddenString_10_n) {
+  nntrainer::props::Name n;
+  EXPECT_THROW(n.set("lay+er"), std::invalid_argument);
+}
+
+TEST(NameProperty, forbiddenString_11_n) {
+  nntrainer::props::Name n;
+  EXPECT_THROW(n.set("+layer"), std::invalid_argument);
+}
+
+TEST(NameProperty, forbiddenString_12_n) {
+  nntrainer::props::Name n;
+  EXPECT_THROW(n.set("+ layer"), std::invalid_argument);
+}
+
+TEST(NameProperty, mustStartWithAlphaNumeric_01_n) {
+  nntrainer::props::Name n;
+  EXPECT_THROW(n.set("+layer"), std::invalid_argument);
+}
+
+/**
+ * @brief Main gtest
+ */
+int main(int argc, char **argv) {
+  int result = -1;
+
+  try {
+    testing::InitGoogleTest(&argc, argv);
+  } catch (...) {
+    std::cerr << "Error duing IniGoogleTest" << std::endl;
+    return 0;
+  }
+
+  try {
+    result = RUN_ALL_TESTS();
+  } catch (...) {
+    std::cerr << "Error duing RUN_ALL_TESTS()" << std::endl;
+  }
+
+  return result;
+}
diff --git a/test/unittest/unittest_properties.cpp b/test/unittest/unittest_properties.cpp
deleted file mode 100644 (file)
index 07f5e2e..0000000
+++ /dev/null
@@ -1,354 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-/**
- * Copyright (C) 2021 Jihoon Lee <jhoon.it.lee@samsung.com>
- *
- * @file unittest_properties.h
- * @date 09 April 2021
- * @brief This file contains test and specification of properties and exporter
- * @see        https://github.com/nnstreamer/nntrainer
- * @author Jihoon Lee <jhoon.it.lee@samsung.com>
- * @bug No known bugs except for NYI items
- */
-#include <gtest/gtest.h>
-
-#include <array>
-#include <utility>
-#include <vector>
-
-#include <base_properties.h>
-#include <fc_layer.h>
-#include <nntrainer_error.h>
-#include <node_exporter.h>
-#include <util_func.h>
-
-namespace { /**< define a property for testing */
-
-/**
- * @brief banana property tag for example
- *
- */
-struct banana_prop_tag : nntrainer::int_prop_tag {};
-
-/**
- * @brief Number of banana property
- *
- */
-class NumBanana : public nntrainer::Property<int> {
-public:
-  NumBanana(int num = 1) : Property<int>(num) {}   /**< default value if any */
-  static constexpr const char *key = "num_banana"; /**< unique key to access */
-  using prop_tag = banana_prop_tag;                /**< property type */
-
-  bool isValid(const int &v) const override { return v >= 0; }
-};
-
-/**
- * @brief QualityOfBanana property for example, this has to end with "good"
- *
- */
-class QualityOfBanana : public nntrainer::Property<std::string> {
-public:
-  QualityOfBanana(const char *value = "") : Property<std::string>(value) {}
-  static constexpr const char *key = "quality_banana";
-  using prop_tag = nntrainer::str_prop_tag;
-
-  bool isValid(const std::string &v) const override {
-    /// assuming quality of banana property must ends with word "good";
-    return nntrainer::endswith(v, "good");
-  }
-};
-
-/**
- * @brief DimensionOfBanana property for example, this has to have batch size of
- * 1
- *
- */
-class DimensionOfBanana : public nntrainer::Property<nntrainer::TensorDim> {
-public:
-  static constexpr const char *key = "banana_size";
-  using prop_tag = nntrainer::dimension_prop_tag;
-
-  bool isValid(const nntrainer::TensorDim &dim) const override {
-    std::cerr << dim;
-    return dim.batch() == 1;
-  }
-};
-} // namespace
-
-TEST(BasicProperty, tagCast) {
-  EXPECT_EQ(1, 1); /**< this is to prevent no assert tc from TCM */
-
-  { /**< tag_cast simple cast */
-    using T =
-      nntrainer::tag_cast<banana_prop_tag, nntrainer::int_prop_tag>::type;
-    ::testing::StaticAssertTypeEq<T, nntrainer::int_prop_tag>();
-  }
-
-  { /**< tag_cast ranged cast */
-    using T = nntrainer::tag_cast<banana_prop_tag, nntrainer::float_prop_tag,
-                                  nntrainer::int_prop_tag>::type;
-    ::testing::StaticAssertTypeEq<T, nntrainer::int_prop_tag>();
-  }
-
-  { /**< tag_cast does not have appropriate candidates */
-    using T = nntrainer::tag_cast<banana_prop_tag, int, std::string>::type;
-    ::testing::StaticAssertTypeEq<T, banana_prop_tag>();
-  }
-}
-
-/// @todo convert this to typed param test
-TEST(BasicProperty, valid_p) {
-  { /** set -> get / to_string, int*/
-    NumBanana b;
-    b.set(123);
-    int ib = b;
-    EXPECT_EQ(ib, 123);
-    EXPECT_EQ(b.get(), 123);
-    EXPECT_EQ(nntrainer::to_string(b), "123");
-  }
-
-  { /**< from_string -> get / to_string, int*/
-    NumBanana b;
-    nntrainer::from_string("3", b);
-    EXPECT_EQ(b.get(), 3);
-    EXPECT_EQ(nntrainer::to_string(b), "3");
-  }
-
-  { /** set -> get / to_string, string*/
-    QualityOfBanana q;
-    q.set("this is good");
-    std::string sq = q;
-    EXPECT_EQ(sq, "this is good");
-    EXPECT_EQ(q.get(), "this is good");
-    EXPECT_EQ(nntrainer::to_string(q), "this is good");
-  }
-
-  { /**< from_string -> get / to_string, string prop */
-    QualityOfBanana q;
-    nntrainer::from_string("this is good", q);
-    EXPECT_EQ(q.get(), "this is good");
-    EXPECT_EQ(nntrainer::to_string(q), "this is good");
-  }
-
-  { /** set -> get / to_string, dimension*/
-    DimensionOfBanana q;
-    q.set({1, 2, 3, 4});
-    EXPECT_EQ(q.get(), nntrainer::TensorDim(1, 2, 3, 4));
-    EXPECT_EQ(nntrainer::to_string(q), "1:2:3:4");
-  }
-
-  { /**< from_string -> get / to_string, dimension */
-    DimensionOfBanana q;
-    nntrainer::from_string("1:2:3:4", q);
-    EXPECT_EQ(q.get(), nntrainer::TensorDim(1, 2, 3, 4));
-    EXPECT_EQ(nntrainer::to_string(q), "1:2:3:4");
-  }
-
-  { /**< from_string -> get / to_string, dimension */
-    DimensionOfBanana q;
-    nntrainer::from_string("3:4", q);
-    EXPECT_EQ(q.get(), nntrainer::TensorDim(1, 1, 3, 4));
-    EXPECT_EQ(nntrainer::to_string(q), "1:1:3:4");
-  }
-
-  { /**< from_string -> get / to_string, uint vector prop */
-    std::vector<NumBanana> bananas;
-    EXPECT_EQ(nntrainer::getPropKey(bananas), "num_banana");
-    nntrainer::from_string("1, 2,3, 4, 5", bananas);
-    auto expected = std::vector<NumBanana>({1, 2, 3, 4, 5});
-    EXPECT_EQ(bananas, expected);
-    EXPECT_EQ(nntrainer::to_string(bananas), "1,2,3,4,5");
-  }
-
-  { /**< from_string -> get / to_string, uint array prop */
-    std::array<NumBanana, 4> bananas;
-    EXPECT_EQ(nntrainer::getPropKey(bananas), "num_banana");
-    nntrainer::from_string("1, 2,3, 4", bananas);
-    auto expected = std::array<NumBanana, 4>({1, 2, 3, 4});
-    EXPECT_EQ(bananas, expected);
-    EXPECT_EQ(nntrainer::to_string(bananas), "1,2,3,4");
-  }
-
-  { /**< exporter test */
-    auto props = std::make_tuple(NumBanana(), QualityOfBanana());
-
-    nntrainer::Exporter e;
-    e.save_result(props, nntrainer::ExportMethods::METHOD_STRINGVECTOR);
-
-    auto result = e.get_result<nntrainer::ExportMethods::METHOD_STRINGVECTOR>();
-
-    auto pair = std::pair<std::string, std::string>("num_banana", "1");
-    EXPECT_EQ(result[0], pair);
-
-    auto pair2 = std::pair<std::string, std::string>("quality_banana", "");
-    EXPECT_EQ(result[1], pair2);
-  }
-
-  { /**< export from layer */
-    auto layer = nntrainer::FullyConnectedLayer(1);
-    nntrainer::Exporter e;
-    layer.export_to(e);
-
-    auto result = e.get_result<nntrainer::ExportMethods::METHOD_STRINGVECTOR>();
-    auto pair0 = std::pair<std::string, std::string>("name", "");
-    EXPECT_EQ(result[0], pair0);
-    auto pair1 = std::pair<std::string, std::string>("unit", "1");
-    EXPECT_EQ(result[1], pair1);
-  }
-
-  { /**< load from layer */
-    auto props =
-      std::make_tuple(NumBanana(), QualityOfBanana(), DimensionOfBanana());
-
-    auto v = nntrainer::loadProperties(
-      {"num_banana=2", "quality_banana=thisisgood", "num_banana=42",
-       "banana_size=2:2:3", "not_used=key"},
-      props);
-
-    EXPECT_EQ(v, std::vector<std::string>{"not_used=key"});
-    EXPECT_EQ(std::get<0>(props).get(), 42);
-    EXPECT_EQ(std::get<1>(props).get(), "thisisgood");
-  }
-
-  { /**< load from layer */
-    std::tuple<std::array<NumBanana, 4>, std::vector<QualityOfBanana>> props;
-
-    auto v = nntrainer::loadProperties(
-      {"num_banana=1,2, 3 ,4", "quality_banana=thisisgood, thisisverygood",
-       "not_used=key"},
-      props);
-
-    EXPECT_EQ(v, std::vector<std::string>{"not_used=key"});
-    auto expected = std::array<NumBanana, 4>({1, 2, 3, 4});
-    EXPECT_EQ(std::get<0>(props), expected);
-    auto expected2 =
-      std::vector<QualityOfBanana>({"thisisgood", "thisisverygood"});
-    EXPECT_EQ(std::get<1>(props), expected2);
-  }
-}
-
-TEST(BasicProperty, setNotValid_01_n) {
-  NumBanana b;
-  EXPECT_THROW(b.set(-1), std::invalid_argument);
-}
-
-TEST(BasicProperty, setNotValid_02_n) {
-  QualityOfBanana q;
-  EXPECT_THROW(q.set("invalid_str"), std::invalid_argument);
-}
-
-TEST(BasicProperty, setNotValid_03_n) {
-  DimensionOfBanana d;
-  EXPECT_THROW(d.set({3, 3, 2, 4}), std::invalid_argument);
-}
-
-TEST(BasicProperty, fromStringNotValid_01_n) {
-  NumBanana b;
-  EXPECT_THROW(nntrainer::from_string("not integer", b), std::invalid_argument);
-}
-
-TEST(BasicProperty, fromStringNotValid_02_n) {
-  NumBanana b;
-  EXPECT_THROW(nntrainer::from_string("-1", b), std::invalid_argument);
-}
-
-TEST(BasicProperty, fromStringNotValid_03_n) {
-  QualityOfBanana q;
-  EXPECT_THROW(nntrainer::from_string("invalid_str", q), std::invalid_argument);
-}
-
-TEST(BasicProperty, fromStringNotValid_04_n) {
-  DimensionOfBanana d;
-  EXPECT_THROW(nntrainer::from_string("1:1:2:3:5", d), std::invalid_argument);
-}
-
-TEST(BasicProperty, fromStringNotValid_05_n) {
-  DimensionOfBanana d;
-  EXPECT_THROW(nntrainer::from_string("2:2:3:5", d), std::invalid_argument);
-}
-
-TEST(BasicProperty, fromStringNotValid_06_n) {
-  DimensionOfBanana d;
-  EXPECT_THROW(nntrainer::from_string("", d), std::invalid_argument);
-}
-
-TEST(BasicProperty, fromStringNotValid_07_n) {
-  DimensionOfBanana d;
-  EXPECT_THROW(nntrainer::from_string(":2:3:5", d), std::invalid_argument);
-}
-
-TEST(BasicProperty, fromStringVectorElementContainNotValidString_n) {
-  std::vector<NumBanana> bs;
-  EXPECT_THROW(nntrainer::from_string("1, 2, 3, not_valid", bs),
-               std::invalid_argument);
-}
-
-TEST(BasicProperty, fromStringVectorElementContainNotValidProp_n) {
-  std::vector<NumBanana> bs;
-  EXPECT_THROW(nntrainer::from_string("1, 2, 3, -1", bs),
-               std::invalid_argument);
-}
-
-TEST(BasicProperty, fromStringLessArrayElementSize_n) {
-  std::array<NumBanana, 4> bs;
-  EXPECT_THROW(nntrainer::from_string("1, 2, 3", bs), std::invalid_argument);
-}
-
-TEST(BasicProperty, fromStringOverArrayElementSize_n) {
-  std::array<NumBanana, 4> bs;
-  EXPECT_THROW(nntrainer::from_string("1, 2, 3,4,5", bs),
-               std::invalid_argument);
-}
-
-TEST(BasicProperty, fromStringArrayNotValidString_n) {
-  std::array<NumBanana, 4> bs;
-  EXPECT_THROW(nntrainer::from_string("1, 2, invalid, 4", bs),
-               std::invalid_argument);
-}
-
-TEST(BasicProperty, fromStringArrayNotValidProp_n) {
-  std::array<NumBanana, 4> bs;
-  EXPECT_THROW(nntrainer::from_string("1, 2, -1, 4", bs),
-               std::invalid_argument);
-}
-
-TEST(Exporter, invalidMethods_n) {
-  auto props = std::make_tuple(NumBanana(), QualityOfBanana());
-
-  nntrainer::Exporter e;
-  EXPECT_THROW(e.save_result(props, nntrainer::ExportMethods::METHOD_UNDEFINED),
-               nntrainer::exception::not_supported);
-}
-
-TEST(Exporter, notExported_n) {
-  auto props = std::make_tuple(NumBanana(), QualityOfBanana());
-
-  nntrainer::Exporter e;
-  /// intended comment
-  // e.save_result(props, nntrainer::ExportMethods::METHOD_STRINGVECTOR);
-
-  EXPECT_THROW(e.get_result<nntrainer::ExportMethods::METHOD_STRINGVECTOR>(),
-               std::invalid_argument);
-}
-
-/**
- * @brief Main gtest
- */
-int main(int argc, char **argv) {
-  int result = -1;
-
-  try {
-    testing::InitGoogleTest(&argc, argv);
-  } catch (...) {
-    std::cerr << "Error duing IniGoogleTest" << std::endl;
-    return 0;
-  }
-
-  try {
-    result = RUN_ALL_TESTS();
-  } catch (...) {
-    std::cerr << "Error duing RUN_ALL_TESTS()" << std::endl;
-  }
-
-  return result;
-}