xaizek / dit (License: GPLv3) (since 2018-12-07)
Command-line task keeper that remembers all old values and is meant to combine several orthogonal features to be rather flexible in managing items.
Commit 1fdbcbba2f3351b17887fed2ae5f9546359192ec

Add tests for the "log" sub-command
Author: xaizek
Author date (UTC): 2016-06-06 18:13
Committer name: xaizek
Committer date (UTC): 2016-06-06 18:28
Parent(s): 00559113f9ea547529d816afdb752c0ee2ae3da2
Signing key: 99DC5E4DB05F6BE2
Tree: 65ab78d4adde721ffdee5066fab15f0d3f8b3f8a
File Lines added Lines deleted
tests/cmds/LogCmd.cpp 216 0
File tests/cmds/LogCmd.cpp added (mode: 100644) (index 0000000..68953e3)
1 // Copyright (C) 2016 xaizek <xaizek@openmailbox.org>
2 //
3 // This file is part of dit.
4 //
5 // dit is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // dit is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with dit. If not, see <http://www.gnu.org/licenses/>.
17
18 #include "Catch/catch.hpp"
19
20 #include <boost/algorithm/string/predicate.hpp>
21
22 #include <cstdlib>
23
24 #include <sstream>
25 #include <stdexcept>
26
27 #include "utils/strings.hpp"
28 #include "Change.hpp"
29 #include "Command.hpp"
30 #include "Commands.hpp"
31 #include "Item.hpp"
32 #include "Project.hpp"
33
34 #include "Tests.hpp"
35
36 TEST_CASE("Log fails on wrong invocation", "[cmds][log][invocation]")
37 {
38 std::unique_ptr<Project> prj = Tests::makeProject();
39 Command *const cmd = Commands::get("log");
40
41 std::ostringstream out, err;
42 Tests::setStreams(out, err);
43
44 boost::optional<int> exitCode;
45
46 SECTION("Fails on zero arguments")
47 {
48 exitCode = cmd->run(*prj, { });
49 REQUIRE(exitCode);
50 REQUIRE(*exitCode == EXIT_FAILURE);
51 REQUIRE(out.str() == std::string());
52 REQUIRE(err.str() != std::string());
53 }
54
55 SECTION("Wrong id")
56 {
57 REQUIRE_THROWS_AS(cmd->run(*prj, { "asdf" }), std::runtime_error);
58 }
59 }
60
61 TEST_CASE("Log filters fields", "[cmds][log]")
62 {
63 std::unique_ptr<Project> prj = Tests::makeProject();
64 Command *const cmd = Commands::get("log");
65 Storage &storage = prj->getStorage();
66
67 std::ostringstream out, err;
68 Tests::setStreams(out, err);
69
70 Item item = Tests::makeItem("id");
71 item.setValue("title", "something");
72 item.setValue("bug_number", "22");
73 Tests::storeItem(storage, std::move(item));
74
75 boost::optional<int> exitCode = cmd->run(*prj, { "id", "title" });
76 REQUIRE(exitCode);
77 REQUIRE(*exitCode == EXIT_SUCCESS);
78
79 const std::vector<std::string> lines = split(out.str(), '\n');
80 REQUIRE(boost::starts_with(lines[0], "title created:"));
81 REQUIRE(lines[1] == std::string());
82 REQUIRE(err.str() == std::string());
83 }
84
85 TEST_CASE("Log displays operations correctly", "[cmds][log]")
86 {
87 std::unique_ptr<Project> prj = Tests::makeProject();
88 Command *const cmd = Commands::get("log");
89 Storage &storage = prj->getStorage();
90
91 std::ostringstream out, err;
92 Tests::setStreams(out, err);
93
94 std::time_t t = std::time(nullptr);
95 MockTimeSource timeMock([&t](){ return t++; });
96
97 SECTION("Creation")
98 {
99 Item item = Tests::makeItem("id");
100 item.setValue("bug_number", "22");
101 Tests::storeItem(storage, std::move(item));
102
103 boost::optional<int> exitCode = cmd->run(*prj, { "id" });
104 REQUIRE(exitCode);
105 REQUIRE(*exitCode == EXIT_SUCCESS);
106
107 REQUIRE(boost::starts_with(split(out.str(), '\n')[0],
108 "bug_number created:"));
109 REQUIRE(err.str() == std::string());
110 }
111
112 SECTION("Removal")
113 {
114 Item item = Tests::makeItem("id");
115 item.setValue("bug_number", "22");
116 item.setValue("bug_number", "");
117 Tests::storeItem(storage, std::move(item));
118
119 boost::optional<int> exitCode = cmd->run(*prj, { "id" });
120 REQUIRE(exitCode);
121 REQUIRE(*exitCode == EXIT_SUCCESS);
122
123 REQUIRE(boost::starts_with(split(out.str(), '\n')[1],
124 "bug_number deleted"));
125 REQUIRE(err.str() == std::string());
126 }
127
128 SECTION("Changing")
129 {
130 Item item = Tests::makeItem("id");
131 item.setValue("bug_number", "22");
132 item.setValue("bug_number", "21");
133 Tests::storeItem(storage, std::move(item));
134
135 boost::optional<int> exitCode = cmd->run(*prj, { "id" });
136 REQUIRE(exitCode);
137 REQUIRE(*exitCode == EXIT_SUCCESS);
138
139 REQUIRE(boost::starts_with(split(out.str(), '\n')[1],
140 "bug_number changed"));
141 REQUIRE(err.str() == std::string());
142 }
143 }
144
145 TEST_CASE("Completion of id for log", "[cmds][log][completion]")
146 {
147 std::unique_ptr<Project> prj = Tests::makeProject();
148 Storage &storage = prj->getStorage();
149
150 Item item = Tests::makeItem("id");
151
152 Tests::storeItem(storage, std::move(item));
153
154 Command *const cmd = Commands::get("log");
155
156 std::ostringstream out, err;
157 Tests::setStreams(out, err);
158
159 boost::optional<int> exitCode = cmd->complete(*prj, { "i" });
160 REQUIRE(exitCode);
161 REQUIRE(*exitCode == EXIT_SUCCESS);
162
163 const std::string expectedOut = "id\n";
164 REQUIRE(out.str() == expectedOut);
165 REQUIRE(err.str() == std::string());
166 }
167
168 TEST_CASE("Completion of field name for log", "[cmds][log][completion]")
169 {
170 std::unique_ptr<Project> prj = Tests::makeProject();
171 Storage &storage = prj->getStorage();
172
173 Item item = Tests::makeItem("id");
174 item.setValue("title", "title");
175 item.setValue("bug_number", "22");
176
177 Tests::storeItem(storage, std::move(item));
178
179 Command *const cmd = Commands::get("log");
180
181 std::ostringstream out, err;
182 Tests::setStreams(out, err);
183
184 std::string expectedOut;
185
186 SECTION("Wrong id produces error")
187 {
188 boost::optional<int> exitCode = cmd->complete(*prj, { "idd", "ti" });
189 REQUIRE(exitCode);
190 REQUIRE(*exitCode == EXIT_FAILURE);
191 }
192
193 SECTION("First filter value")
194 {
195 boost::optional<int> exitCode = cmd->complete(*prj, { "id", "ti" });
196 REQUIRE(exitCode);
197 REQUIRE(*exitCode == EXIT_SUCCESS);
198
199 expectedOut =
200 "bug_number\n"
201 "title\n";
202 }
203
204 SECTION("Second filter value")
205 {
206 boost::optional<int> exitCode = cmd->complete(*prj,
207 { "id", "title", "b" });
208 REQUIRE(exitCode);
209 REQUIRE(*exitCode == EXIT_SUCCESS);
210
211 expectedOut = "bug_number\n";
212 }
213
214 REQUIRE(out.str() == expectedOut);
215 REQUIRE(err.str() == std::string());
216 }
Hints

Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://code.reversed.top/user/xaizek/dit

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@code.reversed.top/user/xaizek/dit

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a pull request:
... clone the repository ...
... make some changes and some commits ...
git push origin master