Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/GEOS-ESM/MAPL --skill pfunit-troubleshooting명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
SOC 직업 분류 기준
SKILL.md 표시 중
| name | pfunit-troubleshooting |
| description | Debug and fix pFUnit test failures in MAPL |
| compatibility | opencode |
This skill provides comprehensive guidance for debugging and fixing pFUnit test failures in MAPL. pFUnit is the parallel Fortran unit testing framework used throughout MAPL.
# Run single test with diagnostics
./TestName.x -d
# Run filtered tests (substring match)
./TestName.x -f substring
# Run with verbose output
./TestName.x -v
# List all tests
./TestName.x -l
# Run specific test by exact name
./TestName.x -f exact_test_name
# From MAPL build directory (e.g., ~/swdev/VS/MAPL/nag)
cd generic3g/MAPL_cfio/MAPL_cfio_r4.tests
# Set library path (required for NAG)
export DYLD_LIBRARY_PATH=/usr/local/nag/lib:$DYLD_LIBRARY_PATH
# Run tests (< 1 minute)
./generic3g.x
MAPL uses consistent naming for test executables:
generic3g.x - Generic 3D grid testsTestName.x - Other component testsTests are organized by component:
build-dir/
├── base/
│ └── tests/
│ └── TestSomething.x
├── generic3g/
│ └── MAPL_cfio/
│ └── MAPL_cfio_r4.tests/
│ └── generic3g.x
├── gridcomps/
│ └── tests/
└── ...
*.pf - pFUnit test source files (preprocessed to .F90)*.F90 - Generated or manual Fortran test files*.x - Compiled test executablesWhen ctest reports a failure:
# Run ctest to see which tests fail
ctest
# Example output:
# 99% tests passed, 1 tests failed out of 100
# The following tests FAILED:
# 42 - generic3g (Failed)
Navigate to test directory and run with diagnostics:
# Find the test executable
find . -name "generic3g.x" -type f
# Navigate to test directory
cd generic3g/MAPL_cfio/MAPL_cfio_r4.tests
# Run with diagnostics
./generic3g.x -d
The -d flag shows:
Use -f to filter to specific test:
# If test is named "test_vertical_interpolation"
./generic3g.x -f vertical_interpolation
# Multiple matches possible (substring matching)
./generic3g.x -f interpolation
IMPORTANT: The -f flag does substring matching, NOT wildcard/glob matching. Do not use * or ?.
Common failure patterns:
Location: test_vertical_interpolation.pf:45
Expected: 1.23456
Actual: 1.23457
Difference exceeds tolerance
What to check:
Program received signal SIGSEGV: Segmentation fault
What to check:
Test runs but never completes.
What to check:
Symptom:
./generic3g.x -f my_test
# No tests run
Solution: List all available tests:
./generic3g.x -l
Check exact test name and use correct substring.
Symptom:
dyld: Library not loaded: @rpath/libnag_nag.dylib
Solution (NAG on macOS):
export DYLD_LIBRARY_PATH=/usr/local/nag/lib:$DYLD_LIBRARY_PATH
./generic3g.x
Solution (gfortran on macOS):
export DYLD_LIBRARY_PATH=/usr/local/gfortran/lib:$DYLD_LIBRARY_PATH
./generic3g.x
IMPORTANT: This is required for direct test execution. Not needed for ctest if properly configured.
Possible causes:
Debugging approach:
Symptom:
Expected: 1.2345678
Actual: 1.2345679
Common causes:
Solutions:
Relax tolerance (if difference is negligible):
@assertEqual(expected, actual, tolerance=1.0e-5)
Use relative tolerance:
@assertEqual(expected, actual, tolerance=abs(expected)*1.0e-6)
Investigate algorithm if difference is significant
Symptom: Test fails only when run with multiple processes.
Debugging approach:
Run with single process:
mpirun -np 1 ./TestName.x
Run with multiple processes:
mpirun -np 4 ./TestName.x
Check for:
Symptom:
./TestName.x
bash: ./TestName.x: No such file or directory
Solution: Test may not have been built. Rebuild:
cd <build-directory>
make -j8 install
If still not found, test may be disabled or have build errors. Check CMake output.
Debugging workflow:
Verify change didn't break assumptions:
Update tests if behavior intentionally changed:
! Update expected values
@assertEqual(new_expected_value, actual)
Fix code if tests revealed bugs:
Check for stale build artifacts:
make clean
make -j8 install
ctest
@test
subroutine test_my_function()
use pfunit_mod
use MyModule
implicit none
integer :: result
integer :: expected
! Setup
expected = 42
! Execute
result = my_function(input)
! Verify
@assertEqual(expected, result)
end subroutine test_my_function
! Equality assertions
@assertEqual(expected, actual)
@assertEqual(expected, actual, tolerance=1.0e-6)
@assertEqual(expected, actual, message="Custom error message")
! Boolean assertions
@assertTrue(condition)
@assertFalse(condition)
! Exception/error assertions
@assertExceptionRaised("Expected error message")
! Array assertions
@assertEqual(expected_array, actual_array)
@assertEqual(expected_array, actual_array, tolerance=1.0e-6)
@before
subroutine setUp()
! Initialize test fixtures
! Allocate arrays
! Open files
end subroutine setUp
@after
subroutine tearDown()
! Clean up test fixtures
! Deallocate arrays
! Close files
end subroutine tearDown
@test
subroutine test_something()
! setUp() called automatically before this
! Test code here
! tearDown() called automatically after this
end subroutine test_something
CRITICAL: Never use exact equality for floating-point:
! BAD - fragile, compiler-dependent
@assertEqual(1.23456, result)
! GOOD - uses tolerance
@assertEqual(1.23456, result, tolerance=1.0e-5)
! BETTER - relative tolerance for large numbers
@assertEqual(expected, result, tolerance=abs(expected)*1.0e-6)
@test
subroutine test_array_operation()
use pfunit_mod
implicit none
real, allocatable :: expected(:)
real, allocatable :: result(:)
integer :: i
allocate(expected(10))
allocate(result(10))
! Setup expected values
do i = 1, 10
expected(i) = real(i) * 2.0
end do
! Call function under test
call compute_array(result)
! Verify
@assertEqual(expected, result, tolerance=1.0e-6)
deallocate(expected)
deallocate(result)
end subroutine test_array_operation
Quick debugging in pFUnit tests:
@test
subroutine test_with_debug_output()
use pfunit_mod
implicit none
integer :: result
result = my_function(42)
print *, "DEBUG: result =", result
print *, "DEBUG: expected =", 84
@assertEqual(84, result)
end subroutine test_with_debug_output
Run test to see debug output:
./TestName.x -d -f test_with_debug_output
# Compile with debug symbols (should already be in Debug build)
cmake .. -DCMAKE_BUILD_TYPE=Debug
make -j8 install
# Run test under GDB
gdb ./TestName.x
# In GDB:
(gdb) run -f failing_test
(gdb) bt # backtrace when it crashes
(gdb) print variable_name
lldb ./TestName.x
# In LLDB:
(lldb) run -f failing_test
(lldb) bt # backtrace
(lldb) frame variable # show local variables
Different compilers offer different debugging capabilities:
NAG:
# Already has excellent runtime checking in Debug mode
cmake .. -DCMAKE_BUILD_TYPE=Debug
gfortran:
# Add extra runtime checks
cmake .. -DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_Fortran_FLAGS="-g -fbacktrace -fcheck=all"
Intel:
# Add runtime checks
cmake .. -DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_Fortran_FLAGS="-g -traceback -check all"
# Time entire test suite
time ./TestName.x
# Time specific test
time ./TestName.x -f specific_test
# Run with verbose output to see timing
ctest -V
# Or use ctest's built-in timing
ctest --output-on-failure --verbose
If a test is unexpectedly slow:
CRITICAL: Disabling tests should be rare and temporary.
Valid reasons:
How to disable:
@test(ifdef=SOME_FEATURE_FLAG)
subroutine test_to_disable()
! This test only runs if SOME_FEATURE_FLAG is defined
end subroutine test_to_disable
Or remove from CMakeLists.txt temporarily (prefer ifdef approach).
Good test names are descriptive:
! GOOD
@test
subroutine test_vertical_interpolation_linear_profile()
@test
subroutine test_grid_create_with_invalid_dimensions_should_fail()
! BAD (too vague)
@test
subroutine test1()
@test
subroutine test_grid()
# Run full test suite locally
cd <build-directory>
ctest
# If any failures, debug and fix
cd path/to/failing/test
./TestName.x -d
# Fix code or test, rebuild, retest
make -j8 install
ctest
CRITICAL: All tests must pass before creating PR.
If tests pass locally but fail in CI:
See github-workflow skill for PR process.
When debugging MPI-parallel tests:
# Run under MPI with debugger
mpirun -np 4 xterm -e gdb ./TestName.x
This opens separate debugger windows for each MPI rank.
# Check for memory leaks
valgrind --leak-check=full ./TestName.x -f specific_test
# Check for uninitialized memory
valgrind --track-origins=yes ./TestName.x -f specific_test
Note: Valgrind may report false positives with MPI and OpenMP.
pFUnit tests can't directly test private procedures. Options:
For testing multiple similar cases:
@test(cases=[1, 2, 3, 4, 5])
subroutine test_with_parameter(n)
integer, intent(in) :: n
! Test using parameter n
@assertEqual(n * 2, my_double_function(n))
end subroutine test_with_parameter
When to use this skill: