Skip to content

Commit

Permalink
🚚 Fix atomic spin lock & merge mock with util (#41)
Browse files Browse the repository at this point in the history
* 🐛 Fix linking error with atomic_spin_lock

* 🚚 Migrate libhal-mock to libhal-util

Deprecate libhal-mock and merge with libhal-util.
Rationale: Maintaining additional package repos requires effort and
work. I don't see the value in keeping mock as its own repo when we
could provide it via util. I don't think mocks are going to change that
often to be destructive to libhal-util. I don't see what value they have
as their own repos. But I see valuing in util having mocking
capabilities built in.
  • Loading branch information
kammce authored Nov 30, 2024
1 parent 370e32d commit 293fe8f
Show file tree
Hide file tree
Showing 16 changed files with 1,145 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ set(TEST_SOURCES_LIST
tests/inert_drivers/inert_temperature_sensor.test.cpp
tests/inert_drivers/inert_timer.test.cpp
tests/as_bytes.test.cpp
tests/atomic_spin_lock.test.cpp
tests/can.test.cpp
tests/bit.test.cpp
tests/enum.test.cpp
Expand All @@ -58,6 +59,7 @@ set(TEST_SOURCES_LIST
set(SOURCES_LIST
src/steady_clock.cpp
src/streams.cpp
src/atomic_spin_lock.cpp
)

if(NOT ${CMAKE_CROSSCOMPILING})
Expand Down
57 changes: 57 additions & 0 deletions include/libhal-util/mock/adc.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright 2024 Khalil Estell
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

#include <queue>

#include <libhal/adc.hpp>
#include <libhal/error.hpp>

namespace hal {
/**
* @brief Mock adc implementation for use in unit tests and simulations.
*/
struct mock_adc : public hal::adc
{
/**
* @brief Queues the floats to be returned for read()
*
* @param p_adc_values - queue of floats
*/
void set(std::queue<float>& p_adc_values)
{
m_adc_values = p_adc_values;
}

private:
/**
* @brief mock implementation of driver_read()
*
* @return float - adc value from queue
* @throws throw hal::operation_not_permitted - if the adc queue runs out
*/
float driver_read() override
{
if (m_adc_values.size() == 0) {
throw hal::operation_not_permitted(this);
}
auto m_current_value = m_adc_values.front();
m_adc_values.pop();
return m_current_value;
}

std::queue<float> m_adc_values{};
};
} // namespace hal
100 changes: 100 additions & 0 deletions include/libhal-util/mock/can.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// Copyright 2024 Khalil Estell
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

#include <libhal/can.hpp>
#include <libhal/functional.hpp>

#include "testing.hpp"

namespace hal {
/**
* @brief Mock can implementation for use in unit tests and simulations
*
*/
struct mock_can : public hal::can
{
/**
* @brief Reset spy information for functions
*
*/
void reset()
{
spy_configure.reset();
spy_send.reset();
spy_on_receive.reset();
spy_bus_on.reset();
}

/// Spy handler for hal::can::configure()
spy_handler<settings> spy_configure;
/// Spy handler for hal::can::send()
spy_handler<message_t> spy_send;
/// Spy handler for hal::can::bus_on() will always have content of "true"
spy_handler<bool> spy_bus_on;
/// Spy handler for hal::can::on_receive()
spy_handler<hal::callback<handler>> spy_on_receive;

private:
void driver_configure(settings const& p_settings) override
{
spy_configure.record(p_settings);
}

void driver_bus_on() override
{
spy_bus_on.record(true);
}

void driver_send(message_t const& p_message) override
{
spy_send.record(p_message);
}

void driver_on_receive(hal::callback<handler> p_handler) override
{
spy_on_receive.record(p_handler);
}
};
} // namespace hal

/**
* @brief print can::message_t type using ostreams
*
* Meant for unit testing, testing and simulation purposes
* C++ streams, in general, should not be used for any embedded project that
* will ever have to be used on an MCU due to its memory cost.
*
* @tparam CharT - character type
* @tparam Traits - ostream traits type
* @param p_ostream - the ostream
* @param p_message - object to convert to a string
* @return std::basic_ostream<CharT, Traits>& - reference to the ostream
*/
template<class CharT, class Traits>
std::basic_ostream<CharT, Traits>& operator<<(
std::basic_ostream<CharT, Traits>& p_ostream,
hal::can::message_t const& p_message)
{
p_ostream << "{ id: " << std::hex << "0x" << p_message.id;
p_ostream << ", length: " << std::dec << unsigned{ p_message.length };
p_ostream << ", is_remote_request: " << p_message.is_remote_request;
p_ostream << ", payload = [";
for (auto const& element : p_message.payload) {
p_ostream << std::hex << "0x" << unsigned{ element } << ", ";
}
p_ostream << "] }";
return p_ostream;
}
47 changes: 47 additions & 0 deletions include/libhal-util/mock/dac.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright 2024 Khalil Estell
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

#include <libhal/dac.hpp>

#include "testing.hpp"

namespace hal {
/**
* @brief Mock dac implementation for use in unit tests and simulations with a
* spy function for write()
*
*/
struct dac_mock : public hal::dac
{
/**
* @brief Reset spy information for write()
*
*/
void reset()
{
spy_write.reset();
}

/// Spy handler for hal::dac::write()
spy_handler<float> spy_write;

private:
void driver_write(float p_value) override
{
spy_write.record(p_value);
};
};
} // namespace hal
80 changes: 80 additions & 0 deletions include/libhal-util/mock/input_pin.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Copyright 2024 Khalil Estell
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

#include <libhal/error.hpp>
#include <queue>

#include <libhal/input_pin.hpp>

#include "testing.hpp"

namespace hal {
/**
* @brief mock input_pin implementation for use in unit tests and simulations.
*
*/
struct mock_input_pin : public hal::input_pin
{
/**
* @brief Reset spy information for configure()
*
*/
void reset()
{
spy_configure.reset();
}

/// Spy handler for embed:input_pin::configure()
spy_handler<settings> spy_configure;

/**
* @brief Queues the active levels to be returned for levels()
*
* @param p_levels - queue of actives levels
*/
void set(std::queue<bool>& p_levels)
{
m_levels = p_levels;
}

private:
void driver_configure(settings const& p_settings) override
{
spy_configure.record(p_settings);
}
/**
* @brief Mock implementation of input_pin::driver_level
*
* @return true - high voltage
* @return false - low voltage
* @throws throw hal::operation_not_permitted - if the input pin value queue
* runs out of elements
*/
bool driver_level() override
{
// This comparison performs bounds checking because front() and pop() do
// not bounds check and results in undefined behavior if the queue is empty.
if (m_levels.size() == 0) {
throw hal::operation_not_permitted(this);
}
auto m_current_value = m_levels.front();
m_levels.pop();
return m_current_value;
}

std::queue<bool> m_levels{};
};
} // namespace hal
55 changes: 55 additions & 0 deletions include/libhal-util/mock/interrupt_pin.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright 2024 Khalil Estell
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

#include <libhal/interrupt_pin.hpp>

#include "testing.hpp"

namespace hal {
/**
* @brief mock interrupt_pin implementation for use in unit tests and
* simulations.
*
*/
struct mock_interrupt_pin : public hal::interrupt_pin
{
/**
* @brief Reset spy information for configure(), on_trigger(), and
* disable()
*
*/
void reset()
{
spy_configure.reset();
spy_on_trigger.reset();
}

/// Spy handler for hal::interrupt_pin::configure()
spy_handler<settings> spy_configure;
/// Spy handler for hal::interrupt_pin::on_trigger()
spy_handler<std::function<handler>> spy_on_trigger;

private:
void driver_configure(settings const& p_settings) override
{
spy_configure.record(p_settings);
}
void driver_on_trigger(hal::callback<handler> p_callback) override
{
spy_on_trigger.record(p_callback);
}
};
} // namespace hal
Loading

0 comments on commit 293fe8f

Please sign in to comment.