1/*
2 * Copyright © 2020 Google LLC
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#include <driconf.h>
26#include <xmlconfig.h>
27
28class xmlconfig_test : public ::testing::Test {
29protected:
30   xmlconfig_test();
31   ~xmlconfig_test();
32
33   driOptionCache drirc_init(const char *driver, const char *drm,
34                             const char *exec_name,
35                             const char *app, int appver,
36                             const char *engine, int enginever);
37
38   driOptionCache options;
39};
40
41xmlconfig_test::xmlconfig_test()
42{
43   /* Unset variables from the envrionment to prevent user settings from
44    * impacting the tests.
45    */
46   unsetenv("glsl_zero_init");
47   unsetenv("always_have_depth_buffer");
48   unsetenv("opt");
49   unsetenv("vblank_mode");
50   unsetenv("not_present");
51   unsetenv("mesa_b_option");
52   unsetenv("mesa_s_option");
53   unsetenv("mest_test_unknown_option");
54   unsetenv("mest_drirc_option");
55
56   options = {};
57}
58
59xmlconfig_test::~xmlconfig_test()
60{
61   driDestroyOptionInfo(&options);
62}
63
64/* wraps a DRI_CONF_OPT_* in the required xml bits */
65#define DRI_CONF_TEST_OPT(x) x
66
67TEST_F(xmlconfig_test, bools)
68{
69   driOptionDescription driconf[] = {
70      DRI_CONF_SECTION_MISCELLANEOUS
71      DRI_CONF_GLSL_ZERO_INIT(false)
72      DRI_CONF_ALWAYS_HAVE_DEPTH_BUFFER(true)
73   };
74   driParseOptionInfo(&options, driconf, ARRAY_SIZE(driconf));
75
76   EXPECT_EQ(driQueryOptionb(&options, "glsl_zero_init"), false);
77   EXPECT_EQ(driQueryOptionb(&options, "always_have_depth_buffer"), true);
78}
79
80TEST_F(xmlconfig_test, ints)
81{
82   driOptionDescription driconf[] = {
83      DRI_CONF_SECTION_MISCELLANEOUS
84      DRI_CONF_OPT_I(opt, 2, 0, 999, "option")
85   };
86   driParseOptionInfo(&options, driconf, ARRAY_SIZE(driconf));
87
88   EXPECT_EQ(driQueryOptioni(&options, "opt"), 2);
89}
90
91TEST_F(xmlconfig_test, floats)
92{
93   driOptionDescription driconf[] = {
94      DRI_CONF_SECTION_MISCELLANEOUS
95      DRI_CONF_OPT_F(opt, 2.0, 1.0, 2.0, "option")
96   };
97   driParseOptionInfo(&options, driconf, ARRAY_SIZE(driconf));
98
99   EXPECT_EQ(driQueryOptionf(&options, "opt"), 2.0);
100}
101
102TEST_F(xmlconfig_test, enums)
103{
104   driOptionDescription driconf[] = {
105      DRI_CONF_SECTION_MISCELLANEOUS
106      DRI_CONF_VBLANK_MODE(DRI_CONF_VBLANK_DEF_INTERVAL_1)
107   };
108   driParseOptionInfo(&options, driconf, ARRAY_SIZE(driconf));
109
110   EXPECT_EQ(driQueryOptioni(&options, "vblank_mode"), DRI_CONF_VBLANK_DEF_INTERVAL_1);
111}
112
113TEST_F(xmlconfig_test, enums_from_env)
114{
115   driOptionDescription driconf[] = {
116      DRI_CONF_SECTION_MISCELLANEOUS
117      DRI_CONF_VBLANK_MODE(DRI_CONF_VBLANK_DEF_INTERVAL_1)
118   };
119
120   setenv("vblank_mode", "0", 1);
121   driParseOptionInfo(&options, driconf, ARRAY_SIZE(driconf));
122
123   EXPECT_EQ(0, driQueryOptioni(&options, "vblank_mode"));
124}
125
126TEST_F(xmlconfig_test, string)
127{
128   driOptionDescription driconf[] = {
129      DRI_CONF_SECTION_MISCELLANEOUS
130      DRI_CONF_OPT_S(opt, value, "option")
131   };
132   driParseOptionInfo(&options, driconf, ARRAY_SIZE(driconf));
133
134   EXPECT_STREQ(driQueryOptionstr(&options, "opt"), "value");
135}
136
137TEST_F(xmlconfig_test, check_option)
138{
139   driOptionDescription driconf[] = {
140      DRI_CONF_SECTION_MISCELLANEOUS
141      DRI_CONF_GLSL_ZERO_INIT(true)
142      DRI_CONF_ALWAYS_HAVE_DEPTH_BUFFER(true)
143   };
144   driParseOptionInfo(&options, driconf, ARRAY_SIZE(driconf));
145
146   EXPECT_EQ(driCheckOption(&options, "glsl_zero_init", DRI_BOOL), true);
147
148   EXPECT_EQ(driCheckOption(&options, "glsl_zero_init", DRI_ENUM), false);
149   EXPECT_EQ(driCheckOption(&options, "glsl_zero_init", DRI_INT), false);
150   EXPECT_EQ(driCheckOption(&options, "glsl_zero_init", DRI_FLOAT), false);
151   EXPECT_EQ(driCheckOption(&options, "glsl_zero_init", DRI_STRING), false);
152
153   EXPECT_EQ(driCheckOption(&options, "not_present", DRI_BOOL), false);
154}
155
156TEST_F(xmlconfig_test, copy_cache)
157{
158   driOptionDescription driconf[] = {
159      DRI_CONF_SECTION_MISCELLANEOUS
160      DRI_CONF_OPT_B(mesa_b_option, true, "description")
161      DRI_CONF_OPT_S(mesa_s_option, value, "description")
162   };
163   driParseOptionInfo(&options, driconf, ARRAY_SIZE(driconf));
164
165   driOptionCache cache;
166
167   /* This tries to parse user config files.  We've called our option
168    * "mesa_test_option" so the test shouldn't end up with something from the
169    * user's homedir/environment that would override us.
170    */
171   driParseConfigFiles(&cache, &options,
172                       0, "driver", "drm", NULL,
173                       NULL, 0,
174                       NULL, 0);
175
176   /* Can we inspect the cache? */
177   EXPECT_EQ(driCheckOption(&cache, "mesa_b_option", DRI_BOOL), true);
178   EXPECT_EQ(driCheckOption(&cache, "mesa_s_option", DRI_STRING), true);
179   EXPECT_EQ(driCheckOption(&cache, "mesa_test_unknown_option", DRI_BOOL), false);
180
181   /* Did the value get copied? */
182   EXPECT_EQ(driQueryOptionb(&cache, "mesa_b_option"), true);
183   EXPECT_STREQ(driQueryOptionstr(&cache, "mesa_s_option"), "value");
184
185   driDestroyOptionCache(&cache);
186}
187
188driOptionCache
189xmlconfig_test::drirc_init(const char *driver, const char *drm,
190                           const char *exec_name,
191                           const char *app, int appver,
192                           const char *engine, int enginever)
193{
194   /* Make the parser look in the directory of config files for the test,
195    * passed in by meson.build.
196    */
197   driInjectDataDir(getenv("DRIRC_CONFIGDIR"));
198
199   driInjectExecName(exec_name);
200
201   driOptionDescription driconf[] = {
202      DRI_CONF_SECTION_MISCELLANEOUS
203      DRI_CONF_OPT_I(mesa_drirc_option, 0, 0, 200, "description")
204   };
205   driParseOptionInfo(&options, driconf, ARRAY_SIZE(driconf));
206
207   driOptionCache cache;
208
209   /* This should parse the "user" drirc files under ./tests/drirc_test/,
210    * based on the setting of $HOME by meson.build.
211    */
212   driParseConfigFiles(&cache, &options,
213                       0, driver, drm, NULL,
214                       app, appver,
215                       engine, enginever);
216
217   return cache;
218}
219
220TEST_F(xmlconfig_test, drirc_app)
221{
222   driOptionCache cache = drirc_init("driver", "drm",
223                                     "app1",
224                                     NULL, 0,
225                                     NULL, 0);
226#if WITH_XMLCONFIG
227   EXPECT_EQ(driQueryOptioni(&cache, "mesa_drirc_option"), 1);
228#else
229   EXPECT_EQ(driQueryOptioni(&cache, "mesa_drirc_option"), 0);
230#endif
231   driDestroyOptionCache(&cache);
232}
233
234TEST_F(xmlconfig_test, drirc_user_app)
235{
236   driOptionCache cache = drirc_init("driver", "drm",
237                                     "app3",
238                                     NULL, 0,
239                                     NULL, 0);
240#if WITH_XMLCONFIG
241   EXPECT_EQ(driQueryOptioni(&cache, "mesa_drirc_option"), 10);
242#else
243   EXPECT_EQ(driQueryOptioni(&cache, "mesa_drirc_option"), 0);
244#endif
245   driDestroyOptionCache(&cache);
246}
247
248TEST_F(xmlconfig_test, drirc_env_override)
249{
250   setenv("mesa_drirc_option", "7", 1);
251   driOptionCache cache = drirc_init("driver", "drm",
252                                     "app1",
253                                     NULL, 0,
254                                     NULL, 0);
255   /* env var takes precedence over config files */
256   EXPECT_EQ(driQueryOptioni(&cache, "mesa_drirc_option"), 7);
257   unsetenv("mesa_drirc_option");
258   driDestroyOptionCache(&cache);
259}
260
261#if WITH_XMLCONFIG
262TEST_F(xmlconfig_test, drirc_app_versioned)
263{
264   driOptionCache cache = drirc_init("driver", "drm",
265                                     NULL,
266                                     "Versioned App Name", 1,
267                                     NULL, 0);
268   EXPECT_EQ(driQueryOptioni(&cache, "mesa_drirc_option"), 3);
269   driDestroyOptionCache(&cache);
270}
271
272TEST_F(xmlconfig_test, drirc_engine_versioned)
273{
274   driOptionCache cache = drirc_init("driver", "drm",
275                                     NULL,
276                                     "unknownapp", 0,
277                                     "Versioned Engine Name", 1);
278   EXPECT_EQ(driQueryOptioni(&cache, "mesa_drirc_option"), 5);
279   driDestroyOptionCache(&cache);
280}
281
282TEST_F(xmlconfig_test, drirc_exec_regexp)
283{
284   driOptionCache cache = drirc_init("driver", "drm",
285                                     "app2v4",
286                                     NULL, 0,
287                                     NULL, 0);
288   EXPECT_EQ(driQueryOptioni(&cache, "mesa_drirc_option"), 7);
289   driDestroyOptionCache(&cache);
290}
291#endif
292