Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions bindings/c/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -192,8 +192,9 @@ install(FILES
)

# Build tests if requested
# if(SVS_BUILD_C_API_TESTS)
# add_subdirectory(tests)
# endif()
option(SVS_BUILD_C_API_TESTS "Build C API tests" ON)
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SVS_BUILD_C_API_TESTS defaults to ON, which means building the C API will build the test executable (and potentially FetchContent-download Catch2) by default. This differs from the repo’s other test knobs (e.g., SVS_BUILD_TESTS / SVS_BUILD_RUNTIME_TESTS, which are opt-in) and can be surprising for consumers embedding bindings/c. Consider defaulting this option to OFF (or tying it to the parent project’s test option) so tests are only built when explicitly requested.

Suggested change
option(SVS_BUILD_C_API_TESTS "Build C API tests" ON)
if(DEFINED SVS_BUILD_TESTS)
option(SVS_BUILD_C_API_TESTS "Build C API tests" ${SVS_BUILD_TESTS})
else()
option(SVS_BUILD_C_API_TESTS "Build C API tests" OFF)
endif()

Copilot uses AI. Check for mistakes.
if(SVS_BUILD_C_API_TESTS)
add_subdirectory(tests)
endif()

add_subdirectory(samples)
18 changes: 15 additions & 3 deletions bindings/c/src/svs_c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -661,20 +661,32 @@ extern "C" size_t svs_index_dynamic_delete_points(
svs_index_h index, const size_t* ids, size_t num_ids, svs_error_h out_err
) {
using namespace svs::c_runtime;
return wrap_exceptions(
std::shared_ptr<DynamicIndex> dynamic_index_ptr;
auto result = wrap_exceptions(
[&]() {
EXPECT_ARG_NOT_NULL(index);
EXPECT_ARG_NOT_NULL(ids);
EXPECT_ARG_GT_THAN(num_ids, 0);
auto dynamic_index_ptr = std::dynamic_pointer_cast<DynamicIndex>(index->impl);
dynamic_index_ptr = std::dynamic_pointer_cast<DynamicIndex>(index->impl);
INVALID_ARGUMENT_IF(
dynamic_index_ptr == nullptr, "Index does not support dynamic updates"
);
return dynamic_index_ptr->delete_points(std::span(ids, num_ids));
return 0; // return 0 for success, actual deletion happens in the next
// wrap_exceptions call
},
out_err,
static_cast<size_t>(-1)
);
if (result != 0) {
return result;
}
// Call delete_points in a separate wrap_exceptions to return 0 if no entries are
// deleted.
return wrap_exceptions(
[&]() { return dynamic_index_ptr->delete_points(std::span(ids, num_ids)); },
out_err,
0
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

svs_index_dynamic_delete_points now uses a second wrap_exceptions(..., 0) call. If out_err is NULL and delete_points() throws, the function will return 0 (which is also the valid “deleted 0 points” result), violating the header contract that failures return (size_t)-1 and potentially hiding errors from callers that don’t pass an error handle. Use an error sentinel (e.g., (size_t)-1) for the second wrap_exceptions as well (or revert to a single wrap_exceptions call) so failures remain distinguishable even when out_err == NULL.

Suggested change
0
static_cast<size_t>(-1)

Copilot uses AI. Check for mistakes.
);
}

extern "C" bool svs_index_dynamic_has_id(
Expand Down
105 changes: 105 additions & 0 deletions bindings/c/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# Copyright 2026 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set(TARGET_NAME svs_c_api_test)
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test executable target is named svs_c_api_test, but the README/build instructions in this PR refer to svs_c_api_tests (plural). This mismatch will break the documented make/run commands and CTest -R filtering. Consider renaming the target (and add_test name) to match the documented name, or update the README consistently.

Suggested change
set(TARGET_NAME svs_c_api_test)
set(TARGET_NAME svs_c_api_tests)

Copilot uses AI. Check for mistakes.

# Check if Catch2 is available
find_package(Catch2 3 QUIET)

if(NOT Catch2_FOUND)
message(STATUS "Catch2 not found, fetching from GitHub...")
include(FetchContent)

# Do wide printing for the console logger for Catch2
set(CATCH_CONFIG_CONSOLE_WIDTH "100" CACHE STRING "" FORCE)
set(CATCH_BUILD_TESTING OFF CACHE BOOL "" FORCE)
set(CATCH_CONFIG_ENABLE_BENCHMARKING OFF CACHE BOOL "" FORCE)
set(CATCH_CONFIG_FAST_COMPILE OFF CACHE BOOL "" FORCE)
set(CATCH_CONFIG_PREFIX_ALL ON CACHE BOOL "" FORCE)

Comment on lines +17 to +30
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This CMakeLists supports find_package(Catch2 ...), but the test sources use the prefixed Catch2 macros (CATCH_TEST_CASE, CATCH_SECTION, etc.). Those macros are only available when CATCH_CONFIG_PREFIX_ALL is enabled for the consumer compile, which isn’t guaranteed for a pre-installed Catch2 found via find_package. To avoid build failures when Catch2_FOUND, explicitly add the needed compile definition(s) to ${TARGET_NAME} (or avoid find_package and always FetchContent with the required configuration).

Copilot uses AI. Check for mistakes.
set(PRESET_CMAKE_CXX_STANDARD ${CMAKE_CXX_STANDARD})
set(CMAKE_CXX_STANDARD 20)
FetchContent_Declare(
Catch2
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
GIT_TAG v3.11.0
)
FetchContent_MakeAvailable(Catch2)
set(CMAKE_CXX_STANDARD ${PRESET_CMAKE_CXX_STANDARD})
endif()

# Define test sources
set(C_API_TEST_SOURCES
c_api_error.cpp
c_api_algorithm.cpp
c_api_storage.cpp
c_api_search_params.cpp
c_api_index_builder.cpp
c_api_index.cpp
c_api_dynamic_index.cpp
)

# Create test executable
add_executable(${TARGET_NAME} ${C_API_TEST_SOURCES})

# Link with C API library and Catch2
target_link_libraries(${TARGET_NAME} PRIVATE
svs_c_api
Catch2::Catch2WithMain
)

# Set C++ standard
target_compile_features(${TARGET_NAME} PRIVATE cxx_std_20)
set_target_properties(${TARGET_NAME} PROPERTIES
CXX_STANDARD 20
CXX_STANDARD_REQUIRED ON
CXX_EXTENSIONS OFF
)

# Include directories
target_include_directories(${TARGET_NAME} PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/../include
)

# Add test to CTest
include(CTest)
enable_testing()

# Add the test to CTest
add_test(NAME ${TARGET_NAME} COMMAND ${TARGET_NAME})

# Set test properties
set_tests_properties(${TARGET_NAME} PROPERTIES
LABELS "c_api"
)

# Add Catch2 CMake module path
if(NOT Catch2_FOUND)
# Catch2 was fetched, use its source directory
list(APPEND CMAKE_MODULE_PATH ${catch2_SOURCE_DIR}/extras)
else()
# Catch2 was found via find_package, use its module directory
list(APPEND CMAKE_MODULE_PATH ${Catch2_DIR})
endif()

include(Catch)
catch_discover_tests(${TARGET_NAME})

# Add a custom target to run tests
add_custom_target(run_c_api_tests
COMMAND ${TARGET_NAME}
DEPENDS ${TARGET_NAME}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Running C API tests..."
)
164 changes: 164 additions & 0 deletions bindings/c/tests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
# C API Tests

This directory contains comprehensive tests for the SVS C API using the Catch2 testing framework.

## Test Structure

The tests are organized into separate files by functionality:

- **c_api_error.cpp**: Tests for error handling functionality
- **c_api_algorithm.cpp**: Tests for algorithm creation and configuration (Vamana)
- **c_api_storage.cpp**: Tests for storage configurations (Simple, LeanVec, LVQ, SQ)
- **c_api_search_params.cpp**: Tests for search parameter creation and configuration
- **c_api_index_builder.cpp**: Tests for index builder creation and configuration
- **c_api_index.cpp**: Tests for index building, searching, and basic operations
- **c_api_dynamic_index.cpp**: Tests for dynamic index operations (add, delete, consolidate, compact)

Note: The main() function is provided by Catch2::Catch2WithMain automatically.

## Building the Tests

The tests are built as part of the C API build process. To build them:

```bash
# From the build directory
cmake -DSVS_BUILD_C_API_TESTS=ON ..
make svs_c_api_tests
```
Comment on lines +21 to +27
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The build/run commands reference svs_c_api_tests (plural), but bindings/c/tests/CMakeLists.txt currently creates svs_c_api_test (singular). Update the README commands to match the actual target/executable name (or rename the target) so the instructions work as-written.

Copilot uses AI. Check for mistakes.

To disable building tests:

```bash
cmake -DSVS_BUILD_C_API_TESTS=OFF ..
```

## Running the Tests

### Run all tests

```bash
./svs_c_api_tests
```

### Run specific test cases

```bash
# Run error handling tests only
./svs_c_api_tests "[c_api][error]"

# Run algorithm tests only
./svs_c_api_tests "[c_api][algorithm]"

# Run all index tests
./svs_c_api_tests "[c_api][index]"

# Run dynamic index tests
./svs_c_api_tests "[c_api][dynamic]"
```

### Run with verbose output

```bash
./svs_c_api_tests -s
```

### List all available tests

```bash
./svs_c_api_tests --list-tests
```

### Run with CTest

```bash
ctest -R svs_c_api_tests
```

## Test Coverage

The tests cover the following aspects of the C API:

### Error Handling

- Error handle creation and cleanup
- Error state checking
- Error codes and messages
- NULL error handle support

### Algorithm Configuration

- Vamana algorithm creation
- Parameter getters and setters (graph_degree, build_window_size, alpha, search_history)
- Invalid parameter handling

### Storage Configuration

- Simple storage (Float32, Float16, Int8, Uint8)
- LeanVec storage (various primary/secondary combinations)
- LVQ storage (with and without residual)
- Scalar Quantization storage

### Search Parameters

- Vamana search parameter creation
- Various window sizes

### Index Builder

- Index builder creation with different metrics (Euclidean, Cosine, Dot Product)
- Storage configuration
- Thread pool configuration (Native, OMP, Custom)

### Index Operations

- Index building from data
- Searching with queries
- Different K values
- Distance calculation
- Vector reconstruction
- Thread count management

### Dynamic Index Operations

- Dynamic index building with/without explicit IDs
- Adding points
- Deleting points
- ID existence checking
- Index consolidation
- Index compaction
- Search after modifications

## Test Patterns

The tests follow the patterns established in the SVS project:

1. Use `CATCH_TEST_CASE` for test case definitions
2. Use `CATCH_SECTION` for test subsections
3. Use `CATCH_REQUIRE` for assertions
4. Clean up all resources (free handles) after each test
5. Test both success and error paths
6. Test with and without NULL error handles

## Adding New Tests

When adding new tests:

1. Create a new `.cpp` file or add to an existing one
2. Follow the existing structure and naming conventions
3. Include proper copyright header
4. Use appropriate test tags: `[c_api][functionality]`
5. Add the new test file to `CMakeLists.txt` if needed
6. Clean up all allocated resources
7. Test both success and error conditions

## Dependencies

- Catch2 v3.x (automatically fetched if not found)
- SVS C API library
- C++17 or later compiler
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dependencies section says “C++17 or later compiler”, but this repository (and the test target in bindings/c/tests/CMakeLists.txt) requires C++20. Please update the README to reflect the actual minimum standard to avoid confusing users/build failures.

Suggested change
- C++17 or later compiler
- C++20 or later compiler

Copilot uses AI. Check for mistakes.

## Notes

- Tests use a simple sequential thread pool for deterministic behavior
- Test data is generated programmatically for repeatability
- Some tests may be skipped if optional features are not enabled (e.g., LVQ/LeanVec)
Loading
Loading