Skip to content

Commit e958611

Browse files
committed
Add tests for cat-file
1 parent cb4839e commit e958611

File tree

8 files changed

+165
-34
lines changed

8 files changed

+165
-34
lines changed

.zed/settings.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"languages": {
3+
"C++": {
4+
"format_on_save": "on"
5+
}
6+
},
7+
"lsp": {
8+
"clangd": {
9+
"binary": {
10+
"path": "/usr/bin/clangd",
11+
"arguments": [
12+
"-log=verbose",
13+
"-pretty",
14+
"--background-index",
15+
"--enable-config"
16+
]
17+
}
18+
}
19+
}
20+
}

include/parsers/CatfileParser.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#ifndef CATFILEPARSER_H
2+
#define CATFILEPARSER_H
3+
4+
#include "tclap/CmdLine.h"
5+
#include <string>
6+
#include <vector>
7+
8+
class CatfileParser {
9+
public:
10+
static CatfileParser &get();
11+
void parse(std::vector<std::string> &args);
12+
std::string getType() const;
13+
std::string getHash() const;
14+
15+
private:
16+
// hides constructors to avoid accidental instantiation
17+
CatfileParser();
18+
CatfileParser(const CatfileParser &) = delete;
19+
CatfileParser &operator=(const CatfileParser &) = delete;
20+
CatfileParser(CatfileParser &&) = delete;
21+
CatfileParser &operator=(CatfileParser &&) = delete;
22+
~CatfileParser() = default;
23+
// data members
24+
TCLAP::CmdLine cmd;
25+
TCLAP::UnlabeledValueArg<std::string> typeArg;
26+
TCLAP::UnlabeledValueArg<std::string> objArg;
27+
};
28+
29+
#endif // CATFILEPARSER_H

src/commands/cat-file.cpp

Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,24 @@
11
#include "commands/cat-file.h"
22
#include <iostream>
3+
#include <stdexcept>
34

45
#include "object.h"
6+
#include "parsers/CatfileParser.h"
57
#include "repository.h"
6-
#include "tclap/CmdLine.h"
78

89
namespace commands {
910
void catfile(std::vector<std::string> &args) {
10-
TCLAP::CmdLine cmd("cat-file", ' ', "0.1");
11+
CatfileParser &parser = CatfileParser::get();
12+
parser.parse(args);
13+
std::string type = parser.getType();
14+
std::string hash = parser.getHash();
1115

12-
// defines arguments
13-
TCLAP::UnlabeledValueArg<std::string> typeArg("type", "type of object", true,
14-
"blob", "blob");
15-
TCLAP::UnlabeledValueArg<std::string> objArg(
16-
"object", "object hash", true, "e6c0a6d3b2ca0dbb3313843238d7e27f63259d3a",
17-
"string");
16+
std::optional<GitRepository> repo = GitRepository::find();
1817

19-
cmd.add(typeArg);
20-
cmd.add(objArg);
21-
cmd.parse(args);
22-
std::string &type = typeArg.getValue();
23-
std::string &hash = objArg.getValue();
24-
25-
// process args
26-
try {
27-
std::optional<GitRepository> repo = GitRepository::find();
28-
if (repo) {
29-
GitObject *obj = GitObject::read(*repo, GitObject::find(*repo, hash));
30-
std::cout << obj->serialise(*repo);
31-
}
32-
} catch (std::runtime_error &err) {
33-
std::cerr << err.what() << "\n";
18+
if (!repo) {
19+
throw std::runtime_error("No git repository found");
3420
}
21+
GitObject *obj = GitObject::read(*repo, GitObject::find(*repo, hash));
22+
std::cout << obj->serialise(*repo);
3523
}
3624
} // namespace commands

src/commit.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,14 @@ std::string GitCommit::serialise(GitRepository &repo) {
2121
<< this->keyValuePairs["author_email"] << "> "
2222
<< this->keyValuePairs["author_unix_timestamp"] << " "
2323
<< this->keyValuePairs["author_timezone"] << "\n";
24-
ss << "committer " << this->keyValuePairs["committer_name"] << " "
24+
ss << "committer " << this->keyValuePairs["committer_name"] << " <"
2525
<< this->keyValuePairs["committer_email"] << "> "
2626
<< this->keyValuePairs["committer_unix_timestamp"] << " "
2727
<< this->keyValuePairs["committer_timezone"] << "\n";
28-
ss << "gpgsig " << this->keyValuePairs["gpgsig"] << "\n\n";
28+
if (this->keyValuePairs.find("gpgsig") != this->keyValuePairs.end()) {
29+
ss << "gpgsig " << this->keyValuePairs["gpgsig"];
30+
}
31+
ss << "\n\n";
2932
ss << this->keyValuePairs["message"];
3033
return ss.str();
3134
}

src/parsers/CatfileParser.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#include "parsers/CatfileParser.h"
2+
#include <string>
3+
#include <vector>
4+
5+
void CatfileParser::parse(std::vector<std::string> &args) {
6+
cmd.reset();
7+
cmd.parse(args);
8+
}
9+
10+
std::string CatfileParser::getType() const { return typeArg.getValue(); }
11+
std::string CatfileParser::getHash() const { return objArg.getValue(); }
12+
13+
CatfileParser &CatfileParser::get() {
14+
static CatfileParser instance;
15+
return instance;
16+
}
17+
18+
CatfileParser::CatfileParser()
19+
: cmd("cat-file", ' ', "0.1"),
20+
typeArg("type", "type of object", true, "blob", "blob"),
21+
objArg("object", "object hash", true,
22+
"e6c0a6d3b2ca0dbb3313843238d7e27f63259d3a", "string") {
23+
cmd.ignoreUnmatched(true);
24+
cmd.add(typeArg);
25+
cmd.add(objArg);
26+
}

test.sh

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,17 @@ BUILD_TYPE=${BUILD_TYPE:-Debug}
77
#If the environment is specified as "prod", set the build type to Release
88
if [ "$1" == "-p" ];
99
then
10-
BUILD_TYPE=Release
10+
BUILD_TYPE=Release
1111
fi
1212

1313
#remove old build if any
1414
if [ -f "app/gyt" ];
15-
then
16-
rm -rf app/gyt
15+
then
16+
rm -rf app/gyt
1717
fi
1818

1919
#Print the selected build type
20-
echo "Selected build type: $BUILD_TYPE"
20+
echo "Selected build type: $BUILD_TYPE"
2121
echo "Building the project... This will take a while to install dependencies for the first time."
2222

2323
rm -rf ../tests/gitrepo/.git
@@ -30,8 +30,8 @@ cmake .. -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_EXPORT_COMPILE_COMMANDS=1 -DBUIL
3030
ninja
3131

3232
# test
33-
ctest --output-on-failure
33+
ctest --output-on-failure -R catfile
3434

3535
#symlink - so I can run it like gyt[arguments....]
36-
sudo rm /usr/local/bin/gyt
36+
sudo rm /usr/local/bin/gyt
3737
sudo ln -s "$(pwd)/app/gyt" /usr/local/bin/gyt

tests/CMakeLists.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
add_executable(tests tests.cpp repository_t.cpp tag_t.cpp object_t.cpp checkout_t.cpp utils/gitreposetup.cpp)
1+
add_executable(tests tests.cpp repository_t.cpp tag_t.cpp object_t.cpp checkout_t.cpp cat-file.cpp utils/gitreposetup.cpp)
22
target_include_directories(tests PUBLIC ../ext)
33

44
target_link_libraries(tests PUBLIC boost_libraries repository commands)
5-
file(COPY ${CMAKE_SOURCE_DIR}/tests/gitrepo
5+
file(COPY ${CMAKE_SOURCE_DIR}/tests/gitrepo
66
DESTINATION ${CMAKE_BINARY_DIR}/tests)
77

88
# allow user to run tests with `make test` or `ctest`
99
include(../cmake/Catch.cmake)
10-
catch_discover_tests(tests)
10+
catch_discover_tests(tests)

tests/cat-file.cpp

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#include "commands/cat-file.h"
2+
#include "catch2/catch.hpp"
3+
#include "repository.h"
4+
#include "utils/gitreposetup.h"
5+
#include <filesystem>
6+
#include <iostream>
7+
#include <sstream>
8+
namespace fs = std::filesystem;
9+
10+
TEST_CASE("catfile command", "[catfile]") {
11+
GitRepoSetup gitRepoSetup;
12+
SECTION("Valid git catfile command - catfile commit", "catfile commit") {
13+
std::vector<std::string> args({"cat-file", "commit", "head"});
14+
15+
std::stringstream buffer;
16+
std::streambuf *oldCout = std::cout.rdbuf();
17+
std::cout.rdbuf(buffer.rdbuf());
18+
commands::catfile(args);
19+
std::cout.rdbuf(oldCout);
20+
REQUIRE(buffer.str() ==
21+
"tree 19f66fa2b7cba386a1d185449eed1c024d71df25\n"
22+
"parent 1723ac93b92db1fc2c28de8e5da814136937f8c6\n"
23+
"author Chow Jia Ying <[email protected]> 1747142657 +0800\n"
24+
"committer Chow Jia Ying <[email protected]> 1747142657 "
25+
"+0800\n\n\n"
26+
27+
"Test file2\n");
28+
}
29+
SECTION("Valid git catfile command - catfile a blob", "catfile blob") {
30+
std::vector<std::string> args(
31+
{"cat-file", "blob", "9daeafb9864cf43055ae93beb0afd6c7d144bfa4"});
32+
std::stringstream buffer;
33+
std::streambuf *oldCout = std::cout.rdbuf();
34+
std::cout.rdbuf(buffer.rdbuf());
35+
commands::catfile(args);
36+
std::cout.rdbuf(oldCout);
37+
REQUIRE_NOTHROW(GitRepository(VALID_GIT_PATH, true));
38+
REQUIRE(buffer.str() == "test\n");
39+
}
40+
}
41+
42+
// TEST_CASE("catfile with errors", "[catfile errors]") {
43+
// GitRepoSetup gitRepoSetup;
44+
// SECTION("Git catfile already exists") {
45+
// std::vector<std::string> args({"catfile", "v1.0"});
46+
// commands::catfile(args);
47+
48+
// REQUIRE_NOTHROW(GitRepository(VALID_GIT_PATH, true));
49+
// REQUIRE(fs::exists(".git/refs/tags/v1.0"));
50+
// REQUIRE(GitRepoSetup::get_file_contents(".git/refs/tags/v1.0") ==
51+
// SECOND_COMMIT);
52+
53+
// std::vector<std::string> args2({"tag", "v1.0"});
54+
// REQUIRE_THROWS_WITH(commands::catfile(args2), "tag 'v1.0' already
55+
// exists");
56+
// }
57+
// SECTION("Git tag failed with non-existent commit") {
58+
// std::vector<std::string> args({"tag", "v1.0", "nonexistentcommit"});
59+
// REQUIRE_NOTHROW(GitRepository(VALID_GIT_PATH, true));
60+
61+
// REQUIRE_THROWS_WITH(commands::catfile(args),
62+
// "nonexistentcommit: not a valid commit");
63+
// REQUIRE(!fs::exists(".git/refs/tags/v1.0"));
64+
// }
65+
// }

0 commit comments

Comments
 (0)