generated from wessel/boilerplate
test: Update Database tests, create IMUDatabaseWriter tests
This commit is contained in:
@@ -60,39 +60,40 @@ if(BUILD_TESTING)
|
||||
tomlplusplus::tomlplusplus
|
||||
)
|
||||
|
||||
# Add gtest for IMUDatabaseWriter node
|
||||
ament_add_gtest(${PROJECT_NAME}_test_imu_database_writer
|
||||
test/IMUDatabaseWriter.test.cpp
|
||||
src/imu_database_writer/nodes/IMUDatabaseWriter.cpp
|
||||
src/database/DatabaseManager.cpp
|
||||
src/config/ConfigManager.cpp
|
||||
)
|
||||
target_include_directories(${PROJECT_NAME}_test_imu_database_writer PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/imu_database_writer
|
||||
)
|
||||
ament_target_dependencies(${PROJECT_NAME}_test_imu_database_writer
|
||||
rclcpp
|
||||
sensor_msgs
|
||||
)
|
||||
target_link_libraries(${PROJECT_NAME}_test_imu_database_writer
|
||||
pqxx pq tomlplusplus::tomlplusplus
|
||||
)
|
||||
|
||||
# Add gtest for DatabaseManager
|
||||
# ament_add_gtest(${PROJECT_NAME}_test_database_manager
|
||||
# test/DatabaseManager.test.cpp
|
||||
# src/database/DatabaseManager.cpp
|
||||
# src/config/ConfigManager.cpp
|
||||
# )
|
||||
# target_include_directories(${PROJECT_NAME}_test_database_manager PRIVATE
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||
# )
|
||||
# ament_target_dependencies(${PROJECT_NAME}_test_database_manager
|
||||
# rclcpp
|
||||
# )
|
||||
# target_link_libraries(${PROJECT_NAME}_test_database_manager
|
||||
# pqxx pq tomlplusplus::tomlplusplus
|
||||
# )
|
||||
#
|
||||
# # Add gtest for ExamResultGenerator
|
||||
# ament_add_gtest(${PROJECT_NAME}_test_exam_result_generator
|
||||
# test/ExamResultGenerator.test.cpp
|
||||
# src/exam_result_generator/nodes/ExamResultGenerator.cpp
|
||||
# src/database/DatabaseManager.cpp
|
||||
# src/config/ConfigManager.cpp
|
||||
# )
|
||||
# target_include_directories(${PROJECT_NAME}_test_exam_result_generator PRIVATE
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||
# ${CMAKE_CURRENT_SOURCE_DIR}/src/exam_result_generator
|
||||
# )
|
||||
# ament_target_dependencies(${PROJECT_NAME}_test_exam_result_generator
|
||||
# rclcpp
|
||||
# )
|
||||
# target_link_libraries(${PROJECT_NAME}_test_exam_result_generator
|
||||
# pqxx pq tomlplusplus::tomlplusplus
|
||||
# )
|
||||
ament_add_gtest(${PROJECT_NAME}_test_database_manager
|
||||
test/DatabaseManager.test.cpp
|
||||
src/database/DatabaseManager.cpp
|
||||
src/config/ConfigManager.cpp
|
||||
)
|
||||
target_include_directories(${PROJECT_NAME}_test_database_manager PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||
)
|
||||
ament_target_dependencies(${PROJECT_NAME}_test_database_manager
|
||||
rclcpp
|
||||
)
|
||||
target_link_libraries(${PROJECT_NAME}_test_database_manager
|
||||
pqxx pq tomlplusplus::tomlplusplus
|
||||
)
|
||||
|
||||
# Add Python integration tests
|
||||
# find_package(ament_cmake_pytest REQUIRED)
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#include <rclcpp/rclcpp.hpp>
|
||||
|
||||
#include "database/DatabaseManager.hpp"
|
||||
#include "database/StudentCourse.hpp"
|
||||
|
||||
using namespace assignments::two;
|
||||
|
||||
@@ -31,49 +30,18 @@ TEST_F(DatabaseManagerTest, ConstructorTest) {
|
||||
}
|
||||
|
||||
TEST_F(DatabaseManagerTest, ConnectionStatusTest) {
|
||||
// Should return a boolean (connected or not) — here no DB configured so expect false
|
||||
bool status = db_manager_->is_connected();
|
||||
|
||||
EXPECT_TRUE(status == true || status == false);
|
||||
}
|
||||
|
||||
TEST_F(DatabaseManagerTest, QueuePendingCombinationsTest) {
|
||||
auto combinations = db_manager_->queue_pending_combinations();
|
||||
|
||||
EXPECT_GE(combinations.size(), 0);
|
||||
TEST_F(DatabaseManagerTest, StoreIMUDataWhenNotConnected) {
|
||||
// Without a real DB connection, storing IMU data should return false
|
||||
bool result = db_manager_->store_imu_data(1.0, 2.0, 3.0, 0.1, 0.2, 0.3);
|
||||
EXPECT_FALSE(result);
|
||||
}
|
||||
|
||||
TEST_F(DatabaseManagerTest, StoreExamResultTest) {
|
||||
bool result = db_manager_->store_exam_result("TestStudent", "TestCourse", 85);
|
||||
|
||||
EXPECT_TRUE(result == true || result == false);
|
||||
}
|
||||
|
||||
TEST_F(DatabaseManagerTest, EnrollStudentTest) {
|
||||
StudentCourse sc;
|
||||
sc.student_name = "TestStudent";
|
||||
sc.course_name = "TestCourse";
|
||||
|
||||
bool result = db_manager_->enroll_student_into_course(sc);
|
||||
|
||||
EXPECT_TRUE(result == true || result == false);
|
||||
}
|
||||
|
||||
TEST_F(DatabaseManagerTest, GetFinalGradeTest) {
|
||||
StudentCourse sc;
|
||||
sc.student_name = "NonExistentStudent";
|
||||
sc.course_name = "NonExistentCourse";
|
||||
|
||||
int grade = db_manager_->get_final_course_grade(sc);
|
||||
|
||||
EXPECT_EQ(grade, -1);
|
||||
}
|
||||
|
||||
TEST_F(DatabaseManagerTest, StoreFinalResultTest) {
|
||||
StudentCourse sc;
|
||||
sc.student_name = "TestStudent";
|
||||
sc.course_name = "TestCourse";
|
||||
|
||||
bool result = db_manager_->store_final_course_result(sc, 3, 75, false);
|
||||
|
||||
EXPECT_TRUE(result == true || result == false);
|
||||
TEST_F(DatabaseManagerTest, CreateTablesNoCrash) {
|
||||
// create_tables should be safe to call even when not connected (no throw)
|
||||
EXPECT_NO_THROW(db_manager_->create_tables());
|
||||
}
|
||||
|
||||
104
src/g2_2025_imu_reader_pkg/test/IMUDatabaseWriter.test.cpp
Normal file
104
src/g2_2025_imu_reader_pkg/test/IMUDatabaseWriter.test.cpp
Normal file
@@ -0,0 +1,104 @@
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <rclcpp/rclcpp.hpp>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "imu_database_writer/nodes/IMUDatabaseWriter.hpp"
|
||||
#include "database/DatabaseManager.hpp"
|
||||
#include "sensor_msgs/msg/imu.hpp"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
using namespace assignments::two::imu_database_writer;
|
||||
|
||||
namespace assignments::two {
|
||||
|
||||
class MockDatabaseManager : public DatabaseManager {
|
||||
public:
|
||||
explicit MockDatabaseManager(rclcpp::Logger logger = rclcpp::get_logger("mock_db"))
|
||||
: DatabaseManager(logger) {
|
||||
}
|
||||
|
||||
// Match the current DatabaseManager::store_imu_data signature (no timestamp)
|
||||
bool store_imu_data(
|
||||
double linear_accel_x, double linear_accel_y, double linear_accel_z,
|
||||
double angular_vel_x, double angular_vel_y, double angular_vel_z
|
||||
) override {
|
||||
called_ = true;
|
||||
last_la_x_ = linear_accel_x;
|
||||
last_la_y_ = linear_accel_y;
|
||||
last_la_z_ = linear_accel_z;
|
||||
last_av_x_ = angular_vel_x;
|
||||
last_av_y_ = angular_vel_y;
|
||||
last_av_z_ = angular_vel_z;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool called_ = false;
|
||||
double last_la_x_ = 0.0, last_la_y_ = 0.0, last_la_z_ = 0.0;
|
||||
double last_av_x_ = 0.0, last_av_y_ = 0.0, last_av_z_ = 0.0;
|
||||
};
|
||||
|
||||
} // namespace assignments::two
|
||||
|
||||
class IMUDatabaseWriterTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
rclcpp::init(0, nullptr);
|
||||
test_node_ = std::make_shared<rclcpp::Node>("test_node");
|
||||
|
||||
// create mock db and inject
|
||||
mock_db_ = std::make_unique<assignments::two::MockDatabaseManager>(rclcpp::get_logger("test_mock_db"));
|
||||
mock_db_ptr_ = mock_db_.get();
|
||||
|
||||
imu_node_ = std::make_shared<IMUDatabaseWriter>(std::move(mock_db_));
|
||||
|
||||
// publisher in test node
|
||||
imu_publisher_ = test_node_->create_publisher<sensor_msgs::msg::Imu>("imu_data", 10);
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
imu_node_.reset();
|
||||
test_node_.reset();
|
||||
rclcpp::shutdown();
|
||||
}
|
||||
|
||||
void spin_some_time(std::chrono::milliseconds duration = 200ms) {
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
while (std::chrono::steady_clock::now() - start < duration) {
|
||||
rclcpp::spin_some(test_node_);
|
||||
if (imu_node_) rclcpp::spin_some(imu_node_);
|
||||
std::this_thread::sleep_for(10ms);
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<rclcpp::Node> test_node_;
|
||||
std::shared_ptr<IMUDatabaseWriter> imu_node_;
|
||||
std::unique_ptr<assignments::two::MockDatabaseManager> mock_db_;
|
||||
assignments::two::MockDatabaseManager* mock_db_ptr_ = nullptr;
|
||||
rclcpp::Publisher<sensor_msgs::msg::Imu>::SharedPtr imu_publisher_;
|
||||
};
|
||||
|
||||
TEST_F(IMUDatabaseWriterTest, ConstructorTest) {
|
||||
ASSERT_NE(imu_node_, nullptr);
|
||||
}
|
||||
|
||||
TEST_F(IMUDatabaseWriterTest, ReceivesAndForwardsIMU) {
|
||||
auto msg = sensor_msgs::msg::Imu();
|
||||
msg.linear_acceleration.x = 1.23;
|
||||
msg.linear_acceleration.y = -0.5;
|
||||
msg.linear_acceleration.z = 0.0;
|
||||
msg.angular_velocity.x = 0.01;
|
||||
msg.angular_velocity.y = -0.02;
|
||||
msg.angular_velocity.z = 0.03;
|
||||
|
||||
imu_publisher_->publish(msg);
|
||||
|
||||
spin_some_time(300ms);
|
||||
|
||||
EXPECT_TRUE(mock_db_ptr_->called_);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
@@ -5,7 +5,6 @@
|
||||
namespace assignments::two {
|
||||
|
||||
struct MockStoredResult {
|
||||
StudentCourse sc;
|
||||
int exam_count;
|
||||
int final_grade;
|
||||
bool is_retake;
|
||||
@@ -28,45 +27,13 @@ public:
|
||||
connection_status_ = status;
|
||||
}
|
||||
|
||||
std::vector<StudentCourse> get_failed_course_results() {
|
||||
return failed_students_;
|
||||
}
|
||||
|
||||
bool store_final_course_result(
|
||||
const StudentCourse& sc,
|
||||
int exam_count,
|
||||
int final_grade,
|
||||
bool is_retake
|
||||
) {
|
||||
stored_results.push_back({ sc, exam_count, final_grade, is_retake });
|
||||
return true;
|
||||
}
|
||||
|
||||
bool update_retake_status(const StudentCourse& sc) {
|
||||
retake_status_updates.push_back(sc);
|
||||
return true;
|
||||
}
|
||||
|
||||
void clear_failed_students() {
|
||||
failed_students_.clear();
|
||||
}
|
||||
|
||||
void add_failed_student(const std::string& student_name, const std::string& course_name) {
|
||||
StudentCourse sc;
|
||||
sc.student_name = student_name;
|
||||
sc.course_name = course_name;
|
||||
failed_students_.push_back(sc);
|
||||
}
|
||||
|
||||
void set_failed_students(const std::vector<StudentCourse>& failed_students) {
|
||||
failed_students_ = failed_students;
|
||||
}
|
||||
|
||||
std::vector<MockStoredResult> stored_results;
|
||||
std::vector<StudentCourse> retake_status_updates;
|
||||
|
||||
private:
|
||||
std::vector<StudentCourse> failed_students_;
|
||||
bool connection_status_ = true;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace assignments::two {
|
||||
|
||||
class MockRetakeActionServer {
|
||||
public:
|
||||
MockRetakeActionServer(std::shared_ptr<rclcpp::Node> node) : node_(node) {
|
||||
action_server_ = rclcpp_action::create_server<g2_2025_interfaces::action::Retake>(
|
||||
node_,
|
||||
"retake_action",
|
||||
std::bind(&MockRetakeActionServer::handle_goal, this, std::placeholders::_1, std::placeholders::_2),
|
||||
std::bind(&MockRetakeActionServer::handle_cancel, this, std::placeholders::_1),
|
||||
std::bind(&MockRetakeActionServer::handle_accepted, this, std::placeholders::_1)
|
||||
);
|
||||
}
|
||||
|
||||
rclcpp_action::GoalResponse handle_goal(
|
||||
const rclcpp_action::GoalUUID & uuid,
|
||||
std::shared_ptr<const g2_2025_interfaces::action::Retake::Goal> goal
|
||||
) {
|
||||
(void)uuid;
|
||||
received_goals_.push_back(*goal);
|
||||
return goal_response_;
|
||||
}
|
||||
|
||||
rclcpp_action::CancelResponse handle_cancel(
|
||||
const std::shared_ptr<rclcpp_action::ServerGoalHandle<g2_2025_interfaces::action::Retake>> goal_handle
|
||||
) {
|
||||
(void)goal_handle;
|
||||
cancel_requests++;
|
||||
return rclcpp_action::CancelResponse::ACCEPT;
|
||||
}
|
||||
|
||||
void handle_accepted(const std::shared_ptr<rclcpp_action::ServerGoalHandle<g2_2025_interfaces::action::Retake>> goal_handle) {
|
||||
accepted_goals++;
|
||||
|
||||
// Simulate immediate success
|
||||
auto result = std::make_shared<g2_2025_interfaces::action::Retake::Result>();
|
||||
result->result = 0.0;
|
||||
goal_handle->succeed(result);
|
||||
}
|
||||
|
||||
void set_goal_response(rclcpp_action::GoalResponse response) {
|
||||
goal_response_ = response;
|
||||
}
|
||||
|
||||
std::vector<g2_2025_interfaces::action::Retake::Goal> received_goals_;
|
||||
int accepted_goals = 0;
|
||||
int cancel_requests = 0;
|
||||
|
||||
private:
|
||||
std::shared_ptr<rclcpp::Node> node_;
|
||||
rclcpp_action::Server<g2_2025_interfaces::action::Retake>::SharedPtr action_server_;
|
||||
rclcpp_action::GoalResponse goal_response_ = rclcpp_action::GoalResponse::ACCEPT_AND_EXECUTE;
|
||||
};
|
||||
|
||||
} // namespace assignments::two
|
||||
Reference in New Issue
Block a user