diff --git a/eqpalg/CMakeLists.txt b/eqpalg/CMakeLists.txt index fb64423..c94c913 100644 --- a/eqpalg/CMakeLists.txt +++ b/eqpalg/CMakeLists.txt @@ -94,23 +94,33 @@ target_include_directories( set_target_properties(eqpalg PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${bin_dir}) # ###################### add test ######################## -# 1. loss_compress_test -# -# ############################################################################## -# include(../cmake_include/unit_test.cmake) +include(CTest) -# add_executable(loss_compress_test ${DISTRIBUTION} test/loss_compress_test.cc) -# target_link_libraries(loss_compress_test ${LINK_OPTION} -# Boost::unit_test_framework) -# target_include_directories( -# loss_compress_test PUBLIC ./ ../ ../../inc ../../inc/dbinc -# ${iPlature_include}) +aux_source_directory(./test TEST_SOURCES) -# set_target_properties(loss_compress_test PROPERTIES RUNTIME_OUTPUT_DIRECTORY -# ${UNIT_TEST_BIN_OUTPUT_DIR}) +add_executable(eqpalg_test + ${TEST_SOURCES} + ./utility/expression_engine.cpp +) -# enable_testing() -# add_test( -# NAME loss_compress_test -# WORKING_DIRECTORY ${UNIT_TEST_BIN_OUTPUT_DIR} -# COMMAND loss_compress_test) +target_include_directories(eqpalg_test PUBLIC + ./ + ../ + ${my_lib_include} + ${iplature_include} +) + +target_link_libraries(eqpalg_test + ${LINK_OPTION} + ${Boost_LIBRARIES} + ${mix_cc} + nlohmann_json::nlohmann_json + Eigen3::Eigen +) + +set_target_properties(eqpalg_test PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/test) + +enable_testing() +add_test(NAME eqpalg_test + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/test + COMMAND eqpalg_test) diff --git a/eqpalg/test/test_expression_engine.cc b/eqpalg/test/test_expression_engine.cc new file mode 100644 index 0000000..43695fa --- /dev/null +++ b/eqpalg/test/test_expression_engine.cc @@ -0,0 +1,140 @@ +// eqpalg/test/test_expression_engine.cc +#include "test_harness.h" +#include +#include +#include +#include + +// 测试辅助:构建最小环境 +struct TestEnv { + std::map vars; + std::vector tags; + ExpressionEngine engine; + + TestEnv() : engine(vars, tags) { + tags = {"tag1", "tag2"}; + + vars["tag1"] = 10.0; + vars["tag2"] = 20.0; + vars["p1"] = 10.0; + vars["p2"] = 20.0; + vars["now"] = 0; + vars["stime"] = 0; + vars["time"] = 0; + vars["etime"] = 0; + } +}; + +// ==================== 注册与求值 ==================== + +TEST(register_and_evaluate_simple_expression) { + TestEnv env; + int ret = env.engine.registerExpression("test", "tag1 + tag2"); + CHECK_EQ(ret, 0); + CHECK_FLOAT_EQ(env.engine.evaluate("test"), 30.0, 0.001); + CHECK_EQ(env.engine.evaluateBool("test"), true); +} + +TEST(register_duplicate_is_idempotent) { + TestEnv env; + CHECK_EQ(env.engine.registerExpression("dup", "tag1"), 0); + CHECK_EQ(env.engine.registerExpression("dup", "tag2"), 0); + CHECK_FLOAT_EQ(env.engine.evaluate("dup"), 10.0, 0.001); +} + +TEST(evaluate_unregistered_returns_zero) { + TestEnv env; + CHECK_FLOAT_EQ(env.engine.evaluate("nonexistent"), 0.0, 0.001); + CHECK_EQ(env.engine.evaluateBool("nonexistent"), false); +} + +TEST(evaluate_zero_expression) { + TestEnv env; + CHECK_EQ(env.engine.registerExpression("zero", "0"), 0); + CHECK_FLOAT_EQ(env.engine.evaluate("zero"), 0.0, 0.001); + CHECK_EQ(env.engine.evaluateBool("zero"), false); +} + +TEST(evaluate_boolean_true_constant) { + TestEnv env; + CHECK_EQ(env.engine.registerExpression("one", "1"), 0); + CHECK_EQ(env.engine.evaluateBool("one"), true); +} + +// ==================== 变量变化反映到求值 ==================== + +TEST(variable_change_reflected_in_evaluation) { + TestEnv env; + CHECK_EQ(env.engine.registerExpression("x", "tag1"), 0); + CHECK_FLOAT_EQ(env.engine.evaluate("x"), 10.0, 0.001); + + env.vars["tag1"] = 100.0; + CHECK_FLOAT_EQ(env.engine.evaluate("x"), 100.0, 0.001); +} + +// ==================== 多表达式并存 ==================== + +TEST(multiple_expressions_independent) { + TestEnv env; + CHECK_EQ(env.engine.registerExpression("a", "tag1"), 0); + CHECK_EQ(env.engine.registerExpression("b", "tag2"), 0); + CHECK_EQ(env.engine.registerExpression("sum", "tag1 + tag2"), 0); + + CHECK_FLOAT_EQ(env.engine.evaluate("a"), 10.0, 0.001); + CHECK_FLOAT_EQ(env.engine.evaluate("b"), 20.0, 0.001); + CHECK_FLOAT_EQ(env.engine.evaluate("sum"), 30.0, 0.001); + + env.vars["tag1"] = 100.0; + CHECK_FLOAT_EQ(env.engine.evaluate("a"), 100.0, 0.001); + CHECK_FLOAT_EQ(env.engine.evaluate("sum"), 120.0, 0.001); +} + +// ==================== registerRawExpression ==================== + +TEST(register_raw_no_funvars_processing) { + TestEnv env; + CHECK_EQ(env.engine.registerRawExpression("raw", "tag1 + tag2"), 0); + CHECK_FLOAT_EQ(env.engine.evaluate("raw"), 30.0, 0.001); +} + +// ==================== FunVars 重置控制 ==================== + +TEST(autoReset_does_nothing_when_not_marked) { + TestEnv env; + CHECK_EQ(env.engine.registerExpression("test", "tag1"), 0); + // 无标记时 autoReset 什么都不做 + env.engine.autoResetFunVars(); + CHECK_FLOAT_EQ(env.engine.evaluate("test"), 10.0, 0.001); +} + +TEST(mark_and_autoReset_sequence) { + TestEnv env; + CHECK_EQ(env.engine.registerExpression("test", "tag1"), 0); + env.engine.markFunVarsNeedReset(); + env.engine.autoResetFunVars(); // 执行重置并清除标记 + // 第二次应该是 no-op + env.engine.autoResetFunVars(); +} + +TEST(forceReset_works) { + TestEnv env; + CHECK_EQ(env.engine.registerExpression("test", "tag1"), 0); + env.engine.forceResetFunVars(); +} + +// ==================== 复杂表达式 ==================== + +TEST(comparison_expression) { + TestEnv env; + CHECK_EQ(env.engine.registerExpression("cmp", "tag1 > tag2"), 0); + CHECK_EQ(env.engine.evaluateBool("cmp"), false); + + env.vars["tag1"] = 30.0; + CHECK_EQ(env.engine.evaluateBool("cmp"), true); +} + +TEST(arithmetic_with_comparison) { + TestEnv env; + CHECK_EQ(env.engine.registerExpression("arith", "tag1 * 2 + tag2"), 0); + CHECK_FLOAT_EQ(env.engine.evaluate("arith"), 40.0, 0.001); +}