1/*
2 * This content is released under the MIT License as specified in https://raw.githubusercontent.com/gabime/spdlog/master/LICENSE
3 */
4#include "includes.h"
5
6#define TEST_FILENAME "test_logs/file_helper_test.txt"
7
8using spdlog::details::file_helper;
9
10static void write_with_helper(file_helper &helper, size_t howmany)
11{
12 spdlog::memory_buf_t formatted;
13 spdlog::fmt_lib::format_to(std::back_inserter(formatted), "{}", std::string(howmany, '1'));
14 helper.write(formatted);
15 helper.flush();
16}
17
18TEST_CASE("file_helper_filename", "[file_helper::filename()]]")
19{
20 prepare_logdir();
21
22 file_helper helper;
23 spdlog::filename_t target_filename = SPDLOG_FILENAME_T(TEST_FILENAME);
24 helper.open(target_filename);
25 REQUIRE(helper.filename() == target_filename);
26}
27
28TEST_CASE("file_helper_size", "[file_helper::size()]]")
29{
30 prepare_logdir();
31 spdlog::filename_t target_filename = SPDLOG_FILENAME_T(TEST_FILENAME);
32 size_t expected_size = 123;
33 {
34 file_helper helper;
35 helper.open(target_filename);
36 write_with_helper(helper, expected_size);
37 REQUIRE(static_cast<size_t>(helper.size()) == expected_size);
38 }
39 REQUIRE(get_filesize(TEST_FILENAME) == expected_size);
40}
41
42TEST_CASE("file_helper_reopen", "[file_helper::reopen()]]")
43{
44 prepare_logdir();
45 spdlog::filename_t target_filename = SPDLOG_FILENAME_T(TEST_FILENAME);
46 file_helper helper;
47 helper.open(target_filename);
48 write_with_helper(helper, 12);
49 REQUIRE(helper.size() == 12);
50 helper.reopen(true);
51 REQUIRE(helper.size() == 0);
52}
53
54TEST_CASE("file_helper_reopen2", "[file_helper::reopen(false)]]")
55{
56 prepare_logdir();
57 spdlog::filename_t target_filename = SPDLOG_FILENAME_T(TEST_FILENAME);
58 size_t expected_size = 14;
59 file_helper helper;
60 helper.open(target_filename);
61 write_with_helper(helper, expected_size);
62 REQUIRE(helper.size() == expected_size);
63 helper.reopen(false);
64 REQUIRE(helper.size() == expected_size);
65}
66
67static void test_split_ext(const spdlog::filename_t::value_type *fname, const spdlog::filename_t::value_type *expect_base,
68 const spdlog::filename_t::value_type *expect_ext)
69{
70 spdlog::filename_t filename(fname);
71 spdlog::filename_t expected_base(expect_base);
72 spdlog::filename_t expected_ext(expect_ext);
73
74 spdlog::filename_t basename;
75 spdlog::filename_t ext;
76 std::tie(basename, ext) = file_helper::split_by_extension(filename);
77 REQUIRE(basename == expected_base);
78 REQUIRE(ext == expected_ext);
79}
80
81TEST_CASE("file_helper_split_by_extension", "[file_helper::split_by_extension()]]")
82{
83 test_split_ext(SPDLOG_FILENAME_T("mylog.txt"), SPDLOG_FILENAME_T("mylog"), SPDLOG_FILENAME_T(".txt"));
84 test_split_ext(SPDLOG_FILENAME_T(".mylog.txt"), SPDLOG_FILENAME_T(".mylog"), SPDLOG_FILENAME_T(".txt"));
85 test_split_ext(SPDLOG_FILENAME_T(".mylog"), SPDLOG_FILENAME_T(".mylog"), SPDLOG_FILENAME_T(""));
86 test_split_ext(SPDLOG_FILENAME_T("/aaa/bb.d/mylog"), SPDLOG_FILENAME_T("/aaa/bb.d/mylog"), SPDLOG_FILENAME_T(""));
87 test_split_ext(SPDLOG_FILENAME_T("/aaa/bb.d/mylog.txt"), SPDLOG_FILENAME_T("/aaa/bb.d/mylog"), SPDLOG_FILENAME_T(".txt"));
88 test_split_ext(SPDLOG_FILENAME_T("aaa/bbb/ccc/mylog.txt"), SPDLOG_FILENAME_T("aaa/bbb/ccc/mylog"), SPDLOG_FILENAME_T(".txt"));
89 test_split_ext(SPDLOG_FILENAME_T("aaa/bbb/ccc/mylog."), SPDLOG_FILENAME_T("aaa/bbb/ccc/mylog."), SPDLOG_FILENAME_T(""));
90 test_split_ext(SPDLOG_FILENAME_T("aaa/bbb/ccc/.mylog.txt"), SPDLOG_FILENAME_T("aaa/bbb/ccc/.mylog"), SPDLOG_FILENAME_T(".txt"));
91 test_split_ext(SPDLOG_FILENAME_T("/aaa/bbb/ccc/mylog.txt"), SPDLOG_FILENAME_T("/aaa/bbb/ccc/mylog"), SPDLOG_FILENAME_T(".txt"));
92 test_split_ext(SPDLOG_FILENAME_T("/aaa/bbb/ccc/.mylog"), SPDLOG_FILENAME_T("/aaa/bbb/ccc/.mylog"), SPDLOG_FILENAME_T(""));
93 test_split_ext(SPDLOG_FILENAME_T("../mylog.txt"), SPDLOG_FILENAME_T("../mylog"), SPDLOG_FILENAME_T(".txt"));
94 test_split_ext(SPDLOG_FILENAME_T(".././mylog.txt"), SPDLOG_FILENAME_T(".././mylog"), SPDLOG_FILENAME_T(".txt"));
95 test_split_ext(SPDLOG_FILENAME_T(".././mylog.txt/xxx"), SPDLOG_FILENAME_T(".././mylog.txt/xxx"), SPDLOG_FILENAME_T(""));
96 test_split_ext(SPDLOG_FILENAME_T("/mylog.txt"), SPDLOG_FILENAME_T("/mylog"), SPDLOG_FILENAME_T(".txt"));
97 test_split_ext(SPDLOG_FILENAME_T("//mylog.txt"), SPDLOG_FILENAME_T("//mylog"), SPDLOG_FILENAME_T(".txt"));
98 test_split_ext(SPDLOG_FILENAME_T(""), SPDLOG_FILENAME_T(""), SPDLOG_FILENAME_T(""));
99 test_split_ext(SPDLOG_FILENAME_T("."), SPDLOG_FILENAME_T("."), SPDLOG_FILENAME_T(""));
100 test_split_ext(SPDLOG_FILENAME_T("..txt"), SPDLOG_FILENAME_T("."), SPDLOG_FILENAME_T(".txt"));
101}
102
103TEST_CASE("file_event_handlers", "[file_helper]")
104{
105 enum class flags
106 {
107 before_open,
108 after_open,
109 before_close,
110 after_close
111 };
112 prepare_logdir();
113
114 spdlog::filename_t test_filename = SPDLOG_FILENAME_T(TEST_FILENAME);
115 // define event handles that update vector of flags when called
116 std::vector<flags> events;
117 spdlog::file_event_handlers handlers;
118 handlers.before_open = [&](spdlog::filename_t filename) {
119 REQUIRE(filename == test_filename);
120 events.push_back(flags::before_open);
121 };
122 handlers.after_open = [&](spdlog::filename_t filename, std::FILE *fstream) {
123 REQUIRE(filename == test_filename);
124 REQUIRE(fstream);
125 fputs("after_open\n", fstream);
126 events.push_back(flags::after_open);
127 };
128 handlers.before_close = [&](spdlog::filename_t filename, std::FILE *fstream) {
129 REQUIRE(filename == test_filename);
130 REQUIRE(fstream);
131 fputs("before_close\n", fstream);
132 events.push_back(flags::before_close);
133 };
134 handlers.after_close = [&](spdlog::filename_t filename) {
135 REQUIRE(filename == test_filename);
136 events.push_back(flags::after_close);
137 };
138 {
139 spdlog::details::file_helper helper{handlers};
140 REQUIRE(events.empty());
141
142 helper.open(test_filename);
143 REQUIRE(events == std::vector<flags>{flags::before_open, flags::after_open});
144
145 events.clear();
146 helper.close();
147 REQUIRE(events == std::vector<flags>{flags::before_close, flags::after_close});
148 REQUIRE(file_contents(TEST_FILENAME) == "after_open\nbefore_close\n");
149
150 helper.reopen(true);
151 events.clear();
152 }
153 // make sure that the file_helper destrcutor calls the close callbacks if needed
154 REQUIRE(events == std::vector<flags>{flags::before_close, flags::after_close});
155 REQUIRE(file_contents(TEST_FILENAME) == "after_open\nbefore_close\n");
156}
157
158TEST_CASE("file_helper_open", "[file_helper]")
159{
160 prepare_logdir();
161 spdlog::filename_t target_filename = SPDLOG_FILENAME_T(TEST_FILENAME);
162 file_helper helper;
163 helper.open(target_filename);
164 helper.close();
165
166 target_filename += SPDLOG_FILENAME_T("/invalid");
167 REQUIRE_THROWS_AS(helper.open(target_filename), spdlog::spdlog_ex);
168}
169