Initial commit
This commit is contained in:
85
tests/README.md
Normal file
85
tests/README.md
Normal file
@@ -0,0 +1,85 @@
|
||||
# WASM Regression Tests
|
||||
|
||||
## How to run
|
||||
|
||||
1. Build the business WASM module:
|
||||
|
||||
```powershell
|
||||
npm run build
|
||||
```
|
||||
|
||||
2. Run the regression suite:
|
||||
|
||||
```powershell
|
||||
npm run test:wasm
|
||||
```
|
||||
|
||||
3. Build and run in one step:
|
||||
|
||||
```powershell
|
||||
npm test
|
||||
```
|
||||
|
||||
The runner loads `public/wasm/smart_math.js`, calls `init_func`, then executes the business API through `func`.
|
||||
|
||||
## Test program
|
||||
|
||||
- Runner: `scripts/run_wasm_tests.js`
|
||||
- Entry exports used:
|
||||
- `_init_func`
|
||||
- `_func`
|
||||
- `_smart_free_string`
|
||||
|
||||
The runner is data-driven for stable request samples, and adds two dynamic FK/IK roundtrip cases so inverse kinematics is checked against forward kinematics instead of hard-coded pose strings.
|
||||
|
||||
## Test data
|
||||
|
||||
### Kinematics
|
||||
|
||||
- `tests/testdata/kinematics/list_robots.json`
|
||||
- Verifies the built-in robot initialization completed and at least two robots are available.
|
||||
- `tests/testdata/kinematics/forward_zero.json`
|
||||
- Verifies TCP forward kinematics at zero joints.
|
||||
- `tests/testdata/kinematics/forward_all_joints_path.json`
|
||||
- Verifies all-joint forward export for two frames.
|
||||
- `tests/testdata/kinematics/roundtrip_single_seed.json`
|
||||
- Seed joints for FK -> IK -> FK single-pose regression.
|
||||
- `tests/testdata/kinematics/roundtrip_path_seed.json`
|
||||
- Seed joints for two-pose path interpolation regression.
|
||||
|
||||
### SPC
|
||||
|
||||
- `tests/testdata/spc/basic_5x30.json`
|
||||
- Canonical 150-point SPC sample.
|
||||
- Uses the actual command name `Cmd_Spc`.
|
||||
|
||||
### Four-bar / Crank slider
|
||||
|
||||
- `tests/testdata/fourbar/crank_slider_valid.json`
|
||||
- Normal calculation case.
|
||||
- `tests/testdata/fourbar/crank_slider_invalid.json`
|
||||
- Invalid parameter case to verify validation and error return.
|
||||
|
||||
### Quadruped robot
|
||||
|
||||
- `tests/testdata/quadruped/calculate_points_from_motor_angles.json`
|
||||
- Verifies reverse result export from motor angles.
|
||||
- `tests/testdata/quadruped/perform_forward_kinematics.json`
|
||||
- Verifies gait trajectory generation with explicit gait/system parameters.
|
||||
|
||||
## What is asserted
|
||||
|
||||
- Top-level API success and required result fields.
|
||||
- Expected frame count / robot count / array length.
|
||||
- Four-bar validation errors for bad inputs.
|
||||
- SPC subgroup size and spec limits.
|
||||
- Quadruped result structure.
|
||||
- FK/IK roundtrip tolerances:
|
||||
- single pose position tolerance: `0.002`
|
||||
- single pose quaternion tolerance: `0.002`
|
||||
- path endpoint position tolerance: `0.01`
|
||||
|
||||
## Notes
|
||||
|
||||
- The old ad-hoc files such as `spc_in.txt` and `WorkTest.json` are still useful as raw references, but the regression runner uses the normalized data under `tests/testdata`.
|
||||
- If you change URDF, robot naming, or quadruped default config, update the corresponding files under `tests/testdata` first.
|
||||
188
tests/test_smart_json.cpp
Normal file
188
tests/test_smart_json.cpp
Normal file
@@ -0,0 +1,188 @@
|
||||
#include "../src/smart_json_wrapper.h"
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
void printSeparator()
|
||||
{
|
||||
std::cout << "\n"
|
||||
<< std::string(60, '=') << "\n"
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
void printTestResult(const std::string &testName, bool passed)
|
||||
{
|
||||
std::cout << (passed ? "✅ " : "❌ ") << testName << std::endl;
|
||||
}
|
||||
|
||||
void testFunctionRegistry()
|
||||
{
|
||||
std::cout << "测试函数注册表..." << std::endl;
|
||||
|
||||
auto ®istry = FunctionRegistry::instance();
|
||||
auto functions = registry.getAllFunctions();
|
||||
|
||||
std::cout << "注册的函数数量: " << functions.size() << std::endl;
|
||||
for (const auto &[name, func] : functions)
|
||||
{
|
||||
std::cout << " - " << name << ": " << func->description << std::endl;
|
||||
}
|
||||
|
||||
printTestResult("函数注册表测试", functions.size() > 0);
|
||||
}
|
||||
|
||||
void testSmartJsonProcessor()
|
||||
{
|
||||
std::cout << "测试智能JSON处理器..." << std::endl;
|
||||
|
||||
SmartJsonProcessor processor;
|
||||
|
||||
// 测试用例
|
||||
std::vector<std::pair<std::string, std::string>> test_cases = {
|
||||
{"标准参数名",
|
||||
R"({
|
||||
"req_code": "TEST_001",
|
||||
"req_cmd": "add",
|
||||
"a": 10,
|
||||
"b": 20
|
||||
})"},
|
||||
{"别名参数名",
|
||||
R"({
|
||||
"req_code": "TEST_002",
|
||||
"req_cmd": "add",
|
||||
"num1": 30,
|
||||
"num2": 40
|
||||
})"},
|
||||
{"不同大小写",
|
||||
R"({
|
||||
"req_code": "TEST_003",
|
||||
"req_cmd": "ADD",
|
||||
"First": 50,
|
||||
"Second": 60
|
||||
})"},
|
||||
{"浮点数乘法",
|
||||
R"({
|
||||
"req_code": "TEST_004",
|
||||
"req_cmd": "multiply",
|
||||
"a": 2.5,
|
||||
"b": 4.0
|
||||
})"},
|
||||
{"斐波那契",
|
||||
R"({
|
||||
"req_code": "TEST_005",
|
||||
"req_cmd": "fibonacci",
|
||||
"n": 10
|
||||
})"}};
|
||||
|
||||
int passed_tests = 0;
|
||||
for (const auto &[test_name, json_request] : test_cases)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto response = processor.processRequest(json_request);
|
||||
std::cout << " " << test_name << ": ";
|
||||
if (response.success)
|
||||
{
|
||||
std::cout << "✅ (耗时: " << response.execution_time << "ms)" << std::endl;
|
||||
passed_tests++;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "❌ 错误: " << response.msg << std::endl;
|
||||
}
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
std::cout << " " << test_name << ": ❌ 异常: " << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
printTestResult("智能JSON处理器测试", passed_tests == test_cases.size());
|
||||
}
|
||||
|
||||
void testFunctionInfo()
|
||||
{
|
||||
std::cout << "测试函数信息查询..." << std::endl;
|
||||
|
||||
SmartJsonProcessor processor;
|
||||
|
||||
std::vector<std::string> functions_to_test = {"add", "multiply", "fibonacci", "unknown_function"};
|
||||
|
||||
int passed_tests = 0;
|
||||
for (const auto &func_name : functions_to_test)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::string info = processor.getFunctionInfo(func_name);
|
||||
std::cout << " " << func_name << ": ";
|
||||
if (info.find("未找到") == std::string::npos)
|
||||
{
|
||||
std::cout << "✅" << std::endl;
|
||||
passed_tests++;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "❌ " << info << std::endl;
|
||||
}
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
std::cout << " " << func_name << ": ❌ 异常: " << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
printTestResult("函数信息查询测试", passed_tests >= 3);
|
||||
}
|
||||
|
||||
void testAvailableFunctions()
|
||||
{
|
||||
std::cout << "测试可用函数列表..." << std::endl;
|
||||
|
||||
SmartJsonProcessor processor;
|
||||
auto functions = processor.getAvailableFunctions();
|
||||
|
||||
std::cout << "可用函数:" << std::endl;
|
||||
for (const auto &[name, func_info] : functions)
|
||||
{
|
||||
std::cout << " - " << name << " (" << func_info->description << ")" << std::endl;
|
||||
std::cout << " 参数: ";
|
||||
for (const auto ¶m : func_info->params)
|
||||
{
|
||||
std::cout << param.name << "(" << param.getTypeName() << ") ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
printTestResult("可用函数列表测试", !functions.empty());
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cout << "\n";
|
||||
std::cout << "=========================================" << std::endl;
|
||||
std::cout << " Smart WASM JSON API 测试套件 " << std::endl;
|
||||
std::cout << "=========================================" << std::endl;
|
||||
|
||||
try
|
||||
{
|
||||
testFunctionRegistry();
|
||||
printSeparator();
|
||||
|
||||
testSmartJsonProcessor();
|
||||
printSeparator();
|
||||
|
||||
testFunctionInfo();
|
||||
printSeparator();
|
||||
|
||||
testAvailableFunctions();
|
||||
printSeparator();
|
||||
|
||||
std::cout << "\n🎉 所有测试完成!" << std::endl;
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
std::cerr << "\n❌ 测试过程中发生异常: " << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
12
tests/testdata/fourbar/crank_slider_invalid.json
vendored
Normal file
12
tests/testdata/fourbar/crank_slider_invalid.json
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"msg": "fourbar invalid",
|
||||
"req_code": "CASE_FB_002",
|
||||
"req_from": "wasm_test",
|
||||
"req_cmd": "Cmd_FourBar_CrankSlider",
|
||||
"req_param": {
|
||||
"L_AB": 0.0,
|
||||
"L_BS": 0.2,
|
||||
"S_OFS": 0.5,
|
||||
"angleDeg": 30.0
|
||||
}
|
||||
}
|
||||
12
tests/testdata/fourbar/crank_slider_valid.json
vendored
Normal file
12
tests/testdata/fourbar/crank_slider_valid.json
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"msg": "fourbar valid",
|
||||
"req_code": "CASE_FB_001",
|
||||
"req_from": "wasm_test",
|
||||
"req_cmd": "Cmd_FourBar_CrankSlider",
|
||||
"req_param": {
|
||||
"L_AB": 0.5,
|
||||
"L_BS": 2.0,
|
||||
"S_OFS": 0.0,
|
||||
"angleDeg": 45.0
|
||||
}
|
||||
}
|
||||
10
tests/testdata/kinematics/forward_all_joints_path.json
vendored
Normal file
10
tests/testdata/kinematics/forward_all_joints_path.json
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"msg": "fk all joints path",
|
||||
"req_code": "CASE_FK_ALL_001",
|
||||
"req_from": "wasm_test",
|
||||
"req_cmd": "Cmd_Kinematics_forward_all_joints",
|
||||
"req_param": {
|
||||
"robot_uuid": "abb_irb120_3_58",
|
||||
"joints_str": "0,0,0,0,0,0;0.15,-0.25,0.35,0.10,-0.20,0.30"
|
||||
}
|
||||
}
|
||||
10
tests/testdata/kinematics/forward_zero.json
vendored
Normal file
10
tests/testdata/kinematics/forward_zero.json
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"msg": "fk zero pose",
|
||||
"req_code": "CASE_FK_001",
|
||||
"req_from": "wasm_test",
|
||||
"req_cmd": "Cmd_Kinematics_forward_pose_str",
|
||||
"req_param": {
|
||||
"robot_uuid": "abb_irb120_3_58",
|
||||
"q_init_str": "0,0,0,0,0,0"
|
||||
}
|
||||
}
|
||||
9
tests/testdata/kinematics/list_robots.json
vendored
Normal file
9
tests/testdata/kinematics/list_robots.json
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"msg": "list robots after init",
|
||||
"req_code": "CASE_LIST_001",
|
||||
"req_from": "wasm_test",
|
||||
"req_cmd": "Cmd_ListRobots",
|
||||
"req_param": {
|
||||
"detail": true
|
||||
}
|
||||
}
|
||||
8
tests/testdata/kinematics/roundtrip_path_seed.json
vendored
Normal file
8
tests/testdata/kinematics/roundtrip_path_seed.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"robot_uuid": "abb_irb120_3_58",
|
||||
"q_init_str": "0,0,0,0,0,0",
|
||||
"start_joints": [0.00, 0.00, 0.00, 0.00, 0.00, 0.00],
|
||||
"end_joints": [0.20, -0.20, 0.30, 0.10, -0.10, 0.20],
|
||||
"steps": 12,
|
||||
"position_tolerance": 0.01
|
||||
}
|
||||
7
tests/testdata/kinematics/roundtrip_single_seed.json
vendored
Normal file
7
tests/testdata/kinematics/roundtrip_single_seed.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"robot_uuid": "abb_irb120_3_58",
|
||||
"q_init_str": "0,0,0,0,0,0",
|
||||
"target_joints": [0.15, -0.25, 0.35, 0.10, -0.20, 0.30],
|
||||
"position_tolerance": 0.002,
|
||||
"orientation_tolerance": 0.002
|
||||
}
|
||||
30
tests/testdata/quadruped/calculate_points_from_motor_angles.json
vendored
Normal file
30
tests/testdata/quadruped/calculate_points_from_motor_angles.json
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"msg": "quadruped points from motor angles",
|
||||
"req_code": "CASE_QP_001",
|
||||
"req_from": "wasm_test",
|
||||
"req_cmd": "Cmd_QuadrupedRobot_CalculateAllPointsFromMotorAngles",
|
||||
"req_param": {
|
||||
"Param": {
|
||||
"LF": {
|
||||
"thigh_angle_deg": -37.4784578338516,
|
||||
"shank_angle_deg": -22.4917532451628,
|
||||
"ankle_angle_deg": 0.0
|
||||
},
|
||||
"LH": {
|
||||
"thigh_angle_deg": -34.0564623655754,
|
||||
"shank_angle_deg": -22.1353106546916,
|
||||
"ankle_angle_deg": 0.0
|
||||
},
|
||||
"RF": {
|
||||
"thigh_angle_deg": 34.0564623655754,
|
||||
"shank_angle_deg": 22.1353106546916,
|
||||
"ankle_angle_deg": 0.0
|
||||
},
|
||||
"RH": {
|
||||
"thigh_angle_deg": 37.4784578338516,
|
||||
"shank_angle_deg": 22.4917532451628,
|
||||
"ankle_angle_deg": 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
47
tests/testdata/quadruped/perform_forward_kinematics.json
vendored
Normal file
47
tests/testdata/quadruped/perform_forward_kinematics.json
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"msg": "quadruped forward gait",
|
||||
"req_code": "CASE_QP_002",
|
||||
"req_from": "wasm_test",
|
||||
"req_cmd": "Cmd_QuadrupedRobot_PerformForwardKinematics",
|
||||
"req_param": {
|
||||
"GaitInfo": {
|
||||
"GaitType": "trot",
|
||||
"Period": 0.8,
|
||||
"Frequency": 50.0,
|
||||
"StepTime": 0.02,
|
||||
"SupportTime": 0.4,
|
||||
"SwingTime": 0.4,
|
||||
"SupportRatio": 0.5,
|
||||
"SwingRatio": 0.5,
|
||||
"TotalFrames": 40,
|
||||
"TotalTime": 0.8
|
||||
},
|
||||
"SystemParameters": {
|
||||
"A_x": 0.0,
|
||||
"A_y": 500.0,
|
||||
"L10": 300.0,
|
||||
"L20": 286.0,
|
||||
"L30": 55.0,
|
||||
"StepLength": 60.0,
|
||||
"StepHeight": 50.0,
|
||||
"X": 30.0,
|
||||
"DeltaX": 0.0,
|
||||
"L21": 70.0,
|
||||
"L22": 292.0,
|
||||
"L23": 80.0,
|
||||
"Beta1": 166.0,
|
||||
"BB2_BC_Angle": 3.3859387489,
|
||||
"C1_B_Length": 107.0,
|
||||
"CC1": 179.0,
|
||||
"L31": 32.0,
|
||||
"C2C3_Length": 32.0,
|
||||
"Lead": 10.0,
|
||||
"D1_L_Offset": 90.0,
|
||||
"D2_L_Offset": 50.0,
|
||||
"C4_D2_Offset": 18.0,
|
||||
"ThighMotorReduction": 1.0,
|
||||
"ShankMotorReduction": 1.0,
|
||||
"AnkleMotorReduction": 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
44
tests/testdata/spc/basic_5x30.json
vendored
Normal file
44
tests/testdata/spc/basic_5x30.json
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"msg": "spc basic 5x30",
|
||||
"req_code": "CASE_SPC_001",
|
||||
"req_from": "wasm_test",
|
||||
"req_cmd": "Cmd_Spc",
|
||||
"req_param": {
|
||||
"n": 5,
|
||||
"k": 30,
|
||||
"usl": 1.7,
|
||||
"lsl": 1.5,
|
||||
"x": [
|
||||
1.55, 1.58, 1.61, 1.6, 1.6,
|
||||
1.58, 1.63, 1.63, 1.62, 1.63,
|
||||
1.62, 1.63, 1.62, 1.59, 1.58,
|
||||
1.58, 1.6, 1.61, 1.62, 1.63,
|
||||
1.58, 1.64, 1.63, 1.62, 1.62,
|
||||
1.62, 1.62, 1.63, 1.61, 1.57,
|
||||
1.64, 1.62, 1.61, 1.6, 1.58,
|
||||
1.57, 1.59, 1.61, 1.62, 1.63,
|
||||
1.58, 1.61, 1.6, 1.62, 1.63,
|
||||
1.6, 1.61, 1.64, 1.64, 1.63,
|
||||
1.58, 1.6, 1.62, 1.63, 1.65,
|
||||
1.62, 1.58, 1.59, 1.57, 1.58,
|
||||
1.57, 1.57, 1.58, 1.59, 1.64,
|
||||
1.61, 1.64, 1.62, 1.6, 1.59,
|
||||
1.65, 1.62, 1.62, 1.6, 1.58,
|
||||
1.57, 1.59, 1.57, 1.59, 1.62,
|
||||
1.56, 1.57, 1.57, 1.61, 1.62,
|
||||
1.56, 1.58, 1.59, 1.6, 1.62,
|
||||
1.58, 1.6, 1.6, 1.62, 1.63,
|
||||
1.58, 1.59, 1.6, 1.63, 1.62,
|
||||
1.58, 1.59, 1.62, 1.63, 1.64,
|
||||
1.58, 1.59, 1.62, 1.63, 1.61,
|
||||
1.58, 1.59, 1.6, 1.61, 1.63,
|
||||
1.57, 1.59, 1.61, 1.61, 1.62,
|
||||
1.58, 1.58, 1.6, 1.61, 1.63,
|
||||
1.62, 1.58, 1.58, 1.58, 1.57,
|
||||
1.63, 1.59, 1.57, 1.58, 1.57,
|
||||
1.58, 1.62, 1.61, 1.63, 1.61,
|
||||
1.58, 1.57, 1.59, 1.6, 1.62,
|
||||
1.62, 1.6, 1.6, 1.57, 1.57
|
||||
]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user