Initial commit

This commit is contained in:
zhangshun
2026-06-01 15:55:59 +08:00
commit 40f9bdb590
1799 changed files with 362227 additions and 0 deletions

85
tests/README.md Normal file
View 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
View 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 &registry = 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 &param : 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;
}

View 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
}
}

View 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
}
}

View 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"
}
}

View 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"
}
}

View 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
}
}

View 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
}

View 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
}

View 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
}
}
}
}

View 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
View 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
]
}
}