[imx227][test] Add tests for camera sensor

- Added Camera Sensor Unit Tests
- Added basic tests for Sensor APIs
- Currently tests run before the actual driver is added
TODO: Run only in test environment.

CAM-29 #done

Test: Ran this test on Sherlock

Change-Id: Ibdc65303c8190631e5f4864933ec6b95b1184322
diff --git a/zircon/system/dev/camera/imx227/BUILD.gn b/zircon/system/dev/camera/imx227/BUILD.gn
index 2a6d318..099fd95 100644
--- a/zircon/system/dev/camera/imx227/BUILD.gn
+++ b/zircon/system/dev/camera/imx227/BUILD.gn
@@ -4,6 +4,7 @@
 
 driver("imx227") {
   sources = [
+    "imx227-test.cpp",
     "imx227.cpp",
   ]
   deps = [
@@ -22,5 +23,6 @@
     "$zx/system/ulib/sync",
     "$zx/system/ulib/zircon",
     "$zx/system/ulib/zx",
+    "$zx/system/ulib/zxtest",
   ]
 }
diff --git a/zircon/system/dev/camera/imx227/imx227-test.cpp b/zircon/system/dev/camera/imx227/imx227-test.cpp
new file mode 100644
index 0000000..6a8fca0
--- /dev/null
+++ b/zircon/system/dev/camera/imx227/imx227-test.cpp
@@ -0,0 +1,64 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "imx227-test.h"
+#include "imx227.h"
+
+#include <ddk/debug.h>
+#include <fbl/alloc_checker.h>
+
+namespace camera {
+
+namespace {
+
+constexpr uint32_t kValidSensorMode = 0;
+
+}
+
+Imx227Device* g_sensor_device;
+
+void Imx227DeviceTester::SetUp() {
+    ASSERT_NOT_NULL(g_sensor_device);
+    EXPECT_EQ(ZX_OK, g_sensor_device->CameraSensorInit());
+}
+
+void Imx227DeviceTester::TearDown() {
+    g_sensor_device->CameraSensorDeInit();
+}
+
+TEST_F(Imx227DeviceTester, TestSetMode) {
+    EXPECT_EQ(ZX_OK, g_sensor_device->CameraSensorSetMode(kValidSensorMode));
+    EXPECT_EQ(ZX_ERR_INVALID_ARGS, g_sensor_device->CameraSensorSetMode(0xFF));
+}
+
+TEST_F(Imx227DeviceTester, TestStreaming) {
+    EXPECT_EQ(ZX_OK, g_sensor_device->CameraSensorStartStreaming());
+    // TODO(braval): Figure out a way to validate starting & stopping of streaming
+    EXPECT_EQ(ZX_OK, g_sensor_device->CameraSensorStopStreaming());
+}
+
+TEST_F(Imx227DeviceTester, TestDeInitState) {
+    TearDown();
+    EXPECT_NE(ZX_OK, g_sensor_device->CameraSensorSetMode(kValidSensorMode));
+    EXPECT_NE(ZX_OK, g_sensor_device->CameraSensorStartStreaming());
+    EXPECT_NE(ZX_OK, g_sensor_device->CameraSensorStopStreaming());
+}
+
+TEST_F(Imx227DeviceTester, TestStreamingOff) {
+    EXPECT_NE(ZX_OK, g_sensor_device->CameraSensorStopStreaming());
+}
+
+TEST_F(Imx227DeviceTester, TestStreamingOn) {
+    EXPECT_EQ(ZX_OK, g_sensor_device->CameraSensorStartStreaming());
+    EXPECT_NE(ZX_OK, g_sensor_device->CameraSensorStartStreaming());
+}
+
+zx_status_t Imx227DeviceTester::RunTests(Imx227Device* sensor) {
+    g_sensor_device = sensor;
+    const int kArgc = 1;
+    const char* argv[kArgc] = {"imx227-test"};
+    return RUN_ALL_TESTS(kArgc, const_cast<char**>(argv));
+}
+
+} // namespace camera
diff --git a/zircon/system/dev/camera/imx227/imx227-test.h b/zircon/system/dev/camera/imx227/imx227-test.h
new file mode 100644
index 0000000..504c2fb
--- /dev/null
+++ b/zircon/system/dev/camera/imx227/imx227-test.h
@@ -0,0 +1,25 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#pragma once
+
+#include <ddktl/device.h>
+#include <memory>
+#include <zxtest/zxtest.h>
+
+namespace camera {
+// |Imx227Devicetester| is spawned by the driver in |imx227.cpp|
+class Imx227Device;
+
+class Imx227DeviceTester : public zxtest::Test {
+public:
+    static zx_status_t RunTests(Imx227Device* device);
+
+protected:
+    // Setup & TearDown
+    void SetUp();
+    void TearDown();
+};
+
+} // namespace camera
diff --git a/zircon/system/dev/camera/imx227/imx227.cpp b/zircon/system/dev/camera/imx227/imx227.cpp
index e754331..2a08a4d 100644
--- a/zircon/system/dev/camera/imx227/imx227.cpp
+++ b/zircon/system/dev/camera/imx227/imx227.cpp
@@ -4,6 +4,7 @@
 
 #include "imx227.h"
 #include "imx227-seq.h"
+#include "imx227-test.h"
 #include <ddk/binding.h>
 #include <ddk/debug.h>
 #include <ddk/metadata.h>
@@ -302,7 +303,7 @@
 }
 
 zx_status_t Imx227Device::CameraSensorStartStreaming() {
-    if (!IsSensorInitialized()) {
+    if (!IsSensorInitialized() || ctx_.streaming_flag) {
         return ZX_ERR_BAD_STATE;
     }
     zxlogf(INFO, "%s Camera Sensor Start Streaming\n", __func__);
@@ -312,7 +313,7 @@
 }
 
 zx_status_t Imx227Device::CameraSensorStopStreaming() {
-    if (!IsSensorInitialized()) {
+    if (!IsSensorInitialized() || !ctx_.streaming_flag) {
         return ZX_ERR_BAD_STATE;
     }
     ctx_.streaming_flag = 0;
@@ -337,7 +338,10 @@
     return ZX_ERR_NOT_SUPPORTED;
 }
 
-zx_status_t Imx227Device::Create(void* ctx, zx_device_t* parent) {
+// static
+zx_status_t Imx227Device::Setup(void* ctx,
+                                zx_device_t* parent,
+                                std::unique_ptr<Imx227Device>* out) {
     ddk::CompositeProtocolClient composite(parent);
     if (!composite.is_valid()) {
         zxlogf(ERROR, "%s could not get composite protocoln", __func__);
@@ -371,24 +375,8 @@
         zxlogf(ERROR, "%s InitPdev failed\n", __func__);
         return status;
     }
-
-    zx_device_prop_t props[] = {
-        {BIND_PLATFORM_DEV_VID, 0, PDEV_VID_SONY},
-        {BIND_PLATFORM_DEV_PID, 0, PDEV_PID_SONY_IMX227},
-        {BIND_PLATFORM_DEV_DID, 0, PDEV_DID_CAMERA_SENSOR},
-    };
-
-    status = sensor_device->DdkAdd("imx227", 0, props, countof(props));
-    if (status != ZX_OK) {
-        zxlogf(ERROR, "imx227: Could not create imx227 sensor device: %d\n", status);
-        return status;
-    } else {
-        zxlogf(INFO, "imx227 driver added\n");
-    }
-
-    // sensor_device intentionally leaked as it is now held by DevMgr.
-    __UNUSED auto* dev = sensor_device.release();
-    return ZX_OK;
+    *out = std::move(sensor_device);
+    return status;
 }
 
 void Imx227Device::ShutDown() {
@@ -404,7 +392,39 @@
 }
 
 zx_status_t imx227_bind(void* ctx, zx_device_t* device) {
-    return camera::Imx227Device::Create(ctx, device);
+    std::unique_ptr<Imx227Device> sensor_device;
+    zx_status_t status = camera::Imx227Device::Setup(ctx, device, &sensor_device);
+    if (status != ZX_OK) {
+        zxlogf(ERROR, "imx227: Could not setup imx227 sensor device: %d\n", status);
+        return status;
+    }
+    zx_device_prop_t props[] = {
+        {BIND_PLATFORM_DEV_VID, 0, PDEV_VID_SONY},
+        {BIND_PLATFORM_DEV_PID, 0, PDEV_PID_SONY_IMX227},
+        {BIND_PLATFORM_DEV_DID, 0, PDEV_DID_CAMERA_SENSOR},
+    };
+
+    // Run the unit tests for this device
+    // TODO(braval): CAM-44 (Run only when build flag enabled)
+    // This needs to be replaced with run unittests hooks when
+    // the framework is available.
+    status = camera::Imx227DeviceTester::RunTests(sensor_device.get());
+    if (status != ZX_OK) {
+        zxlogf(ERROR, "%s: Device Unit Tests Failed \n", __func__);
+        return status;
+    }
+
+    status = sensor_device->DdkAdd("imx227", 0, props, countof(props));
+    if (status != ZX_OK) {
+        zxlogf(ERROR, "imx227: Could not add imx227 sensor device: %d\n", status);
+        return status;
+    } else {
+        zxlogf(INFO, "imx227 driver added\n");
+    }
+
+    // sensor_device intentionally leaked as it is now held by DevMgr.
+    __UNUSED auto* dev = sensor_device.release();
+    return ZX_OK;
 }
 
 static zx_driver_ops_t driver_ops = []() {
diff --git a/zircon/system/dev/camera/imx227/imx227.h b/zircon/system/dev/camera/imx227/imx227.h
index cf80fbd..dcc9739 100644
--- a/zircon/system/dev/camera/imx227/imx227.h
+++ b/zircon/system/dev/camera/imx227/imx227.h
@@ -72,7 +72,9 @@
         : DeviceType(device), i2c_(i2c), gpio_vana_enable_(gpio_vana),
           gpio_vdig_enable_(gpio_vdig), gpio_cam_rst_(gpio_cam_rst),
           clk24_(clk24), mipi_(mipicsi) {}
-
+    static zx_status_t Setup(void* ctx,
+                             zx_device_t* parent,
+                             std::unique_ptr<Imx227Device>* device);
     // Methods required by the ddk mixins.
     void DdkUnbind();
     void DdkRelease();
@@ -97,6 +99,7 @@
                                               size_t* out_modes_actual);
 
 private:
+    friend class Imx227DeviceTester;
     // Sensor Context
     sensor_context_t ctx_;
 
diff --git a/zircon/system/ulib/ddk/include/ddk/protodefs.h b/zircon/system/ulib/ddk/include/ddk/protodefs.h
index 404f048..e4bfaaf 100644
--- a/zircon/system/ulib/ddk/include/ddk/protodefs.h
+++ b/zircon/system/ulib/ddk/include/ddk/protodefs.h
@@ -104,7 +104,6 @@
 DDK_PROTOCOL_DEF(QMI_TRANSPORT,  'pQMI', "qmi-transport", 0)
 DDK_PROTOCOL_DEF(MIPI_CSI,       'pMIP', "mipi-csi", PF_NOPUB)
 DDK_PROTOCOL_DEF(LIGHT,          'pLIG', "light", 0)
-DDK_PROTOCOL_DEF(ISP_IMPL,       'pIPL', "isp-impl", PF_NOPUB)
 DDK_PROTOCOL_DEF(DSI_IMPL,       'pDSI', "dsi-impl", PF_NOPUB)
 DDK_PROTOCOL_DEF(POWER_IMPL,     'pPWI', "power-impl", PF_NOPUB)
 // Protocol definition at garnet/magma/src/magma_util/platform/zircon/zircon_platform_ioctl.h