1 /*
2 * Copyright © 2022 Yonggang Luo
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24 #include <gtest/gtest.h>
25
26 #include "util/memstream.h"
27 #include "util/u_memory.h"
28 #include "util/u_printf.h"
29
30 class u_printf_test : public ::testing::Test
31 {
32 private:
33 template<typename T>
add_to_buffer(const T & t)34 void add_to_buffer(const T& t)
35 {
36 const uint8_t *data = reinterpret_cast<const uint8_t*>(&t);
37 buffer.insert(buffer.end(), data, data + sizeof(t));
38 }
39
40 protected:
41 char *out_buffer = nullptr;
42 size_t buffer_size = 0;
43
44 struct format {
45 std::vector<char> fmt;
46 std::vector<unsigned> args;
47 };
48
49 std::vector<format> formats;
50 std::vector<char> buffer;
51 unsigned last_format;
52
SetUp()53 virtual void SetUp()
54 {
55 }
56
TearDown()57 virtual void TearDown()
58 {
59 if (out_buffer != NULL) {
60 free(out_buffer);
61 }
62 }
63
add_format(const char * string,std::vector<unsigned> arg_sizes)64 void add_format(const char *string, std::vector<unsigned> arg_sizes)
65 {
66 format fmt;
67 fmt.fmt = std::vector<char>(string, string + strlen(string) + 1);
68 fmt.args = arg_sizes;
69 formats.push_back(fmt);
70 }
71
use_format(uint32_t idx)72 void use_format(uint32_t idx)
73 {
74 last_format = idx;
75 idx += 1;
76 add_to_buffer(idx);
77 }
78
add_arg(const char * str)79 void add_arg(const char *str)
80 {
81 format &fmt = formats[last_format];
82 uint64_t pos = fmt.fmt.size();
83
84 fmt.fmt.insert(fmt.fmt.end(), str, str + strlen(str) + 1);
85
86 add_to_buffer(pos);
87 }
88
89 template<typename T>
add_arg(typename std::enable_if<std::is_scalar<T>::value,T>::type t)90 void add_arg(typename std::enable_if<std::is_scalar<T>::value, T>::type t)
91 {
92 add_to_buffer(t);
93 }
94
95 template<typename T, size_t N>
add_arg(const T (& t)[N])96 void add_arg(const T (&t)[N])
97 {
98 for (unsigned i = 0; i < N; i++)
99 add_to_buffer(t[i]);
100 }
101
parse()102 std::string parse()
103 {
104 u_memstream stream;
105 FILE* out;
106 u_memstream_open(&stream, &out_buffer, &buffer_size);
107 out = u_memstream_get(&stream);
108 std::vector<u_printf_info> infos;
109
110 for (auto& format : formats) {
111 u_printf_info info;
112 info.num_args = static_cast<unsigned>(format.args.size());
113 info.arg_sizes = format.args.data();
114 info.string_size = format.fmt.size();
115 info.strings = const_cast<char*>(format.fmt.data());
116 infos.push_back(info);
117 }
118
119 u_printf(out, buffer.data(), buffer.size(), infos.data(), infos.size());
120 u_memstream_close(&stream);
121
122 return out_buffer;
123 }
124 };
125
TEST_F(u_printf_test,util_printf_next_spec_pos)126 TEST_F(u_printf_test, util_printf_next_spec_pos)
127 {
128 EXPECT_EQ(util_printf_next_spec_pos("%d%d", 0), 1);
129 EXPECT_EQ(util_printf_next_spec_pos("%%d", 0), -1);
130 EXPECT_EQ(util_printf_next_spec_pos("%dd", 0), 1);
131 EXPECT_EQ(util_printf_next_spec_pos("%%%%%%", 0), -1);
132 EXPECT_EQ(util_printf_next_spec_pos("%%%%%%%d", 0), 7);
133 EXPECT_EQ(util_printf_next_spec_pos("abcdef%d", 0), 7);
134 EXPECT_EQ(util_printf_next_spec_pos("abcdef%d", 6), 7);
135 EXPECT_EQ(util_printf_next_spec_pos("abcdef%d", 7), -1);
136 EXPECT_EQ(util_printf_next_spec_pos("abcdef%%", 7), -1);
137 EXPECT_EQ(util_printf_next_spec_pos("abcdef%d%d", 0), 7);
138 EXPECT_EQ(util_printf_next_spec_pos("%rrrrr%d%d", 0), 7);
139 EXPECT_EQ(util_printf_next_spec_pos("%%rrrr%d%d", 0), 7);
140 }
141
TEST_F(u_printf_test,util_printf_simple)142 TEST_F(u_printf_test, util_printf_simple)
143 {
144 add_format("Hello", { });
145 use_format(0);
146 EXPECT_EQ(parse(), "Hello");
147 }
148
TEST_F(u_printf_test,util_printf_single_string)149 TEST_F(u_printf_test, util_printf_single_string)
150 {
151 add_format("%s\n", { 8 });
152
153 use_format(0);
154 add_arg("Hello");
155
156 EXPECT_EQ(parse(), "Hello\n");
157 }
158
TEST_F(u_printf_test,util_printf_multiple_string)159 TEST_F(u_printf_test, util_printf_multiple_string)
160 {
161 add_format("foo %s bar\n", { 8 });
162 add_format("%s[%s]: %s\n", { 8, 8, 8 });
163 add_format("!!! %s !!!", { 8 });
164
165 use_format(2);
166 add_arg("ERROR");
167
168 use_format(0);
169 add_arg("OpenCL\n");
170
171 use_format(1);
172 add_arg("mesa");
173 add_arg("12345");
174 add_arg("error");
175
176 use_format(0);
177 add_arg("ABCDE\n");
178
179 EXPECT_EQ(parse(), "!!! ERROR !!!foo OpenCL\n bar\nmesa[12345]: error\nfoo ABCDE\n bar\n");
180 }
181
TEST_F(u_printf_test,util_printf_mixed)182 TEST_F(u_printf_test, util_printf_mixed)
183 {
184 add_format("LOG[%s] %u + %u = %u", { 8, 4, 4, 4 });
185
186 use_format(0);
187 add_arg("DEBUG");
188 add_arg<uint32_t>(5);
189 add_arg<uint32_t>(8);
190 add_arg<uint32_t>(13);
191
192 EXPECT_EQ(parse(), "LOG[DEBUG] 5 + 8 = 13");
193 }
194
TEST_F(u_printf_test,util_printf_mixed_multiple)195 TEST_F(u_printf_test, util_printf_mixed_multiple)
196 {
197 add_format("%%%%%s %u %f %.1v4hlf ", { 8, 4, 4, 16 });
198 add_format("%i %u\n", { 4, 4 });
199 add_format("ABCED\n", {});
200 add_format("foo %hx bar\n", { 2 });
201
202 use_format(2);
203
204 use_format(1);
205 add_arg<int32_t>(-5);
206 add_arg<uint32_t>(6);
207
208 float floats[4] = {
209 1.0,
210 2.0,
211 3.0,
212 4.0
213 };
214 use_format(0);
215 add_arg("mesa");
216 add_arg<uint32_t>(10);
217 add_arg<float>(3.0);
218 add_arg<float, 4>(floats);
219
220 EXPECT_EQ(parse(), "ABCED\n-5 6\n%%%%mesa 10 3.000000 1.0,2.0,3.0,4.0 ");
221 }
222