The Battle for Wesnoth  1.19.5+dev
test_filesystem.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2015 - 2024
3  by Iris Morelle <shadowm2006@gmail.com>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 #include <boost/test/unit_test.hpp>
17 
18 #include "config_cache.hpp"
19 #include "filesystem.hpp"
20 #include "game_config.hpp"
21 #include "log.hpp"
22 
23 #if 0
24 namespace {
25 
26 template<typename T>
27 void dump(const T& v)
28 {
29  for(typename T::const_iterator k = v.begin(); k != v.end(); ++k) {
30  PLAIN_LOG << " * " << *k;
31  }
32 }
33 
34 }
35 #endif
36 
37 BOOST_AUTO_TEST_SUITE( filesystem ); // implicit namespace filesystem
38 
39 const std::string& gamedata = game_config::path;
40 
41 BOOST_AUTO_TEST_CASE( test_fs_game_path_reverse_engineering )
42 {
43  const std::string maincfg = "_main.cfg";
44 
45  std::string gamedata_rev = get_wml_location("_main.cfg").value();
46 
47  const std::size_t strip_len = (maincfg + "/data/").length();
48  BOOST_REQUIRE(gamedata_rev.length() > strip_len);
49  gamedata_rev.resize(gamedata_rev.length() - strip_len);
50 
51  BOOST_CHECK_EQUAL( gamedata_rev, gamedata );
52 }
53 
54 BOOST_AUTO_TEST_CASE( test_fs_base )
55 {
56  BOOST_CHECK( is_root("/") );
57  BOOST_CHECK( is_root("////") );
58  BOOST_CHECK( is_root("/../") );
59  BOOST_CHECK( is_root("/../.././") );
60  BOOST_CHECK( is_root("/.././../.") );
61  BOOST_CHECK( is_root("/.") );
62 
63  BOOST_CHECK( is_relative(".") );
64  BOOST_CHECK( is_relative("..") );
65  BOOST_CHECK( is_relative("../foo") );
66  BOOST_CHECK( is_relative("foo") );
67  BOOST_CHECK( !is_relative("/./../foo/..") );
68  BOOST_CHECK( !is_relative("/foo/..") );
69  BOOST_CHECK( !is_relative("/foo") );
70  BOOST_CHECK( !is_relative("///foo") );
71 
72  BOOST_CHECK( is_directory("/") );
73  BOOST_CHECK( is_directory("/.") );
74  BOOST_CHECK( is_directory("/./././.") );
75  BOOST_CHECK( is_directory("/..") );
76 
77  BOOST_CHECK( is_directory(".") );
78  BOOST_CHECK( is_directory("..") );
79  BOOST_CHECK( is_directory("./././.") );
80 
81  BOOST_CHECK( is_directory(gamedata + "/data/core/../../data/././../data/././core") );
82 
83  BOOST_CHECK( file_exists("/") );
84  BOOST_CHECK( file_exists("/.") );
85  BOOST_CHECK( file_exists("/./././.") );
86  BOOST_CHECK( file_exists("/..") );
87 
88  BOOST_CHECK_EQUAL( base_name("foo/bar/baz.cfg"), "baz.cfg" );
89  // FIXME: BFS gives "." for this, Unix basename gives "bar"!
90  //BOOST_CHECK_EQUAL( base_name("foo/bar/"), "bar" );
91  BOOST_CHECK_EQUAL( base_name("foo/bar"), "bar" );
92  BOOST_CHECK_EQUAL( base_name("/"), "/" );
93  BOOST_CHECK_EQUAL( base_name(""), "" );
94 
95  BOOST_CHECK_EQUAL( directory_name("foo/bar/baz.cfg"), "foo/bar" );
96  BOOST_CHECK_EQUAL( directory_name("foo/bar/"), "foo/bar" );
97  BOOST_CHECK_EQUAL( directory_name("foo/bar"), "foo" );
98  BOOST_CHECK_EQUAL( directory_name("/"), "" );
99  BOOST_CHECK_EQUAL( directory_name(""), "" );
100 
101  // TODO normalize_path
102 
103  //BOOST_CHECK_EQUAL( normalize_path(gamedata + "/data/core/../../data/././../data/././core"),
104  // gamedata + "/data/core" );
105 }
106 
107 BOOST_AUTO_TEST_CASE( test_fs_enum )
108 {
109  const std::string path = "data/test/test/filesystem/enum";
110 
111  const std::vector<std::string> expected_filenames {
112  "_initial.cfg",
113  "A1.cfg",
114  "A2.cfg",
115  "A3.cfg",
116  "B1.cfg",
117  "B2.cfg",
118  "B3.cfg",
119  "_final.cfg"};
120  const std::vector<std::string> expected_dirnames {
121  "D1",
122  "D2",
123  "D3"};
124 
125  std::vector<std::string> files, dirs;
126  std::vector<std::string> expected_filepaths, expected_dirpaths;
127 
128  for(const std::string& n : expected_filenames) {
129  expected_filepaths.push_back(gamedata + "/" + path + "/" + n);
130  }
131 
132  for(const std::string& n : expected_dirnames) {
133  expected_dirpaths.push_back(gamedata + "/" + path + "/" + n);
134  }
135 
136  // FIXME: get_files_in_dir with mode == FILE_NAME_ONLY will fail to reorder
137  // entries because the sorting code looks for forward slashes.
138  // This affects both the BFS-based and legacy implementations.
139  get_files_in_dir(path, &files, &dirs, name_mode::ENTIRE_FILE_PATH, filter_mode::NO_FILTER, reorder_mode::DO_REORDER);
140 
141  BOOST_CHECK( files == expected_filepaths );
142  BOOST_CHECK( dirs == expected_dirpaths );
143 }
144 
145 BOOST_AUTO_TEST_CASE( test_fs_binary_path )
146 {
147  config main_config;
148  game_config_view game_config_view_ = game_config_view::wrap(main_config);
150 
151  cache.clear_defines();
152  cache.add_define("EDITOR");
153  cache.add_define("MULTIPLAYER");
154  cache.get_config(game_config::path +"/data", main_config);
155 
156  const filesystem::binary_paths_manager bin_paths_manager(game_config_view_);
157 
158  //load_language_list();
159  game_config::load_config(main_config.mandatory_child("game_config"));
160 
161  BOOST_CHECK_EQUAL( get_binary_dir_location("images", ".").value(), gamedata + "/images/." );
162 
163  BOOST_CHECK_EQUAL( get_binary_file_location("images", "wesnoth-icon.png").value(),
164  gamedata + "/data/core/images/wesnoth-icon.png" );
165 
166  BOOST_CHECK_EQUAL( get_binary_file_location("music", "silence.ogg").value(),
167  gamedata + "/data/core/music/silence.ogg" );
168 
169  BOOST_CHECK_EQUAL( get_binary_file_location("sounds", "explosion.ogg").value(),
170  gamedata + "/data/core/sounds/explosion.ogg" );
171 
172  BOOST_CHECK_EQUAL( get_independent_binary_file_path("images", "wesnoth-icon.png").value(),
173  "data/core/images/wesnoth-icon.png" );
174 
175  // Inexistent paths are resolved empty.
176  BOOST_CHECK( !get_binary_dir_location("images", "").has_value() );
177  BOOST_CHECK( !get_binary_dir_location("inexistent_resource_type", "").has_value() );
178  BOOST_CHECK( !get_binary_file_location("image", "wesnoth-icon.png").has_value() );
179  BOOST_CHECK( !get_binary_file_location("images", "bunnies_and_ponies_and_rainbows_oh_em_gee.psd").has_value() );
180  BOOST_CHECK( !get_binary_file_location("music", "this_track_does_not_exist.aiff").has_value() );
181  BOOST_CHECK( !get_binary_file_location("sounds", "rude_noises.aiff").has_value() );
182  BOOST_CHECK( !get_independent_binary_file_path("images", "dopefish.txt").has_value() );
183 }
184 
185 BOOST_AUTO_TEST_CASE( test_fs_wml_path )
186 {
187  const std::string& userdata = get_user_data_dir();
188 
189  BOOST_CHECK_EQUAL( get_wml_location("").value_or(""), "" );
190 
191  BOOST_CHECK_EQUAL( get_wml_location("_main.cfg").value_or(""), gamedata + "/data/_main.cfg" );
192  BOOST_CHECK_EQUAL( get_wml_location("core/_main.cfg").value_or(""), gamedata + "/data/core/_main.cfg" );
193  BOOST_CHECK_EQUAL( get_wml_location(".", std::string("")).value_or(""), "." );
194 
195  BOOST_CHECK_EQUAL( get_wml_location("~/").value_or(""), userdata + "/data/" );
196 
197  // Inexistent paths are resolved empty.
198  BOOST_CHECK( !get_wml_location("why_would_anyone_ever_name_a_file_like_this").has_value() );
199 }
200 
201 BOOST_AUTO_TEST_CASE( test_fs_search )
202 {
203  const std::string& userdata = get_user_data_dir();
204 
205  BOOST_CHECK_EQUAL( nearest_extant_parent(userdata + "/THIS_DOES_NOT_EXIST/foo/bar"), userdata );
206 
207  BOOST_CHECK_EQUAL( nearest_extant_parent(gamedata + "/THIS_DOES_NOT_EXIST_EITHER/foo"), gamedata );
208  BOOST_CHECK_EQUAL( nearest_extant_parent(gamedata + "/data/_main.cfg"), gamedata + "/data" );
209  BOOST_CHECK_EQUAL( nearest_extant_parent(gamedata + "/data/core/THIS_DOES_NOT_EXIST/test"), gamedata + "/data/core" );
210 
211  BOOST_CHECK_EQUAL( nearest_extant_parent("/THIS_HOPEFULLY_DOES_NOT_EXIST"), "/" );
212  BOOST_CHECK_EQUAL( nearest_extant_parent("/THIS_HOPEFULLY_DOES_NOT_EXIST/foo/bar"), "/" );
213  BOOST_CHECK_EQUAL( nearest_extant_parent("/THIS_HOPEFULLY_DOES_NOT_EXIST/foo/bar/.."), "/" );
214 }
215 
216 BOOST_AUTO_TEST_CASE( test_fs_fluff )
217 {
218  BOOST_CHECK( looks_like_pbl("foo.pbl") );
219  BOOST_CHECK( looks_like_pbl("FOO.PBL") );
220  BOOST_CHECK( looks_like_pbl("Foo.Pbl") );
221  BOOST_CHECK( !looks_like_pbl("foo.pbl.cfg") );
222 
223  BOOST_CHECK( is_gzip_file("foo.gz") );
224  BOOST_CHECK( !is_gzip_file("foo.gz.bz2") );
225  BOOST_CHECK( is_bzip2_file("foo.bz2") );
226  BOOST_CHECK( !is_bzip2_file("foo.bz2.gz") );
227 
228  BOOST_CHECK( is_compressed_file("foo.gz") );
229  BOOST_CHECK( is_compressed_file("foo.bz2") );
230  BOOST_CHECK( !is_compressed_file("foo.txt") );
231 
232  // FIXME: Is this even intended?
233  BOOST_CHECK( !is_gzip_file("foo.GZ") );
234  BOOST_CHECK( !is_bzip2_file("foo.BZ2") );
235  BOOST_CHECK( !is_compressed_file("foo.GZ") );
236  BOOST_CHECK( !is_compressed_file("foo.BZ2") );
237 }
238 
239 BOOST_AUTO_TEST_SUITE_END()
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:172
config & mandatory_child(config_key_type key, int n=0)
Returns the nth child with the given key, or throws an error if there is none.
Definition: config.cpp:366
Singleton class to manage game config file caching.
void add_define(const std::string &define)
Add a entry to preproc defines map.
static config_cache & instance()
Get reference to the singleton object.
void clear_defines()
Clear stored defines map to default values.
void get_config(const std::string &path, config &cfg, abstract_validator *validator=nullptr)
Gets a config object from given path.
A class grating read only view to a vector of config objects, viewed as one config with all children ...
static game_config_view wrap(const config &cfg)
Declarations for File-IO.
Standard logging facilities (interface).
#define PLAIN_LOG
Definition: log.hpp:299
bool is_bzip2_file(const std::string &filename)
Returns true if the file ends with '.bz2'.
bool is_relative(const std::string &path)
Returns whether the path seems to be relative.
bool is_root(const std::string &path)
Returns whether the path is the root of the file hierarchy.
void get_files_in_dir(const std::string &dir, std::vector< std::string > *files, std::vector< std::string > *dirs, name_mode mode, filter_mode filter, reorder_mode reorder, file_tree_checksum *checksum)
Get a list of all files and/or directories in a given directory.
Definition: filesystem.cpp:444
std::string get_user_data_dir()
Definition: filesystem.cpp:827
std::string base_name(const std::string &file, const bool remove_extension)
Returns the base filename of a file, with directory name stripped.
bool is_gzip_file(const std::string &filename)
Returns true if the file ends with '.gz'.
static bool file_exists(const bfs::path &fpath)
Definition: filesystem.cpp:325
bool is_directory(const std::string &fname)
Returns true if the given file is a directory.
utils::optional< std::string > get_wml_location(const std::string &path, const utils::optional< std::string > &current_dir)
Returns a translated path to the actual file or directory, if it exists.
bool is_compressed_file(const std::string &filename)
Definition: filesystem.hpp:292
utils::optional< std::string > get_binary_file_location(const std::string &type, const std::string &filename)
Returns a complete path to the actual file of a given type, if it exists.
std::string directory_name(const std::string &file)
Returns the directory name of a file, with filename stripped.
utils::optional< std::string > get_binary_dir_location(const std::string &type, const std::string &filename)
Returns a complete path to the actual directory of a given type, if it exists.
std::string nearest_extant_parent(const std::string &file)
Finds the nearest parent in existence for a file or directory.
bool looks_like_pbl(const std::string &file)
utils::optional< std::string > get_independent_binary_file_path(const std::string &type, const std::string &filename)
Returns an asset path to filename for binary path-independent use in saved games.
std::string path
Definition: filesystem.cpp:90
void load_config(const config &v)
The paths manager is responsible for recording the various paths that binary files may be located at.
Definition: filesystem.hpp:438
BOOST_AUTO_TEST_SUITE(filesystem)
const std::string & gamedata
BOOST_AUTO_TEST_CASE(test_fs_game_path_reverse_engineering)
static map_location::direction n