|
@@ -125,7 +125,7 @@ void test_to_json_text_empty() {
|
|
|
check(to_json_text(d) == "null", "to_json_text of empty Doc is \"null\"");
|
|
check(to_json_text(d) == "null", "to_json_text of empty Doc is \"null\"");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-void test_doc_is_move_only() {
|
|
|
|
|
|
|
+void test_doc_supports_move() {
|
|
|
auto d1 = encode(json({{"a", 1}}));
|
|
auto d1 = encode(json({{"a", 1}}));
|
|
|
check(!d1.empty(), "encoded doc not empty");
|
|
check(!d1.empty(), "encoded doc not empty");
|
|
|
Doc d2 = std::move(d1);
|
|
Doc d2 = std::move(d1);
|
|
@@ -135,6 +135,53 @@ void test_doc_is_move_only() {
|
|
|
check(field.has_value() && field->get<int>() == 1, "moved Doc still readable");
|
|
check(field.has_value() && field->get<int>() == 1, "moved Doc still readable");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+void test_doc_copy_semantics() {
|
|
|
|
|
+ // Phase B T3 follow-up: Doc gained copy support because Document is
|
|
|
|
|
+ // copied by value across the codebase (vector<Document>, replication
|
|
|
|
|
+ // paths, etc.). Copies must be independent — mutating the source must
|
|
|
|
|
+ // not affect the copy, and vice versa.
|
|
|
|
|
+ auto src = encode(json({{"name", "Zoe"}, {"count", 42}}));
|
|
|
|
|
+ check(!src.empty(), "source doc not empty");
|
|
|
|
|
+
|
|
|
|
|
+ // Copy-construct.
|
|
|
|
|
+ Doc copy = src;
|
|
|
|
|
+ check(!copy.empty(), "copied Doc holds data");
|
|
|
|
|
+ check(!src.empty(), "source Doc still holds data after copy");
|
|
|
|
|
+
|
|
|
|
|
+ // Both should decode to the same JSON tree.
|
|
|
|
|
+ json src_json = decode(src);
|
|
|
|
|
+ json copy_json = decode(copy);
|
|
|
|
|
+ check(src_json == copy_json, "copy and source decode to equal trees");
|
|
|
|
|
+
|
|
|
|
|
+ // Independence check: replace the source with new content via move-
|
|
|
|
|
+ // assignment; the copy must remain unchanged.
|
|
|
|
|
+ auto replacement = encode(json({{"name", "Other"}, {"count", 0}}));
|
|
|
|
|
+ src = std::move(replacement);
|
|
|
|
|
+ json copy_after = decode(copy);
|
|
|
|
|
+ check(copy_after == json({{"name", "Zoe"}, {"count", 42}}),
|
|
|
|
|
+ "copy unaffected by source mutation");
|
|
|
|
|
+
|
|
|
|
|
+ // Copy-assignment with self-assignment safety.
|
|
|
|
|
+ Doc d = encode(json({{"k", "v"}}));
|
|
|
|
|
+ d = d; // NOLINT(clang-diagnostic-self-assign-overloaded)
|
|
|
|
|
+ auto field = get_field(d, "k");
|
|
|
|
|
+ check(field.has_value() && field->get<std::string>() == "v",
|
|
|
|
|
+ "self-copy-assignment preserves contents");
|
|
|
|
|
+
|
|
|
|
|
+ // Copy-assignment from a non-empty to another non-empty.
|
|
|
|
|
+ Doc a = encode(json({{"a", 1}}));
|
|
|
|
|
+ Doc b = encode(json({{"b", 2}}));
|
|
|
|
|
+ a = b;
|
|
|
|
|
+ check(decode(a) == json({{"b", 2}}), "copy-assignment overwrites target");
|
|
|
|
|
+ check(decode(b) == json({{"b", 2}}), "copy-assignment leaves source intact");
|
|
|
|
|
+
|
|
|
|
|
+ // Copy from an empty Doc → target becomes empty.
|
|
|
|
|
+ Doc empty;
|
|
|
|
|
+ Doc target = encode(json({{"x", 1}}));
|
|
|
|
|
+ target = empty;
|
|
|
|
|
+ check(target.empty(), "copy-assignment from empty Doc empties target");
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
} // namespace
|
|
} // namespace
|
|
|
|
|
|
|
|
int main() {
|
|
int main() {
|
|
@@ -149,7 +196,8 @@ int main() {
|
|
|
test_get_field_on_empty();
|
|
test_get_field_on_empty();
|
|
|
test_to_json_text_roundtrip();
|
|
test_to_json_text_roundtrip();
|
|
|
test_to_json_text_empty();
|
|
test_to_json_text_empty();
|
|
|
- test_doc_is_move_only();
|
|
|
|
|
|
|
+ test_doc_supports_move();
|
|
|
|
|
+ test_doc_copy_semantics();
|
|
|
std::cout << "test_doc_binary: all passed\n";
|
|
std::cout << "test_doc_binary: all passed\n";
|
|
|
return 0;
|
|
return 0;
|
|
|
}
|
|
}
|