• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

GothenburgBitFactory / taskwarrior / 9863873185

09 Jul 2024 08:39PM UTC coverage: 84.355% (+0.2%) from 84.172%
9863873185

push

github

web-flow
Add support for task expiration (#3546)

11 of 17 new or added lines in 4 files covered. (64.71%)

1 existing line in 1 file now uncovered.

19287 of 22864 relevant lines covered (84.36%)

20273.16 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

77.86
/src/tc/Replica.cpp
1
////////////////////////////////////////////////////////////////////////////////
2
//
3
// Copyright 2022, Dustin J. Mitchell
4
//
5
// Permission is hereby granted, free of charge, to any person obtaining a copy
6
// of this software and associated documentation files (the "Software"), to deal
7
// in the Software without restriction, including without limitation the rights
8
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
// copies of the Software, and to permit persons to whom the Software is
10
// furnished to do so, subject to the following conditions:
11
//
12
// The above copyright notice and this permission notice shall be included
13
// in all copies or substantial portions of the Software.
14
//
15
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
// SOFTWARE.
22
//
23
// https://www.opensource.org/licenses/mit-license.php
24
//
25
////////////////////////////////////////////////////////////////////////////////
26

27
#include <cmake.h>
28
#include <format.h>
29
#include "tc/Replica.h"
30
#include "tc/Task.h"
31
#include "tc/Server.h"
32
#include "tc/WorkingSet.h"
33
#include "tc/util.h"
34
#include <iostream>
35

36
using namespace tc::ffi;
37

38
////////////////////////////////////////////////////////////////////////////////
39
tc::ReplicaGuard::ReplicaGuard (Replica &replica, Task &task) :
3,439✔
40
  replica(replica),
3,439✔
41
  task(task)
3,439✔
42
{
43
  // "steal" the reference from the Replica and store it locally, so that any
44
  // attempt to use the Replica will fail
45
  tcreplica = replica.inner.release();
3,439✔
46
  task.to_mut(tcreplica);
3,439✔
47
}
3,439✔
48

49
////////////////////////////////////////////////////////////////////////////////
50
tc::ReplicaGuard::~ReplicaGuard ()
3,439✔
51
{
52
  task.to_immut();
3,439✔
53
  // return the reference to the Replica.
54
  replica.inner.reset(tcreplica);
3,439✔
55
}
3,439✔
56

57
////////////////////////////////////////////////////////////////////////////////
58
tc::Replica::Replica ()
4,362✔
59
{
60
  inner = unique_tcreplica_ptr (
8,724✔
61
      tc_replica_new_in_memory (),
62
      [](TCReplica* rep) { tc_replica_free (rep); });
8,724✔
63
}
4,362✔
64

65
////////////////////////////////////////////////////////////////////////////////
66
tc::Replica::Replica (Replica &&other) noexcept
×
67
{
68
  // move inner from other
69
  inner = unique_tcreplica_ptr (
×
70
      other.inner.release (),
71
      [](TCReplica* rep) { tc_replica_free (rep); });
×
72
}
73

74
////////////////////////////////////////////////////////////////////////////////
75
tc::Replica& tc::Replica::operator= (Replica &&other) noexcept
4,353✔
76
{
77
  if (this != &other) {
4,353✔
78
    // move inner from other
79
    inner = unique_tcreplica_ptr (
8,706✔
80
        other.inner.release (),
81
        [](TCReplica* rep) { tc_replica_free (rep); });
8,706✔
82
  }
83
  return *this;
4,353✔
84
}
85

86
////////////////////////////////////////////////////////////////////////////////
87
tc::Replica::Replica (const std::string& dir, bool create_if_missing)
4,354✔
88
{
89
  TCString path = tc_string_borrow (dir.c_str ());
4,354✔
90
  TCString error;
91
  auto tcreplica = tc_replica_new_on_disk (path, create_if_missing, &error);
4,354✔
92
  if (!tcreplica) {
4,354✔
93
    auto errmsg = format ("Could not create replica at {1}: {2}", dir, tc_string_content (&error));
2✔
94
    tc_string_free (&error);
1✔
95
    throw errmsg;
1✔
96
  }
1✔
97
  inner = unique_tcreplica_ptr (
8,706✔
98
      tcreplica,
99
      [](TCReplica* rep) { tc_replica_free (rep); });
4,353✔
100
}
4,354✔
101

102
////////////////////////////////////////////////////////////////////////////////
103
tc::WorkingSet tc::Replica::working_set ()
4,657✔
104
{
105
  TCWorkingSet *tcws = tc_replica_working_set (&*inner);
4,657✔
106
  if (!tcws) {
4,657✔
107
    throw replica_error ();
×
108
  }
109
  return WorkingSet {tcws};
4,657✔
110
}
111

112
////////////////////////////////////////////////////////////////////////////////
113
std::optional<tc::Task> tc::Replica::get_task (const std::string &uuid)
27,060✔
114
{
115
  TCTask *tctask = tc_replica_get_task (&*inner, uuid2tc (uuid));
27,060✔
116
  if (!tctask) {
27,060✔
117
    auto error = tc_replica_error (&*inner);
1,587✔
118
    if (error.ptr) {
1,587✔
119
      throw replica_error (error);
×
120
    } else {
121
      return std::nullopt;
1,587✔
122
    }
123
  }
124
  return std::make_optional (Task (tctask));
25,473✔
125
}
126

127
////////////////////////////////////////////////////////////////////////////////
128
tc::Task tc::Replica::new_task (tc::Status status, const std::string &description)
1✔
129
{
130
  TCTask *tctask = tc_replica_new_task (&*inner, (tc::ffi::TCStatus)status, string2tc (description));
1✔
131
  if (!tctask) {
1✔
132
    throw replica_error ();
×
133
  }
134
  return Task (tctask);
1✔
135
}
136

137
////////////////////////////////////////////////////////////////////////////////
138
tc::Task tc::Replica::import_task_with_uuid (const std::string &uuid)
2,912✔
139
{
140
  TCTask *tctask = tc_replica_import_task_with_uuid (&*inner, uuid2tc (uuid));
2,912✔
141
  if (!tctask) {
2,912✔
142
    throw replica_error ();
×
143
  }
144
  return Task (tctask);
2,912✔
145
}
146

147
////////////////////////////////////////////////////////////////////////////////
148
void tc::Replica::expire_tasks ()
1✔
149
{
150
  auto res = tc_replica_expire_tasks (&*inner);
1✔
151
  if (res != TC_RESULT_OK) {
1✔
NEW
152
    throw replica_error ();
×
153
  }
154
}
1✔
155

156
////////////////////////////////////////////////////////////////////////////////
157
void tc::Replica::sync (Server server, bool avoid_snapshots)
2✔
158
{
159
  // The server remains owned by this function, per tc_replica_sync docs.
160
  auto res = tc_replica_sync (&*inner, server.inner.get(), avoid_snapshots);
2✔
161
  if (res != TC_RESULT_OK) {
2✔
162
    throw replica_error ();
×
163
  }
164
}
2✔
165

166
////////////////////////////////////////////////////////////////////////////////
167
TCReplicaOpList tc::Replica::get_undo_ops ()
7✔
168
{
169
  return tc_replica_get_undo_ops(&*inner);
7✔
170
}
171

172
////////////////////////////////////////////////////////////////////////////////
173
void tc::Replica::commit_undo_ops (TCReplicaOpList tc_undo_ops, int32_t *undone_out)
4✔
174
{
175
  auto res = tc_replica_commit_undo_ops (&*inner, tc_undo_ops, undone_out);
4✔
176
  if (res != TC_RESULT_OK) {
4✔
177
    throw replica_error ();
×
178
  }
179
}
4✔
180

181
////////////////////////////////////////////////////////////////////////////////
182
void tc::Replica::free_replica_ops (TCReplicaOpList tc_undo_ops)
3✔
183
{
184
  tc_replica_op_list_free(&tc_undo_ops);
3✔
185
}
3✔
186

187
////////////////////////////////////////////////////////////////////////////////
188
std::string tc::Replica::get_op_uuid(TCReplicaOp &tc_replica_op) const
27✔
189
{
190
  TCString uuid = tc_replica_op_get_uuid(&tc_replica_op);
27✔
191
  return tc2string(uuid);
54✔
192
}
193

194
////////////////////////////////////////////////////////////////////////////////
195
std::string tc::Replica::get_op_property(TCReplicaOp &tc_replica_op) const
25✔
196
{
197
  TCString property = tc_replica_op_get_property(&tc_replica_op);
25✔
198
  return tc2string(property);
50✔
199
}
200

201
////////////////////////////////////////////////////////////////////////////////
202
std::string tc::Replica::get_op_value(TCReplicaOp &tc_replica_op) const
25✔
203
{
204
  TCString value = tc_replica_op_get_value(&tc_replica_op);
25✔
205
  return tc2string(value);
50✔
206
}
207

208
////////////////////////////////////////////////////////////////////////////////
209
std::string tc::Replica::get_op_old_value(TCReplicaOp &tc_replica_op) const
25✔
210
{
211
  TCString old_value = tc_replica_op_get_old_value(&tc_replica_op);
25✔
212
  return tc2string(old_value);
50✔
213
}
214

215
////////////////////////////////////////////////////////////////////////////////
216
std::string tc::Replica::get_op_timestamp(TCReplicaOp &tc_replica_op) const
×
217
{
218
  TCString timestamp = tc_replica_op_get_timestamp(&tc_replica_op);
×
219
  return tc2string(timestamp);
×
220
}
221

222
////////////////////////////////////////////////////////////////////////////////
223
std::string tc::Replica::get_op_old_task_description(TCReplicaOp &tc_replica_op) const
×
224
{
225
  TCString description = tc_replica_op_get_old_task_description(&tc_replica_op);
×
226
  return tc2string(description);
×
227
}
228

229
////////////////////////////////////////////////////////////////////////////////
230
int64_t tc::Replica::num_local_operations ()
5✔
231
{
232
  auto num = tc_replica_num_local_operations (&*inner);
5✔
233
  if (num < 0) {
5✔
234
    throw replica_error ();
×
235
  }
236
  return num;
5✔
237
}
238

239
////////////////////////////////////////////////////////////////////////////////
240
int64_t tc::Replica::num_undo_points ()
3✔
241
{
242
  auto num = tc_replica_num_undo_points (&*inner);
3✔
243
  if (num < 0) {
3✔
244
    throw replica_error ();
×
245
  }
246
  return num;
3✔
247
}
248

249
////////////////////////////////////////////////////////////////////////////////
250
std::vector<tc::Task> tc::Replica::all_tasks ()
2,283✔
251
{
252
  TCTaskList tasks = tc_replica_all_tasks (&*inner);
2,283✔
253
  if (!tasks.items) {
2,283✔
254
    throw replica_error ();
×
255
  }
256

257
  std::vector <Task> all;
2,283✔
258
  all.reserve (tasks.len);
2,283✔
259
  for (size_t i = 0; i < tasks.len; i++) {
737,070✔
260
    auto tctask = tc_task_list_take (&tasks, i);
734,787✔
261
    if (tctask) {
734,787✔
262
      all.push_back (Task (tctask));
734,787✔
263
    }
264
  }
265

266
  return all;
4,566✔
267
}
268

269
////////////////////////////////////////////////////////////////////////////////
270
void tc::Replica::rebuild_working_set (bool force)
864✔
271
{
272
  auto res = tc_replica_rebuild_working_set (&*inner, force);
864✔
273
  if (res != TC_RESULT_OK) {
864✔
274
    throw replica_error ();
×
275
  }
276
}
864✔
277

278
////////////////////////////////////////////////////////////////////////////////
279
tc::ReplicaGuard tc::Replica::mutate_task (tc::Task &task) {
3,439✔
280
  return ReplicaGuard(*this, task);
3,439✔
281
}
282

283
////////////////////////////////////////////////////////////////////////////////
284
std::string tc::Replica::replica_error () {
×
285
  return replica_error (tc_replica_error (&*inner));
×
286
}
287

288
////////////////////////////////////////////////////////////////////////////////
289
std::string tc::Replica::replica_error (TCString error) {
×
290
  std::string errmsg;
×
291
  if (!error.ptr) {
×
292
    errmsg = std::string ("Unknown TaskChampion error");
×
293
  } else {
294
    errmsg = std::string (tc_string_content (&error));
×
295
  }
296
  tc_string_free (&error);
×
297
  return errmsg;
×
298
}
299

300
////////////////////////////////////////////////////////////////////////////////
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc