#include "list_crdt_changes.hpp"
#include <string>
#include <cassert>
void print_list(const std::vector<std::string>& list, const std::string& label) {
std::cout << label << ": [";
for (size_t i = 0; i < list.size(); i++) {
if (i > 0) std::cout << ", ";
std::cout << list[i];
}
std::cout << "]\n";
}
void assert_lists_equal(const std::vector<std::string>& a, const std::vector<std::string>& b) {
print_list(a, "List A");
print_list(b, "List B");
assert(a.size() == b.size());
for (size_t i = 0; i < a.size(); i++) {
assert(a[i] == b[i]);
}
}
void test_changes_tracking() {
ListCRDTWithChanges<std::string> replicaA(1);
ListCRDTWithChanges<std::string> replicaB(2);
CrdtVector<ListChange<std::string>> changesA;
replicaA.insert(0, "Hello", &changesA);
replicaA.insert(1, "World", &changesA);
assert(changesA.size() == 2);
assert(changesA[0].value.value() == "Hello");
assert(changesA[1].value.value() == "World");
replicaB.apply_changes(std::move(changesA));
assert_lists_equal(replicaA.get_values(), replicaB.get_values());
std::cout << "Changes tracking test passed!\n";
}
void test_sync_with_version() {
std::cout << "\nStarting sync test...\n";
ListCRDTWithChanges<std::string> replicaA(1);
ListCRDTWithChanges<std::string> replicaB(2);
uint64_t last_sync_version = 0;
std::cout << "Initial state:\n";
print_list(replicaA.get_values(), "Replica A");
print_list(replicaB.get_values(), "Replica B");
std::cout << "\nMaking changes to replicas...\n";
replicaA.insert(0, "First");
replicaA.insert(1, "Second");
replicaB.insert(0, "Third");
replicaB.insert(1, "Fourth");
std::cout << "After changes:\n";
print_list(replicaA.get_values(), "Replica A");
print_list(replicaB.get_values(), "Replica B");
std::cout << "\nSyncing A to B...\n";
sync_list_nodes(replicaA, replicaB, last_sync_version);
print_list(replicaB.get_values(), "Replica B after A->B sync");
std::cout << "Syncing B to A...\n";
sync_list_nodes(replicaB, replicaA, last_sync_version);
print_list(replicaA.get_values(), "Replica A after B->A sync");
std::cout << "\nVerifying convergence...\n";
assert_lists_equal(replicaA.get_values(), replicaB.get_values());
std::cout << "\nMaking new change to A...\n";
replicaA.insert(2, "Fifth");
sync_list_nodes(replicaA, replicaB, last_sync_version);
std::cout << "\nFinal verification...\n";
assert_lists_equal(replicaA.get_values(), replicaB.get_values());
std::cout << "Sync with version test passed!\n";
}
void test_concurrent_changes() {
ListCRDTWithChanges<std::string> replicaA(1);
ListCRDTWithChanges<std::string> replicaB(2);
CrdtVector<ListChange<std::string>> changesA, changesB;
replicaA.insert(0, "A1", &changesA);
replicaA.insert(1, "A2", &changesA);
replicaB.insert(0, "B1", &changesB);
replicaB.insert(1, "B2", &changesB);
replicaA.apply_changes(std::move(changesB));
replicaB.apply_changes(std::move(changesA));
assert_lists_equal(replicaA.get_values(), replicaB.get_values());
changesA.clear();
changesB.clear();
replicaA.delete_element(0, &changesA);
replicaB.delete_element(1, &changesB);
replicaA.apply_changes(std::move(changesB));
replicaB.apply_changes(std::move(changesA));
assert_lists_equal(replicaA.get_values(), replicaB.get_values());
std::cout << "Concurrent changes test passed!\n";
}
int main() {
std::cout << "Running ListCRDTWithChanges tests...\n\n";
test_changes_tracking();
test_sync_with_version();
test_concurrent_changes();
std::cout << "\nAll tests passed!\n";
return 0;
}