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
|
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
|
# Add gtest for DatabaseManager
|
||||||
# ament_add_gtest(${PROJECT_NAME}_test_database_manager
|
ament_add_gtest(${PROJECT_NAME}_test_database_manager
|
||||||
# test/DatabaseManager.test.cpp
|
test/DatabaseManager.test.cpp
|
||||||
# src/database/DatabaseManager.cpp
|
src/database/DatabaseManager.cpp
|
||||||
# src/config/ConfigManager.cpp
|
src/config/ConfigManager.cpp
|
||||||
# )
|
)
|
||||||
# target_include_directories(${PROJECT_NAME}_test_database_manager PRIVATE
|
target_include_directories(${PROJECT_NAME}_test_database_manager PRIVATE
|
||||||
# ${CMAKE_CURRENT_SOURCE_DIR}/src
|
${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||||
# )
|
)
|
||||||
# ament_target_dependencies(${PROJECT_NAME}_test_database_manager
|
ament_target_dependencies(${PROJECT_NAME}_test_database_manager
|
||||||
# rclcpp
|
rclcpp
|
||||||
# )
|
)
|
||||||
# target_link_libraries(${PROJECT_NAME}_test_database_manager
|
target_link_libraries(${PROJECT_NAME}_test_database_manager
|
||||||
# pqxx pq tomlplusplus::tomlplusplus
|
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
|
|
||||||
# )
|
|
||||||
|
|
||||||
# Add Python integration tests
|
# Add Python integration tests
|
||||||
# find_package(ament_cmake_pytest REQUIRED)
|
# find_package(ament_cmake_pytest REQUIRED)
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
#include <rclcpp/rclcpp.hpp>
|
#include <rclcpp/rclcpp.hpp>
|
||||||
|
|
||||||
#include "database/DatabaseManager.hpp"
|
#include "database/DatabaseManager.hpp"
|
||||||
#include "database/StudentCourse.hpp"
|
|
||||||
|
|
||||||
using namespace assignments::two;
|
using namespace assignments::two;
|
||||||
|
|
||||||
@@ -31,49 +30,18 @@ TEST_F(DatabaseManagerTest, ConstructorTest) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DatabaseManagerTest, ConnectionStatusTest) {
|
TEST_F(DatabaseManagerTest, ConnectionStatusTest) {
|
||||||
|
// Should return a boolean (connected or not) — here no DB configured so expect false
|
||||||
bool status = db_manager_->is_connected();
|
bool status = db_manager_->is_connected();
|
||||||
|
|
||||||
EXPECT_TRUE(status == true || status == false);
|
EXPECT_TRUE(status == true || status == false);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DatabaseManagerTest, QueuePendingCombinationsTest) {
|
TEST_F(DatabaseManagerTest, StoreIMUDataWhenNotConnected) {
|
||||||
auto combinations = db_manager_->queue_pending_combinations();
|
// 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_GE(combinations.size(), 0);
|
EXPECT_FALSE(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DatabaseManagerTest, StoreExamResultTest) {
|
TEST_F(DatabaseManagerTest, CreateTablesNoCrash) {
|
||||||
bool result = db_manager_->store_exam_result("TestStudent", "TestCourse", 85);
|
// create_tables should be safe to call even when not connected (no throw)
|
||||||
|
EXPECT_NO_THROW(db_manager_->create_tables());
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|||||||
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 {
|
namespace assignments::two {
|
||||||
|
|
||||||
struct MockStoredResult {
|
struct MockStoredResult {
|
||||||
StudentCourse sc;
|
|
||||||
int exam_count;
|
int exam_count;
|
||||||
int final_grade;
|
int final_grade;
|
||||||
bool is_retake;
|
bool is_retake;
|
||||||
@@ -28,45 +27,13 @@ public:
|
|||||||
connection_status_ = status;
|
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() {
|
void clear_failed_students() {
|
||||||
failed_students_.clear();
|
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<MockStoredResult> stored_results;
|
||||||
std::vector<StudentCourse> retake_status_updates;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<StudentCourse> failed_students_;
|
|
||||||
bool connection_status_ = true;
|
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