LCOV - code coverage report
Current view: top level - test/unitTest/conversationRepository - conversationRepository.cpp (source / functions) Hit Total Coverage
Test: jami-coverage-filtered.info Lines: 261 280 93.2 %
Date: 2024-04-18 08:01:59 Functions: 19 19 100.0 %

          Line data    Source code
       1             : /*
       2             :  *  Copyright (C) 2017-2024 Savoir-faire Linux Inc.
       3             :  *  Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
       4             :  *
       5             :  *  This program 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             :  *  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.
      14             :  *
      15             :  *  You should have received a copy of the GNU General Public License
      16             :  *  along with this program. If not, see <https://www.gnu.org/licenses/>.
      17             :  */
      18             : 
      19             : #include "manager.h"
      20             : #include "jamidht/conversationrepository.h"
      21             : #include "jamidht/gitserver.h"
      22             : #include "jamidht/jamiaccount.h"
      23             : #include "../../test_runner.h"
      24             : #include "jami.h"
      25             : #include "base64.h"
      26             : #include "fileutils.h"
      27             : #include "account_const.h"
      28             : #include "common.h"
      29             : 
      30             : #include <git2.h>
      31             : 
      32             : #include <dhtnet/connectionmanager.h>
      33             : 
      34             : #include <cppunit/TestAssert.h>
      35             : #include <cppunit/TestFixture.h>
      36             : #include <cppunit/extensions/HelperMacros.h>
      37             : 
      38             : #include <condition_variable>
      39             : #include <string>
      40             : #include <fstream>
      41             : #include <streambuf>
      42             : #include <filesystem>
      43             : 
      44             : using namespace std::string_literals;
      45             : using namespace libjami::Account;
      46             : 
      47             : namespace jami {
      48             : namespace test {
      49             : 
      50             : class ConversationRepositoryTest : public CppUnit::TestFixture
      51             : {
      52             : public:
      53           7 :     ConversationRepositoryTest()
      54           7 :     {
      55             :         // Init daemon
      56           7 :         libjami::init(
      57             :             libjami::InitFlag(libjami::LIBJAMI_FLAG_DEBUG | libjami::LIBJAMI_FLAG_CONSOLE_LOG));
      58           7 :         if (not Manager::instance().initialized)
      59           1 :             CPPUNIT_ASSERT(libjami::start("jami-sample.yml"));
      60           7 :     }
      61          14 :     ~ConversationRepositoryTest() { libjami::fini(); }
      62           2 :     static std::string name() { return "ConversationRepository"; }
      63             :     void setUp();
      64             :     void tearDown();
      65             : 
      66             :     std::string aliceId;
      67             :     std::string bobId;
      68             : 
      69             : private:
      70             :     void testCreateRepository();
      71             :     void testAddSomeMessages();
      72             :     void testLogMessages();
      73             :     void testMerge();
      74             :     void testFFMerge();
      75             :     void testDiff();
      76             : 
      77             :     void testMergeProfileWithConflict();
      78             : 
      79             :     std::string addCommit(git_repository* repo,
      80             :                           const std::shared_ptr<JamiAccount> account,
      81             :                           const std::string& branch,
      82             :                           const std::string& commit_msg);
      83             :     void addAll(git_repository* repo);
      84             :     bool merge_in_main(const std::shared_ptr<JamiAccount> account,
      85             :                        git_repository* repo,
      86             :                        const std::string& commit_ref);
      87             : 
      88           2 :     CPPUNIT_TEST_SUITE(ConversationRepositoryTest);
      89           1 :     CPPUNIT_TEST(testCreateRepository);
      90           1 :     CPPUNIT_TEST(testAddSomeMessages);
      91           1 :     CPPUNIT_TEST(testLogMessages);
      92           1 :     CPPUNIT_TEST(testMerge);
      93           1 :     CPPUNIT_TEST(testFFMerge);
      94           1 :     CPPUNIT_TEST(testDiff);
      95           1 :     CPPUNIT_TEST(testMergeProfileWithConflict);
      96             : 
      97           4 :     CPPUNIT_TEST_SUITE_END();
      98             : };
      99             : 
     100             : CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(ConversationRepositoryTest,
     101             :                                       ConversationRepositoryTest::name());
     102             : 
     103             : void
     104           7 : ConversationRepositoryTest::setUp()
     105             : {
     106          14 :     auto actors = load_actors_and_wait_for_announcement("actors/alice-bob.yml");
     107           7 :     aliceId = actors["alice"];
     108           7 :     bobId = actors["bob"];
     109           7 : }
     110             : 
     111             : void
     112           7 : ConversationRepositoryTest::tearDown()
     113             : {
     114          21 :     wait_for_removal_of({aliceId, bobId});
     115           7 : }
     116             : 
     117             : void
     118           1 : ConversationRepositoryTest::testCreateRepository()
     119             : {
     120           1 :     auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId);
     121           1 :     auto aliceDeviceId = DeviceId(std::string(aliceAccount->currentDeviceId()));
     122           1 :     auto uri = aliceAccount->getUsername();
     123             : 
     124           2 :     auto repository = ConversationRepository::createConversation(aliceAccount);
     125             : 
     126             :     // Assert that repository exists
     127           1 :     CPPUNIT_ASSERT(repository != nullptr);
     128           2 :     auto repoPath = fileutils::get_data_dir() / aliceAccount->getAccountID()
     129           4 :                     / "conversations" / repository->id();
     130           1 :     CPPUNIT_ASSERT(std::filesystem::is_directory(repoPath));
     131             : 
     132             :     // Assert that first commit is signed by alice
     133             :     git_repository* repo;
     134           1 :     CPPUNIT_ASSERT(git_repository_open(&repo, repoPath.c_str()) == 0);
     135             : 
     136             :     // 1. Verify that last commit is correctly signed by alice
     137             :     git_oid commit_id;
     138           1 :     CPPUNIT_ASSERT(git_reference_name_to_id(&commit_id, repo, "HEAD") == 0);
     139             : 
     140           1 :     git_buf signature = {}, signed_data = {};
     141           1 :     git_commit_extract_signature(&signature, &signed_data, repo, &commit_id, "signature");
     142           2 :     auto pk = base64::decode(std::string(signature.ptr, signature.ptr + signature.size));
     143           1 :     auto data = std::vector<uint8_t>(signed_data.ptr, signed_data.ptr + signed_data.size);
     144           1 :     git_repository_free(repo);
     145             : 
     146           1 :     CPPUNIT_ASSERT(aliceAccount->identity().second->getPublicKey().checkSignature(data, pk));
     147             : 
     148             :     // 2. Check created files
     149           2 :     auto CRLsPath = repoPath / "CRLs" / aliceDeviceId.toString();
     150           1 :     CPPUNIT_ASSERT(std::filesystem::is_directory(repoPath));
     151             : 
     152           2 :     auto adminCrt = repoPath / "admins" / (uri + ".crt");
     153           1 :     CPPUNIT_ASSERT(std::filesystem::is_regular_file(adminCrt));
     154             : 
     155           1 :     auto crt = std::ifstream(adminCrt);
     156           1 :     std::string adminCrtStr((std::istreambuf_iterator<char>(crt)), std::istreambuf_iterator<char>());
     157             : 
     158           1 :     auto cert = aliceAccount->identity().second;
     159           1 :     auto deviceCert = cert->toString(false);
     160           1 :     auto parentCert = cert->issuer->toString(true);
     161             : 
     162           1 :     CPPUNIT_ASSERT(adminCrtStr == parentCert);
     163             : 
     164           2 :     auto deviceCrt = repoPath / "devices" / (aliceDeviceId.toString() + ".crt");
     165           1 :     CPPUNIT_ASSERT(std::filesystem::is_regular_file(deviceCrt));
     166             : 
     167           1 :     crt = std::ifstream(deviceCrt);
     168             :     std::string deviceCrtStr((std::istreambuf_iterator<char>(crt)),
     169           1 :                              std::istreambuf_iterator<char>());
     170             : 
     171           1 :     CPPUNIT_ASSERT(deviceCrtStr == deviceCert);
     172           1 : }
     173             : 
     174             : void
     175           1 : ConversationRepositoryTest::testAddSomeMessages()
     176             : {
     177           1 :     auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId);
     178           2 :     auto repository = ConversationRepository::createConversation(aliceAccount);
     179             : 
     180           2 :     auto id1 = repository->commitMessage("Commit 1");
     181           2 :     auto id2 = repository->commitMessage("Commit 2");
     182           2 :     auto id3 = repository->commitMessage("Commit 3");
     183             : 
     184           1 :     auto messages = repository->log();
     185           1 :     CPPUNIT_ASSERT(messages.size() == 4 /* 3 + initial */);
     186           1 :     CPPUNIT_ASSERT(messages[0].id == id3);
     187           1 :     CPPUNIT_ASSERT(messages[0].parents.front() == id2);
     188           1 :     CPPUNIT_ASSERT(messages[0].commit_msg == "Commit 3");
     189           1 :     CPPUNIT_ASSERT(messages[0].author.name == messages[3].author.name);
     190           1 :     CPPUNIT_ASSERT(messages[0].author.email == messages[3].author.email);
     191           1 :     CPPUNIT_ASSERT(messages[1].id == id2);
     192           1 :     CPPUNIT_ASSERT(messages[1].parents.front() == id1);
     193           1 :     CPPUNIT_ASSERT(messages[1].commit_msg == "Commit 2");
     194           1 :     CPPUNIT_ASSERT(messages[1].author.name == messages[3].author.name);
     195           1 :     CPPUNIT_ASSERT(messages[1].author.email == messages[3].author.email);
     196           1 :     CPPUNIT_ASSERT(messages[2].id == id1);
     197           1 :     CPPUNIT_ASSERT(messages[2].commit_msg == "Commit 1");
     198           1 :     CPPUNIT_ASSERT(messages[2].author.name == messages[3].author.name);
     199           1 :     CPPUNIT_ASSERT(messages[2].author.email == messages[3].author.email);
     200           1 :     CPPUNIT_ASSERT(messages[2].parents.front() == repository->id());
     201             :     // Check sig
     202           1 :     CPPUNIT_ASSERT(
     203             :         aliceAccount->identity().second->getPublicKey().checkSignature(messages[0].signed_content,
     204             :                                                                        messages[0].signature));
     205           1 :     CPPUNIT_ASSERT(
     206             :         aliceAccount->identity().second->getPublicKey().checkSignature(messages[1].signed_content,
     207             :                                                                        messages[1].signature));
     208           1 :     CPPUNIT_ASSERT(
     209             :         aliceAccount->identity().second->getPublicKey().checkSignature(messages[2].signed_content,
     210             :                                                                        messages[2].signature));
     211           1 : }
     212             : 
     213             : void
     214           1 : ConversationRepositoryTest::testLogMessages()
     215             : {
     216           1 :     auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId);
     217           2 :     auto repository = ConversationRepository::createConversation(aliceAccount);
     218             : 
     219           2 :     auto id1 = repository->commitMessage("Commit 1");
     220           2 :     auto id2 = repository->commitMessage("Commit 2");
     221           2 :     auto id3 = repository->commitMessage("Commit 3");
     222             : 
     223           1 :     LogOptions options;
     224           1 :     options.from = repository->id();
     225           1 :     options.nbOfCommits = 1;
     226           1 :     auto messages = repository->log(options);
     227           1 :     CPPUNIT_ASSERT(messages.size() == 1);
     228           1 :     CPPUNIT_ASSERT(messages[0].id == repository->id());
     229           1 :     options.from = id2;
     230           1 :     options.nbOfCommits = 2;
     231           1 :     messages = repository->log(options);
     232           1 :     CPPUNIT_ASSERT(messages.size() == 2);
     233           1 :     CPPUNIT_ASSERT(messages[0].id == id2);
     234           1 :     CPPUNIT_ASSERT(messages[1].id == id1);
     235           1 :     options.from = repository->id();
     236           1 :     options.nbOfCommits = 3;
     237           1 :     messages = repository->log(options);
     238           1 :     CPPUNIT_ASSERT(messages.size() == 1);
     239           1 :     CPPUNIT_ASSERT(messages[0].id == repository->id());
     240           1 : }
     241             : 
     242             : std::string
     243           7 : ConversationRepositoryTest::addCommit(git_repository* repo,
     244             :                                       const std::shared_ptr<JamiAccount> account,
     245             :                                       const std::string& branch,
     246             :                                       const std::string& commit_msg)
     247             : {
     248           7 :     auto deviceId = DeviceId(std::string(account->currentDeviceId()));
     249           7 :     auto name = account->getDisplayName();
     250           7 :     if (name.empty())
     251           0 :         name = deviceId.toString();
     252             : 
     253           7 :     git_signature* sig_ptr = nullptr;
     254             :     // Sign commit's buffer
     255           7 :     if (git_signature_new(&sig_ptr, name.c_str(), deviceId.to_c_str(), std::time(nullptr), 0) < 0) {
     256           0 :         JAMI_ERR("Unable to create a commit signature.");
     257           0 :         return {};
     258             :     }
     259           7 :     GitSignature sig {sig_ptr, git_signature_free};
     260             : 
     261             :     // Retrieve current HEAD
     262             :     git_oid commit_id;
     263           7 :     if (git_reference_name_to_id(&commit_id, repo, "HEAD") < 0) {
     264           0 :         JAMI_ERR("Cannot get reference for HEAD");
     265           0 :         return {};
     266             :     }
     267             : 
     268           7 :     git_commit* head_ptr = nullptr;
     269           7 :     if (git_commit_lookup(&head_ptr, repo, &commit_id) < 0) {
     270           0 :         JAMI_ERR("Could not look up HEAD commit");
     271           0 :         return {};
     272             :     }
     273           7 :     GitCommit head_commit {head_ptr, git_commit_free};
     274             : 
     275             :     // Retrieve current index
     276           7 :     git_index* index_ptr = nullptr;
     277           7 :     if (git_repository_index(&index_ptr, repo) < 0) {
     278           0 :         JAMI_ERR("Could not open repository index");
     279           0 :         return {};
     280             :     }
     281           7 :     GitIndex index {index_ptr, git_index_free};
     282             : 
     283             :     git_oid tree_id;
     284           7 :     if (git_index_write_tree(&tree_id, index.get()) < 0) {
     285           0 :         JAMI_ERR("Unable to write initial tree from index");
     286           0 :         return {};
     287             :     }
     288             : 
     289           7 :     git_tree* tree_ptr = nullptr;
     290           7 :     if (git_tree_lookup(&tree_ptr, repo, &tree_id) < 0) {
     291           0 :         JAMI_ERR("Could not look up initial tree");
     292           0 :         return {};
     293             :     }
     294           7 :     GitTree tree = {tree_ptr, git_tree_free};
     295             : 
     296           7 :     git_buf to_sign = {};
     297           7 :     const git_commit* head_ref[1] = {head_commit.get()};
     298          14 :     if (git_commit_create_buffer(&to_sign,
     299             :                                  repo,
     300           7 :                                  sig.get(),
     301           7 :                                  sig.get(),
     302             :                                  nullptr,
     303             :                                  commit_msg.c_str(),
     304           7 :                                  tree.get(),
     305             :                                  1,
     306             :                                  &head_ref[0])
     307           7 :         < 0) {
     308           0 :         JAMI_ERR("Could not create commit buffer");
     309           0 :         return {};
     310             :     }
     311             : 
     312             :     // git commit -S
     313           7 :     auto to_sign_vec = std::vector<uint8_t>(to_sign.ptr, to_sign.ptr + to_sign.size);
     314           7 :     auto signed_buf = account->identity().first->sign(to_sign_vec);
     315           7 :     std::string signed_str = base64::encode(signed_buf);
     316           7 :     if (git_commit_create_with_signature(&commit_id,
     317             :                                          repo,
     318           7 :                                          to_sign.ptr,
     319             :                                          signed_str.c_str(),
     320             :                                          "signature")
     321           7 :         < 0) {
     322           0 :         JAMI_ERR("Could not sign commit");
     323           0 :         return {};
     324             :     }
     325             : 
     326           7 :     auto commit_str = git_oid_tostr_s(&commit_id);
     327           7 :     if (commit_str) {
     328           7 :         JAMI_INFO("New commit added with id: %s", commit_str);
     329             :         // Move commit to main branch
     330           7 :         git_reference* ref_ptr = nullptr;
     331           7 :         std::string branch_name = "refs/heads/" + branch;
     332           7 :         if (git_reference_create(&ref_ptr, repo, branch_name.c_str(), &commit_id, true, nullptr)
     333           7 :             < 0) {
     334           0 :             JAMI_WARN("Could not move commit to main");
     335             :         }
     336           7 :         git_reference_free(ref_ptr);
     337           7 :     }
     338           7 :     return commit_str ? commit_str : "";
     339           7 : }
     340             : 
     341             : void
     342           3 : ConversationRepositoryTest::addAll(git_repository* repo)
     343             : {
     344             :     // git add -A
     345           3 :     git_index* index_ptr = nullptr;
     346           3 :     if (git_repository_index(&index_ptr, repo) < 0)
     347           0 :         return;
     348           3 :     GitIndex index {index_ptr, git_index_free};
     349           3 :     git_strarray array = {nullptr, 0};
     350           3 :     git_index_add_all(index.get(), &array, 0, nullptr, nullptr);
     351           3 :     git_index_write(index.get());
     352           3 :     git_strarray_free(&array);
     353           3 : }
     354             : 
     355             : void
     356           1 : ConversationRepositoryTest::testMerge()
     357             : {
     358           1 :     auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId);
     359           2 :     auto repository = ConversationRepository::createConversation(aliceAccount);
     360             : 
     361             :     // Assert that repository exists
     362           1 :     CPPUNIT_ASSERT(repository != nullptr);
     363           2 :     auto repoPath = fileutils::get_data_dir() / aliceAccount->getAccountID()
     364           4 :                     / "conversations" / repository->id();
     365           1 :     CPPUNIT_ASSERT(std::filesystem::is_directory(repoPath));
     366             : 
     367             :     // Assert that first commit is signed by alice
     368             :     git_repository* repo;
     369           1 :     CPPUNIT_ASSERT(git_repository_open(&repo, repoPath.c_str()) == 0);
     370           2 :     auto id1 = addCommit(repo, aliceAccount, "main", "Commit 1");
     371             : 
     372           1 :     git_reference* ref = nullptr;
     373           1 :     git_commit* commit = nullptr;
     374             :     git_oid commit_id;
     375           1 :     git_oid_fromstr(&commit_id, repository->id().c_str());
     376           1 :     git_commit_lookup(&commit, repo, &commit_id);
     377           1 :     git_branch_create(&ref, repo, "to_merge", commit, false);
     378           1 :     git_reference_free(ref);
     379           1 :     git_repository_set_head(repo, "refs/heads/to_merge");
     380             : 
     381           2 :     auto id2 = addCommit(repo, aliceAccount, "to_merge", "Commit 2");
     382           1 :     git_repository_free(repo);
     383             : 
     384             :     // This will create a merge commit
     385           1 :     repository->merge(id2);
     386             : 
     387           1 :     CPPUNIT_ASSERT(repository->log().size() == 4 /* Initial, commit 1, 2, merge */);
     388           1 : }
     389             : 
     390             : void
     391           1 : ConversationRepositoryTest::testFFMerge()
     392             : {
     393           1 :     auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId);
     394           2 :     auto repository = ConversationRepository::createConversation(aliceAccount);
     395             : 
     396             :     // Assert that repository exists
     397           1 :     CPPUNIT_ASSERT(repository != nullptr);
     398           2 :     auto repoPath = fileutils::get_data_dir() / aliceAccount->getAccountID()
     399           4 :                     / "conversations" / repository->id();
     400           1 :     CPPUNIT_ASSERT(std::filesystem::is_directory(repoPath));
     401             : 
     402             :     // Assert that first commit is signed by alice
     403             :     git_repository* repo;
     404           1 :     CPPUNIT_ASSERT(git_repository_open(&repo, repoPath.c_str()) == 0);
     405           2 :     auto id1 = addCommit(repo, aliceAccount, "main", "Commit 1");
     406             : 
     407           1 :     git_reference* ref = nullptr;
     408           1 :     git_commit* commit = nullptr;
     409             :     git_oid commit_id;
     410           1 :     git_oid_fromstr(&commit_id, id1.c_str());
     411           1 :     git_commit_lookup(&commit, repo, &commit_id);
     412           1 :     git_branch_create(&ref, repo, "to_merge", commit, false);
     413           1 :     git_reference_free(ref);
     414           1 :     git_repository_set_head(repo, "refs/heads/to_merge");
     415             : 
     416           2 :     auto id2 = addCommit(repo, aliceAccount, "to_merge", "Commit 2");
     417           1 :     git_repository_free(repo);
     418             : 
     419             :     // This will use a fast forward merge
     420           1 :     repository->merge(id2);
     421             : 
     422           1 :     CPPUNIT_ASSERT(repository->log().size() == 3 /* Initial, commit 1, 2 */);
     423           1 : }
     424             : 
     425             : void
     426           1 : ConversationRepositoryTest::testDiff()
     427             : {
     428           1 :     auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId);
     429           1 :     auto aliceDeviceId = DeviceId(std::string(aliceAccount->currentDeviceId()));
     430           1 :     auto uri = aliceAccount->getUsername();
     431           2 :     auto repository = ConversationRepository::createConversation(aliceAccount);
     432             : 
     433           2 :     auto id1 = repository->commitMessage("Commit 1");
     434           2 :     auto id2 = repository->commitMessage("Commit 2");
     435           2 :     auto id3 = repository->commitMessage("Commit 3");
     436             : 
     437           1 :     auto diff = repository->diffStats(id2, id1);
     438           1 :     CPPUNIT_ASSERT(ConversationRepository::changedFiles(diff).empty());
     439           1 :     diff = repository->diffStats(id1);
     440           1 :     auto changedFiles = ConversationRepository::changedFiles(diff);
     441           1 :     CPPUNIT_ASSERT(!changedFiles.empty());
     442           1 :     CPPUNIT_ASSERT(changedFiles[0] == "admins/" + uri + ".crt");
     443           1 :     CPPUNIT_ASSERT(changedFiles[1] == "devices/" + aliceDeviceId.toString() + ".crt");
     444           1 : }
     445             : 
     446             : void
     447           1 : ConversationRepositoryTest::testMergeProfileWithConflict()
     448             : {
     449           1 :     auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId);
     450           2 :     auto repository = ConversationRepository::createConversation(aliceAccount);
     451             : 
     452             :     // Assert that repository exists
     453           1 :     CPPUNIT_ASSERT(repository != nullptr);
     454           2 :     auto repoPath = fileutils::get_data_dir() / aliceAccount->getAccountID()
     455           4 :                     / "conversations" / repository->id();
     456           1 :     CPPUNIT_ASSERT(std::filesystem::is_directory(repoPath));
     457             : 
     458             :     // Assert that first commit is signed by alice
     459             :     git_repository* repo;
     460           1 :     CPPUNIT_ASSERT(git_repository_open(&repo, repoPath.c_str()) == 0);
     461             : 
     462           2 :     auto profile = std::ofstream(repoPath / "profile.vcf");
     463           1 :     if (profile.is_open()) {
     464           1 :         profile << "TITLE: SWARM\n";
     465           1 :         profile << "SUBTITLE: Some description\n";
     466           1 :         profile << "AVATAR: BASE64\n";
     467           1 :         profile.close();
     468             :     }
     469           1 :     addAll(repo);
     470           2 :     auto id1 = addCommit(repo, aliceAccount, "main", "add profile");
     471           1 :     profile = std::ofstream(repoPath / "profile.vcf");
     472           1 :     if (profile.is_open()) {
     473           1 :         profile << "TITLE: SWARM\n";
     474           1 :         profile << "SUBTITLE: New description\n";
     475           1 :         profile << "AVATAR: BASE64\n";
     476           1 :         profile.close();
     477             :     }
     478           1 :     addAll(repo);
     479           2 :     auto id2 = addCommit(repo, aliceAccount, "main", "modify profile");
     480             : 
     481           1 :     git_reference* ref = nullptr;
     482           1 :     git_commit* commit = nullptr;
     483             :     git_oid commit_id;
     484           1 :     git_oid_fromstr(&commit_id, id1.c_str());
     485           1 :     git_commit_lookup(&commit, repo, &commit_id);
     486           1 :     git_branch_create(&ref, repo, "to_merge", commit, false);
     487           1 :     git_reference_free(ref);
     488           1 :     git_repository_set_head(repo, "refs/heads/to_merge");
     489             : 
     490           1 :     profile = std::ofstream(repoPath / "profile.vcf");
     491           1 :     if (profile.is_open()) {
     492           1 :         profile << "TITLE: SWARM\n";
     493           1 :         profile << "SUBTITLE: Another description\n";
     494           1 :         profile << "AVATAR: BASE64\n";
     495           1 :         profile.close();
     496             :     }
     497           1 :     addAll(repo);
     498           2 :     auto id3 = addCommit(repo, aliceAccount, "to_merge", "modify profile merge");
     499             : 
     500             :     // This will create a merge commit
     501           1 :     repository->merge(id3);
     502           1 :     CPPUNIT_ASSERT(repository->log().size() == 5 /* Initial, add, modify 1, modify 2, merge */);
     503           1 : }
     504             : 
     505             : } // namespace test
     506             : } // namespace jami
     507             : 
     508           1 : RING_TEST_RUNNER(jami::test::ConversationRepositoryTest::name())

Generated by: LCOV version 1.14