mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-08 16:24:53 +08:00
[cpp] Fix double free crash in SkeletonBinary::readSkeletonDataFile, add terminal logging utilities and style guide, add nostdcpp
This commit is contained in:
parent
aaca02ad81
commit
2036aa3e76
3
.gitignore
vendored
3
.gitignore
vendored
@ -254,3 +254,6 @@ spine-c/codegen/spine-cpp-types.json
|
||||
spine-flutter/example/devtools_options.yaml
|
||||
spine-glfw/.cache
|
||||
formatters/eclipse-formatter/format-diff.txt
|
||||
spine-cpp/build-debug
|
||||
spine-cpp/build-linux
|
||||
spine-cpp/build-release-debug
|
||||
|
||||
93
formatters/logging/bash-colors.sh
Normal file
93
formatters/logging/bash-colors.sh
Normal file
@ -0,0 +1,93 @@
|
||||
#!/bin/bash
|
||||
# Bash color and formatting utilities
|
||||
# Source this file in your bash scripts for colored output
|
||||
|
||||
# Colors
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[0;33m'
|
||||
BLUE='\033[0;34m'
|
||||
MAGENTA='\033[0;35m'
|
||||
CYAN='\033[0;36m'
|
||||
WHITE='\033[0;37m'
|
||||
GRAY='\033[0;90m'
|
||||
|
||||
# Bright colors
|
||||
BRIGHT_RED='\033[0;91m'
|
||||
BRIGHT_GREEN='\033[0;92m'
|
||||
BRIGHT_YELLOW='\033[0;93m'
|
||||
BRIGHT_BLUE='\033[0;94m'
|
||||
BRIGHT_MAGENTA='\033[0;95m'
|
||||
BRIGHT_CYAN='\033[0;96m'
|
||||
BRIGHT_WHITE='\033[0;97m'
|
||||
|
||||
# Background colors
|
||||
BG_RED='\033[41m'
|
||||
BG_GREEN='\033[42m'
|
||||
BG_YELLOW='\033[43m'
|
||||
BG_BLUE='\033[44m'
|
||||
BG_MAGENTA='\033[45m'
|
||||
BG_CYAN='\033[46m'
|
||||
BG_WHITE='\033[47m'
|
||||
|
||||
# Text styles
|
||||
BOLD='\033[1m'
|
||||
DIM='\033[2m'
|
||||
UNDERLINE='\033[4m'
|
||||
BLINK='\033[5m'
|
||||
REVERSE='\033[7m'
|
||||
STRIKETHROUGH='\033[9m'
|
||||
|
||||
# Reset
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Design principles:
|
||||
# 1. Minimal visual noise - use color sparingly for emphasis
|
||||
# 2. Clear hierarchy - different levels of information have different treatments
|
||||
# 3. Consistent spacing - clean vertical rhythm
|
||||
# 4. Accessible - readable without colors
|
||||
|
||||
# Main header for script/tool name
|
||||
log_title() {
|
||||
echo ""
|
||||
echo -e "${BOLD}$1${NC}"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Section headers for major phases
|
||||
log_section() {
|
||||
echo -e "${BOLD}${BLUE}$1${NC}"
|
||||
}
|
||||
|
||||
# Individual actions/steps
|
||||
log_action() {
|
||||
echo -e " $1..."
|
||||
}
|
||||
|
||||
# Results - success/failure/info
|
||||
log_ok() {
|
||||
echo -e " ${GREEN}✓${NC} $1"
|
||||
}
|
||||
|
||||
log_fail() {
|
||||
echo -e " ${RED}✗${NC} $1"
|
||||
}
|
||||
|
||||
log_warn() {
|
||||
echo -e " ${YELLOW}!${NC} $1"
|
||||
}
|
||||
|
||||
log_skip() {
|
||||
echo -e " ${GRAY}-${NC} $1"
|
||||
}
|
||||
|
||||
# Final summary
|
||||
log_summary() {
|
||||
echo ""
|
||||
echo -e "${BOLD}$1${NC}"
|
||||
}
|
||||
|
||||
# Detailed output (errors, etc.)
|
||||
log_detail() {
|
||||
echo -e "${GRAY}$1${NC}"
|
||||
}
|
||||
153
formatters/logging/terminal-logging-guide.md
Normal file
153
formatters/logging/terminal-logging-guide.md
Normal file
@ -0,0 +1,153 @@
|
||||
# Terminal Logging Style Guide
|
||||
|
||||
This guide defines the terminal output style for all bash scripts in the Spine Runtimes project.
|
||||
|
||||
## Design Principles
|
||||
|
||||
1. **Minimal visual noise** - Use color sparingly for emphasis, not decoration
|
||||
2. **Clear hierarchy** - Different levels of information have distinct visual treatments
|
||||
3. **Consistent spacing** - Clean vertical rhythm throughout output
|
||||
4. **Accessible** - Readable and meaningful even without colors
|
||||
5. **Scannable** - Easy to quickly identify successes, failures, and important information
|
||||
|
||||
## Visual Hierarchy
|
||||
|
||||
### 1. Title (`log_title`)
|
||||
- **Purpose**: Main script/tool name
|
||||
- **Style**: Bold with vertical spacing
|
||||
- **Usage**: Once at the beginning of script execution
|
||||
|
||||
```bash
|
||||
log_title "Spine-C++ Test"
|
||||
```
|
||||
|
||||
### 2. Section (`log_section`)
|
||||
- **Purpose**: Major phases or groups of operations
|
||||
- **Style**: Bold blue text, no extra spacing
|
||||
- **Usage**: Build, Test, Deploy, etc.
|
||||
|
||||
```bash
|
||||
log_section "Build"
|
||||
log_section "Test"
|
||||
```
|
||||
|
||||
### 3. Action (`log_action`)
|
||||
- **Purpose**: Individual operations in progress
|
||||
- **Style**: Indented, followed by "..."
|
||||
- **Usage**: Before starting an operation
|
||||
|
||||
```bash
|
||||
log_action "Building all variants"
|
||||
log_action "Testing headless-test"
|
||||
```
|
||||
|
||||
### 4. Results
|
||||
- **Purpose**: Outcome of operations
|
||||
- **Style**: Indented with colored symbols
|
||||
|
||||
```bash
|
||||
log_ok "Build completed" # Green ✓
|
||||
log_fail "Build failed" # Red ✗
|
||||
log_warn "Deprecated feature" # Yellow !
|
||||
log_skip "Not supported on macOS" # Gray -
|
||||
```
|
||||
|
||||
### 5. Detail (`log_detail`)
|
||||
- **Purpose**: Secondary information, error output, debug info
|
||||
- **Style**: Gray text, indented
|
||||
- **Usage**: Additional context, error messages
|
||||
|
||||
```bash
|
||||
log_detail "Platform: Darwin"
|
||||
log_detail "$ERROR_OUTPUT"
|
||||
```
|
||||
|
||||
### 6. Summary (`log_summary`)
|
||||
- **Purpose**: Final result or conclusion
|
||||
- **Style**: Bold with vertical spacing
|
||||
- **Usage**: End of script execution
|
||||
|
||||
```bash
|
||||
log_summary "✓ All tests passed (5/5)"
|
||||
log_summary "✗ Tests failed (3/5)"
|
||||
```
|
||||
|
||||
## Complete Example
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
source ../formatters/bash-colors.sh
|
||||
|
||||
log_title "Spine-C++ Test"
|
||||
log_detail "Platform: $(uname)"
|
||||
|
||||
log_section "Build"
|
||||
log_action "Building all variants"
|
||||
if BUILD_OUTPUT=$(./build.sh clean release 2>&1); then
|
||||
log_ok "Build completed"
|
||||
else
|
||||
log_fail "Build failed"
|
||||
log_detail "$BUILD_OUTPUT"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_section "Test"
|
||||
log_action "Testing headless-test"
|
||||
if test_result; then
|
||||
log_ok "headless-test"
|
||||
else
|
||||
log_fail "headless-test - execution failed"
|
||||
log_detail "$error_output"
|
||||
fi
|
||||
|
||||
log_summary "✓ All tests passed (2/2)"
|
||||
```
|
||||
|
||||
## Output Preview
|
||||
|
||||
```
|
||||
Spine-C++ Test
|
||||
|
||||
Platform: Darwin
|
||||
|
||||
Build
|
||||
Building all variants...
|
||||
✓ Build completed
|
||||
|
||||
Test
|
||||
Testing headless-test...
|
||||
✓ headless-test
|
||||
Testing headless-test-nostdcpp...
|
||||
✓ headless-test-nostdcpp
|
||||
|
||||
✓ All tests passed (2/2)
|
||||
```
|
||||
|
||||
## Error Handling Best Practices
|
||||
|
||||
1. **Capture output**: Use `OUTPUT=$(command 2>&1)` to capture both stdout and stderr
|
||||
2. **Check exit codes**: Always check if critical operations succeeded
|
||||
3. **Show details on failure**: Use `log_detail` to show error output
|
||||
4. **Fail fast**: Exit immediately on critical failures
|
||||
5. **Clear error messages**: Make failure reasons obvious
|
||||
|
||||
```bash
|
||||
if BUILD_OUTPUT=$(./build.sh clean release 2>&1); then
|
||||
log_ok "Build completed"
|
||||
else
|
||||
log_fail "Build failed"
|
||||
log_detail "$BUILD_OUTPUT"
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
1. Source the utilities in your script:
|
||||
```bash
|
||||
source ../formatters/logging/bash-colors.sh
|
||||
```
|
||||
|
||||
2. Follow the hierarchy patterns shown above
|
||||
3. Use appropriate functions for each type of output
|
||||
4. Test output both with and without color support
|
||||
@ -7,7 +7,11 @@ option(SPINE_NO_FILE_IO "Disable file I/O operations" OFF)
|
||||
|
||||
include_directories(include)
|
||||
file(GLOB INCLUDES "include/**/*.h")
|
||||
file(GLOB SOURCES "src/**/*.cpp")
|
||||
file(GLOB ALL_SOURCES "src/**/*.cpp")
|
||||
|
||||
# Exclude nostdcpp.cpp from regular build
|
||||
list(FILTER ALL_SOURCES EXCLUDE REGEX "src/nostdcpp\\.cpp$")
|
||||
set(SOURCES ${ALL_SOURCES})
|
||||
|
||||
add_library(spine-cpp STATIC ${SOURCES} ${INCLUDES})
|
||||
target_include_directories(spine-cpp PUBLIC include)
|
||||
@ -17,7 +21,7 @@ if(SPINE_NO_FILE_IO)
|
||||
endif()
|
||||
|
||||
# nostdcpp variant (no C++ standard library)
|
||||
file(GLOB NOSTDCPP_SOURCES ${SOURCES} "src/nostdlib.cpp")
|
||||
set(NOSTDCPP_SOURCES ${SOURCES} "src/nostdcpp.cpp")
|
||||
add_library(spine-cpp-nostdcpp STATIC ${NOSTDCPP_SOURCES} ${INCLUDES})
|
||||
target_include_directories(spine-cpp-nostdcpp PUBLIC include)
|
||||
|
||||
@ -35,28 +39,39 @@ export(
|
||||
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
||||
add_executable(headless-test ${CMAKE_CURRENT_SOURCE_DIR}/tests/HeadlessTest.cpp)
|
||||
target_link_libraries(headless-test spine-cpp)
|
||||
|
||||
|
||||
if(SPINE_NO_FILE_IO)
|
||||
target_compile_definitions(headless-test PRIVATE SPINE_NO_FILE_IO)
|
||||
endif()
|
||||
|
||||
# nostdcpp test executable (no C++ stdlib)
|
||||
|
||||
# Configure nostdcpp linking for different platforms
|
||||
add_executable(headless-test-nostdcpp ${CMAKE_CURRENT_SOURCE_DIR}/tests/HeadlessTest.cpp)
|
||||
|
||||
target_link_libraries(headless-test-nostdcpp spine-cpp-nostdcpp)
|
||||
|
||||
if(MSVC)
|
||||
# On Windows/MSVC, disable default libraries but keep C runtime
|
||||
target_link_libraries(headless-test-nostdcpp spine-cpp-nostdcpp)
|
||||
target_link_options(headless-test-nostdcpp PRIVATE /NODEFAULTLIB)
|
||||
target_link_libraries(headless-test-nostdcpp msvcrt kernel32)
|
||||
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
target_link_options(headless-test-nostdcpp PRIVATE -nostdlib++ -lc)
|
||||
else()
|
||||
# Unix/Linux: avoid linking libstdc++ automatically
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
target_link_libraries(headless-test-nostdcpp spine-cpp-nostdcpp)
|
||||
target_link_options(headless-test-nostdcpp PRIVATE -nostdlib++ -lc)
|
||||
else()
|
||||
# GCC: use -nodefaultlibs and link minimal libraries including libgcc for operator new/delete
|
||||
target_link_options(headless-test-nostdcpp PRIVATE -nodefaultlibs)
|
||||
target_link_libraries(headless-test-nostdcpp spine-cpp-nostdcpp -lm -lc -lgcc)
|
||||
target_link_options(headless-test-nostdcpp PRIVATE -nodefaultlibs)
|
||||
target_link_libraries(headless-test-nostdcpp -lm -lc -lgcc)
|
||||
endif()
|
||||
|
||||
# Static variants (Linux only)
|
||||
if(UNIX AND NOT APPLE)
|
||||
add_executable(headless-test-static ${CMAKE_CURRENT_SOURCE_DIR}/tests/HeadlessTest.cpp)
|
||||
target_link_libraries(headless-test-static spine-cpp)
|
||||
target_link_options(headless-test-static PRIVATE -static)
|
||||
|
||||
add_executable(headless-test-nostdcpp-static ${CMAKE_CURRENT_SOURCE_DIR}/tests/HeadlessTest.cpp)
|
||||
target_link_libraries(headless-test-nostdcpp-static spine-cpp-nostdcpp)
|
||||
target_link_options(headless-test-nostdcpp-static PRIVATE -static -static-libgcc -Wl,--exclude-libs,libstdc++.a)
|
||||
target_link_libraries(headless-test-nostdcpp-static -lm -lc)
|
||||
|
||||
if(SPINE_NO_FILE_IO)
|
||||
target_compile_definitions(headless-test-static PRIVATE SPINE_NO_FILE_IO)
|
||||
target_compile_definitions(headless-test-nostdcpp-static PRIVATE SPINE_NO_FILE_IO)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
63
spine-cpp/src/nostdcpp.cpp
Normal file
63
spine-cpp/src/nostdcpp.cpp
Normal file
@ -0,0 +1,63 @@
|
||||
/******************************************************************************
|
||||
* Spine Runtimes License Agreement
|
||||
* Last updated April 5, 2025. Replaces all prior versions.
|
||||
*
|
||||
* Copyright (c) 2013-2025, Esoteric Software LLC
|
||||
*
|
||||
* Integration of the Spine Runtimes into software or otherwise creating
|
||||
* derivative works of the Spine Runtimes is permitted under the terms and
|
||||
* conditions of Section 2 of the Spine Editor License Agreement:
|
||||
* http://esotericsoftware.com/spine-editor-license
|
||||
*
|
||||
* Otherwise, it is permitted to integrate the Spine Runtimes into software
|
||||
* or otherwise create derivative works of the Spine Runtimes (collectively,
|
||||
* "Products"), provided that each user of the Products must obtain their own
|
||||
* Spine Editor license and redistribution of the Products in any form must
|
||||
* include this license and copyright notice.
|
||||
*
|
||||
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
|
||||
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
// Stubs for C++ stdlib functions spine-cpp depends on. Used for nostdcpp builds.
|
||||
// These are weak symbols to allow overriding in custom builds, e.g. headless-test-nostdcpp
|
||||
// where the main app still requires C++.
|
||||
|
||||
extern "C" {
|
||||
void* malloc(size_t size);
|
||||
void free(void* ptr);
|
||||
}
|
||||
|
||||
__attribute__((weak)) void* operator new(size_t size) {
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
__attribute__((weak)) void operator delete(void* ptr) {
|
||||
if (ptr) free(ptr);
|
||||
}
|
||||
|
||||
extern "C" __attribute__((weak)) int __cxa_guard_acquire(char* guard) {
|
||||
return *guard == 0 ? (*guard = 1, 1) : 0;
|
||||
}
|
||||
|
||||
extern "C" __attribute__((weak)) void __cxa_guard_release(char* guard) {
|
||||
// No-op for single-threaded
|
||||
(void)guard;
|
||||
}
|
||||
|
||||
extern "C" __attribute__((weak)) void __cxa_pure_virtual() {
|
||||
}
|
||||
|
||||
extern "C" __attribute__((weak)) char __stack_chk_guard = 0;
|
||||
extern "C" __attribute__((weak)) void __stack_chk_fail() {
|
||||
}
|
||||
@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Minimal runtime stubs for nostdlib spine-cpp build
|
||||
*
|
||||
* Provides minimal implementations of C++ runtime symbols required
|
||||
* for spine-cpp to work without the standard library.
|
||||
*/
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
// ============================================================================
|
||||
// C++ Runtime Stubs
|
||||
// ============================================================================
|
||||
|
||||
// Memory operators - basic malloc/free wrappers
|
||||
// Note: These require a C library that provides malloc/free
|
||||
extern "C" {
|
||||
void* malloc(size_t size);
|
||||
void free(void* ptr);
|
||||
}
|
||||
|
||||
// Memory operators - use malloc/free but with careful implementation
|
||||
// Make them weak so system can override if needed
|
||||
__attribute__((weak)) void* operator new(size_t size) {
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
__attribute__((weak)) void operator delete(void* ptr) {
|
||||
if (ptr) free(ptr);
|
||||
}
|
||||
|
||||
// Static initialization guards (single-threaded stubs)
|
||||
// Make them weak so system can override if needed
|
||||
extern "C" __attribute__((weak)) int __cxa_guard_acquire(char* guard) {
|
||||
return *guard == 0 ? (*guard = 1, 1) : 0;
|
||||
}
|
||||
|
||||
extern "C" __attribute__((weak)) void __cxa_guard_release(char* guard) {
|
||||
// No-op for single-threaded
|
||||
(void)guard;
|
||||
}
|
||||
|
||||
// Pure virtual function handler
|
||||
extern "C" __attribute__((weak)) void __cxa_pure_virtual() {
|
||||
// In a real implementation, this would abort or throw
|
||||
// For minimal stub, we'll just return (undefined behavior but won't crash)
|
||||
// This should never be called in a correctly written program
|
||||
}
|
||||
|
||||
// Stack protection (for GCC -fstack-protector)
|
||||
// Make it weak so libc can override it in static builds
|
||||
extern "C" __attribute__((weak)) char __stack_chk_guard = 0;
|
||||
extern "C" __attribute__((weak)) void __stack_chk_fail() {
|
||||
// Could call abort() or be no-op for minimal runtime
|
||||
}
|
||||
@ -118,7 +118,7 @@ SkeletonData *SkeletonBinary::readSkeletonDataFile(const String &path) {
|
||||
const char *lastDot = strrchr(nameWithoutExtension.buffer(), '.');
|
||||
if (lastDot) {
|
||||
int length = lastDot - nameWithoutExtension.buffer();
|
||||
nameWithoutExtension = String(nameWithoutExtension.buffer(), length);
|
||||
nameWithoutExtension = nameWithoutExtension.substring(0, length);
|
||||
}
|
||||
skeletonData->_name = nameWithoutExtension;
|
||||
}
|
||||
|
||||
@ -1,82 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# Build or reuse Docker image
|
||||
IMAGE_NAME="spine-cpp-nostdcpp-test"
|
||||
if ! docker image inspect $IMAGE_NAME >/dev/null 2>&1; then
|
||||
echo "Building Docker image (one-time setup)..."
|
||||
docker build -t $IMAGE_NAME - <<'EOF'
|
||||
FROM ubuntu:22.04
|
||||
RUN apt-get update >/dev/null 2>&1 && \
|
||||
apt-get install -y build-essential cmake ninja-build git file >/dev/null 2>&1 && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
EOF
|
||||
fi
|
||||
|
||||
echo "Running spine-cpp nostdcpp test..."
|
||||
|
||||
# Run Docker container with spine-runtimes directory mounted
|
||||
docker run --rm \
|
||||
-v "$(pwd)/..:/workspace/spine-runtimes" \
|
||||
-w /workspace/spine-runtimes/spine-cpp \
|
||||
$IMAGE_NAME \
|
||||
bash -c "
|
||||
|
||||
# Build everything first
|
||||
echo '=== Building all variants ==='
|
||||
./build.sh clean release >/dev/null 2>&1
|
||||
|
||||
# Try to build static regular executable
|
||||
echo 'Building static regular executable...'
|
||||
g++ -static -o build/headless-test-static build/CMakeFiles/headless-test.dir/tests/HeadlessTest.cpp.o build/libspine-cpp.a >/dev/null 2>&1 || echo 'Static regular build failed'
|
||||
|
||||
# Try to build static nostdcpp executable (multiple approaches)
|
||||
echo 'Building static nostdcpp executable...'
|
||||
|
||||
# Approach 1: Try with -static-libgcc and -static-libstdc++ but no libstdc++
|
||||
if g++ -static -static-libgcc -Wl,--exclude-libs,libstdc++.a -o build/headless-test-nostdcpp-static build/CMakeFiles/headless-test-nostdcpp.dir/tests/HeadlessTest.cpp.o build/libspine-cpp-nostdcpp.a -lm -lc 2>/dev/null; then
|
||||
echo 'SUCCESS: Static nostdcpp built (approach 1)'
|
||||
# Approach 2: Try minimal static linking
|
||||
elif g++ -static -o build/headless-test-nostdcpp-static-minimal build/CMakeFiles/headless-test-nostdcpp.dir/tests/HeadlessTest.cpp.o build/libspine-cpp-nostdcpp.a 2>/dev/null; then
|
||||
echo 'SUCCESS: Static nostdcpp built (approach 2 - minimal)'
|
||||
else
|
||||
echo 'All static nostdcpp approaches failed - static linking may not be practical on this system'
|
||||
fi
|
||||
|
||||
echo ''
|
||||
echo '=== FINAL RESULTS ==='
|
||||
echo ''
|
||||
echo 'File sizes:'
|
||||
for exe in build/headless-test*; do
|
||||
if [ -f \"\$exe\" ]; then
|
||||
ls -lah \"\$exe\" | awk '{printf \"%-30s %s\\n\", \$9, \$5}'
|
||||
fi
|
||||
done
|
||||
|
||||
echo ''
|
||||
echo 'Dependencies:'
|
||||
for exe in build/headless-test*; do
|
||||
if [ -f \"\$exe\" ]; then
|
||||
echo \"\$(basename \$exe):\"
|
||||
ldd \"\$exe\" 2>/dev/null || echo \" (statically linked)\"
|
||||
echo ''
|
||||
fi
|
||||
done
|
||||
|
||||
echo 'Functional test:'
|
||||
if [ -f build/headless-test-nostdcpp ]; then
|
||||
echo 'Testing headless-test-nostdcpp with spineboy...'
|
||||
if OUTPUT=\$(./build/headless-test-nostdcpp ../examples/spineboy/export/spineboy-pro.skel ../examples/spineboy/export/spineboy-pma.atlas idle 2>&1); then
|
||||
echo \"\$OUTPUT\" | head -10
|
||||
echo '... (output truncated)'
|
||||
echo 'SUCCESS: nostdcpp executable works!'
|
||||
else
|
||||
echo 'FAILED: nostdcpp executable failed to run'
|
||||
echo \"Error: \$OUTPUT\"
|
||||
fi
|
||||
else
|
||||
echo 'nostdcpp executable not found'
|
||||
fi
|
||||
"
|
||||
89
spine-cpp/tests/test.sh
Executable file
89
spine-cpp/tests/test.sh
Executable file
@ -0,0 +1,89 @@
|
||||
#!/bin/bash
|
||||
# Spine-C++ Smoke Test
|
||||
#
|
||||
# Tests all spine-cpp build variants with spineboy example data:
|
||||
# - headless-test (regular dynamic)
|
||||
# - headless-test-nostdcpp (nostdcpp dynamic)
|
||||
# - headless-test-static (regular static, Linux only)
|
||||
# - headless-test-nostdcpp-static (nostdcpp static, Linux only)
|
||||
|
||||
set -e
|
||||
|
||||
# Change to spine-cpp root directory
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
# Source logging utilities
|
||||
source ../formatters/logging/bash-colors.sh
|
||||
|
||||
# Test configuration - spineboy example files and animation
|
||||
SPINEBOY_SKEL="../examples/spineboy/export/spineboy-pro.skel"
|
||||
SPINEBOY_ATLAS="../examples/spineboy/export/spineboy-pma.atlas"
|
||||
SPINEBOY_ANIM="idle"
|
||||
|
||||
# Expected output pattern - first 10 lines of skeleton JSON data
|
||||
EXPECTED_OUTPUT="=== SKELETON DATA ===
|
||||
{
|
||||
\"type\": \"SkeletonData\",
|
||||
\"bones\": [{
|
||||
\"type\": \"BoneData\",
|
||||
\"index\": 0,
|
||||
\"parent\": null,
|
||||
\"length\": 0,
|
||||
\"color\": {
|
||||
\"r\": 0.607843,"
|
||||
|
||||
log_title "Spine-C++ Test"
|
||||
log_detail "Platform: $(uname)"
|
||||
|
||||
log_section "Build"
|
||||
log_action "Building all variants"
|
||||
if BUILD_OUTPUT=$(./build.sh clean release 2>&1); then
|
||||
log_ok "Build completed"
|
||||
else
|
||||
log_fail "Build failed"
|
||||
log_detail "$BUILD_OUTPUT"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_section "Test"
|
||||
|
||||
test_count=0
|
||||
pass_count=0
|
||||
|
||||
for exe in build/headless-test*; do
|
||||
if [ -f "$exe" ] && [ -x "$exe" ]; then
|
||||
exe_name=$(basename "$exe")
|
||||
log_action "Testing $exe_name"
|
||||
|
||||
test_count=$((test_count + 1))
|
||||
|
||||
if OUTPUT=$("$exe" $SPINEBOY_SKEL $SPINEBOY_ATLAS $SPINEBOY_ANIM 2>&1); then
|
||||
actual_output=$(echo "$OUTPUT" | head -10)
|
||||
|
||||
if [ "$actual_output" = "$EXPECTED_OUTPUT" ]; then
|
||||
log_ok "$exe_name"
|
||||
pass_count=$((pass_count + 1))
|
||||
else
|
||||
log_fail "$exe_name - output mismatch"
|
||||
log_detail "Expected:"
|
||||
log_detail "$EXPECTED_OUTPUT"
|
||||
log_detail ""
|
||||
log_detail "Actual:"
|
||||
log_detail "$actual_output"
|
||||
echo ""
|
||||
fi
|
||||
else
|
||||
log_fail "$exe_name - execution failed"
|
||||
log_detail "$OUTPUT"
|
||||
echo ""
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $pass_count -eq $test_count ] && [ $test_count -gt 0 ]; then
|
||||
log_summary "✓ All tests passed ($pass_count/$test_count)"
|
||||
exit 0
|
||||
else
|
||||
log_summary "✗ Tests failed ($pass_count/$test_count)"
|
||||
exit 1
|
||||
fi
|
||||
Loading…
x
Reference in New Issue
Block a user