• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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