KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_git_compare_handler.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.TXT for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 3
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/gpl-3.0.html
19 */
20
26
28
32
33#include <git2.h>
34
35#include <map>
36
38
39#include <wx/filename.h>
40
41
42static const char* TEST_AUTHOR_NAME = "Test Author";
44
45
52{
55 {
56 initRepo();
57 }
58
59
61 void writeFile( const wxString& aFile, const wxString& aContent )
62 {
63 KI_TEST::WriteGitFile( m_repoPath, aFile, aContent.utf8_string() );
64 }
65
66
67 void removeFile( const wxString& aFile )
68 {
69 wxRemoveFile( m_repoPath + wxFileName::GetPathSeparator() + aFile );
70 }
71
72
74 void commitAll( const wxString& aMessage ) { KI_TEST::CommitAllGitFiles( m_repo.get(), aMessage ); }
75
76
77 git_repository* repo() const { return m_repo.get(); }
78
79
80private:
81 void initRepo()
82 {
84
85 writeFile( wxT( "a.txt" ), wxT( "alpha\n" ) );
86 writeFile( wxT( "b.txt" ), wxT( "bravo\n" ) );
87 commitAll( wxT( "First commit" ) );
88
89 writeFile( wxT( "a.txt" ), wxT( "alpha modified\n" ) );
90 removeFile( wxT( "b.txt" ) );
91 writeFile( wxT( "c.txt" ), wxT( "charlie\n" ) );
92 commitAll( wxT( "Second commit" ) );
93 }
94
95
97 wxString m_repoPath;
98};
99
100
101BOOST_FIXTURE_TEST_SUITE( GitCompareHandler, GIT_COMPARE_FIXTURE )
102
103
104BOOST_AUTO_TEST_CASE( ResolveRefToTree_Valid )
105{
106 KIGIT::GitTreePtr head( KIGIT::ResolveRefToTree( repo(), wxT( "HEAD" ) ) );
107 BOOST_CHECK( head.get() != nullptr );
108
109 KIGIT::GitTreePtr prev( KIGIT::ResolveRefToTree( repo(), wxT( "HEAD~1" ) ) );
110 BOOST_CHECK( prev.get() != nullptr );
111
112 // HEAD and its parent point at different trees.
113 BOOST_CHECK( head.get() != prev.get() );
114}
115
116
117BOOST_AUTO_TEST_CASE( ResolveRefToTree_Invalid )
118{
119 BOOST_CHECK( KIGIT::ResolveRefToTree( repo(), wxT( "does-not-exist" ) ) == nullptr );
120 BOOST_CHECK( KIGIT::ResolveRefToTree( nullptr, wxT( "HEAD" ) ) == nullptr );
121}
122
123
124BOOST_AUTO_TEST_CASE( CollectDiffDeltas_NullDiffIsNoOp )
125{
126 int calls = 0;
127 KIGIT::CollectDiffDeltas( nullptr, [&calls]( const git_diff_delta& ) { ++calls; } );
128 BOOST_CHECK_EQUAL( calls, 0 );
129}
130
131
132BOOST_AUTO_TEST_CASE( CollectDiffDeltas_WalksEveryDelta )
133{
134 KIGIT::GitTreePtr baseTree( KIGIT::ResolveRefToTree( repo(), wxT( "HEAD~1" ) ) );
135 KIGIT::GitTreePtr headTree( KIGIT::ResolveRefToTree( repo(), wxT( "HEAD" ) ) );
136
137 BOOST_REQUIRE( baseTree.get() );
138 BOOST_REQUIRE( headTree.get() );
139
140 git_diff* diff = nullptr;
141 git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
142
143 BOOST_REQUIRE_EQUAL(
144 git_diff_tree_to_tree( &diff, repo(), baseTree.get(), headTree.get(), &opts ), 0 );
145
146 KIGIT::GitDiffPtr diffPtr( diff );
147
148 std::map<wxString, git_delta_t> seen;
150 [&seen]( const git_diff_delta& aDelta )
151 {
152 const char* path = aDelta.new_file.path ? aDelta.new_file.path
153 : aDelta.old_file.path;
154 seen[wxString::FromUTF8( path )] = aDelta.status;
155 } );
156
157 BOOST_CHECK_EQUAL( seen.size(), 3u );
158 BOOST_CHECK( seen.at( wxT( "a.txt" ) ) == GIT_DELTA_MODIFIED );
159 BOOST_CHECK( seen.at( wxT( "b.txt" ) ) == GIT_DELTA_DELETED );
160 BOOST_CHECK( seen.at( wxT( "c.txt" ) ) == GIT_DELTA_ADDED );
161}
162
163
164BOOST_AUTO_TEST_CASE( CompareRefs_ReportsExpectedChanges )
165{
166 std::vector<KIGIT::CHANGED_FILE> changes =
167 KIGIT::CompareRefs( repo(), wxT( "HEAD~1" ), wxT( "HEAD" ) );
168
169 std::map<wxString, KIGIT::FILE_CHANGE_STATUS> byPath;
170
171 for( const KIGIT::CHANGED_FILE& f : changes )
172 byPath[f.path] = f.status;
173
174 BOOST_CHECK_EQUAL( byPath.size(), 3u );
175 BOOST_CHECK( byPath.at( wxT( "a.txt" ) ) == KIGIT::FILE_CHANGE_STATUS::MODIFIED );
176 BOOST_CHECK( byPath.at( wxT( "b.txt" ) ) == KIGIT::FILE_CHANGE_STATUS::REMOVED );
177 BOOST_CHECK( byPath.at( wxT( "c.txt" ) ) == KIGIT::FILE_CHANGE_STATUS::ADDED );
178}
179
180
181BOOST_AUTO_TEST_CASE( CompareRefs_InvalidRefReturnsEmpty )
182{
183 BOOST_CHECK( KIGIT::CompareRefs( repo(), wxT( "HEAD" ), wxT( "nope" ) ).empty() );
184 BOOST_CHECK( KIGIT::CompareRefs( nullptr, wxT( "HEAD~1" ), wxT( "HEAD" ) ).empty() );
185}
186
187
188// An empty base ref compares against the empty tree, so the initial commit (which has no parent
189// to name) reports all of its files as added instead of returning nothing.
190BOOST_AUTO_TEST_CASE( CompareRefs_EmptyBaseComparesAgainstEmptyTree )
191{
192 std::vector<KIGIT::CHANGED_FILE> changes = KIGIT::CompareRefs( repo(), wxEmptyString, wxT( "HEAD~1" ) );
193
194 std::map<wxString, KIGIT::FILE_CHANGE_STATUS> byPath;
195
196 for( const KIGIT::CHANGED_FILE& f : changes )
197 byPath[f.path] = f.status;
198
199 BOOST_REQUIRE_EQUAL( changes.size(), 2u );
200 BOOST_REQUIRE( byPath.count( wxT( "a.txt" ) ) );
201 BOOST_REQUIRE( byPath.count( wxT( "b.txt" ) ) );
202 BOOST_CHECK( byPath[wxT( "a.txt" )] == KIGIT::FILE_CHANGE_STATUS::ADDED );
203 BOOST_CHECK( byPath[wxT( "b.txt" )] == KIGIT::FILE_CHANGE_STATUS::ADDED );
204}
205
206
Give each test a backend and a temporary directory.
const wxString & TempPath() const
static bool empty(const wxTextEntryBase *aCtrl)
std::unique_ptr< git_tree, decltype([](git_tree *aTree) { git_tree_free(aTree); })> GitTreePtr
A unique pointer for git_tree objects with automatic cleanup.
std::vector< CHANGED_FILE > CompareRefs(git_repository *aRepo, const wxString &aBaseRef, const wxString &aHeadRef)
Compare two git refs (branch / tag / commit OID) within a repository and return the per-file change l...
std::unique_ptr< git_repository, decltype([](git_repository *aRepo) { git_repository_free(aRepo); })> GitRepositoryPtr
A unique pointer for git_repository objects with automatic cleanup.
git_tree * ResolveRefToTree(git_repository *aRepo, const wxString &aRef)
Resolve a string ref (branch name, short OID, full OID, tag) to its tree.
void CollectDiffDeltas(git_diff *aDiff, const std::function< void(const git_diff_delta &)> &aCallback)
Walk every delta in a computed diff, invoking aCallback once per delta.
std::unique_ptr< git_diff, decltype([](git_diff *aDiff) { git_diff_free(aDiff); })> GitDiffPtr
A unique pointer for git_diff objects with automatic cleanup.
KIGIT::GitRepositoryPtr InitGitRepository(const wxString &aPath, const char *aBranch="main", const char *aAuthorName="QA Test", const char *aAuthorEmail="[email protected]")
Pin the branch and author so repository setup does not depend on the user's Git config.
void WriteGitFile(const wxString &aRepoPath, const wxString &aRelativePath, const std::string &aContents)
Write test data without staging it. Create parent directories when needed.
git_oid CommitAllGitFiles(git_repository *aRepo, const wxString &aMessage)
Stage all changes, including deletions, and commit them.
Build a temp working repo with two commits.
git_repository * repo() const
KIGIT::GitRepositoryPtr m_repo
void removeFile(const wxString &aFile)
void commitAll(const wxString &aMessage)
Stage every change, including deletions, and create a commit on HEAD.
void writeFile(const wxString &aFile, const wxString &aContent)
Write a file in the working tree.
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
static const char * TEST_AUTHOR_NAME
BOOST_AUTO_TEST_CASE(ResolveRefToTree_Valid)
static const char * TEST_AUTHOR_EMAIL
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
std::string path
BOOST_CHECK_EQUAL(result, "25.4")