Fix typos
[TortoiseGit.git] / test / UnitTests / libgitTest.cpp
bloba70e041c85e497b30954068ccc564a102c1eab3d
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2016-2020, 2022-2023 - TortoiseGit
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // This program 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.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "stdafx.h"
21 #include "Git.h"
22 #include "StringUtils.h"
23 #include "gitdll.h"
25 TEST(libgit, BrokenConfig)
27 CAutoTempDir tempdir;
28 g_Git.m_CurrentDir = tempdir.GetTempDir();
29 g_Git.m_IsGitDllInited = false;
30 g_Git.m_IsUseGitDLL = true;
31 g_Git.m_IsUseLibGit2 = false;
32 g_Git.m_IsUseLibGit2_mask = 0;
33 // libgit relies on CWD being set to working tree
34 SetCurrentDirectory(g_Git.m_CurrentDir);
36 CString output;
37 EXPECT_EQ(0, g_Git.Run(L"git.exe init", &output, CP_UTF8));
38 EXPECT_STRNE(L"", output);
39 CString testFile = tempdir.GetTempDir() + L"\\.git\\config";
40 EXPECT_TRUE(CStringUtils::WriteStringToTextFile(testFile, L"[push]\ndefault=something-that-is-invalid\n"));
42 EXPECT_THROW(g_Git.CheckAndInitDll(), const char*);
45 TEST(libgit, Mailmap)
47 CAutoTempDir tempdir;
48 g_Git.m_CurrentDir = tempdir.GetTempDir();
49 // libgit relies on CWD being set to working tree
50 SetCurrentDirectory(g_Git.m_CurrentDir);
52 CString output;
53 EXPECT_EQ(0, g_Git.Run(L"git.exe init", &output, CP_UTF8));
54 EXPECT_STRNE(L"", output);
55 g_Git.ForceReInitDll();
57 GIT_MAILMAP mailmap = reinterpret_cast<void*>(0x12345678);
58 git_read_mailmap(&mailmap);
59 EXPECT_EQ(nullptr, mailmap);
61 CString mailmapFile = tempdir.GetTempDir() + L"\\.mailmap";
62 EXPECT_TRUE(CStringUtils::WriteStringToTextFile(mailmapFile, L""));
64 mailmap = reinterpret_cast<void*>(0x12345678);
65 git_read_mailmap(&mailmap);
66 EXPECT_EQ(nullptr, mailmap);
68 EXPECT_TRUE(CStringUtils::WriteStringToTextFile(mailmapFile, L"Sven Strickroth <sven@tortoisegit.org>"));
69 git_read_mailmap(&mailmap);
70 EXPECT_NE(nullptr, mailmap);
71 const char* email1 = nullptr;
72 const char* author1 = nullptr;
73 EXPECT_EQ(-1, git_lookup_mailmap(mailmap, &email1, &author1, "email@cs-ware.de", nullptr, [](void*) { return "Sven S."; }));
74 EXPECT_EQ(0, git_lookup_mailmap(mailmap, &email1, &author1, "sven@tortoisegit.org", nullptr, [](void*) { return "Sven S."; }));
75 EXPECT_EQ(nullptr, email1);
76 EXPECT_STREQ("Sven Strickroth", author1);
78 email1 = nullptr;
79 author1 = nullptr;
80 EXPECT_EQ(0, git_lookup_mailmap(mailmap, &email1, &author1, "Sven@tortoisegit.org", nullptr, [](void*) { return "Sven S."; }));
81 EXPECT_EQ(nullptr, email1);
82 EXPECT_STREQ("Sven Strickroth", author1);
84 git_free_mailmap(mailmap);
85 CString content;
86 for (auto& entry : { L"", L"1", L"2", L"A", L"4", L"5", L"b", L"7" })
87 content.AppendFormat(L"Sven%s Strickroth <sven%s@tortoisegit.org> <email%s@cs-ware.de>\n", entry, entry, entry);
88 EXPECT_TRUE(CStringUtils::WriteStringToTextFile(mailmapFile, content));
89 git_read_mailmap(&mailmap);
90 EXPECT_NE(nullptr, mailmap);
91 email1 = nullptr;
92 author1 = nullptr;
93 EXPECT_EQ(-1, git_lookup_mailmap(mailmap, &email1, &author1, "sven@tortoisegit.org", nullptr, [](void*) { return "Sven S."; }));
94 EXPECT_EQ(-1, git_lookup_mailmap(mailmap, &email1, &author1, "aaa@tortoisegit.org", nullptr, [](void*) { return "Sven S."; }));
95 EXPECT_EQ(-1, git_lookup_mailmap(mailmap, &email1, &author1, "zzz@tortoisegit.org", nullptr, [](void*) { return "Sven S."; }));
96 for (auto& entry : { "", "1", "2", "A", "4", "5", "b", "7" })
98 CStringA maillookup, mail, name;
99 maillookup.Format("email%s@cs-ware.de", entry);
100 mail.Format("sven%s@tortoisegit.org", entry);
101 name.Format("Sven%s Strickroth", entry);
102 email1 = nullptr;
103 author1 = nullptr;
104 EXPECT_EQ(0, git_lookup_mailmap(mailmap, &email1, &author1, maillookup, nullptr, [](void*) { return "Sven S."; }));
105 EXPECT_STREQ(mail, email1);
106 EXPECT_STREQ(name, author1);
109 email1 = nullptr;
110 author1 = nullptr;
111 EXPECT_EQ(0, git_lookup_mailmap(mailmap, &email1, &author1, "email@cs-ware.de", nullptr, [](void*) { return "Sven Strickroth"; }));
112 EXPECT_STREQ("sven@tortoisegit.org", email1);
113 EXPECT_STREQ("Sven Strickroth", author1);
115 git_free_mailmap(mailmap);
116 EXPECT_TRUE(CStringUtils::WriteStringToTextFile(mailmapFile, L"<sven@tortoisegit.org> <email@cs-ware.de>\nSven S. <sven@tortoisegit.org> Sven Strickroth <email@cs-ware.de>\n<another@example.com> S. Strickroth <email@cs-ware.de>\n"));
117 git_read_mailmap(&mailmap);
118 EXPECT_NE(nullptr, mailmap);
119 email1 = nullptr;
120 author1 = nullptr;
121 EXPECT_EQ(-1, git_lookup_mailmap(mailmap, &email1, &author1, "sven@tortoisegit.org", nullptr, [](void*) { return "Sven S."; }));
122 EXPECT_EQ(-1, git_lookup_mailmap(mailmap, &email1, &author1, "aaa@tortoisegit.org", nullptr, [](void*) { return "Sven S."; }));
123 EXPECT_EQ(-1, git_lookup_mailmap(mailmap, &email1, &author1, "zzz@tortoisegit.org", nullptr, [](void*) { return "Sven S."; }));
124 EXPECT_EQ(0, git_lookup_mailmap(mailmap, &email1, &author1, "email@cs-ware.de", nullptr, [](void*) { return "Sven S."; }));
125 EXPECT_STREQ("sven@tortoisegit.org", email1);
126 EXPECT_STREQ(nullptr, author1);
127 email1 = nullptr;
128 author1 = nullptr;
129 EXPECT_EQ(0, git_lookup_mailmap(mailmap, &email1, &author1, "email@cs-ware.de", nullptr, [](void*) { return "Sven Strickroth"; }));
130 EXPECT_STREQ("sven@tortoisegit.org", email1);
131 EXPECT_STREQ("Sven S.", author1);
132 email1 = nullptr;
133 author1 = nullptr;
134 EXPECT_EQ(0, git_lookup_mailmap(mailmap, &email1, &author1, "email@cs-ware.de", nullptr, [](void*) { return "S. Strickroth"; }));
135 EXPECT_STREQ("another@example.com", email1);
136 EXPECT_STREQ(nullptr, author1);
139 TEST(libgit, MkDir)
141 CAutoTempDir tempdir;
142 CString subdir = tempdir.GetTempDir() + L"\\abc";
144 EXPECT_FALSE(PathFileExists(subdir));
145 EXPECT_EQ(0, git_mkdir(CUnicodeUtils::GetUTF8(subdir)));
146 EXPECT_TRUE(PathFileExists(subdir));
147 EXPECT_TRUE(PathIsDirectory(subdir));
148 EXPECT_EQ(-1, git_mkdir(CUnicodeUtils::GetUTF8(subdir)));
151 TEST(libgit, RefreshIndex)
153 CAutoTempDir tempdir;
154 g_Git.m_CurrentDir = tempdir.GetTempDir();
155 g_Git.m_bInitialized = false;
156 g_Git.m_IsGitDllInited = false;
157 g_Git.m_IsUseGitDLL = true;
158 g_Git.m_IsUseLibGit2 = false;
159 g_Git.m_IsUseLibGit2_mask = 0;
161 // libgit relies on CWD being set to working tree
162 SetCurrentDirectory(g_Git.m_CurrentDir);
164 git_repository_init_options options = GIT_REPOSITORY_INIT_OPTIONS_INIT;
165 options.flags = GIT_REPOSITORY_INIT_MKPATH | GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE;
166 CAutoRepository repo;
167 ASSERT_EQ(0, git_repository_init_ext(repo.GetPointer(), CUnicodeUtils::GetUTF8(tempdir.GetTempDir()), &options));
168 CAutoConfig config(repo);
169 ASSERT_TRUE(config.IsValid());
170 CStringA path = CUnicodeUtils::GetUTF8(g_Git.m_CurrentDir);
171 path.Replace('\\', '/');
172 EXPECT_EQ(0, git_config_set_string(config, "core.autocrlf", "false")); // newer Git complains for adding 1.enc with a safecrlf warning, especially an issue on AppVeyor where AutoCrLf=input is set
173 EXPECT_EQ(0, git_config_set_string(config, "filter.openssl.clean", path + "/clean_filter_openssl"));
174 EXPECT_EQ(0, git_config_set_string(config, "filter.openssl.smudge", path + "/smudge_filter_openssl"));
175 EXPECT_EQ(0, git_config_set_bool(config, "filter.openssl.required", 1));
176 CString cleanFilterFilename = g_Git.m_CurrentDir + L"\\clean_filter_openssl";
177 EXPECT_TRUE(CStringUtils::WriteStringToTextFile(cleanFilterFilename, L"#!/bin/bash\nopenssl version | grep -q \" 1\\\\.0\\\\.\"\nif [[ $? = 0 ]]; then\n\topenssl enc -base64 -aes-256-ecb -S FEEDDEADBEEF -k PASS_FIXED\nelse\n\topenssl enc -base64 -pbkdf2 -aes-256-ecb -nosalt -k PASS_FIXED\nfi\n"));
178 CString smudgeFilterFilename = g_Git.m_CurrentDir + L"\\smudge_filter_openssl";
179 EXPECT_TRUE(CStringUtils::WriteStringToTextFile(smudgeFilterFilename, L"#!/bin/bash\nopenssl version | grep -q \" 1\\\\.0\\\\.\"\nif [[ $? = 0 ]]; then\n\topenssl enc -d -base64 -aes-256-ecb -k PASS_FIXED\nelse\n\topenssl enc -d -base64 -pbkdf2 -aes-256-ecb -nosalt -k PASS_FIXED\nfi\n"));
180 EXPECT_EQ(0, git_config_set_string(config, "filter.test.clean", path + "/clean_filter_openssl"));
181 EXPECT_EQ(0, git_config_set_string(config, "filter.test.smudge", path + "/smudge_filter_openssl"));
182 EXPECT_EQ(0, git_config_set_string(config, "filter.test.process", path + "/clean_filter_openssl"));
183 EXPECT_EQ(0, git_config_set_bool(config, "filter.test.required", 1));
185 // need to make sure sh.exe is on PATH
186 g_Git.CheckMsysGitDir();
187 size_t size;
188 _wgetenv_s(&size, nullptr, 0, L"PATH");
189 ASSERT_LT(0U, size);
190 auto oldEnv = std::make_unique<wchar_t[]>(size);
191 ASSERT_TRUE(oldEnv);
192 _wgetenv_s(&size, oldEnv.get(), size, L"PATH");
193 _wputenv_s(L"PATH", g_Git.m_Environment.GetEnv(L"PATH"));
194 SCOPE_EXIT { _wputenv_s(L"PATH", oldEnv.get()); };
195 EXPECT_TRUE(CStringUtils::WriteStringToTextFile(g_Git.m_CurrentDir + L"\\somefile.txt", L"some content"));
197 g_Git.RefreshGitIndex();
199 CString output;
200 EXPECT_EQ(0, g_Git.Run(L"git.exe add somefile.txt", &output, CP_UTF8));
201 EXPECT_STREQ(L"", output);
203 g_Git.RefreshGitIndex();
205 EXPECT_TRUE(CStringUtils::WriteStringToTextFile(g_Git.m_CurrentDir + L"\\somefile.txt", L"some other content"));
207 g_Git.RefreshGitIndex();
209 output.Empty();
210 EXPECT_EQ(0, g_Git.Run(L"git.exe add somefile.txt", &output, CP_UTF8));
211 EXPECT_STREQ(L"", output);
213 g_Git.RefreshGitIndex();
215 // now check with external command filters defined
216 CString attributesFile = g_Git.m_CurrentDir + L"\\.gitattributes";
217 EXPECT_TRUE(CStringUtils::WriteStringToTextFile(attributesFile, L"*.enc filter=openssl\n"));
219 CString encryptedFileOne = g_Git.m_CurrentDir + L"\\1.enc";
220 EXPECT_TRUE(CStringUtils::WriteStringToTextFile(encryptedFileOne, L"This should be encrypted...\nAnd decrypted on the fly\n"));
222 output.Empty();
223 EXPECT_EQ(0, g_Git.Run(L"git.exe add 1.enc", &output, CP_UTF8));
224 if (!g_Git.ms_bCygwinGit) // on AppVeyor with the VS2017 image we get a warning: "WARNING: can't open config file: /usr/local/ssl/openssl.cnf"
225 EXPECT_STREQ(L"", output);
227 WIN32_FILE_ATTRIBUTE_DATA fdata;
228 GetFileAttributesEx(g_Git.m_CurrentDir + L"\\.git\\index", GetFileExInfoStandard, &fdata);
230 g_Git.RefreshGitIndex();
232 EXPECT_TRUE(CStringUtils::WriteStringToTextFile(g_Git.m_CurrentDir + L"\\1.enc", L"some other content"));
234 g_Git.RefreshGitIndex();
236 // need racy timestamp
237 EXPECT_TRUE(CStringUtils::WriteStringToTextFile(g_Git.m_CurrentDir + L"\\1.enc", L"somE other content"));
239 CAutoGeneralHandle handle = ::CreateFile(g_Git.m_CurrentDir + L"\\1.enc", FILE_WRITE_ATTRIBUTES, 0, nullptr, 0, 0, nullptr);
240 SetFileTime(handle, &fdata.ftCreationTime, &fdata.ftLastAccessTime, &fdata.ftLastWriteTime);
243 g_Git.RefreshGitIndex();
245 // now check with external command filters with multi-filter (process) defined
246 EXPECT_TRUE(CStringUtils::WriteStringToTextFile(attributesFile, L"*.enc filter=test\n"));
248 g_Git.RefreshGitIndex();
250 EXPECT_TRUE(CStringUtils::WriteStringToTextFile(g_Git.m_CurrentDir + L"\\1.enc", L"somE other conTentsome other conTentsome other conTen"));
252 g_Git.RefreshGitIndex();
254 // need racy timestamp
255 GetFileAttributesEx(g_Git.m_CurrentDir + L"\\.git\\index", GetFileExInfoStandard, &fdata);
256 EXPECT_TRUE(CStringUtils::WriteStringToTextFile(g_Git.m_CurrentDir + L"\\1.enc", L"some other conTentsome other conTentsome other conTen"));
258 CAutoGeneralHandle handle = ::CreateFile(g_Git.m_CurrentDir + L"\\1.enc", FILE_WRITE_ATTRIBUTES, 0, nullptr, 0, 0, nullptr);
259 SetFileTime(handle, &fdata.ftCreationTime, &fdata.ftLastAccessTime, &fdata.ftLastWriteTime);
262 g_Git.RefreshGitIndex();
265 TEST(libgit, IncludeIf)
267 CAutoTempDir tempdir;
268 g_Git.m_bInitialized = false;
269 g_Git.m_IsGitDllInited = false;
270 g_Git.m_IsUseGitDLL = true;
271 g_Git.m_IsUseLibGit2 = false;
272 g_Git.m_IsUseLibGit2_mask = 0;
274 // .git dir
275 CString repoDir = tempdir.GetTempDir() + L"\\RepoWithAInPath";
276 g_Git.m_CurrentDir = repoDir;
277 EXPECT_TRUE(CreateDirectory(repoDir, nullptr));
278 // libgit relies on CWD being set to working tree
279 EXPECT_TRUE(SetCurrentDirectory(repoDir));
281 git_repository_init_options options = GIT_REPOSITORY_INIT_OPTIONS_INIT;
282 options.flags = GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE;
283 CAutoRepository repo;
284 ASSERT_EQ(0, git_repository_init_ext(repo.GetPointer(), CUnicodeUtils::GetUTF8(repoDir), &options));
286 EXPECT_TRUE(CStringUtils::WriteStringToTextFile(repoDir + L"\\.git\\config", L"[core]\n repositoryformatversion = 0\n filemode = false\n bare = false\n logallrefupdates = true\n symlinks = false\n ignorecase = true\n hideDotFiles = dotGitOnly\n[something]\n thevalue = jap\n[includeIf \"gitdir:RepoWithAInPath/**\"]\n path = configA\n[includeIf \"gitdir:RepoWithBInPath/**\"]\n path = configB\n"));
287 EXPECT_TRUE(CStringUtils::WriteStringToTextFile(repoDir + L"\\.git\\configA", L"[somethinga]\n thevalue = jop\n"));
288 EXPECT_TRUE(CStringUtils::WriteStringToTextFile(repoDir + L"\\.git\\configB", L"[somethingb]\n thevalue = jup\n"));
290 EXPECT_STREQ(L"jap", g_Git.GetConfigValue(L"something.thevalue"));
291 EXPECT_STREQ(L"jop",g_Git.GetConfigValue(L"somethinga.thevalue"));
292 EXPECT_STREQ(L"", g_Git.GetConfigValue(L"somethingb.thevalue"));
294 // .git file
295 g_Git.m_bInitialized = false;
296 g_Git.m_IsGitDllInited = false;
297 g_Git.m_IsUseGitDLL = true;
298 repoDir = tempdir.GetTempDir() + L"\\RepoWithBInPath";
299 g_Git.m_CurrentDir = repoDir;
300 EXPECT_TRUE(CreateDirectory(repoDir, nullptr));
301 // libgit relies on CWD being set to working tree
302 EXPECT_TRUE(SetCurrentDirectory(repoDir));
303 EXPECT_TRUE(CStringUtils::WriteStringToTextFile(repoDir + L"\\.git", L"gitdir: ../RepoWithAInPath/.git\n"));
305 EXPECT_STREQ(L"jap", g_Git.GetConfigValue(L"something.thevalue"));
306 EXPECT_STREQ(L"jop", g_Git.GetConfigValue(L"somethinga.thevalue"));
307 EXPECT_STREQ(L"", g_Git.GetConfigValue(L"somethingb.thevalue"));
310 TEST(libgit, StoreUninitializedRepositoryConfig)
312 CAutoTempDir tempdir;
313 g_Git.m_CurrentDir = tempdir.GetTempDir();
314 g_Git.m_IsGitDllInited = false;
315 g_Git.m_CurrentDir = g_Git.m_CurrentDir;
316 g_Git.m_IsUseGitDLL = true;
317 g_Git.m_IsUseLibGit2 = false;
318 g_Git.m_IsUseLibGit2_mask = 0;
319 // libgit relies on CWD being set to working tree
320 SetCurrentDirectory(g_Git.m_CurrentDir);
322 // clear any leftovers in caches
323 EXPECT_THROW(g_Git.CheckAndInitDll(), const char*);
325 EXPECT_THROW(git_set_config("something", "else", CONFIG_LOCAL), const char*);