// Copyright 2017 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 #include #include #include //#define TEST_WILL_NOT_COMPILE 1 namespace { class TestNone : public ddk::Device { public: TestNone() : ddk::Device(nullptr) {} void DdkRelease() {} }; #define BEGIN_SUCCESS_CASE(name) \ class Test##name : public ddk::Device { \ public: \ Test##name() : ddk::Device(nullptr) {} \ void DdkRelease() {} #define END_SUCCESS_CASE }; BEGIN_SUCCESS_CASE(GetProtocolable) zx_status_t DdkGetProtocol(uint32_t proto_id, void* protocol) { return ZX_OK; } END_SUCCESS_CASE BEGIN_SUCCESS_CASE(Openable) zx_status_t DdkOpen(zx_device_t** dev_out, uint32_t flags) { return ZX_OK; } END_SUCCESS_CASE BEGIN_SUCCESS_CASE(OpenAtable) zx_status_t DdkOpenAt(zx_device_t** dev_out, const char* path, uint32_t flags) { return ZX_OK; } END_SUCCESS_CASE BEGIN_SUCCESS_CASE(Closable) zx_status_t DdkClose(uint32_t flags) { return ZX_OK; } END_SUCCESS_CASE BEGIN_SUCCESS_CASE(Unbindable) void DdkUnbind() {} END_SUCCESS_CASE BEGIN_SUCCESS_CASE(Readable) zx_status_t DdkRead(void* buf, size_t count, zx_off_t off, size_t* actual) { return ZX_OK; } END_SUCCESS_CASE BEGIN_SUCCESS_CASE(Writable) zx_status_t DdkWrite(const void* buf, size_t count, zx_off_t off, size_t* actual) { return ZX_OK; } END_SUCCESS_CASE BEGIN_SUCCESS_CASE(GetSizable) zx_off_t DdkGetSize() { return 0; } END_SUCCESS_CASE BEGIN_SUCCESS_CASE(Ioctlable) zx_status_t DdkIoctl(uint32_t op, const void* in_buf, size_t in_len, void* out_buf, size_t out_len, size_t* out_actual) { return ZX_OK; } END_SUCCESS_CASE BEGIN_SUCCESS_CASE(Messageable) zx_status_t DdkMessage(fidl_msg_t* msg, fidl_txn_t* txn) { return ZX_OK; } END_SUCCESS_CASE BEGIN_SUCCESS_CASE(Suspendable) zx_status_t DdkSuspend(uint32_t flags) { return ZX_OK; } END_SUCCESS_CASE BEGIN_SUCCESS_CASE(Resumable) zx_status_t DdkResume(uint32_t flags) { return ZX_OK; } END_SUCCESS_CASE BEGIN_SUCCESS_CASE(Rxrpcable) zx_status_t DdkRxrpc(zx_handle_t channel) { return ZX_OK; } END_SUCCESS_CASE template static bool do_test() { BEGIN_TEST; fbl::AllocChecker ac; auto dev = fbl::unique_ptr(new (&ac) T); ASSERT_TRUE(ac.check(), ""); END_TEST; } struct TestDispatch : public ddk::FullDevice { TestDispatch() : ddk::FullDevice(nullptr) {} // Give access to the device ops for testing zx_protocol_device_t* GetDeviceOps() { return &ddk_device_proto_; } zx_status_t DdkGetProtocol(uint32_t proto_id, void* protcool) { get_protocol_called = true; return ZX_OK; } zx_status_t DdkOpen(zx_device_t** dev_out, uint32_t flags) { open_called = true; return ZX_OK; } zx_status_t DdkOpenAt(zx_device_t** dev_out, const char* path, uint32_t flags) { open_at_called = true; return ZX_OK; } zx_status_t DdkClose(uint32_t flags) { close_called = true; return ZX_OK; } void DdkUnbind() { unbind_called = true; } void DdkRelease() { release_called = true; } zx_status_t DdkRead(void* buf, size_t count, zx_off_t off, size_t* actual) { read_called = true; return ZX_OK; } zx_status_t DdkWrite(const void* buf, size_t count, zx_off_t off, size_t* actual) { write_called = true; return ZX_OK; } zx_off_t DdkGetSize() { get_size_called = true; return 0; } zx_status_t DdkIoctl(uint32_t op, const void* in_buf, size_t in_len, void* out_buf, size_t out_len, size_t* out_actual) { ioctl_called = true; return ZX_OK; } zx_status_t DdkSuspend(uint32_t flags) { suspend_called = true; return ZX_OK; } zx_status_t DdkResume(uint32_t flags) { resume_called = true; return ZX_OK; } zx_status_t DdkRxrpc(zx_handle_t channel) { rxrpc_called = true; return ZX_OK; } bool get_protocol_called = false; bool open_called = false; bool open_at_called = false; bool close_called = false; bool unbind_called = false; bool release_called = false; bool read_called = false; bool write_called = false; bool get_size_called = false; bool ioctl_called = false; bool suspend_called = false; bool resume_called = false; bool rxrpc_called = false; }; static bool test_dispatch() { BEGIN_TEST; fbl::AllocChecker ac; auto dev = fbl::unique_ptr(new (&ac) TestDispatch); ASSERT_TRUE(ac.check(), ""); // Since we're not adding the device to devmgr, we don't have a valid zx_device_t. // TODO: use a devmgr API to add a test device, and use that instead auto ctx = dev.get(); auto ops = dev->GetDeviceOps(); EXPECT_EQ(ZX_OK, ops->get_protocol(ctx, 0, nullptr), ""); EXPECT_EQ(ZX_OK, ops->open(ctx, nullptr, 0), ""); EXPECT_EQ(ZX_OK, ops->open_at(ctx, nullptr, "", 0), ""); EXPECT_EQ(ZX_OK, ops->close(ctx, 0), ""); ops->unbind(ctx); ops->release(ctx); EXPECT_EQ(ZX_OK, ops->read(ctx, nullptr, 0, 0, nullptr), ""); EXPECT_EQ(ZX_OK, ops->write(ctx, nullptr, 0, 0, nullptr), ""); EXPECT_EQ(0, ops->get_size(ctx), ""); EXPECT_EQ(ZX_OK, ops->ioctl(ctx, 0, nullptr, 0, nullptr, 0, nullptr), ""); EXPECT_EQ(ZX_OK, ops->suspend(ctx, 0), ""); EXPECT_EQ(ZX_OK, ops->resume(ctx, 0), ""); EXPECT_EQ(ZX_OK, ops->rxrpc(ctx, 0), ""); EXPECT_TRUE(dev->get_protocol_called, ""); EXPECT_TRUE(dev->open_called, ""); EXPECT_TRUE(dev->open_at_called, ""); EXPECT_TRUE(dev->close_called, ""); EXPECT_TRUE(dev->unbind_called, ""); EXPECT_TRUE(dev->release_called, ""); EXPECT_TRUE(dev->read_called, ""); EXPECT_TRUE(dev->write_called, ""); EXPECT_TRUE(dev->get_size_called, ""); EXPECT_TRUE(dev->ioctl_called, ""); EXPECT_TRUE(dev->suspend_called, ""); EXPECT_TRUE(dev->resume_called, ""); EXPECT_TRUE(dev->rxrpc_called, ""); END_TEST; } #if TEST_WILL_NOT_COMPILE || 0 class TestNotReleasable : public ddk::Device { public: TestNotReleasable() : ddk::Device(nullptr) {} }; #define DEFINE_FAIL_CASE(name) \ class TestNot##name : public ddk::Device { \ public: \ TestNot##name() : ddk::Device(nullptr) {} \ void DdkRelease() {} \ }; DEFINE_FAIL_CASE(GetProtocolable) DEFINE_FAIL_CASE(Openable) DEFINE_FAIL_CASE(OpenAtable) DEFINE_FAIL_CASE(Closable) DEFINE_FAIL_CASE(Unbindable) DEFINE_FAIL_CASE(Readable) DEFINE_FAIL_CASE(Writable) DEFINE_FAIL_CASE(IotxnQueueable) DEFINE_FAIL_CASE(GetSizable) DEFINE_FAIL_CASE(Ioctlable) DEFINE_FAIL_CASE(Suspendable) DEFINE_FAIL_CASE(Resumable) DEFINE_FAIL_CASE(Rxrpcable) class TestBadOverride : public ddk::Device { public: TestBadOverride() : ddk::Device(nullptr) {} void DdkRelease() {} void DdkClose(uint32_t flags) {} }; class TestHiddenOverride : public ddk::Device { public: TestHiddenOverride() : ddk::Device(nullptr) {} void DdkRelease() {} private: zx_status_t DdkClose(uint32_t flags) { return ZX_OK; } }; class TestStaticOverride : public ddk::Device { public: TestStaticOverride() : ddk::Device(nullptr) {} void DdkRelease() {} static zx_status_t DdkClose(uint32_t flags) { return ZX_OK; } }; template struct A { explicit A(zx_protocol_device_t* proto) {} }; class TestNotAMixin : public ddk::Device { public: TestNotAMixin() : ddk::Device(nullptr) {} void DdkRelease() {} }; class TestNotAllMixins; using TestNotAllMixinsType = ddk::Device; class TestNotAllMixins : public TestNotAllMixinsType { public: TestNotAllMixins() : TestNotAllMixinsType(nullptr) {} void DdkRelease() {} zx_status_t DdkOpen(zx_device_t** dev_out, uint32_t flags) { return ZX_OK; } zx_status_t DdkClose(uint32_t flags) { return ZX_OK; } }; #endif } // namespace BEGIN_TEST_CASE(ddktl_device) RUN_NAMED_TEST("No mixins", do_test); RUN_NAMED_TEST("ddk::GetProtocolable", do_test); RUN_NAMED_TEST("ddk::Openable", do_test); RUN_NAMED_TEST("ddk::OpenAtable", do_test); RUN_NAMED_TEST("ddk::Closable", do_test); RUN_NAMED_TEST("ddk::Unbindable", do_test); RUN_NAMED_TEST("ddk::Readable", do_test); RUN_NAMED_TEST("ddk::Writable", do_test); RUN_NAMED_TEST("ddk::GetSizable", do_test); RUN_NAMED_TEST("ddk::Ioctlable", do_test); RUN_NAMED_TEST("ddk::Suspendable", do_test); RUN_NAMED_TEST("ddk::Resumable", do_test); RUN_NAMED_TEST("ddk::Rxrpcable", do_test); RUN_NAMED_TEST("Method dispatch test", test_dispatch); #if TEST_WILL_NOT_COMPILE || 0 RUN_NAMED_TEST("FailNoDdkGetProtocol", do_test); RUN_NAMED_TEST("FailNoDdkOpen", do_test); RUN_NAMED_TEST("FailNoDdkOpenAt", do_test); RUN_NAMED_TEST("FailNoDdkClose", do_test); RUN_NAMED_TEST("FailNoDdkUnbind", do_test); RUN_NAMED_TEST("FailNoDdkRelease", do_test); RUN_NAMED_TEST("FailNoDdkRead", do_test); RUN_NAMED_TEST("FailNoDdkWrite", do_test); RUN_NAMED_TEST("FailNoDdkIotxnQueue", do_test); RUN_NAMED_TEST("FailNoDdkGetSize", do_test); RUN_NAMED_TEST("FailNoDdkIoctl", do_test); RUN_NAMED_TEST("FailNoDdkSuspend", do_test); RUN_NAMED_TEST("FailNoDdkResume", do_test); RUN_NAMED_TEST("FailNoDdkRxrpc", do_test); RUN_NAMED_TEST("FailBadOverride", do_test); RUN_NAMED_TEST("FailHiddenOverride", do_test); RUN_NAMED_TEST("FailStaticOverride", do_test); RUN_NAMED_TEST("FailNotAMixin", do_test); RUN_NAMED_TEST("FailNotAllMixins", do_test); #endif END_TEST_CASE(ddktl_device); test_case_element* test_case_ddktl_device = TEST_CASE_ELEMENT(ddktl_device);