# Problem Query Methods - Giải Thích ## "Problem Query Methods" là gì? **Problem Query Methods** là các methods trong class `Problem` dùng để **query (truy vấn) thông tin** về Problem, thay vì thay đổi trạng thái của Problem. ### Ví dụ: - ❌ **Non-query methods** (thay đổi trạng thái): - `AddParameterBlock()` - thêm parameter block - `SetParameterBlockConstant()` - đặt parameter block thành constant - `SetManifold()` - gán manifold cho parameter block - ✅ **Query methods** (chỉ đọc thông tin): - `HasParameterBlock()` - kiểm tra parameter block có tồn tại không - `GetParameterBlockSize()` - lấy kích thước của parameter block - `IsParameterBlockConstant()` - kiểm tra parameter block có constant không - `HasManifold()` - kiểm tra parameter block có manifold không - `GetManifoldHandle()` - lấy manifold handle của parameter block --- ## So Sánh: C Test vs C# Test ### C Test (`test_problem_query_methods`) - Test 11 C test có **explicit tests** cho tất cả query methods: ```c // Test has_parameter_block int has_block = ceres_wrapper_problem_has_parameter_block(problem, params); TEST_ASSERT(has_block == 1, "Has parameter block"); // Test get_parameter_block_size int size = ceres_wrapper_problem_get_parameter_block_size(problem, params); TEST_ASSERT(size == 3, "Get parameter block size"); // Test is_parameter_block_constant int is_constant = ceres_wrapper_problem_is_parameter_block_constant(problem, params); TEST_ASSERT(is_constant == 0, "Parameter block is variable"); // Test has_manifold int has_manifold = ceres_wrapper_problem_has_manifold(problem, params); TEST_ASSERT(has_manifold == 0, "No manifold initially"); // Test get_manifold ceres_manifold_t* manifold = ceres_wrapper_problem_get_manifold(problem, params); TEST_ASSERT(manifold == NULL, "Get manifold returns NULL when no manifold"); // Test với non-existent parameter block double fake_params[2] = {99.0, 99.0}; has_block = ceres_wrapper_problem_has_parameter_block(problem, fake_params); TEST_ASSERT(has_block == 0, "Non-existent parameter block"); size = ceres_wrapper_problem_get_parameter_block_size(problem, fake_params); TEST_ASSERT(size == -1, "Get size returns -1 for non-existent block"); ``` ### C# Test - Hiện Tại C# test **chỉ có tests** cho: - ✅ `IsParameterBlockConstant()` - có 2 tests - `IsParameterBlockConstant_ShouldReturnFalse_WhenVariable` - `IsParameterBlockConstant_ShouldReturnTrue_WhenConstant` **Thiếu tests** cho: - ❌ `HasParameterBlock()` - chưa có test - ❌ `GetParameterBlockSize()` - chưa có test - ❌ `HasManifold()` - chưa có test - ❌ `GetManifoldHandle()` - chưa có test - ❌ `GetParameterBlockTangentSize()` - chưa có test --- ## Tại Sao Cần Test Query Methods? ### 1. **Verify API Works Correctly** Đảm bảo các methods trả về đúng giá trị: - `HasParameterBlock()` trả về `true` khi parameter block tồn tại - `GetParameterBlockSize()` trả về đúng kích thước - `HasManifold()` trả về `true` sau khi set manifold ### 2. **Edge Cases** Test các trường hợp đặc biệt: - Query parameter block không tồn tại → trả về `false` hoặc `-1` - Query manifold khi chưa set → trả về `false` hoặc `IntPtr.Zero` - Query size của non-existent block → trả về `-1` ### 3. **Integration với Other Operations** Verify query methods hoạt động đúng sau các operations: - Sau `AddParameterBlock()` → `HasParameterBlock()` = `true` - Sau `SetManifold()` → `HasManifold()` = `true` - Sau `SetParameterBlockConstant()` → `IsParameterBlockConstant()` = `true` --- ## Các Methods Cần Test ### 1. `HasParameterBlock(double[] parameters)` **Mục đích**: Kiểm tra parameter block có tồn tại trong Problem không **Test cases cần có**: ```csharp [Test] public void HasParameterBlock_ShouldReturnTrue_WhenExists() { using var problem = new Problem(); var parameters = new double[] { 1.0, 2.0 }; problem.AddParameterBlock(parameters, parameters.Length); var hasBlock = problem.HasParameterBlock(parameters); Assert.That(hasBlock, Is.True); } [Test] public void HasParameterBlock_ShouldReturnFalse_WhenNotExists() { using var problem = new Problem(); var parameters = new double[] { 1.0, 2.0 }; var fakeParams = new double[] { 99.0, 99.0 }; problem.AddParameterBlock(parameters, parameters.Length); var hasBlock = problem.HasParameterBlock(fakeParams); Assert.That(hasBlock, Is.False); } ``` ### 2. `GetParameterBlockSize(double[] parameters)` **Mục đích**: Lấy kích thước của parameter block **Test cases cần có**: ```csharp [Test] public void GetParameterBlockSize_ShouldReturnCorrectSize() { using var problem = new Problem(); var parameters = new double[] { 1.0, 2.0, 3.0 }; problem.AddParameterBlock(parameters, parameters.Length); var size = problem.GetParameterBlockSize(parameters); Assert.That(size, Is.EqualTo(3)); } [Test] public void GetParameterBlockSize_ShouldReturnMinusOne_WhenNotExists() { using var problem = new Problem(); var fakeParams = new double[] { 99.0, 99.0 }; var size = problem.GetParameterBlockSize(fakeParams); Assert.That(size, Is.EqualTo(-1)); } ``` ### 3. `HasManifold(double[] parameters)` **Mục đích**: Kiểm tra parameter block có manifold không **Test cases cần có**: ```csharp [Test] public void HasManifold_ShouldReturnFalse_WhenNoManifold() { using var problem = new Problem(); var parameters = new double[] { 1.0, 2.0, 3.0, 4.0 }; problem.AddParameterBlock(parameters, parameters.Length); var hasManifold = problem.HasManifold(parameters); Assert.That(hasManifold, Is.False); } [Test] public void HasManifold_ShouldReturnTrue_WhenManifoldSet() { using var problem = new Problem(); var quaternion = new double[] { 0.0, 0.0, 0.0, 1.0 }; problem.AddParameterBlock(quaternion, quaternion.Length); using var manifold = new QuaternionManifold(); problem.SetManifold(quaternion, manifold); var hasManifold = problem.HasManifold(quaternion); Assert.That(hasManifold, Is.True); } ``` ### 4. `GetManifoldHandle(double[] parameters)` **Mục đích**: Lấy native handle của manifold (trả về `IntPtr.Zero` nếu không có) **Test cases cần có**: ```csharp [Test] public void GetManifoldHandle_ShouldReturnZero_WhenNoManifold() { using var problem = new Problem(); var parameters = new double[] { 1.0, 2.0 }; problem.AddParameterBlock(parameters, parameters.Length); var handle = problem.GetManifoldHandle(parameters); Assert.That(handle, Is.EqualTo(IntPtr.Zero)); } [Test] public void GetManifoldHandle_ShouldReturnNonZero_WhenManifoldSet() { using var problem = new Problem(); var quaternion = new double[] { 0.0, 0.0, 0.0, 1.0 }; problem.AddParameterBlock(quaternion, quaternion.Length); using var manifold = new QuaternionManifold(); problem.SetManifold(quaternion, manifold); var handle = problem.GetManifoldHandle(quaternion); Assert.That(handle, Is.Not.EqualTo(IntPtr.Zero)); } ``` ### 5. `GetParameterBlockTangentSize(double[] parameters)` **Mục đích**: Lấy tangent size của parameter block (khi có manifold) **Test cases cần có**: ```csharp [Test] public void GetParameterBlockTangentSize_ShouldReturnTangentSize_WithManifold() { using var problem = new Problem(); var quaternion = new double[] { 0.0, 0.0, 0.0, 1.0 }; // 4D ambient problem.AddParameterBlock(quaternion, quaternion.Length); using var manifold = new QuaternionManifold(); // 3D tangent problem.SetManifold(quaternion, manifold); var tangentSize = problem.GetParameterBlockTangentSize(quaternion); Assert.That(tangentSize, Is.EqualTo(3)); // Quaternion: 4D ambient → 3D tangent } ``` --- ## Kết Luận ### Hiện Tại - ✅ C# API **đã implement** tất cả query methods - ✅ C# test **đã có** test cho `IsParameterBlockConstant()` - ❌ C# test **thiếu** tests cho 5 methods còn lại ### Khuyến Nghị 1. **Nên thêm tests** cho các query methods để: - Đảm bảo API hoạt động đúng - Test edge cases (non-existent blocks, null parameters) - Verify integration với các operations khác 2. **Priority**: - **High**: `HasParameterBlock()`, `GetParameterBlockSize()` - thường dùng - **Medium**: `HasManifold()`, `GetManifoldHandle()` - dùng khi làm việc với manifolds - **Low**: `GetParameterBlockTangentSize()` - ít dùng, nhưng nên có test 3. **Impact**: - Không ảnh hưởng đến production (API đã implement đúng) - Nhưng thiếu tests có thể dẫn đến bugs không được phát hiện khi refactor --- **Last Updated**: 2024-12-19