DataDirectory.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. /*
  2. * Copyright (C) 2022 The V-Gears Team
  3. *
  4. * This file is part of V-Gears
  5. *
  6. * V-Gears is free software: you can redistribute it and/or modify it under
  7. * terms of the GNU General Public License as published by the Free Software
  8. * Foundation, version 3.0 (GPLv3) of the License.
  9. *
  10. * V-Gears 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. #include <boost/test/unit_test.hpp>
  16. #include <boost/filesystem.hpp>
  17. #include <algorithm>
  18. #include <fstream>
  19. #include <sstream>
  20. #include "common/DataDirectory.h"
  21. namespace fs = boost::filesystem;
  22. namespace dd = VGears::DataDirectory;
  23. namespace{
  24. /**
  25. * A temporary directory that is removed on destruction.
  26. */
  27. struct Sandbox{
  28. fs::path root;
  29. Sandbox(): root(fs::temp_directory_path() / fs::unique_path("vgears-datadir-%%%%-%%%%")){
  30. fs::create_directories(root);
  31. }
  32. ~Sandbox(){
  33. boost::system::error_code ec;
  34. fs::remove_all(root, ec);
  35. }
  36. void Write(const fs::path& file, const std::string& content) const{
  37. fs::create_directories(file.parent_path());
  38. std::ofstream(file.string()) << content;
  39. }
  40. std::string Read(const fs::path& file) const{
  41. std::ifstream in(file.string());
  42. std::stringstream text;
  43. text << in.rdbuf();
  44. return text.str();
  45. }
  46. /**
  47. * Creates a template with the V-Gears files under root/name.
  48. */
  49. fs::path MakeTemplate(const std::string& name) const{
  50. const fs::path dir = root / name;
  51. Write(dir / "plugins.cfg", "template plugins");
  52. Write(dir / "resources.cfg", "template resources");
  53. Write(dir / "data" / "config" / "config.cfg", "template config");
  54. Write(dir / "data" / "scripts" / "menu" / "begin.lua", "template script");
  55. return dir;
  56. }
  57. };
  58. }
  59. BOOST_AUTO_TEST_SUITE(DataDirectoryTests)
  60. BOOST_AUTO_TEST_CASE(IsDataDirectoryNeedsPluginsAndData){
  61. Sandbox box;
  62. BOOST_CHECK(!dd::IsDataDirectory(box.root));
  63. box.Write(box.root / "plugins.cfg", "");
  64. BOOST_CHECK(!dd::IsDataDirectory(box.root));
  65. fs::create_directories(box.root / "data");
  66. BOOST_CHECK(dd::IsDataDirectory(box.root));
  67. BOOST_CHECK(!dd::IsDataDirectory(box.root / "missing"));
  68. }
  69. BOOST_AUTO_TEST_CASE(RequestedDirectoryWins){
  70. Sandbox box;
  71. const fs::path current = box.MakeTemplate("current");
  72. const fs::path requested = box.MakeTemplate("requested");
  73. const dd::Resolution r = dd::Resolve(requested.string(), current, box.root / "default", {});
  74. BOOST_CHECK_EQUAL(r.error, "");
  75. BOOST_CHECK_EQUAL(r.directory, requested);
  76. BOOST_CHECK(!r.seeded);
  77. }
  78. BOOST_AUTO_TEST_CASE(RelativeRequestIsRelativeToCurrent){
  79. Sandbox box;
  80. const fs::path requested = box.MakeTemplate("requested");
  81. const dd::Resolution r = dd::Resolve("requested", box.root, box.root / "default", {});
  82. BOOST_CHECK_EQUAL(r.error, "");
  83. BOOST_CHECK_EQUAL(r.directory, requested);
  84. }
  85. BOOST_AUTO_TEST_CASE(CurrentDirectoryIsUsedIfItHasTheFiles){
  86. Sandbox box;
  87. const fs::path current = box.MakeTemplate("current");
  88. const dd::Resolution r = dd::Resolve("", current, box.root / "default", {box.MakeTemplate("template")});
  89. BOOST_CHECK_EQUAL(r.error, "");
  90. BOOST_CHECK_EQUAL(r.directory, current);
  91. BOOST_CHECK(!r.seeded);
  92. BOOST_CHECK(!fs::exists(box.root / "default"));
  93. }
  94. BOOST_AUTO_TEST_CASE(DefaultDirectoryIsSeededFromTheFirstValidTemplate){
  95. Sandbox box;
  96. const fs::path not_a_template = box.root / "empty";
  97. fs::create_directories(not_a_template);
  98. const fs::path source = box.MakeTemplate("template");
  99. const fs::path second = box.MakeTemplate("second");
  100. box.Write(second / "plugins.cfg", "second plugins");
  101. const fs::path target = box.root / "home" / ".v-gears";
  102. const dd::Resolution r = dd::Resolve("", box.root / "elsewhere", target, {not_a_template, source, second});
  103. BOOST_CHECK_EQUAL(r.error, "");
  104. BOOST_CHECK_EQUAL(r.directory, target);
  105. BOOST_CHECK(r.seeded);
  106. BOOST_CHECK_EQUAL(r.template_directory, source);
  107. BOOST_CHECK_EQUAL(r.copied_files, 4u);
  108. BOOST_CHECK(dd::IsDataDirectory(target));
  109. BOOST_CHECK_EQUAL(box.Read(target / "plugins.cfg"), "template plugins");
  110. BOOST_CHECK_EQUAL(box.Read(target / "data" / "scripts" / "menu" / "begin.lua"), "template script");
  111. }
  112. BOOST_AUTO_TEST_CASE(SeedingKeepsExistingFiles){
  113. Sandbox box;
  114. const fs::path source = box.MakeTemplate("template");
  115. // An installation where the installer extracted the game data but the configuration was not copied.
  116. const fs::path target = box.root / "install";
  117. box.Write(target / "data" / "config" / "config.cfg", "user config");
  118. box.Write(target / "data" / "fields" / "md1_1.xml", "game data");
  119. const dd::Resolution r = dd::Resolve(target.string(), box.root, box.root / "default", {source});
  120. BOOST_CHECK_EQUAL(r.error, "");
  121. BOOST_CHECK(r.seeded);
  122. BOOST_CHECK_EQUAL(r.copied_files, 3u);
  123. BOOST_CHECK_EQUAL(box.Read(target / "data" / "config" / "config.cfg"), "user config");
  124. BOOST_CHECK_EQUAL(box.Read(target / "data" / "fields" / "md1_1.xml"), "game data");
  125. BOOST_CHECK_EQUAL(box.Read(target / "plugins.cfg"), "template plugins");
  126. }
  127. BOOST_AUTO_TEST_CASE(UnrelatedNonEmptyDirectoryIsNotFilled){
  128. Sandbox box;
  129. const fs::path source = box.MakeTemplate("template");
  130. const fs::path target = box.root / "documents";
  131. box.Write(target / "letter.txt", "hello");
  132. const dd::Resolution r = dd::Resolve(target.string(), box.root, box.root / "default", {source});
  133. BOOST_CHECK(!r.error.empty());
  134. BOOST_CHECK(r.directory.empty());
  135. BOOST_CHECK(!fs::exists(target / "plugins.cfg"));
  136. }
  137. BOOST_AUTO_TEST_CASE(MissingTemplateIsAnError){
  138. Sandbox box;
  139. const dd::Resolution r = dd::Resolve("", box.root, box.root / "default", {box.root / "nowhere"});
  140. BOOST_CHECK(!r.error.empty());
  141. BOOST_CHECK(r.directory.empty());
  142. }
  143. BOOST_AUTO_TEST_CASE(EmptyDefaultIsAnError){
  144. Sandbox box;
  145. const dd::Resolution r = dd::Resolve("", box.root, fs::path(), {box.MakeTemplate("template")});
  146. BOOST_CHECK(!r.error.empty());
  147. }
  148. BOOST_AUTO_TEST_CASE(TemplateIsNeverTheTargetItself){
  149. Sandbox box;
  150. const fs::path source = box.MakeTemplate("template");
  151. BOOST_CHECK(dd::FindTemplate({source}, source).empty());
  152. BOOST_CHECK_EQUAL(dd::FindTemplate({source}, box.root / "other"), source);
  153. }
  154. BOOST_AUTO_TEST_CASE(TemplateCandidatesCoverBuildTreeAndPackage){
  155. const fs::path exe("/opt/repo/build/bin");
  156. const std::vector<fs::path> c = dd::TemplateCandidates(exe);
  157. auto has = [&](const fs::path& p){return std::find(c.begin(), c.end(), p) != c.end();};
  158. BOOST_CHECK(has("/opt/repo/build/bin/data"));
  159. BOOST_CHECK(has("/opt/repo/data"));
  160. BOOST_CHECK(has("/opt/repo/build/share/v-gears"));
  161. const std::vector<fs::path> installed = dd::TemplateCandidates("/usr/games");
  162. BOOST_CHECK(std::find(installed.begin(), installed.end(), fs::path("/usr/share/v-gears")) != installed.end());
  163. }
  164. BOOST_AUTO_TEST_SUITE_END()