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

GothenburgBitFactory / taskwarrior / 10152339701

29 Jul 2024 09:45PM UTC coverage: 84.437% (+0.07%) from 84.372%
10152339701

push

github

web-flow
Merge pull request #3566 from felixschurk/add-clang-format

Add clang-format to enforce style guide

12359 of 13760 new or added lines in 147 files covered. (89.82%)

123 existing lines in 42 files now uncovered.

19070 of 22585 relevant lines covered (84.44%)

19724.02 hits per line

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

96.49
/src/commands/CmdStats.cpp
1
////////////////////////////////////////////////////////////////////////////////
2
//
3
// Copyright 2006 - 2021, Tomas Babej, Paul Beckingham, Federico Hernandez.
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
// cmake.h include header must come first
29

30
#include <CmdStats.h>
31
#include <Context.h>
32
#include <Datetime.h>
33
#include <Duration.h>
34
#include <Filter.h>
35
#include <Table.h>
36
#include <format.h>
37
#include <main.h>
38
#include <stdlib.h>
39
#include <util.h>
40

41
#include <iomanip>
42
#include <sstream>
43

44
////////////////////////////////////////////////////////////////////////////////
45
CmdStats::CmdStats() {
4,389✔
46
  _keyword = "stats";
4,389✔
47
  _usage = "task <filter> stats";
4,389✔
48
  _description = "Shows task database statistics";
4,389✔
49
  _read_only = true;
4,389✔
50
  _displays_id = false;
4,389✔
51
  _needs_gc = true;
4,389✔
52
  _uses_context = true;
4,389✔
53
  _accepts_filter = true;
4,389✔
54
  _accepts_modifications = false;
4,389✔
55
  _accepts_miscellaneous = false;
4,389✔
56
  _category = Command::Category::metadata;
4,389✔
57
}
4,389✔
58

59
////////////////////////////////////////////////////////////////////////////////
60
int CmdStats::execute(std::string& output) {
2✔
61
  int rc = 0;
2✔
62
  std::stringstream out;
2✔
63

64
  std::string dateformat = Context::getContext().config.get("dateformat");
4✔
65

66
  // Count the possible reverts.
67
  int undoCount = Context::getContext().tdb2.num_reverts_possible();
2✔
68

69
  // Count the backlog transactions.
70
  int numLocalChanges = Context::getContext().tdb2.num_local_changes();
2✔
71

72
  // Get all the tasks.
73
  Filter filter;
2✔
74
  std::vector<Task> all = Context::getContext().tdb2.all_tasks();
2✔
75
  std::vector<Task> filtered;
2✔
76
  filter.subset(all, filtered);
2✔
77

78
  Datetime now;
2✔
79
  time_t earliest = time(nullptr);
2✔
80
  time_t latest = 1;
2✔
81
  int totalT = 0;
2✔
82
  int deletedT = 0;
2✔
83
  int pendingT = 0;
2✔
84
  int completedT = 0;
2✔
85
  int waitingT = 0;
2✔
86
  int taggedT = 0;
2✔
87
  int annotationsT = 0;
2✔
88
  int recurringT = 0;
2✔
89
  int blockingT = 0;
2✔
90
  int blockedT = 0;
2✔
91
  float daysPending = 0.0;
2✔
92
  int descLength = 0;
2✔
93
  std::map<std::string, int> allTags;
2✔
94
  std::map<std::string, int> allProjects;
2✔
95

96
  for (auto& task : filtered) {
8✔
97
    ++totalT;
6✔
98

99
    Task::status status = task.getStatus();
6✔
100
    switch (status) {
6✔
101
      case Task::deleted:
2✔
102
        ++deletedT;
2✔
103
        break;
2✔
104
      case Task::pending:
2✔
105
        ++pendingT;
2✔
106
        break;
2✔
107
      case Task::completed:
2✔
108
        ++completedT;
2✔
109
        break;
2✔
NEW
110
      case Task::recurring:
×
NEW
111
        ++recurringT;
×
NEW
112
        break;
×
NEW
113
      case Task::waiting:
×
NEW
114
        ++waitingT;
×
NEW
115
        break;
×
116
    }
117

118
    if (task.is_blocked) ++blockedT;
6✔
119
    if (task.is_blocking) ++blockingT;
6✔
120

121
    time_t entry = strtoll(task.get("entry").c_str(), nullptr, 10);
6✔
122
    if (entry < earliest) earliest = entry;
6✔
123
    if (entry > latest) latest = entry;
6✔
124

125
    if (status == Task::completed) {
6✔
126
      time_t end = strtoll(task.get("end").c_str(), nullptr, 10);
2✔
127
      daysPending += (end - entry) / 86400.0;
2✔
128
    }
129

130
    if (status == Task::pending) daysPending += (now.toEpoch() - entry) / 86400.0;
6✔
131

132
    descLength += task.get("description").length();
6✔
133
    annotationsT += task.getAnnotations().size();
6✔
134

135
    auto tags = task.getTags();
6✔
136
    if (tags.size()) ++taggedT;
6✔
137

138
    for (auto& tag : tags) allTags[tag] = 0;
6✔
139

140
    std::string project = task.get("project");
18✔
141
    if (project != "") allProjects[project] = 0;
6✔
142
  }
6✔
143

144
  // Create a table for output.
145
  Table view;
2✔
146
  view.width(Context::getContext().getWidth());
2✔
147
  view.intraPadding(2);
2✔
148
  view.add("Category");
2✔
149
  view.add("Data");
2✔
150
  setHeaderUnderline(view);
2✔
151

152
  int row = view.addRow();
2✔
153
  view.set(row, 0, "Pending");
2✔
154
  view.set(row, 1, pendingT);
2✔
155

156
  row = view.addRow();
2✔
157
  view.set(row, 0, "Waiting");
2✔
158
  view.set(row, 1, waitingT);
2✔
159

160
  row = view.addRow();
2✔
161
  view.set(row, 0, "Recurring");
2✔
162
  view.set(row, 1, recurringT);
2✔
163

164
  row = view.addRow();
2✔
165
  view.set(row, 0, "Completed");
2✔
166
  view.set(row, 1, completedT);
2✔
167

168
  row = view.addRow();
2✔
169
  view.set(row, 0, "Deleted");
2✔
170
  view.set(row, 1, deletedT);
2✔
171

172
  row = view.addRow();
2✔
173
  view.set(row, 0, "Total");
2✔
174
  view.set(row, 1, totalT);
2✔
175

176
  row = view.addRow();
2✔
177
  view.set(row, 0, "Annotations");
2✔
178
  view.set(row, 1, annotationsT);
2✔
179

180
  row = view.addRow();
2✔
181
  view.set(row, 0, "Unique tags");
2✔
182
  view.set(row, 1, (int)allTags.size());
2✔
183

184
  row = view.addRow();
2✔
185
  view.set(row, 0, "Projects");
2✔
186
  view.set(row, 1, (int)allProjects.size());
2✔
187

188
  row = view.addRow();
2✔
189
  view.set(row, 0, "Blocked tasks");
2✔
190
  view.set(row, 1, blockedT);
2✔
191

192
  row = view.addRow();
2✔
193
  view.set(row, 0, "Blocking tasks");
2✔
194
  view.set(row, 1, blockingT);
2✔
195

196
  row = view.addRow();
2✔
197
  view.set(row, 0, "Undo transactions");
2✔
198
  view.set(row, 1, undoCount);
2✔
199

200
  row = view.addRow();
2✔
201
  view.set(row, 0, "Sync backlog transactions");
2✔
202
  view.set(row, 1, numLocalChanges);
2✔
203

204
  if (totalT) {
2✔
205
    row = view.addRow();
2✔
206
    view.set(row, 0, "Tasks tagged");
2✔
207

208
    std::stringstream value;
2✔
209
    value << std::setprecision(3) << (100.0 * taggedT / totalT) << '%';
2✔
210
    view.set(row, 1, value.str());
2✔
211
  }
2✔
212

213
  if (filtered.size()) {
2✔
214
    Datetime e(earliest);
2✔
215
    row = view.addRow();
2✔
216
    view.set(row, 0, "Oldest task");
2✔
217
    view.set(row, 1, e.toString(dateformat));
2✔
218

219
    Datetime l(latest);
2✔
220
    row = view.addRow();
2✔
221
    view.set(row, 0, "Newest task");
2✔
222
    view.set(row, 1, l.toString(dateformat));
2✔
223

224
    row = view.addRow();
2✔
225
    view.set(row, 0, "Task used for");
2✔
226
    view.set(row, 1, Duration(latest - earliest).formatVague());
2✔
227
  }
228

229
  if (totalT) {
2✔
230
    row = view.addRow();
2✔
231
    view.set(row, 0, "Task added every");
2✔
232
    view.set(row, 1, Duration(((latest - earliest) / totalT)).formatVague());
2✔
233
  }
234

235
  if (completedT) {
2✔
236
    row = view.addRow();
2✔
237
    view.set(row, 0, "Task completed every");
2✔
238
    view.set(row, 1, Duration((latest - earliest) / completedT).formatVague());
2✔
239
  }
240

241
  if (deletedT) {
2✔
242
    row = view.addRow();
2✔
243
    view.set(row, 0, "Task deleted every");
2✔
244
    view.set(row, 1, Duration((latest - earliest) / deletedT).formatVague());
2✔
245
  }
246

247
  if (pendingT || completedT) {
2✔
248
    row = view.addRow();
2✔
249
    view.set(row, 0, "Average time pending");
2✔
250
    view.set(row, 1,
4✔
251
             Duration((int)((daysPending / (pendingT + completedT)) * 86400)).formatVague());
4✔
252
  }
253

254
  if (totalT) {
2✔
255
    row = view.addRow();
2✔
256
    view.set(row, 0, "Average desc length");
2✔
257
    view.set(row, 1, format("{1} characters", (int)(descLength / totalT)));
2✔
258
  }
259

260
  // If an alternating row color is specified, notify the table.
261
  if (Context::getContext().color()) {
2✔
262
    Color alternate(Context::getContext().config.get("color.alternate"));
1✔
263
    if (alternate.nontrivial()) {
1✔
264
      view.colorOdd(alternate);
1✔
265
      view.intraColorOdd(alternate);
1✔
266
      view.extraColorOdd(alternate);
1✔
267
    }
268
  }
269

270
  out << optionalBlankLine() << view.render() << optionalBlankLine();
2✔
271

272
  output = out.str();
2✔
273
  return rc;
4✔
274
}
2✔
275

276
////////////////////////////////////////////////////////////////////////////////
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

© 2025 Coveralls, Inc