name: capi-test-fixer description: This skill should be used when the user asks to "C API test failures", "C API unit test issues", "modifier tests failing", "undefined symbol in C API tests", "ARKUI_CAPI_UNITTEST compilation errors", "Converter API issues in tests", "test build configuration problems", "fix C API interface test failures", "capi test fix", "modifier test fix", or mentions fixing C API unit test failures in OpenHarmony ACE Engine. Automatically diagnoses and fixes common C API unit test failures including missing static modifiers, incorrect Converter API usage, and test build configuration issues. version: 1.0.0
C API Test Fixer Skill
This skill automatically diagnoses and fixes common C API unit test failures in OpenHarmony ACE Engine. It handles patterns like missing static modifiers in test builds, incorrect Converter API usage, and test build configuration issues.
When to Use This Skill
Use this skill when encountering C API unit test failures, particularly:
- Linker errors:
undefined symbol: OHOS::Ace::NG::GeneratedModifier::Get*StaticModifier() - Test failures:
modifier_test_base.h:210: Expected: (modifier_) != (nullptr) - Compilation warnings about pointer/reference mismatches
- Build failures with "undefined reference" for static modifier functions
- Test build configuration issues with missing files
Common Failure Patterns
Pattern 1: Missing Static Modifier in Test Builds
Symptoms:
- Linker error:
undefined symbol: OHOS::Ace::NG::GeneratedModifier::Get*StaticModifier() - Test failure:
modifier_test_base.h:210: Expected: (modifier_) != (nullptr)
Root Cause: Modifier function uses DynamicModuleHelper which returns nullptr in tests.
Fix Pattern:
- Add ARKUI_CAPI_UNITTEST conditional compilation to modifier.cpp
- Include static modifier implementation in test BUILD.gn
Pattern 2: Incorrect Converter API Usage
Symptoms:
- Test failure comparing
nulloptvsnullptr - Compilation warnings about pointer/reference mismatches
Root Cause: Using Converter::GetOptPtr(&local_var) instead of Converter::GetOpt(local_var)
Fix Pattern: Replace GetOptPtr(&var) with GetOpt(var) for local variables.
Pattern 3: Test Build Configuration Missing Files
Symptoms:
- Build fails with "undefined reference" for static modifier functions
- File not included in test build sources
Root Cause: Static modifier .cpp file not listed in test BUILD.gn sources
Fix Pattern: Add missing .cpp file to test BUILD.gn sources list.
Pattern 4: Callback Invoke vs InvokeSync Mismatch
Symptoms:
- Test callback values remain at initial value (e.g.,
g_indexValue = 0) - Event callbacks silently don't fire
- Test error:
Expected: g_indexValue == INDEX, Actual: 0 vs 10
Root Cause: Implementation uses CallbackHelper::InvokeSync() but test callbacks
are created with Converter::ArkCallback<T>(lambda) where the lambda matches the call
signature (Ark_Int32 nodeId, ...args). InvokeSync uses callSync field which is
nullptr, so the callback silently does nothing.
The two ArkCallback overloads in reverse_converter.h select based on function signature:
calltype:void (*)(Ark_Int32 resourceId, ...args)→ sets.call,.callSync = nullptrcallSynctype:void (*)(Ark_VMContext vmContext, Ark_Int32 resourceId, ...args)→ sets.callSync,.call = nullptr
Fix Pattern: Add Ark_VMContext vmContext as the first parameter in test callback lambdas.
// Before (matches call signature → InvokeSync finds callSync=nullptr → no-op)
auto callback = [](Ark_Int32 nodeId, const Ark_Int32 index) {
g_indexValue = Converter::Convert<int32_t>(index);
};
// After (matches callSync signature → InvokeSync works correctly)
auto callback = [](Ark_VMContext vmContext, Ark_Int32 nodeId, const Ark_Int32 index) {
g_indexValue = Converter::Convert<int32_t>(index);
};
Common affected tests: Any event callback test (onChange, onSelected, onWillShow, etc.)
where the implementation was changed from Invoke() to InvokeSync().
Pattern 5: Ark_String Dangling Pointer in Getters
Symptoms:
- Getter returns garbage/corrupted data (e.g.,
"\0x\x1D"instead of"xor") - Use-after-free in string return values
- Only affects getters that return
Ark_String
Root Cause: Peer getter returns std::string by value. Converter::ArkValue<Ark_String>()
stores chars pointer to the temporary's data. When the temporary is destroyed, the pointer
dangles.
In reverse_converter.h, AssignArkValue(Ark_String& dst, const std::string_view& src, ConvContext *ctx):
- When
ctx != nullptr: copies data into persistent storage viactx->Store(src) - When
ctx == nullptr(default): stores raw pointerdst.chars = src.data()— dangles if source is temporary
Fix Pattern: Change peer getter to return const std::string& instead of std::string
(since it returns a member variable), so the Ark_String points to stable memory.
// Before (returns by value → Ark_String.chars dangles)
std::string GetGlobalCompositeOperation() const {
return globalCompositeOperation_;
}
// After (returns by reference → Ark_String.chars points to member)
const std::string& GetGlobalCompositeOperation() const {
return globalCompositeOperation_;
}
Alternative fix: Use Converter::FC (frame context) to store the string data persistently:
auto result = peerImpl->GetGlobalCompositeOperation();
return Converter::ArkValue<Ark_String>(result, Converter::FC);
Skill Implementation
The skill performs automated diagnosis through:
1. Error Analysis
- Parse build logs (
out/rk3568/build.log) - Extract linker errors and undefined symbols
- Analyze test failure messages
2. Pattern Matching
# Example patterns from error_patterns.json
PATTERNS = {
"static_modifier_missing": r"undefined symbol.*Get(\w+)StaticModifier",
"converter_api_misuse": r"GetOptPtr\(&",
"nullptr_modifier": r"modifier_test_base\.h.*modifier_.*!=.*nullptr",
}
3. Fix Generation
Based on detected patterns:
Static modifier missing:
- Check if modifier.cpp has ARKUI_CAPI_UNITTEST conditional
- Verify test BUILD.gn includes static_modifier.cpp
- Generate appropriate patches
Converter API misuse:
- Locate offending test file
- Suggest GetOptPtr → GetOpt replacement
Build configuration:
- Check test BUILD.gn source lists
- Add missing static modifier files
Usage Examples
Diagnose and Fix All Issues
claude-code skill capi-test-fixer --diagnose
Fix Specific Test Failure
claude-code skill capi-test-fixer --test SymbolGlyphModifierTest
Analyze Build Log
claude-code skill capi-test-fixer --build-log out/rk3568/build.log
Integration with Existing Skills
This skill complements:
- openharmony-build: Uses build logs for diagnosis
- build-error-analyzer: Focuses specifically on C API test patterns
- tdd: Provides test-specific fixes
File Structure
.claude/skills/capi-test-fixer/
├── SKILL.md # This file
├── README.md # Detailed documentation
├── skill.json # Skill configuration
├── test_skill.py # Test script
├── scripts/
│ ├── diagnose.py # Main diagnosis script
│ ├── fix_static_modifier.py
│ ├── fix_converter_api.py
│ └── fix_build_config.py
├── templates/
│ ├── static_modifier.patch
│ └── converter_fix.patch
└── patterns/
└── error_patterns.json # Error pattern definitions
Error Resolution Workflow
- Collect Data: Build logs, test outputs, source files
- Pattern Match: Identify failure category using error_patterns.json
- Root Cause Analysis: Determine exact issue location
- Fix Generation: Create appropriate patches using templates
- Validation: Verify fixes work by checking test compilation
Common Fix Templates
Static Modifier Fix
// Before
const GENERATED_ArkUI*Modifier* Get*Modifier()
{
auto* module = DynamicModuleHelper::GetInstance().GetDynamicModule("*");
return reinterpret_cast<const GENERATED_ArkUI*Modifier*>(module->GetStaticModifier());
}
// After
#ifdef ARKUI_CAPI_UNITTEST
const GENERATED_ArkUI*Modifier* Get*StaticModifier();
#endif
const GENERATED_ArkUI*Modifier* Get*Modifier()
{
static const GENERATED_ArkUI*Modifier* cachedModifier = nullptr;
if (cachedModifier == nullptr) {
#ifdef ARKUI_CAPI_UNITTEST
cachedModifier = GeneratedModifier::Get*StaticModifier();
#else
auto* module = DynamicModuleHelper::GetInstance().GetDynamicModule("*");
CHECK_NULL_RETURN(module, nullptr);
cachedModifier = reinterpret_cast<const GENERATED_ArkUI*Modifier*>(module->GetStaticModifier());
#endif
}
return cachedModifier;
}
Converter API Fix
// Before
auto optValue = Converter::GetOptPtr(&ptr);
// After
auto optValue = Converter::GetOpt(ptr);
BUILD.gn Fix
# Add to test/unittest/capi/BUILD.gn sources
sources += [
"$ace_root/frameworks/core/components_ng/pattern/*/bridge/*_static_modifier.cpp",
]
Callback InvokeSync Fix
// Before (call signature — InvokeSync ignores this)
auto callback = [](Ark_Int32 nodeId, const Ark_Int32 index) { ... };
// After (callSync signature — InvokeSync uses this)
auto callback = [](Ark_VMContext vmContext, Ark_Int32 nodeId, const Ark_Int32 index) { ... };
// For VoidCallback:
// Before
auto cb = [](const Ark_Int32 resourceId) { ... };
// After
auto cb = [](Ark_VMContext vmContext, const Ark_Int32 resourceId) { ... };
Ark_String Lifetime Fix
// Before (dangling pointer — getter returns std::string by value)
std::string GetValue() const { return member_; }
// After (stable pointer — getter returns const reference)
const std::string& GetValue() const { return member_; }
Best Practices
- Always check existing patterns: Radio modifier already implements ARKUI_CAPI_UNITTEST pattern
- Verify test builds: Ensure
ARKUI_CAPI_UNITTESTis defined in test config - Use proper Converter API:
GetOptfor values,GetOptPtrfor pointers - Maintain consistency: Follow established patterns in codebase
- Test after fixes: Always rebuild and run tests to verify fixes work
Supported Patterns
The skill supports the following error patterns (defined in patterns/error_patterns.json):
- static_modifier_missing: Detects undefined symbol errors for static modifiers
- converter_api_misuse: Detects incorrect
GetOptPtr(&var)usage - nullptr_modifier_in_tests: Detects modifier returning nullptr in tests
- test_build_config_missing_files: Detects missing files in BUILD.gn
- arkui_capi_unittest_compilation_error: Detects ARKUI_CAPI_UNITTEST compilation errors
- dynamic_module_helper_nullptr: Detects DynamicModuleHelper returning nullptr
- callback_invoke_vs_invoke_sync: Detects test callbacks using
callsignature when implementation usesInvokeSync(requirescallSyncsignature) - ark_string_dangling_pointer: Detects Ark_String getters returning dangling pointers from temporary std::string
Limitations
- Cannot fix complex test logic errors
- Requires clear error patterns
- May need manual review for edge cases
- Focuses on C API unit test failures only (not other test types)
Contributing
Add new patterns to patterns/error_patterns.json:
{
"pattern_name": {
"regex": "error pattern",
"category": "static_modifier|converter_api|build_config",
"fix_template": "template_name",
"severity": "high|medium|low"
}
}
Update fix templates in the templates/ directory as needed for new patterns.