| // 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 <zircon/driver/binding.h> |
| |
| #include <fbl/algorithm.h> |
| #include <fbl/ref_counted.h> |
| #include <fbl/ref_ptr.h> |
| #include <zxtest/zxtest.h> |
| |
| #include "binding-internal.h" |
| |
| namespace { |
| |
| class MockDevice : public fbl::RefCounted<MockDevice> { |
| public: |
| MockDevice(fbl::RefPtr<MockDevice> parent, const zx_device_prop_t* props, size_t props_count, |
| uint32_t protocol_id) |
| : parent_(std::move(parent)), protocol_id_(protocol_id) { |
| fbl::Array<zx_device_prop_t> props_array(new zx_device_prop_t[props_count], props_count); |
| if (props != nullptr) { |
| memcpy(props_array.data(), props, sizeof(props[0]) * props_count); |
| } else { |
| ASSERT_EQ(props_count, 0); |
| } |
| props_ = std::move(props_array); |
| for (const auto& prop : props_) { |
| if (prop.id >= BIND_TOPO_START && prop.id <= BIND_TOPO_END) { |
| topo_prop_ = ∝ |
| break; |
| } |
| } |
| } |
| |
| MockDevice& operator=(const MockDevice&) = delete; |
| MockDevice& operator=(MockDevice&&) = delete; |
| MockDevice(const MockDevice&) = delete; |
| MockDevice(MockDevice&&) = delete; |
| |
| const fbl::RefPtr<MockDevice>& parent() { return parent_; } |
| const fbl::Array<const zx_device_prop_t>& props() const { return props_; } |
| const zx_device_prop_t* topo_prop() const { return topo_prop_; } |
| uint32_t protocol_id() const { return protocol_id_; } |
| |
| private: |
| const fbl::RefPtr<MockDevice> parent_; |
| fbl::Array<const zx_device_prop_t> props_; |
| const zx_device_prop_t* topo_prop_ = nullptr; |
| uint32_t protocol_id_ = 0; |
| }; |
| |
| using devmgr::ComponentPartDescriptor; |
| using devmgr::internal::Match; |
| using devmgr::internal::MatchParts; |
| |
| template <size_t N> |
| fbl::Array<const zx_bind_inst_t> MakeBindProgram(const zx_bind_inst_t (&insts)[N]) { |
| fbl::Array<zx_bind_inst_t> array(new zx_bind_inst_t[N], N); |
| memcpy(array.data(), insts, N * sizeof(insts[0])); |
| return array; |
| } |
| |
| TEST(BindingTestCase, CompositeMatchZeroParts) { |
| auto device = fbl::MakeRefCounted<MockDevice>(nullptr, nullptr, 0, 0); |
| |
| Match match = MatchParts(device, nullptr, 0); |
| ASSERT_EQ(match, Match::None); |
| } |
| |
| TEST(BindingTestCase, CompositeMatchOnePartOneDeviceFail) { |
| constexpr uint32_t kProtocolId = 1; |
| auto device = fbl::MakeRefCounted<MockDevice>(nullptr, nullptr, 0, kProtocolId); |
| |
| auto part = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_PROTOCOL, 2), |
| }); |
| ComponentPartDescriptor parts[] = { |
| {std::move(part)}, |
| }; |
| |
| Match match = MatchParts(device, parts, fbl::count_of(parts)); |
| ASSERT_EQ(match, Match::None); |
| } |
| |
| TEST(BindingTestCase, CompositeMatchOnePartOneDeviceSucceed) { |
| constexpr uint32_t kProtocolId = 1; |
| auto device = fbl::MakeRefCounted<MockDevice>(nullptr, nullptr, 0, kProtocolId); |
| |
| auto part = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_PROTOCOL, 1), |
| }); |
| ComponentPartDescriptor parts[] = { |
| {std::move(part)}, |
| }; |
| |
| Match match = MatchParts(device, parts, fbl::count_of(parts)); |
| ASSERT_EQ(match, Match::One); |
| } |
| |
| TEST(BindingTestCase, CompositeMatchTwoPartOneDevice) { |
| constexpr uint32_t kProtocolId = 1; |
| auto device = fbl::MakeRefCounted<MockDevice>(nullptr, nullptr, 0, kProtocolId); |
| |
| // Both parts can match the only device, but only one part is allowed to |
| // match to a given device. |
| auto part1 = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_PROTOCOL, 1), |
| }); |
| auto part2 = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_PROTOCOL, 1), |
| }); |
| ComponentPartDescriptor parts[] = { |
| {std::move(part1)}, |
| {std::move(part2)}, |
| }; |
| |
| Match match = MatchParts(device, parts, fbl::count_of(parts)); |
| ASSERT_EQ(match, Match::None); |
| } |
| |
| TEST(BindingTestCase, CompositeMatchZeroPartsTwoDevices) { |
| fbl::RefPtr<MockDevice> devices[] = { |
| fbl::MakeRefCounted<MockDevice>(nullptr, nullptr, 0, 0), |
| fbl::MakeRefCounted<MockDevice>(devices[0], nullptr, 0, 0), |
| }; |
| |
| Match match = MatchParts(devices[fbl::count_of(devices) - 1], nullptr, 0); |
| ASSERT_EQ(match, Match::None); |
| } |
| |
| TEST(BindingTestCase, CompositeMatchOnePartTwoDevices) { |
| constexpr uint32_t kProtocolId = 1; |
| fbl::RefPtr<MockDevice> devices[] = { |
| fbl::MakeRefCounted<MockDevice>(nullptr, nullptr, 0, kProtocolId), |
| fbl::MakeRefCounted<MockDevice>(devices[0], nullptr, 0, kProtocolId), |
| }; |
| |
| // This program matches both devices |
| auto part = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_PROTOCOL, kProtocolId), |
| }); |
| ComponentPartDescriptor parts[] = { |
| {std::move(part)}, |
| }; |
| |
| Match match = MatchParts(devices[fbl::count_of(devices) - 1], parts, fbl::count_of(parts)); |
| ASSERT_EQ(match, Match::None); |
| } |
| |
| TEST(BindingTestCase, CompositeMatchTwoPartsTwoDevicesFail) { |
| constexpr uint32_t kProtocolId1 = 1; |
| constexpr uint32_t kProtocolId2 = 2; |
| fbl::RefPtr<MockDevice> devices[] = { |
| fbl::MakeRefCounted<MockDevice>(nullptr, nullptr, 0, kProtocolId1), |
| fbl::MakeRefCounted<MockDevice>(devices[0], nullptr, 0, kProtocolId2), |
| }; |
| |
| auto part1 = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_PROTOCOL, kProtocolId1), |
| }); |
| auto part2 = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_PROTOCOL, kProtocolId2), |
| }); |
| ComponentPartDescriptor parts[] = { |
| // First entry should match the root, but this rule matches leaf |
| {std::move(part2)}, |
| // Last entry should match the leaf, but this rule matches root |
| {std::move(part1)}, |
| }; |
| |
| Match match = MatchParts(devices[fbl::count_of(devices) - 1], parts, fbl::count_of(parts)); |
| ASSERT_EQ(match, Match::None); |
| } |
| |
| TEST(BindingTestCase, CompositeMatchTwoPartsTwoDevicesSucceed) { |
| constexpr uint32_t kProtocolId1 = 1; |
| constexpr uint32_t kProtocolId2 = 2; |
| fbl::RefPtr<MockDevice> devices[] = { |
| fbl::MakeRefCounted<MockDevice>(nullptr, nullptr, 0, kProtocolId1), |
| fbl::MakeRefCounted<MockDevice>(devices[0], nullptr, 0, kProtocolId2), |
| }; |
| |
| auto part1 = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_PROTOCOL, kProtocolId1), |
| }); |
| auto part2 = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_PROTOCOL, kProtocolId2), |
| }); |
| ComponentPartDescriptor parts[] = { |
| {std::move(part1)}, |
| {std::move(part2)}, |
| }; |
| |
| Match match = MatchParts(devices[fbl::count_of(devices) - 1], parts, fbl::count_of(parts)); |
| ASSERT_EQ(match, Match::One); |
| } |
| |
| TEST(BindingTestCase, CompositeMatchThreePartsTwoDevices) { |
| constexpr uint32_t kProtocolId1 = 1; |
| constexpr uint32_t kProtocolId2 = 2; |
| fbl::RefPtr<MockDevice> devices[] = { |
| fbl::MakeRefCounted<MockDevice>(nullptr, nullptr, 0, kProtocolId1), |
| fbl::MakeRefCounted<MockDevice>(devices[0], nullptr, 0, kProtocolId2), |
| }; |
| |
| auto part1 = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_PROTOCOL, kProtocolId1), |
| }); |
| auto part2 = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_PROTOCOL, kProtocolId2), |
| }); |
| auto part3 = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_PROTOCOL, kProtocolId2), |
| }); |
| ComponentPartDescriptor parts[] = { |
| {std::move(part1)}, |
| {std::move(part2)}, |
| {std::move(part3)}, |
| }; |
| |
| Match match = MatchParts(devices[fbl::count_of(devices) - 1], parts, fbl::count_of(parts)); |
| ASSERT_EQ(match, Match::None); |
| } |
| |
| TEST(BindingTestCase, CompositeMatchTwoPartsThreeDevicesNoMidTopoFail1) { |
| // No topological property on the middle device |
| zx_device_prop_t mid_props[] = { |
| {BIND_PCI_DID, 0, 1234}, |
| }; |
| |
| constexpr uint32_t kProtocolId1 = 1; |
| constexpr uint32_t kProtocolId2 = 2; |
| constexpr uint32_t kProtocolId3 = 3; |
| fbl::RefPtr<MockDevice> devices[] = { |
| fbl::MakeRefCounted<MockDevice>(nullptr, nullptr, 0, kProtocolId1), |
| fbl::MakeRefCounted<MockDevice>(devices[0], mid_props, fbl::count_of(mid_props), |
| kProtocolId2), |
| fbl::MakeRefCounted<MockDevice>(devices[1], nullptr, 0, kProtocolId3), |
| }; |
| |
| auto part1 = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_PROTOCOL, kProtocolId1), |
| }); |
| auto part2 = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_PROTOCOL, kProtocolId2), |
| }); |
| ComponentPartDescriptor parts[] = { |
| {std::move(part1)}, |
| // This matches the middle device, not the leaf |
| {std::move(part2)}, |
| }; |
| |
| Match match = MatchParts(devices[fbl::count_of(devices) - 1], parts, fbl::count_of(parts)); |
| ASSERT_EQ(match, Match::None); |
| } |
| |
| TEST(BindingTestCase, CompositeMatchTwoPartsThreeDevicesNoMidTopoFail2) { |
| // No topological property on the middle device |
| zx_device_prop_t mid_props[] = { |
| {BIND_PCI_DID, 0, 1234}, |
| }; |
| |
| constexpr uint32_t kProtocolId1 = 1; |
| constexpr uint32_t kProtocolId2 = 2; |
| constexpr uint32_t kProtocolId3 = 3; |
| fbl::RefPtr<MockDevice> devices[] = { |
| fbl::MakeRefCounted<MockDevice>(nullptr, nullptr, 0, kProtocolId1), |
| fbl::MakeRefCounted<MockDevice>(devices[0], mid_props, fbl::count_of(mid_props), |
| kProtocolId2), |
| fbl::MakeRefCounted<MockDevice>(devices[1], nullptr, 0, kProtocolId3), |
| }; |
| |
| auto part1 = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_PROTOCOL, kProtocolId2), |
| }); |
| auto part2 = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_PROTOCOL, kProtocolId3), |
| }); |
| ComponentPartDescriptor parts[] = { |
| // This matches the middle device, not the root |
| {std::move(part1)}, |
| {std::move(part2)}, |
| }; |
| |
| Match match = MatchParts(devices[fbl::count_of(devices) - 1], parts, fbl::count_of(parts)); |
| ASSERT_EQ(match, Match::None); |
| } |
| |
| TEST(BindingTestCase, CompositeMatchTwoPartsThreeDevicesNoMidTopoSuccess) { |
| // No topological property on the middle device |
| zx_device_prop_t mid_props[] = { |
| {BIND_PCI_DID, 0, 1234}, |
| }; |
| |
| constexpr uint32_t kProtocolId1 = 1; |
| constexpr uint32_t kProtocolId2 = 2; |
| constexpr uint32_t kProtocolId3 = 3; |
| fbl::RefPtr<MockDevice> devices[] = { |
| fbl::MakeRefCounted<MockDevice>(nullptr, nullptr, 0, kProtocolId1), |
| fbl::MakeRefCounted<MockDevice>(devices[0], mid_props, fbl::count_of(mid_props), |
| kProtocolId2), |
| fbl::MakeRefCounted<MockDevice>(devices[1], nullptr, 0, kProtocolId3), |
| }; |
| |
| auto part1 = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_PROTOCOL, kProtocolId1), |
| }); |
| auto part2 = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_PROTOCOL, kProtocolId3), |
| }); |
| ComponentPartDescriptor parts[] = { |
| {std::move(part1)}, |
| {std::move(part2)}, |
| }; |
| |
| Match match = MatchParts(devices[fbl::count_of(devices) - 1], parts, fbl::count_of(parts)); |
| ASSERT_EQ(match, Match::One); |
| } |
| |
| TEST(BindingTestCase, CompositeMatchTwoPartsThreeDevicesMidTopo) { |
| // Topological property on the middle device |
| zx_device_prop_t mid_props[] = { |
| {BIND_PCI_DID, 0, 1234}, |
| {BIND_TOPO_PCI, 0, BIND_TOPO_PCI_PACK(0, 0, 0)}, |
| }; |
| |
| constexpr uint32_t kProtocolId1 = 1; |
| constexpr uint32_t kProtocolId2 = 2; |
| constexpr uint32_t kProtocolId3 = 3; |
| fbl::RefPtr<MockDevice> devices[] = { |
| fbl::MakeRefCounted<MockDevice>(nullptr, nullptr, 0, kProtocolId1), |
| fbl::MakeRefCounted<MockDevice>(devices[0], mid_props, fbl::count_of(mid_props), |
| kProtocolId2), |
| fbl::MakeRefCounted<MockDevice>(devices[1], nullptr, 0, kProtocolId3), |
| }; |
| |
| auto part1 = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_PROTOCOL, kProtocolId1), |
| }); |
| auto part2 = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_PROTOCOL, kProtocolId3), |
| }); |
| ComponentPartDescriptor parts[] = { |
| {std::move(part1)}, |
| // We need to match on the topological node, but we don't have a rule |
| // for it. |
| {std::move(part2)}, |
| }; |
| |
| Match match = MatchParts(devices[fbl::count_of(devices) - 1], parts, fbl::count_of(parts)); |
| ASSERT_EQ(match, Match::None); |
| } |
| |
| TEST(BindingTestCase, CompositeMatchThreePartsThreeDevicesMidTopo) { |
| // Topological property on the middle device |
| zx_device_prop_t mid_props[] = { |
| {BIND_PCI_DID, 0, 1234}, |
| {BIND_TOPO_PCI, 0, BIND_TOPO_PCI_PACK(0, 0, 0)}, |
| }; |
| |
| constexpr uint32_t kProtocolId1 = 1; |
| constexpr uint32_t kProtocolId2 = 2; |
| constexpr uint32_t kProtocolId3 = 3; |
| fbl::RefPtr<MockDevice> devices[] = { |
| fbl::MakeRefCounted<MockDevice>(nullptr, nullptr, 0, kProtocolId1), |
| fbl::MakeRefCounted<MockDevice>(devices[0], mid_props, fbl::count_of(mid_props), |
| kProtocolId2), |
| fbl::MakeRefCounted<MockDevice>(devices[1], nullptr, 0, kProtocolId3), |
| }; |
| |
| auto part1 = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_PROTOCOL, kProtocolId1), |
| }); |
| auto part2 = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_TOPO_PCI, BIND_TOPO_PCI_PACK(0, 0, 0)), |
| }); |
| auto part3 = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_PROTOCOL, kProtocolId3), |
| }); |
| ComponentPartDescriptor parts[] = { |
| {std::move(part1)}, |
| {std::move(part2)}, |
| {std::move(part3)}, |
| }; |
| |
| Match match = MatchParts(devices[fbl::count_of(devices) - 1], parts, fbl::count_of(parts)); |
| ASSERT_EQ(match, Match::One); |
| } |
| |
| TEST(BindingTestCase, CompositeMatchTwoPartsFourDevicesOneTopo) { |
| // Topological property on the middle device |
| zx_device_prop_t mid_props[] = { |
| {BIND_PCI_DID, 0, 1234}, |
| {BIND_TOPO_PCI, 0, BIND_TOPO_PCI_PACK(0, 0, 0)}, |
| }; |
| |
| constexpr uint32_t kProtocolId1 = 1; |
| constexpr uint32_t kProtocolId2 = 2; |
| constexpr uint32_t kProtocolId3 = 3; |
| constexpr uint32_t kProtocolId4 = 4; |
| fbl::RefPtr<MockDevice> devices[] = { |
| fbl::MakeRefCounted<MockDevice>(nullptr, nullptr, 0, kProtocolId1), |
| fbl::MakeRefCounted<MockDevice>(devices[0], mid_props, fbl::count_of(mid_props), |
| kProtocolId2), |
| fbl::MakeRefCounted<MockDevice>(devices[1], nullptr, 0, kProtocolId3), |
| fbl::MakeRefCounted<MockDevice>(devices[2], nullptr, 0, kProtocolId4), |
| }; |
| |
| auto part1 = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_PROTOCOL, kProtocolId1), |
| }); |
| auto part2 = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_PROTOCOL, kProtocolId4), |
| }); |
| ComponentPartDescriptor parts[] = { |
| {std::move(part1)}, |
| {std::move(part2)}, |
| }; |
| |
| Match match = MatchParts(devices[fbl::count_of(devices) - 1], parts, fbl::count_of(parts)); |
| ASSERT_EQ(match, Match::None); |
| } |
| |
| TEST(BindingTestCase, CompositeMatchThreePartsFourDevicesOneTopo) { |
| // Topological property on the middle device |
| zx_device_prop_t mid_props[] = { |
| {BIND_PCI_DID, 0, 1234}, |
| {BIND_TOPO_PCI, 0, BIND_TOPO_PCI_PACK(0, 0, 0)}, |
| }; |
| |
| constexpr uint32_t kProtocolId1 = 1; |
| constexpr uint32_t kProtocolId2 = 2; |
| constexpr uint32_t kProtocolId3 = 3; |
| constexpr uint32_t kProtocolId4 = 4; |
| fbl::RefPtr<MockDevice> devices[] = { |
| fbl::MakeRefCounted<MockDevice>(nullptr, nullptr, 0, kProtocolId1), |
| fbl::MakeRefCounted<MockDevice>(devices[0], mid_props, fbl::count_of(mid_props), |
| kProtocolId2), |
| fbl::MakeRefCounted<MockDevice>(devices[1], nullptr, 0, kProtocolId3), |
| fbl::MakeRefCounted<MockDevice>(devices[2], nullptr, 0, kProtocolId4), |
| }; |
| |
| auto part1 = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_PROTOCOL, kProtocolId1), |
| }); |
| auto part2 = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_TOPO_PCI, BIND_TOPO_PCI_PACK(0, 0, 0)), |
| }); |
| auto part3 = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_PROTOCOL, kProtocolId4), |
| }); |
| ComponentPartDescriptor parts[] = { |
| {std::move(part1)}, |
| {std::move(part2)}, |
| {std::move(part3)}, |
| }; |
| |
| Match match = MatchParts(devices[fbl::count_of(devices) - 1], parts, fbl::count_of(parts)); |
| ASSERT_EQ(match, Match::One); |
| } |
| |
| TEST(BindingTestCase, CompositeMatchFourPartsFourDevicesOneTopo) { |
| // Topological property on the middle device |
| zx_device_prop_t mid_props[] = { |
| {BIND_PCI_DID, 0, 1234}, |
| {BIND_TOPO_PCI, 0, BIND_TOPO_PCI_PACK(0, 0, 0)}, |
| }; |
| |
| constexpr uint32_t kProtocolId1 = 1; |
| constexpr uint32_t kProtocolId2 = 2; |
| constexpr uint32_t kProtocolId3 = 3; |
| constexpr uint32_t kProtocolId4 = 4; |
| fbl::RefPtr<MockDevice> devices[] = { |
| fbl::MakeRefCounted<MockDevice>(nullptr, nullptr, 0, kProtocolId1), |
| fbl::MakeRefCounted<MockDevice>(devices[0], mid_props, fbl::count_of(mid_props), |
| kProtocolId2), |
| fbl::MakeRefCounted<MockDevice>(devices[1], nullptr, 0, kProtocolId3), |
| fbl::MakeRefCounted<MockDevice>(devices[2], nullptr, 0, kProtocolId4), |
| }; |
| |
| auto part1 = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_PROTOCOL, kProtocolId1), |
| }); |
| auto part2 = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_TOPO_PCI, BIND_TOPO_PCI_PACK(0, 0, 0)), |
| }); |
| auto part3 = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_PROTOCOL, kProtocolId3), |
| }); |
| auto part4 = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_PROTOCOL, kProtocolId4), |
| }); |
| ComponentPartDescriptor parts[] = { |
| {std::move(part1)}, |
| {std::move(part2)}, |
| {std::move(part3)}, |
| {std::move(part4)}, |
| }; |
| |
| Match match = MatchParts(devices[fbl::count_of(devices) - 1], parts, fbl::count_of(parts)); |
| ASSERT_EQ(match, Match::One); |
| } |
| |
| TEST(BindingTestCase, CompositeMatchThreePartsFourDevicesAmbiguous) { |
| constexpr uint32_t kProtocolId1 = 1; |
| constexpr uint32_t kProtocolId2 = 2; |
| constexpr uint32_t kProtocolId3 = 3; |
| fbl::RefPtr<MockDevice> devices[] = { |
| fbl::MakeRefCounted<MockDevice>(nullptr, nullptr, 0, kProtocolId1), |
| fbl::MakeRefCounted<MockDevice>(devices[0], nullptr, 0, kProtocolId2), |
| fbl::MakeRefCounted<MockDevice>(devices[1], nullptr, 0, kProtocolId2), |
| fbl::MakeRefCounted<MockDevice>(devices[2], nullptr, 0, kProtocolId3), |
| }; |
| |
| auto part1 = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_PROTOCOL, kProtocolId1), |
| }); |
| auto part2 = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_PROTOCOL, kProtocolId2), |
| }); |
| auto part3 = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_PROTOCOL, kProtocolId3), |
| }); |
| ComponentPartDescriptor parts[] = { |
| {std::move(part1)}, |
| // This matches both of the inner devices. |
| {std::move(part2)}, |
| {std::move(part3)}, |
| }; |
| |
| Match match = MatchParts(devices[fbl::count_of(devices) - 1], parts, fbl::count_of(parts)); |
| ASSERT_EQ(match, Match::Many); |
| } |
| |
| TEST(BindingTestCase, CompositeMatchThreePartsFourDevicesAmbiguousAgainstLeaf) { |
| constexpr uint32_t kProtocolId1 = 1; |
| constexpr uint32_t kProtocolId2 = 2; |
| constexpr uint32_t kProtocolId3 = 3; |
| fbl::RefPtr<MockDevice> devices[] = { |
| fbl::MakeRefCounted<MockDevice>(nullptr, nullptr, 0, kProtocolId1), |
| fbl::MakeRefCounted<MockDevice>(devices[0], nullptr, 0, kProtocolId2), |
| fbl::MakeRefCounted<MockDevice>(devices[1], nullptr, 0, kProtocolId3), |
| fbl::MakeRefCounted<MockDevice>(devices[2], nullptr, 0, kProtocolId3), |
| }; |
| |
| auto part1 = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_PROTOCOL, kProtocolId1), |
| }); |
| auto part2 = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_PROTOCOL, kProtocolId2), |
| }); |
| auto part3 = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_PROTOCOL, kProtocolId3), |
| }); |
| ComponentPartDescriptor parts[] = { |
| {std::move(part1)}, |
| {std::move(part2)}, |
| // This matches the leaf and its parent, but is not considered ambiguous |
| // since we force the match to the leaf |
| {std::move(part3)}, |
| }; |
| |
| Match match = MatchParts(devices[fbl::count_of(devices) - 1], parts, fbl::count_of(parts)); |
| ASSERT_EQ(match, Match::One); |
| } |
| |
| TEST(BindingTestCase, CompositeMatchThreePartsFourDevicesAmbiguousAgainstRoot) { |
| constexpr uint32_t kProtocolId1 = 1; |
| constexpr uint32_t kProtocolId2 = 2; |
| constexpr uint32_t kProtocolId3 = 3; |
| fbl::RefPtr<MockDevice> devices[] = { |
| fbl::MakeRefCounted<MockDevice>(nullptr, nullptr, 0, kProtocolId1), |
| fbl::MakeRefCounted<MockDevice>(devices[0], nullptr, 0, kProtocolId1), |
| fbl::MakeRefCounted<MockDevice>(devices[1], nullptr, 0, kProtocolId2), |
| fbl::MakeRefCounted<MockDevice>(devices[2], nullptr, 0, kProtocolId3), |
| }; |
| |
| auto part1 = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_PROTOCOL, kProtocolId1), |
| }); |
| auto part2 = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_PROTOCOL, kProtocolId2), |
| }); |
| auto part3 = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_PROTOCOL, kProtocolId3), |
| }); |
| ComponentPartDescriptor parts[] = { |
| // This matches the root and its immediate child, but is not considered |
| // ambiguous isnce we force the match to the root |
| {std::move(part1)}, |
| {std::move(part2)}, |
| {std::move(part3)}, |
| }; |
| |
| Match match = MatchParts(devices[fbl::count_of(devices) - 1], parts, fbl::count_of(parts)); |
| ASSERT_EQ(match, Match::One); |
| } |
| |
| TEST(BindingTestCase, CompositeMatchComplexTopology) { |
| zx_device_prop_t props1[] = { |
| {BIND_TOPO_PCI, 0, BIND_TOPO_PCI_PACK(0, 0, 0)}, |
| }; |
| zx_device_prop_t props2[] = { |
| {BIND_TOPO_PCI, 0, BIND_TOPO_PCI_PACK(1, 0, 0)}, |
| }; |
| zx_device_prop_t props3[] = { |
| {BIND_TOPO_I2C, 0, BIND_TOPO_I2C_PACK(0x12)}, |
| }; |
| |
| constexpr uint32_t kProtocolId = 1; |
| fbl::RefPtr<MockDevice> devices[] = { |
| fbl::MakeRefCounted<MockDevice>(nullptr, nullptr, 0, 0), |
| fbl::MakeRefCounted<MockDevice>(devices[0], props1, fbl::count_of(props1), 0), |
| fbl::MakeRefCounted<MockDevice>(devices[1], nullptr, 0, 0), |
| fbl::MakeRefCounted<MockDevice>(devices[2], props2, fbl::count_of(props2), 0), |
| fbl::MakeRefCounted<MockDevice>(devices[3], nullptr, 0, 0), |
| fbl::MakeRefCounted<MockDevice>(devices[4], nullptr, 0, 0), |
| fbl::MakeRefCounted<MockDevice>(devices[5], props3, fbl::count_of(props3), 0), |
| fbl::MakeRefCounted<MockDevice>(devices[6], nullptr, 0, 0), |
| fbl::MakeRefCounted<MockDevice>(devices[7], nullptr, 0, kProtocolId), |
| }; |
| |
| auto part1 = MakeBindProgram({ |
| BI_MATCH(), |
| }); |
| auto part2 = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_TOPO_PCI, BIND_TOPO_PCI_PACK(0, 0, 0)), |
| }); |
| auto part3 = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_TOPO_PCI, BIND_TOPO_PCI_PACK(1, 0, 0)), |
| }); |
| auto part4 = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_TOPO_I2C, BIND_TOPO_I2C_PACK(0x12)), |
| }); |
| auto part5 = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_PROTOCOL, kProtocolId), |
| }); |
| ComponentPartDescriptor parts[] = { |
| {std::move(part1)}, {std::move(part2)}, {std::move(part3)}, |
| {std::move(part4)}, {std::move(part5)}, |
| }; |
| |
| Match match = MatchParts(devices[fbl::count_of(devices) - 1], parts, fbl::count_of(parts)); |
| ASSERT_EQ(match, Match::One); |
| } |
| |
| TEST(BindingTestCase, CompositeMatchComplexAmbiguity) { |
| constexpr uint32_t kProtocolId1 = 1; |
| constexpr uint32_t kProtocolId2 = 2; |
| constexpr uint32_t kProtocolId3 = 3; |
| fbl::RefPtr<MockDevice> devices[] = { |
| fbl::MakeRefCounted<MockDevice>(nullptr, nullptr, 0, kProtocolId1), |
| fbl::MakeRefCounted<MockDevice>(devices[0], nullptr, 0, kProtocolId2), |
| fbl::MakeRefCounted<MockDevice>(devices[1], nullptr, 0, kProtocolId2), |
| fbl::MakeRefCounted<MockDevice>(devices[2], nullptr, 0, kProtocolId2), |
| fbl::MakeRefCounted<MockDevice>(devices[3], nullptr, 0, kProtocolId3), |
| }; |
| |
| auto part1 = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_PROTOCOL, kProtocolId1), |
| }); |
| auto part2 = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_PROTOCOL, kProtocolId2), |
| }); |
| auto part3 = MakeBindProgram({ |
| BI_MATCH(), |
| }); |
| auto part4 = MakeBindProgram({ |
| BI_MATCH_IF(EQ, BIND_PROTOCOL, kProtocolId3), |
| }); |
| ComponentPartDescriptor parts[] = { |
| {std::move(part1)}, |
| // parts 2 and 3 can match ancestors 1 and 2 or 2 and 3. |
| {std::move(part2)}, |
| {std::move(part3)}, |
| {std::move(part4)}, |
| }; |
| |
| Match match = MatchParts(devices[fbl::count_of(devices) - 1], parts, fbl::count_of(parts)); |
| ASSERT_EQ(match, Match::Many); |
| } |
| |
| } // namespace |