sensorctl: add options/features for usability 84/143584/1
authorkibak.yoon <kibak.yoon@samsung.com>
Thu, 10 Aug 2017 10:44:11 +0000 (19:44 +0900)
committerkibak.yoon <kibak.yoon@samsung.com>
Thu, 10 Aug 2017 11:10:38 +0000 (20:10 +0900)
This patch supports the below options and features.

[SYNOPSIS]
  - sensorctl test auto [--help] [--list] [--filter=<regex>]
                        [--verbose] [--shuffle] [--repeat]
                        [--output]
  - sensorctl test <sensor_type>
                [--interval=NUMBER] [--batch_latency=NUMBER] [--powersave=TYPE]
                [--repeat=NUMBER] [--output=FILE_PATH] [--help] [--verbose]

[Options]
  -f PATTERN, --filter=<PATTERN>
    Run a subset of the tests for debugging or quickly verifying a
    change. Sensorctl will only run the tests whose full names match the
    filter. This can be used to specify multiple search patterns.

  -l, --list
    Prints the testcase list by following command.

  -h, --help
    Prints the synopsis and a list of the most commonly used commands.

  -v, --verbose
    Prints the log message fully while testcases are running.

  -s, --shuffle
    Run the testcase randomly.

  -r NUMBER, --repeat=NUMBER
    Run the testcase a given number of times.

Change-Id: I30dec0ef2896e12c956be294c2677cb785335ec0
Signed-off-by: kibak.yoon <kibak.yoon@samsung.com>
src/sensorctl/test_bench.cpp
src/sensorctl/test_bench.h

index 3b9cd51..db0b974 100644 (file)
  *
  */
 
-#include "log.h"
 #include "test_bench.h"
 
+#include <getopt.h>
+#include <regex>
+
+#include "log.h"
+
 /*
  * Implementation of test_option
  */
-bool test_option::full_log = false;
-std::string test_option::group = "";
-
-void test_option::show_full_log(bool show)
+bool test_option::verbose = false;
+bool test_option::shuffle = false;
+bool test_option::show_list = false;
+int test_option::repeat = 1;
+std::string test_option::filter = "";
+std::string test_option::output = "";
+int test_option::interval = -1;
+int test_option::latency = -1;
+int test_option::powersave = -1;
+
+bool test_option::set_options(int argc, char *argv[])
 {
-       full_log = show;
-}
-
-void test_option::set_group(const char *gname)
-{
-       group = gname;
-}
+       int c;
+
+       while (1) {
+               static struct option options[] = {
+                       {"list", no_argument, 0, 'l'},
+                       {"filter", required_argument, 0, 'f'},
+                       {"verbose", no_argument, 0, 'v'},
+                       {"shuffle", no_argument, 0, 's'},
+                       {"repeat", required_argument, 0, 'r'},
+                       {"output", required_argument, 0, 'o'},
+
+                       /* For manual test*/
+                       {"interval", required_argument, 0, 'i'},
+                       {"batch_latency", required_argument, 0, 'b'},
+                       {"powersave", required_argument, 0, 'p'},
+
+                       {"help", no_argument, 0, 'h'},
+                       {0, 0, 0, 0}
+               };
+
+               int option_index = 0;
+               c = getopt_long(argc, argv, "lfvsroibph:", options, &option_index);
+               if (c == -1)
+                       return true;
+
+               switch (c) {
+               case 0:
+                       break;
+               case 'l':
+                       _I("== Testcase List ==\n");
+                       test_bench::show_testcases();
+                       test_option::show_list = true;
+                       break;
+               case 'f':
+                       _I("Filter : %s\n", optarg);
+                       if (!optarg) break;
+                       test_option::filter = optarg;
+                       break;
+               case 'v':
+                       _I("Verbose is on\n");
+                       test_option::verbose = true;
+                       break;
+               case 's':
+                       _I("Shuffle is on(Default seed)\n");
+                       test_option::shuffle = true;
+                       break;
+               case 'r':
+                       _I("Repeat : %s\n", optarg);
+                       if (!optarg) break;
+                       test_option::repeat = atoi(optarg);
+                       break;
+               case 'o':
+                       /* [TODO] */
+                       _W("File output is not supported yet, use $sensorctl > out : %s\n", optarg);
+                       if (!optarg) break;
+                       test_option::output = optarg;
+                       break;
+               case 'i':
+                       _I("Interval : %s\n", optarg);
+                       if (!optarg) break;
+                       test_option::interval = atoi(optarg);
+                       break;
+               case 'b':
+                       _I("Batch latency : %s\n", optarg);
+                       if (!optarg) break;
+                       test_option::latency = atoi(optarg);
+                       break;
+               case 'p':
+                       _I("Power save : %s\n", optarg);
+                       if (!optarg) break;
+                       test_option::powersave = atoi(optarg);
+                       break;
+               case 'h':
+               case '?':
+               default:
+                       return false;
+               }
+       }
 
-void test_option::set_options(int argc, char *argv[])
-{
-       /* TODO: use getopt() */
-       if (argc > 3)
-               set_group(argv[3]);
-       if (argc > 4)
-               show_full_log(atoi(argv[4]));
+       return true;
 }
 
 /*
@@ -51,6 +127,7 @@ void test_option::set_options(int argc, char *argv[])
 test_case::test_case(const std::string &group, const std::string &name)
 : m_group(group)
 , m_name(name)
+, m_fullname(group + "." + m_name)
 , m_func(NULL)
 {
        test_bench::register_testcase(group, this);
@@ -58,25 +135,17 @@ test_case::test_case(const std::string &group, const std::string &name)
 
 void test_case::started(void)
 {
-       _I("[----------]\n");
        _I("[ RUN      ] ");
-       _N("%s.%s\n", m_group.c_str(), m_name.c_str());
-}
-
-void test_case::stopped(void)
-{
-       _I("[       OK ] ");
-       _N("%s.%s\n", m_group.c_str(), m_name.c_str());
-       _I("[----------]\n");
+       _N("%s\n", m_fullname.c_str());
 }
 
-void test_case::show(bool result)
+void test_case::stopped(bool result)
 {
        if (result)
-               _I("[  PASSED  ] ");
+               _I("[       OK ] ");
        else
                _E("[  FAILED  ] ");
-       _N("%s.%s\n", m_group.c_str(), m_name.c_str());
+       _N("%s\n", m_fullname.c_str());
 }
 
 void test_case::run_testcase(void)
@@ -85,8 +154,7 @@ void test_case::run_testcase(void)
 
        started();
        result = (this->*m_func)();
-       stopped();
-       show(result);
+       stopped(result);
 }
 
 void test_case::register_func(test_func func)
@@ -103,6 +171,11 @@ test_bench& test_bench::instance()
        return bench;
 }
 
+void test_bench::show_testcases(void)
+{
+       instance().show();
+}
+
 void test_bench::register_testcase(const std::string &group, test_case *testcase)
 {
        instance().add_testcase(group, testcase);
@@ -113,12 +186,15 @@ void test_bench::push_failure(const std::string &function, long line, const std:
        instance().add_failure(function, line, msg);
 }
 
-void test_bench::run_all_testcase(void)
+void test_bench::run_all_testcases(void)
 {
+       if (test_option::show_list)
+               return;
+
        instance().run();
 }
 
-void test_bench::stop_all_testcase(void)
+void test_bench::stop_all_testcases(void)
 {
        instance().stop();
 }
@@ -140,13 +216,36 @@ void test_bench::add_failure(const std::string &function, long line, const std::
 void test_bench::started(void)
 {
        _I("[==========] ");
-       _N("Running %d testcases\n", count(test_option::group));
+       _N("Running %d testcases\n", count());
 }
 
 void test_bench::stopped(void)
 {
        _I("[==========] ");
-       _N("%d testcases ran\n", count(test_option::group));
+       _N("%d testcases ran\n", count());
+}
+
+void test_bench::show(void)
+{
+       /*
+        * [group1]
+        *     [tc name1]
+        *     [tc name2]
+        * [group2]
+        *     [tc name1]
+        */
+
+       for (auto it = testcases.begin(); it != testcases.end();
+                       it = testcases.upper_bound(it->first)) {
+
+               auto range = testcases.equal_range(it->first);
+               _I("[%s]\n", it->first.c_str());
+
+               for (auto testcase = range.first; testcase != range.second; ++testcase)
+                       _N("    * %s\n", testcase->second->name().c_str());
+       }
+
+       _I("Testcase Count : %u\n", count());
 }
 
 void test_bench::show_failures(void)
@@ -154,7 +253,8 @@ void test_bench::show_failures(void)
        _N("================================\n");
 
        if (m_failure_count == 0) {
-               _N("there was no fail case\n");
+               _I("[  PASSED  ] ");
+               _N("%d tests\n", count() - m_failure_count);
                return;
        }
 
@@ -166,28 +266,44 @@ void test_bench::show_failures(void)
        }
 }
 
+bool test_bench::filter(const std::string &name)
+{
+       static std::regex filter(test_option::filter.c_str(), std::regex::optimize);
+       if (!std::regex_match(name, filter)) {
+               //_W("Not Matched : %s(%s)\n", name.c_str(), test_option::filter.c_str());
+               return false;
+       }
+
+       //_I("Matched : %s(%s)\n", name.c_str(), test_option::filter.c_str());
+       return true;
+}
+
 void test_bench::run(void)
 {
-       std::size_t found;
        m_failure_count = 0;
 
        started();
 
-       for (auto it = testcases.begin(); it != testcases.end(); ++it) {
-               if (m_stop)
-                       break;
+       /* For group */
+       for (auto it = testcases.begin(); it != testcases.end();
+                       it = testcases.upper_bound(it->first)) {
+               if (m_stop) break;
+               if (!filter(it->second->fullname())) continue;
 
-               found = it->first.find("skip");
+               auto range = testcases.equal_range(it->first);
 
-               if (test_option::group.empty() && found != std::string::npos)
-                       continue;
+               /* Time measurement for test group */
+               clock_t start = clock();
 
-               found = it->first.find(test_option::group);
+               _I("[----------] %d tests from %s\n", testcases.count(it->first), it->first.c_str());
+               for (auto testcase = range.first; testcase != range.second; ++testcase) {
+                       if (m_stop) break;
+                       testcase->second->run_testcase();
+               }
 
-               if (!test_option::group.empty() && found == std::string::npos)
-                       continue;
-
-               it->second->run_testcase();
+               _I("[----------] %d tests from %s (%.4f sec)\n",
+                       testcases.count(it->first), it->first.c_str(),
+                       (double)(clock() - start)/ CLOCKS_PER_SEC);
        }
 
        stopped();
@@ -199,23 +315,15 @@ void test_bench::stop(void)
        m_stop = true;
 }
 
-unsigned int test_bench::count(std::string &group)
-{
-       if (group.empty())
-               return testcases.size() - count_by_key("skip");
-
-       return count_by_key(group.c_str());
-}
-
-unsigned int test_bench::count_by_key(const char *key)
+unsigned int test_bench::count(void)
 {
        int count = 0;
 
        for (auto it = testcases.begin(); it != testcases.end(); ++it) {
-               std::size_t found = it->first.find(key);
+               if (!filter(it->second->fullname()))
+                       continue;
 
-               if (found != std::string::npos)
-                       count++;
+               count++;
        }
 
        return count;
index 8525e39..f70fdeb 100644 (file)
@@ -38,7 +38,7 @@ do { \
 
 #define PASS(left, comp, right) \
 do { \
-       if (test_option::full_log) { \
+       if (test_option::verbose) { \
                _I("[   PASS   ] "); \
                std::ostringstream os; \
                os << __FUNCTION__ << "(" << __LINE__ << ") : " \
@@ -96,32 +96,37 @@ do { \
 } while (0)
 
 #define TESTCASE(group, name) \
-class test_case_##group_##name : public test_case { \
+class test_case_##group##_##name : public test_case { \
 public: \
-       test_case_##group_##name() \
+       test_case_##group##_##name() \
        : test_case(#group, #name) \
        { \
-               register_func(static_cast<test_case::test_func>(&test_case_##group_##name::test)); \
+               register_func(static_cast<test_case::test_func>(&test_case_##group##_##name::test)); \
        } \
        bool test(void); \
-} test_case_##group_##name##_instance; \
-bool test_case_##group_##name::test(void)
+} test_case_##group##_##name##_instance; \
+bool test_case_##group##_##name::test(void)
 
 /*
  * Declaration of test_option
  */
 class test_option {
 public:
-       static bool full_log;
-       static std::string group;
-
-       static void show_full_log(bool show);
-       static void set_group(const char *gname);
-       static void set_options(int argc, char *argv[]);
+       static bool verbose;
+       static bool shuffle; /* TODO */
+       static bool show_list;
+       static int repeat; /* TODO */
+       static std::string filter;
+       static std::string output; /* TODO */
+       static int interval;
+       static int latency;
+       static int powersave;
+
+       static bool set_options(int argc, char *argv[]);
 };
 
 /*
- * Decloaration of test_result
+ * Declaration of test_result
  */
 class test_result {
 public:
@@ -146,18 +151,19 @@ public:
 
        const std::string& group() const { return m_group; }
        const std::string& name() const { return m_name; }
+       const std::string& fullname() const { return m_fullname; }
 
 protected:
        typedef bool (test_case::*test_func)();
 
        void started(void);
-       void stopped(void);
-       void show(bool result);
+       void stopped(bool result);
        void register_func(test_func func);
 
 private:
        const std::string m_group;
        const std::string m_name;
+       const std::string m_fullname;
        test_func m_func;
 };
 
@@ -171,10 +177,12 @@ public:
        , m_stop(false)
        {}
 
+       static void show_testcases(void);
+
        static void register_testcase(const std::string &group, test_case *testcase);
 
-       static void run_all_testcase(void);
-       static void stop_all_testcase(void);
+       static void run_all_testcases(void);
+       static void stop_all_testcases(void);
 
        static void push_failure(const std::string &function, long line, const std::string &msg);
 
@@ -188,11 +196,14 @@ private:
        void show_failures(void);
 
        void add_testcase(const std::string &group, test_case *testcase);
+
+       bool filter(const std::string &name);
        void run(void);
        void stop(void);
 
-       unsigned int count(std::string &group);
-       unsigned int count_by_key(const char *key);
+       void show(void);
+
+       unsigned int count(void);
 
        std::multimap<const std::string, test_case *> testcases;
        std::vector<test_result> results;