1// Copyright 2017 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <ddktl/device.h> 6#include <fbl/alloc_checker.h> 7#include <fbl/unique_ptr.h> 8#include <unittest/unittest.h> 9 10//#define TEST_WILL_NOT_COMPILE 1 11 12namespace { 13 14class TestNone : public ddk::Device<TestNone> { 15 public: 16 TestNone() : ddk::Device<TestNone>(nullptr) {} 17 18 void DdkRelease() {} 19}; 20 21#define BEGIN_SUCCESS_CASE(name) \ 22class Test##name : public ddk::Device<Test##name, ddk::name> { \ 23 public: \ 24 Test##name() : ddk::Device<Test##name, ddk::name>(nullptr) {} \ 25 void DdkRelease() {} 26 27#define END_SUCCESS_CASE }; 28 29BEGIN_SUCCESS_CASE(GetProtocolable) 30 zx_status_t DdkGetProtocol(uint32_t proto_id, void* protocol) { return ZX_OK; } 31END_SUCCESS_CASE 32 33BEGIN_SUCCESS_CASE(Openable) 34 zx_status_t DdkOpen(zx_device_t** dev_out, uint32_t flags) { return ZX_OK; } 35END_SUCCESS_CASE 36 37BEGIN_SUCCESS_CASE(OpenAtable) 38 zx_status_t DdkOpenAt(zx_device_t** dev_out, const char* path, uint32_t flags) { 39 return ZX_OK; 40 } 41END_SUCCESS_CASE 42 43BEGIN_SUCCESS_CASE(Closable) 44 zx_status_t DdkClose(uint32_t flags) { return ZX_OK; } 45END_SUCCESS_CASE 46 47BEGIN_SUCCESS_CASE(Unbindable) 48 void DdkUnbind() {} 49END_SUCCESS_CASE 50 51BEGIN_SUCCESS_CASE(Readable) 52 zx_status_t DdkRead(void* buf, size_t count, zx_off_t off, size_t* actual) { return ZX_OK; } 53END_SUCCESS_CASE 54 55BEGIN_SUCCESS_CASE(Writable) 56 zx_status_t DdkWrite(const void* buf, size_t count, zx_off_t off, size_t* actual) { 57 return ZX_OK; 58 } 59END_SUCCESS_CASE 60 61BEGIN_SUCCESS_CASE(GetSizable) 62 zx_off_t DdkGetSize() { return 0; } 63END_SUCCESS_CASE 64 65BEGIN_SUCCESS_CASE(Ioctlable) 66 zx_status_t DdkIoctl(uint32_t op, const void* in_buf, size_t in_len, void* out_buf, 67 size_t out_len, size_t* out_actual) { 68 return ZX_OK; 69 } 70END_SUCCESS_CASE 71 72BEGIN_SUCCESS_CASE(Messageable) 73 zx_status_t DdkMessage(fidl_msg_t* msg, fidl_txn_t* txn) { 74 return ZX_OK; 75 } 76END_SUCCESS_CASE 77 78BEGIN_SUCCESS_CASE(Suspendable) 79 zx_status_t DdkSuspend(uint32_t flags) { return ZX_OK; } 80END_SUCCESS_CASE 81 82BEGIN_SUCCESS_CASE(Resumable) 83 zx_status_t DdkResume(uint32_t flags) { return ZX_OK; } 84END_SUCCESS_CASE 85 86BEGIN_SUCCESS_CASE(Rxrpcable) 87 zx_status_t DdkRxrpc(zx_handle_t channel) { return ZX_OK; } 88END_SUCCESS_CASE 89 90template <typename T> 91static bool do_test() { 92 BEGIN_TEST; 93 94 fbl::AllocChecker ac; 95 auto dev = fbl::unique_ptr<T>(new (&ac) T); 96 ASSERT_TRUE(ac.check(), ""); 97 98 END_TEST; 99} 100 101struct TestDispatch : public ddk::FullDevice<TestDispatch> { 102 TestDispatch() : ddk::FullDevice<TestDispatch>(nullptr) {} 103 104 // Give access to the device ops for testing 105 zx_protocol_device_t* GetDeviceOps() { 106 return &ddk_device_proto_; 107 } 108 109 zx_status_t DdkGetProtocol(uint32_t proto_id, void* protcool) { 110 get_protocol_called = true; 111 return ZX_OK; 112 } 113 114 zx_status_t DdkOpen(zx_device_t** dev_out, uint32_t flags) { 115 open_called = true; 116 return ZX_OK; 117 } 118 119 zx_status_t DdkOpenAt(zx_device_t** dev_out, const char* path, uint32_t flags) { 120 open_at_called = true; 121 return ZX_OK; 122 } 123 124 zx_status_t DdkClose(uint32_t flags) { 125 close_called = true; 126 return ZX_OK; 127 } 128 129 void DdkUnbind() { 130 unbind_called = true; 131 } 132 133 void DdkRelease() { 134 release_called = true; 135 } 136 137 zx_status_t DdkRead(void* buf, size_t count, zx_off_t off, size_t* actual) { 138 read_called = true; 139 return ZX_OK; 140 } 141 142 zx_status_t DdkWrite(const void* buf, size_t count, zx_off_t off, size_t* actual) { 143 write_called = true; 144 return ZX_OK; 145 } 146 147 zx_off_t DdkGetSize() { 148 get_size_called = true; 149 return 0; 150 } 151 152 zx_status_t DdkIoctl(uint32_t op, const void* in_buf, size_t in_len, void* out_buf, 153 size_t out_len, size_t* out_actual) { 154 ioctl_called = true; 155 return ZX_OK; 156 } 157 158 zx_status_t DdkSuspend(uint32_t flags) { 159 suspend_called = true; 160 return ZX_OK; 161 } 162 163 zx_status_t DdkResume(uint32_t flags) { 164 resume_called = true; 165 return ZX_OK; 166 } 167 168 zx_status_t DdkRxrpc(zx_handle_t channel) { 169 rxrpc_called = true; 170 return ZX_OK; 171 } 172 173 bool get_protocol_called = false; 174 bool open_called = false; 175 bool open_at_called = false; 176 bool close_called = false; 177 bool unbind_called = false; 178 bool release_called = false; 179 bool read_called = false; 180 bool write_called = false; 181 bool get_size_called = false; 182 bool ioctl_called = false; 183 bool suspend_called = false; 184 bool resume_called = false; 185 bool rxrpc_called = false; 186}; 187 188static bool test_dispatch() { 189 BEGIN_TEST; 190 191 fbl::AllocChecker ac; 192 auto dev = fbl::unique_ptr<TestDispatch>(new (&ac) TestDispatch); 193 ASSERT_TRUE(ac.check(), ""); 194 195 // Since we're not adding the device to devmgr, we don't have a valid zx_device_t. 196 // TODO: use a devmgr API to add a test device, and use that instead 197 auto ctx = dev.get(); 198 auto ops = dev->GetDeviceOps(); 199 EXPECT_EQ(ZX_OK, ops->get_protocol(ctx, 0, nullptr), ""); 200 EXPECT_EQ(ZX_OK, ops->open(ctx, nullptr, 0), ""); 201 EXPECT_EQ(ZX_OK, ops->open_at(ctx, nullptr, "", 0), ""); 202 EXPECT_EQ(ZX_OK, ops->close(ctx, 0), ""); 203 ops->unbind(ctx); 204 ops->release(ctx); 205 EXPECT_EQ(ZX_OK, ops->read(ctx, nullptr, 0, 0, nullptr), ""); 206 EXPECT_EQ(ZX_OK, ops->write(ctx, nullptr, 0, 0, nullptr), ""); 207 EXPECT_EQ(0, ops->get_size(ctx), ""); 208 EXPECT_EQ(ZX_OK, ops->ioctl(ctx, 0, nullptr, 0, nullptr, 0, nullptr), ""); 209 EXPECT_EQ(ZX_OK, ops->suspend(ctx, 0), ""); 210 EXPECT_EQ(ZX_OK, ops->resume(ctx, 0), ""); 211 EXPECT_EQ(ZX_OK, ops->rxrpc(ctx, 0), ""); 212 213 EXPECT_TRUE(dev->get_protocol_called, ""); 214 EXPECT_TRUE(dev->open_called, ""); 215 EXPECT_TRUE(dev->open_at_called, ""); 216 EXPECT_TRUE(dev->close_called, ""); 217 EXPECT_TRUE(dev->unbind_called, ""); 218 EXPECT_TRUE(dev->release_called, ""); 219 EXPECT_TRUE(dev->read_called, ""); 220 EXPECT_TRUE(dev->write_called, ""); 221 EXPECT_TRUE(dev->get_size_called, ""); 222 EXPECT_TRUE(dev->ioctl_called, ""); 223 EXPECT_TRUE(dev->suspend_called, ""); 224 EXPECT_TRUE(dev->resume_called, ""); 225 EXPECT_TRUE(dev->rxrpc_called, ""); 226 227 END_TEST; 228} 229 230#if TEST_WILL_NOT_COMPILE || 0 231 232class TestNotReleasable : public ddk::Device<TestNotReleasable> { 233 public: 234 TestNotReleasable() : ddk::Device<TestNotReleasable>(nullptr) {} 235}; 236 237#define DEFINE_FAIL_CASE(name) \ 238class TestNot##name : public ddk::Device<TestNot##name, ddk::name> { \ 239 public: \ 240 TestNot##name() : ddk::Device<TestNot##name, ddk::name>(nullptr) {} \ 241 void DdkRelease() {} \ 242}; 243 244DEFINE_FAIL_CASE(GetProtocolable) 245DEFINE_FAIL_CASE(Openable) 246DEFINE_FAIL_CASE(OpenAtable) 247DEFINE_FAIL_CASE(Closable) 248DEFINE_FAIL_CASE(Unbindable) 249DEFINE_FAIL_CASE(Readable) 250DEFINE_FAIL_CASE(Writable) 251DEFINE_FAIL_CASE(IotxnQueueable) 252DEFINE_FAIL_CASE(GetSizable) 253DEFINE_FAIL_CASE(Ioctlable) 254DEFINE_FAIL_CASE(Suspendable) 255DEFINE_FAIL_CASE(Resumable) 256DEFINE_FAIL_CASE(Rxrpcable) 257 258class TestBadOverride : public ddk::Device<TestBadOverride, ddk::Closable> { 259 public: 260 TestBadOverride() : ddk::Device<TestBadOverride, ddk::Closable>(nullptr) {} 261 void DdkRelease() {} 262 263 void DdkClose(uint32_t flags) {} 264}; 265 266class TestHiddenOverride : public ddk::Device<TestHiddenOverride, ddk::Closable> { 267 public: 268 TestHiddenOverride() 269 : ddk::Device<TestHiddenOverride, ddk::Closable>(nullptr) {} 270 void DdkRelease() {} 271 272 private: 273 zx_status_t DdkClose(uint32_t flags) { return ZX_OK; } 274}; 275 276class TestStaticOverride : public ddk::Device<TestStaticOverride, ddk::Closable> { 277 public: 278 TestStaticOverride() 279 : ddk::Device<TestStaticOverride, ddk::Closable>(nullptr) {} 280 void DdkRelease() {} 281 282 static zx_status_t DdkClose(uint32_t flags) { return ZX_OK; } 283}; 284 285template <typename D> 286struct A { 287 explicit A(zx_protocol_device_t* proto) {} 288}; 289 290class TestNotAMixin : public ddk::Device<TestNotAMixin, A> { 291 public: 292 TestNotAMixin() : ddk::Device<TestNotAMixin, A>(nullptr) {} 293 void DdkRelease() {} 294}; 295 296class TestNotAllMixins; 297using TestNotAllMixinsType = ddk::Device<TestNotAllMixins, 298 ddk::Openable, 299 ddk::Closable, 300 A>; 301class TestNotAllMixins : public TestNotAllMixinsType { 302 public: 303 TestNotAllMixins() : TestNotAllMixinsType(nullptr) {} 304 void DdkRelease() {} 305 zx_status_t DdkOpen(zx_device_t** dev_out, uint32_t flags) { return ZX_OK; } 306 zx_status_t DdkClose(uint32_t flags) { return ZX_OK; } 307}; 308#endif 309 310} // namespace 311 312BEGIN_TEST_CASE(ddktl_device) 313RUN_NAMED_TEST("No mixins", do_test<TestNone>); 314RUN_NAMED_TEST("ddk::GetProtocolable", do_test<TestGetProtocolable>); 315RUN_NAMED_TEST("ddk::Openable", do_test<TestOpenable>); 316RUN_NAMED_TEST("ddk::OpenAtable", do_test<TestOpenAtable>); 317RUN_NAMED_TEST("ddk::Closable", do_test<TestClosable>); 318RUN_NAMED_TEST("ddk::Unbindable", do_test<TestUnbindable>); 319RUN_NAMED_TEST("ddk::Readable", do_test<TestReadable>); 320RUN_NAMED_TEST("ddk::Writable", do_test<TestWritable>); 321RUN_NAMED_TEST("ddk::GetSizable", do_test<TestGetSizable>); 322RUN_NAMED_TEST("ddk::Ioctlable", do_test<TestIoctlable>); 323RUN_NAMED_TEST("ddk::Suspendable", do_test<TestSuspendable>); 324RUN_NAMED_TEST("ddk::Resumable", do_test<TestResumable>); 325RUN_NAMED_TEST("ddk::Rxrpcable", do_test<TestRxrpcable>); 326 327RUN_NAMED_TEST("Method dispatch test", test_dispatch); 328 329#if TEST_WILL_NOT_COMPILE || 0 330RUN_NAMED_TEST("FailNoDdkGetProtocol", do_test<TestNotGetProtocolable>); 331RUN_NAMED_TEST("FailNoDdkOpen", do_test<TestNotOpenable>); 332RUN_NAMED_TEST("FailNoDdkOpenAt", do_test<TestNotOpenAtable>); 333RUN_NAMED_TEST("FailNoDdkClose", do_test<TestNotClosable>); 334RUN_NAMED_TEST("FailNoDdkUnbind", do_test<TestNotUnbindable>); 335RUN_NAMED_TEST("FailNoDdkRelease", do_test<TestNotReleasable>); 336RUN_NAMED_TEST("FailNoDdkRead", do_test<TestNotReadable>); 337RUN_NAMED_TEST("FailNoDdkWrite", do_test<TestNotWritable>); 338RUN_NAMED_TEST("FailNoDdkIotxnQueue", do_test<TestNotIotxnQueueable>); 339RUN_NAMED_TEST("FailNoDdkGetSize", do_test<TestNotGetSizable>); 340RUN_NAMED_TEST("FailNoDdkIoctl", do_test<TestNotIoctlable>); 341RUN_NAMED_TEST("FailNoDdkSuspend", do_test<TestNotSuspendable>); 342RUN_NAMED_TEST("FailNoDdkResume", do_test<TestNotResumable>); 343RUN_NAMED_TEST("FailNoDdkRxrpc", do_test<TestNotRxrpcable>); 344RUN_NAMED_TEST("FailBadOverride", do_test<TestBadOverride>); 345RUN_NAMED_TEST("FailHiddenOverride", do_test<TestHiddenOverride>); 346RUN_NAMED_TEST("FailStaticOverride", do_test<TestStaticOverride>); 347RUN_NAMED_TEST("FailNotAMixin", do_test<TestNotAMixin>); 348RUN_NAMED_TEST("FailNotAllMixins", do_test<TestNotAllMixins>); 349#endif 350END_TEST_CASE(ddktl_device); 351 352test_case_element* test_case_ddktl_device = TEST_CASE_ELEMENT(ddktl_device); 353