camera_V4L2: Move unittests pass logic from python to cc

media_v4l2_unittest.cc and camera_V4L2.py both have some logic to decide
that test cases in unittest should pass or not.
Move all logic to media_v4l2_unittest.cc to control it easily.

BUG=b:36662557
TEST=test_that -b ${BOARD} ${IP} camera_V4L2

Change-Id: If1766bdc2c9b82d2ee7f21c41092649d3c43eb92
Reviewed-on: https://chromium-review.googlesource.com/477735
Commit-Ready: Heng-ruey Hsu <henryhsu@google.com>
Tested-by: Heng-ruey Hsu <henryhsu@google.com>
Reviewed-by: Heng-ruey Hsu <henryhsu@google.com>
diff --git a/client/site_tests/camera_V4L2/camera_V4L2.py b/client/site_tests/camera_V4L2/camera_V4L2.py
index a7b66cb..c47f0cc 100644
--- a/client/site_tests/camera_V4L2/camera_V4L2.py
+++ b/client/site_tests/camera_V4L2/camera_V4L2.py
@@ -69,75 +69,12 @@
         if not self.v4l2_devices:
             raise error.TestFail("No V4L2 devices found!")
 
-    def unittest_passed(self, testname, stdout):
-        return re.search(r"OK \] V4L2DeviceTest\." + testname, stdout)
-
     def run_v4l2_unittests(self, device):
         self.executable = os.path.join(self.bindir, "media_v4l2_unittest")
         cmd = "%s --device=%s" % (self.executable, device)
         logging.info("Running %s" % cmd)
         stdout = utils.system_output(cmd, retain_output=True)
 
-        # Check the result of unittests.
-        # We had exercise all the optional ioctls in unittest which maybe
-        # optional by V4L2 Specification.  Therefore we need to check those
-        # tests that we thought are mandatory.
-        # 1. Multiple open should be supported for panel application.
-        if not self.unittest_passed("MultipleOpen", stdout):
-            raise error.TestError(device + " does not support multiple open!")
-
-        # 2. Need to make sure this is really support or just driver error.
-        if not self.unittest_passed("MultipleInit", stdout):
-            raise error.TestError(device + " does support multiple init!")
-
-        # 3. EnumInput and EnumStandard is optional.
-
-        # 4. EnumControl is mandatory.
-        if not self.unittest_passed("EnumControl", stdout):
-            raise error.TestError(device + " does support enum controls!")
-        pattern = re.compile(r"Control (\w+) is enabled\((\d+)-(\d+):(\d+)\)")
-        control_info = pattern.findall(stdout)
-        self.supported_controls = [x[0] for x in control_info]
-        logging.info("Supported Controls: %s\n" % self.supported_controls)
-
-        # TODO(jiesun): what is required?
-        mandatory_controls = [
-            "Brightness",
-            "Contrast",
-            "Saturation",
-            "Hue",
-            "Gamma"]
-        for control in mandatory_controls:
-            if self.assert_mandatory_controls and \
-                    control not in self.supported_controls:
-                raise error.TestError(device + " does not support " + control)
-
-        # 5. SetControl is mandatory.
-        if not self.unittest_passed("SetControl", stdout):
-            raise error.TestError(device + " does not support set controls!")
-
-        # 6. 7. Set/GetCrop are both optional.
-
-        # 8. ProbeCaps is mandatory.
-        if not self.unittest_passed("ProbeCaps", stdout):
-            raise error.TestError(device + " does not support probe caps!")
-
-        if not re.search(r"support video capture interface.>>>", stdout):
-            raise error.TestFail(device + " does not support video capture!")
-
-        # 9. EnumFormats is always mandatory.
-        if not self.unittest_passed("EnumFormats", stdout):
-            raise error.TestError(device + " does not support enum formats!")
-
-        pattern = re.compile(r"supported format #\d+: .* \((....)\)")
-        format_info = pattern.findall(stdout)
-        # Remove duplicated pixel formats from list.
-        self.supported_formats = list(set(format_info))
-        logging.info("Supported pixel format: %s\n", self.supported_formats)
-
-        # 10. Get/SetParam for framerate is optional.
-        # 11. EnumFrameSize is optional.
-
     def run_v4l2_capture_test(self, device):
         options = ["--device=%s" % device]
         options += ["--usb-info=%s" % self.usb_info]
diff --git a/client/site_tests/camera_V4L2/src/media_v4l2_unittest.cc b/client/site_tests/camera_V4L2/src/media_v4l2_unittest.cc
index cfbdff3..be95473 100644
--- a/client/site_tests/camera_V4L2/src/media_v4l2_unittest.cc
+++ b/client/site_tests/camera_V4L2/src/media_v4l2_unittest.cc
@@ -8,7 +8,7 @@
 
 #include "media_v4l2_device.h"
 
-void ExerciseControl(V4L2Device* v4l2_dev, uint32_t id, const char* control) {
+bool ExerciseControl(V4L2Device* v4l2_dev, uint32_t id, const char* control) {
   v4l2_queryctrl query_ctrl;
   if (v4l2_dev->QueryControl(id, &query_ctrl)) {
     if (!v4l2_dev->SetControl(id, query_ctrl.maximum))
@@ -19,7 +19,9 @@
       printf("[Warning] Can not set %s to default value\n", control);
   } else {
     printf("[Warning] Can not query control name :%s\n", control);
+    return false;
   }
+  return true;
 }
 
 void TestMultipleOpen(const char* dev_name) {
@@ -27,6 +29,7 @@
   V4L2Device v4l2_dev2(dev_name, 4);
   if (!v4l2_dev1.OpenDevice()) {
     printf("[Error] Can not open device '%s' for the first time\n", dev_name);
+    exit(EXIT_FAILURE);
   }
   if (!v4l2_dev2.OpenDevice()) {
     printf("[Error] Can not open device '%s' for the second time\n", dev_name);
@@ -42,13 +45,16 @@
   V4L2Device v4l2_dev2(dev_name, 4);
   if (!v4l2_dev1.OpenDevice()) {
     printf("[Error] Can not open device '%s' for the first time\n", dev_name);
+    exit(EXIT_FAILURE);
   }
   if (!v4l2_dev2.OpenDevice()) {
     printf("[Error] Can not open device '%s' for the second time\n", dev_name);
+    exit(EXIT_FAILURE);
   }
 
   if (!v4l2_dev1.InitDevice(io, 640, 480, V4L2_PIX_FMT_YUYV, 30)) {
     printf("[Error] Can not init device '%s' for the first time\n", dev_name);
+    exit(EXIT_FAILURE);
   }
 
   // multiple streaming request should fail.
@@ -64,10 +70,12 @@
   printf("[OK ] V4L2DeviceTest.MultipleInit\n");
 }
 
+// EnumInput and EnumStandard are optional.
 void TestEnumInputAndStandard(const char* dev_name) {
   V4L2Device v4l2_dev1(dev_name, 4);
   if (!v4l2_dev1.OpenDevice()) {
     printf("[Error] Can not open device '%s'\n", dev_name);
+    exit(EXIT_FAILURE);
   }
   v4l2_dev1.EnumInput();
   v4l2_dev1.EnumStandard();
@@ -79,6 +87,7 @@
   V4L2Device v4l2_dev(dev_name, 4);
   if (!v4l2_dev.OpenDevice()) {
     printf("[Error] Can not open device '%s'\n", dev_name);
+    exit(EXIT_FAILURE);
   }
   v4l2_dev.EnumControl();
   v4l2_dev.CloseDevice();
@@ -89,22 +98,33 @@
   V4L2Device v4l2_dev(dev_name, 4);
   if (!v4l2_dev.OpenDevice()) {
     printf("[Error] Can not open device '%s'\n", dev_name);
+    exit(EXIT_FAILURE);
   }
-  ExerciseControl(&v4l2_dev, V4L2_CID_BRIGHTNESS, "brightness");
-  ExerciseControl(&v4l2_dev, V4L2_CID_CONTRAST, "contrast");
-  ExerciseControl(&v4l2_dev, V4L2_CID_SATURATION, "saturation");
-  ExerciseControl(&v4l2_dev, V4L2_CID_GAMMA, "gamma");
-  ExerciseControl(&v4l2_dev, V4L2_CID_HUE, "hue");
+  // Test mandatory controls.
+  if (!ExerciseControl(&v4l2_dev, V4L2_CID_BRIGHTNESS, "brightness"))
+    exit(EXIT_FAILURE);
+  if (!ExerciseControl(&v4l2_dev, V4L2_CID_CONTRAST, "contrast"))
+    exit(EXIT_FAILURE);
+  if (!ExerciseControl(&v4l2_dev, V4L2_CID_SATURATION, "saturation"))
+    exit(EXIT_FAILURE);
+  if (!ExerciseControl(&v4l2_dev, V4L2_CID_GAMMA, "gamma"))
+    exit(EXIT_FAILURE);
+  if (!ExerciseControl(&v4l2_dev, V4L2_CID_HUE, "hue"))
+    exit(EXIT_FAILURE);
+
+  // Test optional controls.
   ExerciseControl(&v4l2_dev, V4L2_CID_GAIN, "gain");
   ExerciseControl(&v4l2_dev, V4L2_CID_SHARPNESS, "sharpness");
   v4l2_dev.CloseDevice();
   printf("[OK ] V4L2DeviceTest.SetControl\n");
 }
 
+// SetCrop is optional.
 void TestSetCrop(const char* dev_name) {
   V4L2Device v4l2_dev(dev_name, 4);
   if (!v4l2_dev.OpenDevice()) {
     printf("[Error] Can not open device '%s'\n", dev_name);
+    exit(EXIT_FAILURE);
   }
   v4l2_cropcap cropcap;
   memset(&cropcap, 0, sizeof(cropcap));
@@ -119,10 +139,12 @@
   printf("[OK ] V4L2DeviceTest.SetCrop\n");
 }
 
+// GetCrop is optional.
 void TestGetCrop(const char* dev_name) {
   V4L2Device v4l2_dev(dev_name, 4);
   if (!v4l2_dev.OpenDevice()) {
     printf("[Error] Can not open device '%s'\n", dev_name);
+    exit(EXIT_FAILURE);
   }
   v4l2_crop crop;
   memset(&crop, 0, sizeof(crop));
@@ -136,10 +158,17 @@
   V4L2Device v4l2_dev(dev_name, 4);
   if (!v4l2_dev.OpenDevice()) {
     printf("[Error] Can not open device '%s'\n", dev_name);
+    exit(EXIT_FAILURE);
   }
   v4l2_capability caps;
   if (!v4l2_dev.ProbeCaps(&caps, true)) {
     printf("[Error] Can not probe caps on device '%s'\n", dev_name);
+    exit(EXIT_FAILURE);
+  }
+  if (!(caps.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
+    printf("<<< Info: %s does not support video capture interface.>>>\n",
+        dev_name);
+    exit(EXIT_FAILURE);
   }
   v4l2_dev.CloseDevice();
   printf("[OK ] V4L2DeviceTest.ProbeCaps\n");
@@ -149,8 +178,12 @@
   V4L2Device v4l2_dev(dev_name, 4);
   if (!v4l2_dev.OpenDevice()) {
     printf("[Error] Can not open device '%s'\n", dev_name);
+    exit(EXIT_FAILURE);
   }
-  v4l2_dev.EnumFormat(NULL);
+  if (!v4l2_dev.EnumFormat(NULL)) {
+    printf("[Error] Can not enumerate format on device '%s'\n", dev_name);
+    exit(EXIT_FAILURE);
+  }
   v4l2_dev.CloseDevice();
   printf("[OK ] V4L2DeviceTest.EnumFormats\n");
 }
@@ -159,9 +192,13 @@
   V4L2Device v4l2_dev(dev_name, 4);
   if (!v4l2_dev.OpenDevice()) {
     printf("[Error] Can not open device '%s'\n", dev_name);
+    exit(EXIT_FAILURE);
   }
   uint32_t format_count = 0;
-  v4l2_dev.EnumFormat(&format_count);
+  if (!v4l2_dev.EnumFormat(&format_count)) {
+    printf("[Error] Can not enumerate format on device '%s'\n", dev_name);
+    exit(EXIT_FAILURE);
+  }
   for (uint32_t i = 0; i < format_count; ++i) {
     uint32_t pixfmt;
     if (!v4l2_dev.GetPixelFormat(i, &pixfmt)) {
@@ -170,6 +207,7 @@
     }
     if (!v4l2_dev.EnumFrameSize(pixfmt, NULL)) {
       printf("[Warning] Enumerate frame size error on device '%s'\n", dev_name);
+      exit(EXIT_FAILURE);
     };
   }
   v4l2_dev.CloseDevice();
@@ -183,7 +221,10 @@
     exit(EXIT_FAILURE);
   }
   uint32_t format_count = 0;
-  v4l2_dev.EnumFormat(&format_count);
+  if (!v4l2_dev.EnumFormat(&format_count)) {
+    printf("[Error] Can not enumerate format on device '%s'\n", dev_name);
+    exit(EXIT_FAILURE);
+  }
   for (uint32_t i = 0; i < format_count; ++i) {
     uint32_t pixfmt;
     if (!v4l2_dev.GetPixelFormat(i, &pixfmt)) {
@@ -217,6 +258,7 @@
   V4L2Device v4l2_dev(dev_name, 4);
   if (!v4l2_dev.OpenDevice()) {
     printf("[Error] Can not open device '%s'\n", dev_name);
+    exit(EXIT_FAILURE);
   }
   v4l2_streamparm param;
   if (!v4l2_dev.GetParam(&param)) {
@@ -229,6 +271,8 @@
       printf("[Error] Can not set stream param on device '%s'\n", dev_name);
       exit(EXIT_FAILURE);
     }
+  } else {
+    printf("[Info] %s does not support TIMEPERFRAME.\n", dev_name);
   }
 
   v4l2_dev.CloseDevice();
@@ -238,22 +282,18 @@
 static void PrintUsage() {
   printf("Usage: media_v4l2_unittest [options]\n\n"
          "Options:\n"
-         "--device=DEVICE_NAME   Video device name [/dev/video]\n"
          "--help                 Print usage\n"
-         "--buffer-io=mmap       Use memory mapped buffers\n"
-         "--buffer-io=userp      Use application allocated buffers\n");
+         "--device=DEVICE_NAME   Video device name [/dev/video]\n");
 }
 
-static const char short_options[] = "d:?b";
+static const char short_options[] = "?d:";
 static const struct option long_options[] = {
-        { "device",       required_argument, NULL, 'd' },
-        { "help",         no_argument,       NULL, '?' },
-        { "buffer-io",    required_argument, NULL, 'b' },
+        { "help",   no_argument,       NULL, '?' },
+        { "device", required_argument, NULL, 'd' },
 };
 
 int main(int argc, char** argv) {
-  std::string dev_name = "/dev/video", io_name;
-  V4L2Device::IOMethod io = V4L2Device::IO_METHOD_MMAP;
+  std::string dev_name = "/dev/video";
 
   // Parse the command line.
   for (;;) {
@@ -264,23 +304,12 @@
     switch (c) {
       case 0:  // getopt_long() flag.
         break;
-      case 'd':
-        // Initialize default v4l2 device name.
-        dev_name = strdup(optarg);
-        break;
       case '?':
         PrintUsage();
         exit (EXIT_SUCCESS);
-      case 'b':
-        io_name = strdup(optarg);
-        if (io_name == "mmap") {
-          io = V4L2Device::IO_METHOD_MMAP;
-        } else if (io_name == "userp") {
-          io = V4L2Device::IO_METHOD_USERPTR;
-        } else {
-          PrintUsage();
-          exit(EXIT_FAILURE);
-        }
+      case 'd':
+        // Initialize default v4l2 device name.
+        dev_name = strdup(optarg);
         break;
       default:
         PrintUsage();
@@ -289,7 +318,8 @@
   }
 
   TestMultipleOpen(dev_name.c_str());
-  TestMultipleInit(dev_name.c_str(), io);
+  TestMultipleInit(dev_name.c_str(), V4L2Device::IO_METHOD_MMAP);
+  TestMultipleInit(dev_name.c_str(), V4L2Device::IO_METHOD_USERPTR);
   TestEnumInputAndStandard(dev_name.c_str());
   TestEnumControl(dev_name.c_str());
   TestSetControl(dev_name.c_str());