|
@@ -0,0 +1,114 @@
|
|
|
|
|
+#include "../service/src/views/projection.hpp"
|
|
|
|
|
+
|
|
|
|
|
+#include <cassert>
|
|
|
|
|
+#include <iostream>
|
|
|
|
|
+#include <nlohmann/json.hpp>
|
|
|
|
|
+
|
|
|
|
|
+using smartbotic::database::applyProjection;
|
|
|
|
|
+
|
|
|
|
|
+void test_empty_projection_returns_document_unchanged() {
|
|
|
|
|
+ nlohmann::json doc = {{"name", "Alice"}, {"age", 30}};
|
|
|
|
|
+ auto result = applyProjection(doc, {}, {});
|
|
|
|
|
+ assert(result == doc);
|
|
|
|
|
+ std::cout << "PASS: empty projection returns document unchanged\n";
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void test_include_keeps_only_listed_fields() {
|
|
|
|
|
+ nlohmann::json doc = {{"name", "Alice"}, {"email", "a@x.com"}, {"password", "secret"}};
|
|
|
|
|
+ auto result = applyProjection(doc, {"name", "email"}, {});
|
|
|
|
|
+ assert(result.contains("name"));
|
|
|
|
|
+ assert(result.contains("email"));
|
|
|
|
|
+ assert(!result.contains("password"));
|
|
|
|
|
+ std::cout << "PASS: include keeps only listed fields\n";
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void test_exclude_removes_fields() {
|
|
|
|
|
+ nlohmann::json doc = {{"name", "Alice"}, {"email", "a@x.com"}, {"password", "secret"}};
|
|
|
|
|
+ auto result = applyProjection(doc, {}, {"password"});
|
|
|
|
|
+ assert(result.contains("name"));
|
|
|
|
|
+ assert(result.contains("email"));
|
|
|
|
|
+ assert(!result.contains("password"));
|
|
|
|
|
+ std::cout << "PASS: exclude removes fields\n";
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void test_include_takes_precedence_over_exclude() {
|
|
|
|
|
+ nlohmann::json doc = {{"a", 1}, {"b", 2}, {"c", 3}};
|
|
|
|
|
+ auto result = applyProjection(doc, {"a"}, {"b", "c"});
|
|
|
|
|
+ assert(result.contains("a"));
|
|
|
|
|
+ assert(!result.contains("b"));
|
|
|
|
|
+ assert(!result.contains("c"));
|
|
|
|
|
+ assert(result.size() == 1);
|
|
|
|
|
+ std::cout << "PASS: include takes precedence over exclude\n";
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void test_nested_include_path() {
|
|
|
|
|
+ nlohmann::json doc = {
|
|
|
|
|
+ {"user", {
|
|
|
|
|
+ {"profile", {{"name", "Alice"}, {"bio", "hi"}}},
|
|
|
|
|
+ {"private", {{"ssn", "123"}}}
|
|
|
|
|
+ }}
|
|
|
|
|
+ };
|
|
|
|
|
+ auto result = applyProjection(doc, {"user.profile.name"}, {});
|
|
|
|
|
+ assert(result["user"]["profile"]["name"] == "Alice");
|
|
|
|
|
+ assert(!result["user"]["profile"].contains("bio"));
|
|
|
|
|
+ assert(!result["user"].contains("private"));
|
|
|
|
|
+ std::cout << "PASS: nested include path\n";
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void test_nested_exclude_path() {
|
|
|
|
|
+ nlohmann::json doc = {
|
|
|
|
|
+ {"user", {
|
|
|
|
|
+ {"name", "Alice"},
|
|
|
|
|
+ {"private", {{"ssn", "123"}, {"email", "a@x.com"}}}
|
|
|
|
|
+ }}
|
|
|
|
|
+ };
|
|
|
|
|
+ auto result = applyProjection(doc, {}, {"user.private.ssn"});
|
|
|
|
|
+ assert(result["user"]["name"] == "Alice");
|
|
|
|
|
+ assert(result["user"]["private"]["email"] == "a@x.com");
|
|
|
|
|
+ assert(!result["user"]["private"].contains("ssn"));
|
|
|
|
|
+ std::cout << "PASS: nested exclude path\n";
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void test_metadata_always_preserved_with_include() {
|
|
|
|
|
+ nlohmann::json doc = {
|
|
|
|
|
+ {"_id", "doc-1"},
|
|
|
|
|
+ {"_version", 5},
|
|
|
|
|
+ {"name", "Alice"},
|
|
|
|
|
+ {"secret", "xyz"}
|
|
|
|
|
+ };
|
|
|
|
|
+ auto result = applyProjection(doc, {"name"}, {});
|
|
|
|
|
+ assert(result.contains("_id"));
|
|
|
|
|
+ assert(result.contains("_version"));
|
|
|
|
|
+ assert(result.contains("name"));
|
|
|
|
|
+ assert(!result.contains("secret"));
|
|
|
|
|
+ std::cout << "PASS: metadata always preserved with include\n";
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void test_metadata_cannot_be_excluded() {
|
|
|
|
|
+ nlohmann::json doc = {{"_id", "doc-1"}, {"_version", 5}, {"name", "Alice"}};
|
|
|
|
|
+ auto result = applyProjection(doc, {}, {"_id", "_version"});
|
|
|
|
|
+ assert(result.contains("_id"));
|
|
|
|
|
+ assert(result.contains("_version"));
|
|
|
|
|
+ std::cout << "PASS: metadata cannot be excluded\n";
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void test_missing_path_silently_skipped() {
|
|
|
|
|
+ nlohmann::json doc = {{"name", "Alice"}};
|
|
|
|
|
+ auto result = applyProjection(doc, {"user.profile.name"}, {});
|
|
|
|
|
+ assert(!result.contains("user"));
|
|
|
|
|
+ std::cout << "PASS: missing path silently skipped\n";
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+int main() {
|
|
|
|
|
+ test_empty_projection_returns_document_unchanged();
|
|
|
|
|
+ test_include_keeps_only_listed_fields();
|
|
|
|
|
+ test_exclude_removes_fields();
|
|
|
|
|
+ test_include_takes_precedence_over_exclude();
|
|
|
|
|
+ test_nested_include_path();
|
|
|
|
|
+ test_nested_exclude_path();
|
|
|
|
|
+ test_metadata_always_preserved_with_include();
|
|
|
|
|
+ test_metadata_cannot_be_excluded();
|
|
|
|
|
+ test_missing_path_silently_skipped();
|
|
|
|
|
+ std::cout << "\nAll view projection tests PASSED!\n";
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|