| // Copyright 2020 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 <lib/fake_ddk/fake_ddk.h> |
| #include <lib/zx/vmo.h> |
| |
| #include <ddktl/device.h> |
| #include <zxtest/zxtest.h> |
| |
| TEST(FakeDdk, InspectVmoLeak) { |
| fake_ddk::Bind bind; |
| |
| zx::vmo inspect_vmo; |
| ASSERT_OK(zx::vmo::create(4096u, 0, &inspect_vmo)); |
| |
| zx::vmo dup_vmo; |
| ASSERT_OK(inspect_vmo.duplicate(ZX_RIGHT_SAME_RIGHTS, &dup_vmo)); |
| |
| ddk::DeviceAddArgs args("test-driver"); |
| args.set_inspect_vmo(std::move(dup_vmo)); |
| device_add_args_t device_args = args.get(); |
| |
| zx_device_t* device; |
| EXPECT_OK(device_add(fake_ddk::kFakeParent, &device_args, &device)); |
| |
| device_async_remove(device); |
| EXPECT_TRUE(bind.Ok()); |
| |
| zx_info_handle_count_t count; |
| ASSERT_OK(inspect_vmo.get_info(ZX_INFO_HANDLE_COUNT, &count, sizeof(count), nullptr, nullptr)); |
| |
| // |inspect_vmo| should be the only handle. |
| EXPECT_EQ(1u, count.handle_count); |
| } |
| |
| TEST(FakeDdk, SetMetadata) { |
| fake_ddk::Bind bind; |
| |
| // Can't get metadata to begin. |
| char buf[10] = {}; |
| size_t actual = 0; |
| size_t size = 0; |
| ASSERT_NE(device_get_metadata(nullptr, 42, buf, sizeof(buf), &actual), ZX_OK); |
| ASSERT_NE(device_get_metadata_size(nullptr, 42, &size), ZX_OK); |
| |
| const char kSource[] = "test"; |
| bind.SetMetadata(42, kSource, sizeof(kSource)); |
| |
| // Can get metadata with correct type after setting. |
| ASSERT_OK(device_get_metadata(nullptr, 42, buf, sizeof(buf), &actual)); |
| ASSERT_EQ(actual, sizeof(kSource)); |
| ASSERT_BYTES_EQ(buf, kSource, sizeof(kSource)); |
| ASSERT_OK(device_get_metadata_size(nullptr, 42, &size)); |
| ASSERT_EQ(size, sizeof(kSource)); |
| |
| // Can't get metadata with incorrect type after setting. |
| ASSERT_NE(device_get_metadata(nullptr, 1, buf, sizeof(buf), &actual), ZX_OK); |
| ASSERT_NE(device_get_metadata_size(nullptr, 1, &size), ZX_OK); |
| |
| const char kSource2[] = "other"; |
| bind.SetMetadata(1, kSource2, sizeof(kSource2)); |
| |
| // We can get it after setting it though |
| ASSERT_OK(device_get_metadata(nullptr, 1, buf, sizeof(buf), &actual)); |
| ASSERT_EQ(actual, sizeof(kSource2)); |
| ASSERT_BYTES_EQ(buf, kSource2, sizeof(kSource2)); |
| ASSERT_OK(device_get_metadata_size(nullptr, 1, &size)); |
| ASSERT_EQ(size, sizeof(kSource2)); |
| |
| // Original metadata still works too |
| ASSERT_OK(device_get_metadata(nullptr, 42, buf, sizeof(buf), &actual)); |
| ASSERT_EQ(actual, sizeof(kSource)); |
| ASSERT_BYTES_EQ(buf, kSource, sizeof(kSource)); |
| ASSERT_OK(device_get_metadata_size(nullptr, 42, &size)); |
| ASSERT_EQ(size, sizeof(kSource)); |
| } |
| |
| TEST(FakeDdk, SetProtocol) { |
| fake_ddk::Bind bind; |
| |
| fake_ddk::Protocol proto = {}; |
| EXPECT_NE(device_get_protocol(fake_ddk::FakeParent(), 8, &proto), ZX_OK); |
| |
| const fake_ddk::Protocol kTestProto = { |
| .ctx = reinterpret_cast<void*>(0x10), |
| }; |
| bind.SetProtocol(8, &kTestProto); |
| |
| // Protocol is available after being set. |
| EXPECT_OK(device_get_protocol(fake_ddk::FakeParent(), 8, &proto)); |
| EXPECT_BYTES_EQ(&proto, &kTestProto, sizeof(proto)); |
| |
| // Incorrect proto ids still fail. |
| EXPECT_NE(device_get_protocol(fake_ddk::FakeParent(), 0, &proto), ZX_OK); |
| |
| // nullptr removes it. |
| bind.SetProtocol(8, nullptr); |
| EXPECT_NE(device_get_protocol(fake_ddk::FakeParent(), 8, &proto), ZX_OK); |
| } |
| |
| class CompositeTest : public zxtest::Test { |
| public: |
| ~CompositeTest() override = default; |
| void SetUp() override { |
| fbl::Array<fake_ddk::FragmentEntry> fragments(new fake_ddk::FragmentEntry[2], 2); |
| fragments[0].name = "fragment-1"; |
| fragments[0].protocols.emplace_back( |
| fake_ddk::ProtocolEntry{0, fake_ddk::Protocol{nullptr, nullptr}}); |
| fragments[0].protocols.emplace_back( |
| fake_ddk::ProtocolEntry{1, fake_ddk::Protocol{nullptr, nullptr}}); |
| fragments[1].name = "fragment-2"; |
| fragments[1].protocols.emplace_back( |
| fake_ddk::ProtocolEntry{2, fake_ddk::Protocol{nullptr, nullptr}}); |
| |
| bind.SetFragments(std::move(fragments)); |
| } |
| |
| private: |
| fake_ddk::Bind bind; |
| }; |
| |
| TEST_F(CompositeTest, GetFragmentCount) { |
| EXPECT_EQ(device_get_fragment_count(fake_ddk::FakeParent()), 2); |
| } |
| |
| TEST_F(CompositeTest, GetProtocolParent) { |
| // Protocols are not available under parent device. |
| fake_ddk::Protocol proto = {}; |
| EXPECT_NE(device_get_protocol(fake_ddk::FakeParent(), 0, &proto), ZX_OK); |
| EXPECT_NE(device_get_protocol(fake_ddk::FakeParent(), 1, &proto), ZX_OK); |
| EXPECT_NE(device_get_protocol(fake_ddk::FakeParent(), 2, &proto), ZX_OK); |
| } |
| |
| TEST_F(CompositeTest, GetFragment) { |
| zx_device_t *fragment1, *fragment2; |
| EXPECT_TRUE(device_get_fragment(fake_ddk::FakeParent(), "fragment-1", &fragment1)); |
| EXPECT_TRUE(device_get_fragment(fake_ddk::FakeParent(), "fragment-2", &fragment2)); |
| |
| // Only first two protocols are availably in fragment-1. |
| fake_ddk::Protocol proto = {}; |
| EXPECT_OK(device_get_protocol(fragment1, 0, &proto)); |
| EXPECT_OK(device_get_protocol(fragment1, 1, &proto)); |
| EXPECT_NE(device_get_protocol(fragment1, 2, &proto), ZX_OK); |
| |
| // Only last protocols is availably in fragment-2. |
| EXPECT_NE(device_get_protocol(fragment2, 0, &proto), ZX_OK); |
| EXPECT_NE(device_get_protocol(fragment2, 1, &proto), ZX_OK); |
| EXPECT_OK(device_get_protocol(fragment2, 2, &proto)); |
| } |
| |
| TEST_F(CompositeTest, GetFragments) { |
| composite_device_fragment_t fragments[2] = {}; |
| size_t actual; |
| device_get_fragments(fake_ddk::FakeParent(), fragments, 2, &actual); |
| EXPECT_EQ(actual, 2); |
| |
| // Fragment names line up |
| EXPECT_EQ(strcmp(fragments[0].name, "fragment-1"), 0); |
| EXPECT_EQ(strcmp(fragments[1].name, "fragment-2"), 0); |
| |
| // Only first two protocols are availably in fragment-1. |
| fake_ddk::Protocol proto = {}; |
| EXPECT_OK(device_get_protocol(fragments[0].device, 0, &proto)); |
| EXPECT_OK(device_get_protocol(fragments[0].device, 1, &proto)); |
| EXPECT_NE(device_get_protocol(fragments[0].device, 2, &proto), ZX_OK); |
| |
| // Only last protocols is availably in fragment-2. |
| EXPECT_NE(device_get_protocol(fragments[1].device, 0, &proto), ZX_OK); |
| EXPECT_NE(device_get_protocol(fragments[1].device, 1, &proto), ZX_OK); |
| EXPECT_OK(device_get_protocol(fragments[1].device, 2, &proto)); |
| } |