mirror of
https://github.com/esphome/esphome.git
synced 2026-10-21 13:34:12 +00:00
[packet_interface] Fix clang-tidy findings in tests
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
ecf4d24be6
commit
d24ef14dc0
@@ -60,47 +60,49 @@ class TestTransport : public EntityTransport {
|
||||
using EntityTransport::clear_remote_states_;
|
||||
};
|
||||
|
||||
static Packet header(uint8_t type, uint32_t dictionary_id) {
|
||||
return {type, static_cast<uint8_t>(dictionary_id), static_cast<uint8_t>(dictionary_id >> 8),
|
||||
static_cast<uint8_t>(dictionary_id >> 16), static_cast<uint8_t>(dictionary_id >> 24)};
|
||||
static Packet header(uint8_t packet_type, uint32_t id) {
|
||||
return {packet_type, static_cast<uint8_t>(id), static_cast<uint8_t>(id >> 8), static_cast<uint8_t>(id >> 16),
|
||||
static_cast<uint8_t>(id >> 24)};
|
||||
}
|
||||
|
||||
class EntityTransportTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
new (&App) Application;
|
||||
App.pre_setup(DEVICE_NAME, strlen(DEVICE_NAME), "", 0);
|
||||
static char name[] = "this-device";
|
||||
static char friendly_name[] = "";
|
||||
App.pre_setup(name, sizeof(name) - 1, friendly_name, 0);
|
||||
}
|
||||
void TearDown() override { App.~Application(); }
|
||||
|
||||
// The sender, with a sensor and a binary sensor
|
||||
std::unique_ptr<TestTransport> make_sender() {
|
||||
auto transport = std::make_unique<TestTransport>(&this->link_a);
|
||||
std::unique_ptr<TestTransport> make_sender_() {
|
||||
auto transport = std::make_unique<TestTransport>(&this->link_a_);
|
||||
transport->set_entity_count(2);
|
||||
transport->add_sensor("temp", &this->temp);
|
||||
transport->add_binary_sensor("door", &this->door);
|
||||
transport->add_sensor("temp", &this->temp_);
|
||||
transport->add_binary_sensor("door", &this->door_);
|
||||
transport->setup();
|
||||
return transport;
|
||||
}
|
||||
// The receiver, showing the sender's entities; both run on this device, so they share its name
|
||||
std::unique_ptr<TestTransport> make_receiver(const char *provider = DEVICE_NAME, uint32_t timeout_ms = 0) {
|
||||
auto transport = std::make_unique<TestTransport>(&this->link_b);
|
||||
std::unique_ptr<TestTransport> make_receiver_(const char *provider = DEVICE_NAME, uint32_t timeout_ms = 0) {
|
||||
auto transport = std::make_unique<TestTransport>(&this->link_b_);
|
||||
transport->set_remote_timeout(timeout_ms);
|
||||
transport->add_remote_sensor(provider, "temp", &this->remote_temp);
|
||||
transport->add_remote_binary_sensor(provider, "door", &this->remote_door);
|
||||
transport->add_remote_sensor(provider, "temp", &this->remote_temp_);
|
||||
transport->add_remote_binary_sensor(provider, "door", &this->remote_door_);
|
||||
transport->setup();
|
||||
return transport;
|
||||
}
|
||||
|
||||
MockInterface link_a, link_b;
|
||||
sensor::Sensor temp, remote_temp;
|
||||
binary_sensor::BinarySensor door, remote_door;
|
||||
MockInterface link_a_, link_b_;
|
||||
sensor::Sensor temp_, remote_temp_;
|
||||
binary_sensor::BinarySensor door_, remote_door_;
|
||||
};
|
||||
|
||||
TEST_F(EntityTransportTest, SendsDictionaryThenStates) {
|
||||
this->temp.publish_state(21.5f);
|
||||
this->door.publish_state(true);
|
||||
auto sender = this->make_sender();
|
||||
this->temp_.publish_state(21.5f);
|
||||
this->door_.publish_state(true);
|
||||
auto sender = this->make_sender_();
|
||||
sender->loop();
|
||||
uint32_t id = sender->get_dictionary_id();
|
||||
Packet dictionary = header(PACKET_DICTIONARY, id);
|
||||
@@ -109,204 +111,204 @@ TEST_F(EntityTransportTest, SendsDictionaryThenStates) {
|
||||
dictionary.insert(dictionary.end(), {1, 0, 1, 4, 't', 'e', 'm', 'p', 2, 0, 1, 4, 'd', 'o', 'o', 'r'});
|
||||
Packet data = header(PACKET_DATA, id);
|
||||
data.insert(data.end(), {1, 0, 0x00, 0x00, 0xAC, 0x41, 0, 1});
|
||||
ASSERT_EQ(this->link_a.sent.size(), 2);
|
||||
EXPECT_EQ(this->link_a.sent[0], dictionary);
|
||||
EXPECT_EQ(this->link_a.sent[1], data);
|
||||
ASSERT_EQ(this->link_a_.sent.size(), 2);
|
||||
EXPECT_EQ(this->link_a_.sent[0], dictionary);
|
||||
EXPECT_EQ(this->link_a_.sent[1], data);
|
||||
}
|
||||
|
||||
TEST_F(EntityTransportTest, SendsOnlyChangedStates) {
|
||||
auto sender = this->make_sender();
|
||||
auto sender = this->make_sender_();
|
||||
sender->loop();
|
||||
this->link_a.sent.clear();
|
||||
this->temp.publish_state(3.0f);
|
||||
this->link_a_.sent.clear();
|
||||
this->temp_.publish_state(3.0f);
|
||||
sender->loop();
|
||||
Packet data = header(PACKET_DATA, sender->get_dictionary_id());
|
||||
data.insert(data.end(), {1, 0, 0x00, 0x00, 0x40, 0x40});
|
||||
ASSERT_EQ(this->link_a.sent.size(), 1);
|
||||
EXPECT_EQ(this->link_a.sent[0], data);
|
||||
ASSERT_EQ(this->link_a_.sent.size(), 1);
|
||||
EXPECT_EQ(this->link_a_.sent[0], data);
|
||||
}
|
||||
|
||||
TEST_F(EntityTransportTest, StatesReachRemoteEntities) {
|
||||
this->temp.publish_state(12.25f);
|
||||
this->door.publish_state(true);
|
||||
auto sender = this->make_sender();
|
||||
auto receiver = this->make_receiver();
|
||||
this->temp_.publish_state(12.25f);
|
||||
this->door_.publish_state(true);
|
||||
auto sender = this->make_sender_();
|
||||
auto receiver = this->make_receiver_();
|
||||
sender->loop();
|
||||
this->link_a.deliver_to(this->link_b);
|
||||
EXPECT_EQ(this->remote_temp.get_state(), 12.25f);
|
||||
EXPECT_TRUE(this->remote_door.state);
|
||||
this->door.invalidate_state();
|
||||
this->link_a_.deliver_to(this->link_b_);
|
||||
EXPECT_EQ(this->remote_temp_.get_state(), 12.25f);
|
||||
EXPECT_TRUE(this->remote_door_.state);
|
||||
this->door_.invalidate_state();
|
||||
sender->loop();
|
||||
this->link_a.deliver_to(this->link_b);
|
||||
EXPECT_FALSE(this->remote_door.has_state());
|
||||
this->link_a_.deliver_to(this->link_b_);
|
||||
EXPECT_FALSE(this->remote_door_.has_state());
|
||||
}
|
||||
|
||||
TEST_F(EntityTransportTest, SplitsAcrossPackets) {
|
||||
this->link_a.set_max_packet_size(5 + 1 + strlen(DEVICE_NAME) + 3 + 5);
|
||||
this->temp.publish_state(1.0f);
|
||||
this->door.publish_state(true);
|
||||
auto sender = this->make_sender();
|
||||
auto receiver = this->make_receiver();
|
||||
this->link_a_.set_max_packet_size(5 + 1 + strlen(DEVICE_NAME) + 3 + 5);
|
||||
this->temp_.publish_state(1.0f);
|
||||
this->door_.publish_state(true);
|
||||
auto sender = this->make_sender_();
|
||||
auto receiver = this->make_receiver_();
|
||||
sender->loop();
|
||||
EXPECT_EQ(this->link_a.sent.size(), 3); // one dictionary packet for each entity, then one data packet
|
||||
this->link_a.deliver_to(this->link_b);
|
||||
EXPECT_EQ(this->remote_temp.get_state(), 1.0f);
|
||||
EXPECT_TRUE(this->remote_door.state);
|
||||
EXPECT_EQ(this->link_a_.sent.size(), 3); // one dictionary packet for each entity, then one data packet
|
||||
this->link_a_.deliver_to(this->link_b_);
|
||||
EXPECT_EQ(this->remote_temp_.get_state(), 1.0f);
|
||||
EXPECT_TRUE(this->remote_door_.state);
|
||||
}
|
||||
|
||||
TEST_F(EntityTransportTest, RefusedPacketSentAgain) {
|
||||
this->link_a.accept = false;
|
||||
auto sender = this->make_sender();
|
||||
this->link_a_.accept = false;
|
||||
auto sender = this->make_sender_();
|
||||
sender->loop();
|
||||
EXPECT_TRUE(this->link_a.sent.empty());
|
||||
this->link_a.accept = true;
|
||||
EXPECT_TRUE(this->link_a_.sent.empty());
|
||||
this->link_a_.accept = true;
|
||||
sender->loop();
|
||||
EXPECT_EQ(this->link_a.sent.size(), 2);
|
||||
EXPECT_EQ(this->link_a_.sent.size(), 2);
|
||||
}
|
||||
|
||||
TEST_F(EntityTransportTest, UnknownDictionaryRequested) {
|
||||
this->temp.publish_state(5.0f);
|
||||
auto sender = this->make_sender();
|
||||
auto receiver = this->make_receiver();
|
||||
this->temp_.publish_state(5.0f);
|
||||
auto sender = this->make_sender_();
|
||||
auto receiver = this->make_receiver_();
|
||||
sender->loop();
|
||||
this->link_a.sent.erase(this->link_a.sent.begin()); // the dictionary is lost
|
||||
this->link_a.deliver_to(this->link_b);
|
||||
EXPECT_FALSE(this->remote_temp.has_state());
|
||||
ASSERT_EQ(this->link_b.sent.size(), 1);
|
||||
EXPECT_EQ(this->link_b.sent[0], header(PACKET_REQUEST, sender->get_dictionary_id()));
|
||||
this->link_b.deliver_to(this->link_a);
|
||||
this->link_a_.sent.erase(this->link_a_.sent.begin()); // the dictionary is lost
|
||||
this->link_a_.deliver_to(this->link_b_);
|
||||
EXPECT_FALSE(this->remote_temp_.has_state());
|
||||
ASSERT_EQ(this->link_b_.sent.size(), 1);
|
||||
EXPECT_EQ(this->link_b_.sent[0], header(PACKET_REQUEST, sender->get_dictionary_id()));
|
||||
this->link_b_.deliver_to(this->link_a_);
|
||||
sender->loop();
|
||||
this->link_a.deliver_to(this->link_b);
|
||||
EXPECT_EQ(this->remote_temp.get_state(), 5.0f);
|
||||
this->link_a_.deliver_to(this->link_b_);
|
||||
EXPECT_EQ(this->remote_temp_.get_state(), 5.0f);
|
||||
}
|
||||
|
||||
TEST_F(EntityTransportTest, RequestsLimited) {
|
||||
auto receiver = this->make_receiver();
|
||||
auto receiver = this->make_receiver_();
|
||||
Packet data = header(PACKET_DATA, 0x12345678);
|
||||
data.push_back(0);
|
||||
this->link_b.inject(data);
|
||||
this->link_b.inject(data);
|
||||
EXPECT_EQ(this->link_b.sent.size(), 1);
|
||||
this->link_b_.inject(data);
|
||||
this->link_b_.inject(data);
|
||||
EXPECT_EQ(this->link_b_.sent.size(), 1);
|
||||
}
|
||||
|
||||
TEST_F(EntityTransportTest, OtherProviderAndOwnPacketsIgnored) {
|
||||
this->temp.publish_state(5.0f);
|
||||
auto sender = this->make_sender();
|
||||
auto receiver = this->make_receiver("other-device");
|
||||
this->temp_.publish_state(5.0f);
|
||||
auto sender = this->make_sender_();
|
||||
auto receiver = this->make_receiver_("other-device");
|
||||
sender->loop();
|
||||
auto packets = this->link_a.sent;
|
||||
this->link_a.deliver_to(this->link_b);
|
||||
EXPECT_FALSE(this->remote_temp.has_state());
|
||||
auto packets = this->link_a_.sent;
|
||||
this->link_a_.deliver_to(this->link_b_);
|
||||
EXPECT_FALSE(this->remote_temp_.has_state());
|
||||
for (auto &packet : packets)
|
||||
this->link_a.inject(packet);
|
||||
this->link_a.inject(header(PACKET_REQUEST, 0x12345678));
|
||||
this->link_a_.inject(packet);
|
||||
this->link_a_.inject(header(PACKET_REQUEST, 0x12345678));
|
||||
sender->loop();
|
||||
EXPECT_TRUE(this->link_a.sent.empty());
|
||||
EXPECT_TRUE(this->link_a_.sent.empty());
|
||||
}
|
||||
|
||||
TEST_F(EntityTransportTest, MalformedPacketsIgnored) {
|
||||
auto sender = this->make_sender();
|
||||
auto receiver = this->make_receiver();
|
||||
auto sender = this->make_sender_();
|
||||
auto receiver = this->make_receiver_();
|
||||
sender->loop();
|
||||
Packet dictionary = this->link_a.sent[0];
|
||||
Packet data = this->link_a.sent[1];
|
||||
this->link_b.inject(Packet(dictionary.begin(), dictionary.end() - 1));
|
||||
this->link_b.inject(dictionary);
|
||||
this->link_b.inject(Packet(data.begin(), data.end() - 1));
|
||||
this->link_b.inject({PACKET_DATA, 1, 2});
|
||||
this->link_b.inject({0x21, 0, 0, 0, 0});
|
||||
EXPECT_FALSE(this->remote_temp.has_state());
|
||||
Packet dictionary = this->link_a_.sent[0];
|
||||
Packet data = this->link_a_.sent[1];
|
||||
this->link_b_.inject(Packet(dictionary.begin(), dictionary.end() - 1));
|
||||
this->link_b_.inject(dictionary);
|
||||
this->link_b_.inject(Packet(data.begin(), data.end() - 1));
|
||||
this->link_b_.inject({PACKET_DATA, 1, 2});
|
||||
this->link_b_.inject({0x21, 0, 0, 0, 0});
|
||||
EXPECT_FALSE(this->remote_temp_.has_state());
|
||||
}
|
||||
|
||||
TEST_F(EntityTransportTest, UpdateIntervalFollowsCapabilities) {
|
||||
EXPECT_EQ(this->make_sender()->get_update_interval(), 15000);
|
||||
this->link_a.set_capabilities(packet_interface::CAPABILITY_SESSION);
|
||||
EXPECT_EQ(this->make_sender()->get_update_interval(), 15000);
|
||||
this->link_a.set_capabilities(packet_interface::CAPABILITY_SESSION | packet_interface::CAPABILITY_RELIABILITY);
|
||||
EXPECT_EQ(this->make_sender()->get_update_interval(), SCHEDULER_DONT_RUN);
|
||||
auto transport = std::make_unique<TestTransport>(&this->link_a);
|
||||
EXPECT_EQ(this->make_sender_()->get_update_interval(), 15000);
|
||||
this->link_a_.set_capabilities(packet_interface::CAPABILITY_SESSION);
|
||||
EXPECT_EQ(this->make_sender_()->get_update_interval(), 15000);
|
||||
this->link_a_.set_capabilities(packet_interface::CAPABILITY_SESSION | packet_interface::CAPABILITY_RELIABILITY);
|
||||
EXPECT_EQ(this->make_sender_()->get_update_interval(), SCHEDULER_DONT_RUN);
|
||||
auto transport = std::make_unique<TestTransport>(&this->link_a_);
|
||||
transport->set_update_interval(5000);
|
||||
transport->setup();
|
||||
EXPECT_EQ(transport->get_update_interval(), 5000);
|
||||
}
|
||||
|
||||
TEST_F(EntityTransportTest, SessionConnectSendsAllAndLossClearsRemote) {
|
||||
this->link_a.set_capabilities(packet_interface::CAPABILITY_SESSION);
|
||||
this->link_b.set_capabilities(packet_interface::CAPABILITY_SESSION);
|
||||
this->temp.publish_state(7.0f);
|
||||
auto sender = this->make_sender();
|
||||
auto receiver = this->make_receiver();
|
||||
this->link_a_.set_capabilities(packet_interface::CAPABILITY_SESSION);
|
||||
this->link_b_.set_capabilities(packet_interface::CAPABILITY_SESSION);
|
||||
this->temp_.publish_state(7.0f);
|
||||
auto sender = this->make_sender_();
|
||||
auto receiver = this->make_receiver_();
|
||||
sender->loop();
|
||||
this->link_a.deliver_to(this->link_b);
|
||||
this->link_a.report_session(true);
|
||||
this->link_a_.deliver_to(this->link_b_);
|
||||
this->link_a_.report_session(true);
|
||||
sender->loop();
|
||||
EXPECT_EQ(this->link_a.sent.size(), 2);
|
||||
this->link_b.report_session(false);
|
||||
EXPECT_TRUE(std::isnan(this->remote_temp.get_state()));
|
||||
EXPECT_FALSE(this->remote_door.has_state());
|
||||
EXPECT_EQ(this->link_a_.sent.size(), 2);
|
||||
this->link_b_.report_session(false);
|
||||
EXPECT_TRUE(std::isnan(this->remote_temp_.get_state()));
|
||||
EXPECT_FALSE(this->remote_door_.has_state());
|
||||
}
|
||||
|
||||
TEST_F(EntityTransportTest, RefusedDictionaryPartResumes) {
|
||||
// One entity in each dictionary packet
|
||||
this->link_a.set_max_packet_size(5 + 1 + strlen(DEVICE_NAME) + 3 + 5);
|
||||
this->temp.publish_state(4.0f);
|
||||
this->door.publish_state(true);
|
||||
auto sender = this->make_sender();
|
||||
auto receiver = this->make_receiver();
|
||||
this->link_a.budget = 1;
|
||||
this->link_a_.set_max_packet_size(5 + 1 + strlen(DEVICE_NAME) + 3 + 5);
|
||||
this->temp_.publish_state(4.0f);
|
||||
this->door_.publish_state(true);
|
||||
auto sender = this->make_sender_();
|
||||
auto receiver = this->make_receiver_();
|
||||
this->link_a_.budget = 1;
|
||||
sender->loop();
|
||||
ASSERT_EQ(this->link_a.sent.size(), 1);
|
||||
this->link_a.budget = SIZE_MAX;
|
||||
ASSERT_EQ(this->link_a_.sent.size(), 1);
|
||||
this->link_a_.budget = SIZE_MAX;
|
||||
sender->loop();
|
||||
int dictionaries = 0;
|
||||
for (auto &packet : this->link_a.sent)
|
||||
for (auto &packet : this->link_a_.sent)
|
||||
dictionaries += packet[0] == PACKET_DICTIONARY;
|
||||
EXPECT_EQ(dictionaries, 2); // the first part was not sent again
|
||||
this->link_a.deliver_to(this->link_b);
|
||||
EXPECT_EQ(this->remote_temp.get_state(), 4.0f);
|
||||
EXPECT_TRUE(this->remote_door.state);
|
||||
this->link_a_.deliver_to(this->link_b_);
|
||||
EXPECT_EQ(this->remote_temp_.get_state(), 4.0f);
|
||||
EXPECT_TRUE(this->remote_door_.state);
|
||||
}
|
||||
|
||||
TEST_F(EntityTransportTest, RemoteStatesTimeOut) {
|
||||
this->temp.publish_state(6.0f);
|
||||
this->door.publish_state(true);
|
||||
auto sender = this->make_sender();
|
||||
auto receiver = this->make_receiver(DEVICE_NAME, 5000);
|
||||
this->temp_.publish_state(6.0f);
|
||||
this->door_.publish_state(true);
|
||||
auto sender = this->make_sender_();
|
||||
auto receiver = this->make_receiver_(DEVICE_NAME, 5000);
|
||||
{ LoopBlockingGuard guard{nullptr, nullptr, 1000}; }
|
||||
sender->loop();
|
||||
this->link_a.deliver_to(this->link_b);
|
||||
this->link_a_.deliver_to(this->link_b_);
|
||||
{ LoopBlockingGuard guard{nullptr, nullptr, 6000}; }
|
||||
receiver->clear_remote_states_(true);
|
||||
EXPECT_EQ(this->remote_temp.get_state(), 6.0f);
|
||||
EXPECT_TRUE(this->remote_door.has_state());
|
||||
EXPECT_EQ(this->remote_temp_.get_state(), 6.0f);
|
||||
EXPECT_TRUE(this->remote_door_.has_state());
|
||||
{ LoopBlockingGuard guard{nullptr, nullptr, 6001}; }
|
||||
receiver->clear_remote_states_(true);
|
||||
EXPECT_TRUE(std::isnan(this->remote_temp.get_state()));
|
||||
EXPECT_FALSE(this->remote_door.has_state());
|
||||
EXPECT_TRUE(std::isnan(this->remote_temp_.get_state()));
|
||||
EXPECT_FALSE(this->remote_door_.has_state());
|
||||
}
|
||||
|
||||
TEST_F(EntityTransportTest, IdMatchingOnlyUpToNulNotLearnt) {
|
||||
auto receiver = this->make_receiver();
|
||||
auto receiver = this->make_receiver_();
|
||||
static constexpr uint32_t OTHER_ID = 0x0BADF00D;
|
||||
Packet dictionary = header(PACKET_DICTIONARY, OTHER_ID);
|
||||
dictionary.push_back(strlen(DEVICE_NAME));
|
||||
dictionary.insert(dictionary.end(), DEVICE_NAME, DEVICE_NAME + strlen(DEVICE_NAME));
|
||||
// The id "temp" followed by a NUL and more bytes, nine in all
|
||||
dictionary.insert(dictionary.end(), {1, 0, 1, 9, 't', 'e', 'm', 'p', 0, 'a', 'b', 'c', 'd'});
|
||||
this->link_b.inject(dictionary);
|
||||
this->link_b_.inject(dictionary);
|
||||
Packet data = header(PACKET_DATA, OTHER_ID);
|
||||
data.insert(data.end(), {1, 0, 0x00, 0x00, 0x80, 0x3F});
|
||||
this->link_b.inject(data);
|
||||
EXPECT_FALSE(this->remote_temp.has_state());
|
||||
this->link_b_.inject(data);
|
||||
EXPECT_FALSE(this->remote_temp_.has_state());
|
||||
}
|
||||
|
||||
TEST_F(EntityTransportTest, PacketTooSmallForIdsFailsSetup) {
|
||||
// One byte short of a dictionary packet holding the device name and a four character id
|
||||
this->link_a.set_max_packet_size(5 + 1 + strlen(DEVICE_NAME) + 3 + 1 + 4 - 1);
|
||||
auto sender = this->make_sender();
|
||||
this->link_a_.set_max_packet_size(5 + 1 + strlen(DEVICE_NAME) + 3 + 1 + 4 - 1);
|
||||
auto sender = this->make_sender_();
|
||||
EXPECT_TRUE(sender->is_failed());
|
||||
this->link_a.set_max_packet_size(5 + 1 + strlen(DEVICE_NAME) + 3 + 1 + 4);
|
||||
EXPECT_FALSE(this->make_sender()->is_failed());
|
||||
this->link_a_.set_max_packet_size(5 + 1 + strlen(DEVICE_NAME) + 3 + 1 + 4);
|
||||
EXPECT_FALSE(this->make_sender_()->is_failed());
|
||||
}
|
||||
|
||||
} // namespace esphome::entity_transport::testing
|
||||
|
||||
Reference in New Issue
Block a user