blob: eed06d5c8043d531001635d8ba0969ab060c3837 [file] [log] [blame]
// 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 <fbl/algorithm.h>
#include <fbl/ref_counted.h>
#include <fbl/ref_ptr.h>
#include <zircon/driver/binding.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.get(), 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_ = &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.get(), 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