File: test_log_to_file.cpp

package info (click to toggle)
boost1.90 1.90.0-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 593,120 kB
  • sloc: cpp: 4,190,908; xml: 196,648; python: 34,618; ansic: 23,145; asm: 5,468; sh: 3,774; makefile: 1,161; perl: 1,020; sql: 728; ruby: 676; yacc: 478; java: 77; lisp: 24; csh: 6
file content (123 lines) | stat: -rw-r--r-- 3,327 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
//
// Copyright (c) 2025 Marcelo Zimbres Silva (mzimbres@gmail.com),
// Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//

#include <boost/redis/impl/log_to_file.hpp>

#include <boost/core/lightweight_test.hpp>

#include <cstddef>
#include <cstdio>
#include <limits>
#include <memory>
#include <string>
#include <string_view>

using namespace boost::redis;

namespace {

// RAII helpers for working with C FILE*
struct file_deleter {
   void operator()(FILE* f) const { std::fclose(f); }
};
using unique_file = std::unique_ptr<FILE, file_deleter>;

unique_file create_temporary()
{
   unique_file f{std::tmpfile()};
   if (!BOOST_TEST_NE(f.get(), nullptr))
      exit(1);
   return f;
}

std::string get_file_contents(FILE* f)
{
   if (!BOOST_TEST_EQ(std::fseek(f, 0, SEEK_END), 0))
      exit(1);
   long fsize = std::ftell(f);
   if (!BOOST_TEST_GE(fsize, 0))
      exit(1);
   std::rewind(f);
   std::string res(fsize, 0);
   if (!BOOST_TEST_EQ(std::fread(res.data(), 1u, res.size(), f), fsize))
      exit(1);
   return res;
}

void test_regular()
{
   auto f = create_temporary();
   detail::log_to_file(f.get(), "something happened");
   BOOST_TEST_EQ(get_file_contents(f.get()), "(Boost.Redis) something happened\n");
}

void test_empty_message()
{
   auto f = create_temporary();
   detail::log_to_file(f.get(), {});
   BOOST_TEST_EQ(get_file_contents(f.get()), "(Boost.Redis) \n");
}

void test_empty_prefix()
{
   auto f = create_temporary();
   detail::log_to_file(f.get(), {}, "");
   BOOST_TEST_EQ(get_file_contents(f.get()), "\n");
}

void test_message_not_null_terminated()
{
   constexpr std::string_view str = "some_string";
   auto f = create_temporary();
   detail::log_to_file(f.get(), str.substr(0, 4));
   BOOST_TEST_EQ(get_file_contents(f.get()), "(Boost.Redis) some\n");
}

// NULL bytes don't cause UB. None of our messages have
// them, so this is an edge case
void test_message_null_bytes()
{
   char buff[] = {'a', 'b', 'c', 0, 'l', 0};
   auto f = create_temporary();
   detail::log_to_file(f.get(), std::string_view(buff, sizeof(buff)));
   BOOST_TEST_EQ(get_file_contents(f.get()), "(Boost.Redis) abc\n");
}

// Internally, sizes are converted to int because of C APIs. Check that this
// does not cause trouble. We impose a sanity limit of 0xffff bytes for all messages
void test_message_very_long()
{
   // Setup. Allocating a string of size INT_MAX causes trouble, so we pass a string_view
   // with that size, but with only the first 0xffff bytes being valid
   std::string msg(0xffffu + 1u, 'a');
   const auto msg_size = static_cast<std::size_t>((std::numeric_limits<int>::max)()) + 1u;
   auto f = create_temporary();

   // Log
   detail::log_to_file(f.get(), std::string_view(msg.data(), msg_size));

   // Check
   std::string expected = "(Boost.Redis) ";
   expected += std::string_view(msg.data(), 0xffffu);
   expected += '\n';
   BOOST_TEST_EQ(get_file_contents(f.get()), expected);
}

}  // namespace

int main()
{
   test_regular();
   test_empty_message();
   test_empty_prefix();
   test_message_not_null_terminated();
   test_message_null_bytes();
   test_message_very_long();

   return boost::report_errors();
}