mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-06-26 10:54:26 +02:00
157 lines
6.6 KiB
C++
157 lines
6.6 KiB
C++
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright 2022, Dustin J. Mitchell
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
// in the Software without restriction, including without limitation the rights
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included
|
|
// in all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
// SOFTWARE.
|
|
//
|
|
// https://www.opensource.org/licenses/mit-license.php
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include <cmake.h>
|
|
// cmake.h include header must come first
|
|
|
|
#include <rust/cxx.h>
|
|
#include <stdlib.h>
|
|
#include <taskchampion-cpp/lib.h>
|
|
#include <test.h>
|
|
#include <unistd.h>
|
|
|
|
#include <iostream>
|
|
|
|
std::string uuid2str(tc::Uuid uuid) { return static_cast<std::string>(uuid.to_string()); }
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Tests for the basic cxxbridge functionality. This focuses on the methods with
|
|
// complex cxxbridge implementations, rather than those with complex Rust
|
|
// implementations but simple APIs, like sync.
|
|
int TEST_NAME(int, char **) {
|
|
UnitTest t;
|
|
std::string str;
|
|
|
|
auto replica = tc::new_replica_in_memory();
|
|
auto uuid = tc::uuid_v4();
|
|
auto uuid2 = tc::uuid_v4();
|
|
t.is(uuid2str(uuid).size(), (size_t)36, "uuid string is the right length");
|
|
|
|
rust::Vec<tc::Operation> ops;
|
|
auto task = tc::create_task(uuid, ops);
|
|
t.is(uuid2str(task->get_uuid()), uuid2str(uuid), "new task has correct uuid");
|
|
task->update("status", "pending", ops);
|
|
task->update("description", "a task", ops);
|
|
task->update("description", "a cool task", ops);
|
|
tc::add_undo_point(ops);
|
|
task->delete_task(ops);
|
|
|
|
t.is(ops[0].is_create(), true, "ops[0] is create");
|
|
t.is(uuid2str(ops[0].get_uuid()), uuid2str(uuid), "ops[0] has correct uuid");
|
|
|
|
t.is(ops[1].is_update(), true, "ops[1] is update");
|
|
t.is(uuid2str(ops[1].get_uuid()), uuid2str(uuid), "ops[1] has correct uuid");
|
|
ops[1].get_property(str);
|
|
t.is(str, "status", "ops[1] property is 'status'");
|
|
t.ok(ops[1].get_value(str), "get_value succeeds");
|
|
t.is(str, "pending", "ops[1] value is 'pending'");
|
|
t.ok(!ops[1].get_old_value(str), "get_old_value has no old value");
|
|
|
|
t.is(ops[2].is_update(), true, "ops[2] is update");
|
|
t.is(uuid2str(ops[2].get_uuid()), uuid2str(uuid), "ops[2] has correct uuid");
|
|
ops[2].get_property(str);
|
|
t.is(str, "description", "ops[2] property is 'description'");
|
|
t.ok(ops[2].get_value(str), "get_value succeeds");
|
|
t.is(str, "a task", "ops[2] value is 'a task'");
|
|
t.ok(!ops[2].get_old_value(str), "get_old_value has no old value");
|
|
|
|
t.is(ops[3].is_update(), true, "ops[3] is update");
|
|
t.is(uuid2str(ops[3].get_uuid()), uuid2str(uuid), "ops[3] has correct uuid");
|
|
ops[3].get_property(str);
|
|
t.is(str, "description", "ops[3] property is 'description'");
|
|
t.ok(ops[3].get_value(str), "get_value succeeds");
|
|
t.is(str, "a cool task", "ops[3] value is 'a cool task'");
|
|
t.ok(ops[3].get_old_value(str), "get_old_value succeeds");
|
|
t.is(str, "a task", "ops[3] old value is 'a task'");
|
|
|
|
t.is(ops[4].is_undo_point(), true, "ops[4] is undo_point");
|
|
|
|
t.is(ops[5].is_delete(), true, "ops[5] is delete");
|
|
t.is(uuid2str(ops[5].get_uuid()), uuid2str(uuid), "ops[5] has correct uuid");
|
|
auto old_task = ops[5].get_old_task();
|
|
// old_task is in arbitrary order, so just check that status is in there.
|
|
bool found = false;
|
|
for (auto &pv : old_task) {
|
|
std::string p = static_cast<std::string>(pv.prop);
|
|
if (p == "status") {
|
|
std::string v = static_cast<std::string>(pv.value);
|
|
t.is(v, "pending", "old_task has status:pending");
|
|
found = true;
|
|
}
|
|
}
|
|
t.ok(found, "found the status property in ops[5].old_task");
|
|
|
|
replica->commit_operations(std::move(ops));
|
|
auto maybe_task2 = replica->get_task_data(tc::uuid_v4());
|
|
t.ok(maybe_task2.is_none(), "looking up a random uuid gets nothing");
|
|
|
|
// The last operation deleted the task, but we want to see the task, so undo it..
|
|
auto undo_ops = replica->get_undo_operations();
|
|
t.ok(replica->commit_reversed_operations(std::move(undo_ops)), "undo committed successfully");
|
|
|
|
auto maybe_task3 = replica->get_task_data(uuid);
|
|
t.ok(maybe_task3.is_some(), "looking up the original uuid get TaskData");
|
|
rust::Box<tc::TaskData> task3 = maybe_task3.take();
|
|
t.is(uuid2str(task3->get_uuid()), uuid2str(uuid), "reloaded task has correct uuid");
|
|
t.ok(task3->get("description", str), "reloaded task has a description");
|
|
t.is(str, "a cool task", "reloaded task has correct description");
|
|
t.ok(task3->get("status", str), "reloaded task has a status");
|
|
t.is(str, "pending", "reloaded task has correct status");
|
|
|
|
t.is(task3->properties().size(), (size_t)2, "task has 2 properties");
|
|
t.is(task3->items().size(), (size_t)2, "task has 2 items");
|
|
|
|
rust::Vec<tc::Operation> ops2;
|
|
auto task4 = tc::create_task(uuid2, ops2);
|
|
task4->update("description", "another", ops2);
|
|
replica->commit_operations(std::move(ops2));
|
|
|
|
auto all_tasks = replica->all_task_data();
|
|
t.is(all_tasks.size(), (size_t)2, "now there are 2 tasks");
|
|
for (auto &maybe_task : all_tasks) {
|
|
t.ok(maybe_task.is_some(), "all_tasks is fully populated");
|
|
auto task = maybe_task.take();
|
|
if (task->get_uuid() == uuid) {
|
|
t.ok(task->get("description", str), "get_value succeeds");
|
|
t.is(str, "a cool task", "description is 'a cool task'");
|
|
}
|
|
}
|
|
|
|
// Check exception formatting.
|
|
try {
|
|
replica->sync_to_local("/does/not/exist", false);
|
|
// tc::new_replica_on_disk("/does/not/exist", false);
|
|
} catch (rust::Error &err) {
|
|
t.is(err.what(),
|
|
"unable to open database file: /does/not/exist/taskchampion-local-sync-server.sqlite3: "
|
|
"Error code 14: Unable to open the database file",
|
|
"error message has full context");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|