1/*
2 * Copyright © 2013 Intel Corporation
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
21 * DEALINGS IN THE SOFTWARE.
22 */
23#include <gtest/gtest.h>
24#include <signal.h>
25#include <setjmp.h>
26
27#include "glxclient.h"
28#include "glx_error.h"
29
30extern bool GetGLXScreenConfigs_called;
31extern struct glx_screen *psc;
32
33struct attribute_test_vector {
34   const char *string;
35   int value;
36};
37
38#define E(x) { # x, x }
39
40
41
42static bool got_sigsegv;
43static jmp_buf jmp;
44
45static void
46sigsegv_handler(int sig)
47{
48   (void) sig;
49   got_sigsegv = true;
50   longjmp(jmp, 1);
51}
52
53static bool query_renderer_string_called = false;
54static bool query_renderer_integer_called = false;
55
56static int
57fake_query_renderer_integer(struct glx_screen *psc, int attribute,
58                            unsigned int *value)
59{
60   (void) psc;
61   (void) attribute;
62   (void) value;
63
64   query_renderer_integer_called = true;
65
66   return -1;
67}
68
69static int
70fake_query_renderer_string(struct glx_screen *psc, int attribute,
71                           const char **value)
72{
73   (void) psc;
74   (void) attribute;
75   (void) value;
76
77   query_renderer_string_called = true;
78
79   return -1;
80}
81
82struct glx_screen_vtable fake_vtable = {
83   NULL,
84   NULL,
85   fake_query_renderer_integer,
86   fake_query_renderer_string
87};
88
89class query_renderer_string_test : public ::testing::Test {
90public:
91   virtual void SetUp();
92   virtual void TearDown();
93
94   struct glx_screen scr;
95   struct sigaction sa;
96   struct sigaction old_sa;
97   Display dpy;
98};
99
100class query_renderer_integer_test : public query_renderer_string_test {
101};
102
103void query_renderer_string_test::SetUp()
104{
105   memset(&scr, 0, sizeof(scr));
106   scr.vtable = &fake_vtable;
107   psc = &scr;
108
109   got_sigsegv = false;
110
111   sa.sa_handler = sigsegv_handler;
112   sigemptyset(&sa.sa_mask);
113   sa.sa_flags = 0;
114   sigaction(SIGSEGV, &sa, &old_sa);
115}
116
117void query_renderer_string_test::TearDown()
118{
119   sigaction(SIGSEGV, &old_sa, NULL);
120}
121
122/**
123 * glXQueryRendererStringMESA will return \c NULL if the query_render_string
124 * vtable entry is \c NULL.  It will also not segfault.
125 */
126TEST_F(query_renderer_string_test, null_query_render_string)
127{
128   struct glx_screen_vtable vtable = {
129      NULL,
130      NULL,
131      NULL,
132      NULL
133   };
134
135   scr.vtable = &vtable;
136
137   if (setjmp(jmp) == 0) {
138      const char *str =
139         glXQueryRendererStringMESA(&dpy, 0, 0, GLX_RENDERER_VENDOR_ID_MESA);
140      EXPECT_EQ((char *)0, str);
141   } else {
142      EXPECT_FALSE(got_sigsegv);
143   }
144}
145
146/**
147 * glXQueryRendererStringMESA will not call the screen query_render_string
148 * function with an invalid GLX enum value, and it will return NULL.
149 */
150TEST_F(query_renderer_string_test, invalid_attribute)
151{
152   static const attribute_test_vector invalid_attributes[] = {
153      /* These values are just plain invalid for use with this extension.
154       */
155      E(0),
156      E(GLX_VENDOR),
157      E(GLX_VERSION),
158      E(GLX_EXTENSIONS),
159      E(GLX_RENDERER_VENDOR_ID_MESA + 0x10000),
160      E(GLX_RENDERER_DEVICE_ID_MESA + 0x10000),
161
162      /* These enums are part of the extension, but they are not allowed for
163       * the string query.
164       */
165      E(GLX_RENDERER_VERSION_MESA),
166      E(GLX_RENDERER_ACCELERATED_MESA),
167      E(GLX_RENDERER_VIDEO_MEMORY_MESA),
168      E(GLX_RENDERER_UNIFIED_MEMORY_ARCHITECTURE_MESA),
169      E(GLX_RENDERER_PREFERRED_PROFILE_MESA),
170      E(GLX_RENDERER_OPENGL_CORE_PROFILE_VERSION_MESA),
171      E(GLX_RENDERER_OPENGL_COMPATIBILITY_PROFILE_VERSION_MESA),
172      E(GLX_RENDERER_OPENGL_ES_PROFILE_VERSION_MESA),
173      E(GLX_RENDERER_OPENGL_ES2_PROFILE_VERSION_MESA),
174   };
175
176   for (unsigned i = 0; i < ARRAY_SIZE(invalid_attributes); i++) {
177      query_renderer_integer_called = false;
178      query_renderer_string_called = false;
179
180      const char *str =
181         glXQueryRendererStringMESA(&dpy, 0, 0, invalid_attributes[i].value);
182      EXPECT_EQ((char *)0, str) << invalid_attributes[i].string;
183      EXPECT_FALSE(query_renderer_integer_called)
184         << invalid_attributes[i].string;
185      EXPECT_FALSE(query_renderer_string_called)
186         << invalid_attributes[i].string;
187   }
188}
189
190/**
191 * glXQueryRendererStringMESA will not call GetGLXScreenConfigs if the display
192 * pointer is \c NULL.  It will also not segfault.
193 */
194TEST_F(query_renderer_string_test, null_display_pointer)
195{
196   if (setjmp(jmp) == 0) {
197      GetGLXScreenConfigs_called = false;
198
199      const char *str =
200         glXQueryRendererStringMESA(NULL, 0, 0, GLX_RENDERER_VENDOR_ID_MESA);
201      EXPECT_EQ((char *)0, str);
202      EXPECT_FALSE(GetGLXScreenConfigs_called);
203   } else {
204      EXPECT_FALSE(got_sigsegv);
205   }
206}
207
208/**
209 * glXQueryRendererStringMESA will return error if GetGLXScreenConfigs returns
210 * NULL.  It will also not segfault.
211 */
212TEST_F(query_renderer_string_test, null_screen_pointer)
213{
214   psc = NULL;
215
216   if (setjmp(jmp) == 0) {
217      GetGLXScreenConfigs_called = false;
218
219      const char *str =
220         glXQueryRendererStringMESA(&dpy, 0, 0, GLX_RENDERER_VENDOR_ID_MESA);
221      EXPECT_EQ((char *)0, str);
222      EXPECT_TRUE(GetGLXScreenConfigs_called);
223   } else {
224      EXPECT_FALSE(got_sigsegv);
225   }
226}
227
228/**
229 * glXQueryRendererStringMESA will not call the screen query_render_string
230 * function if the renderer is invalid, and it will return NULL.
231 */
232TEST_F(query_renderer_string_test, invalid_renderer_index)
233{
234   static const int invalid_renderer_indices[] = {
235      -1,
236      1,
237      999,
238   };
239
240   if (setjmp(jmp) == 0) {
241      for (unsigned i = 0; i < ARRAY_SIZE(invalid_renderer_indices); i++) {
242         const char *str =
243            glXQueryRendererStringMESA(&dpy, 0,
244                                       invalid_renderer_indices[i],
245                                       GLX_RENDERER_VENDOR_ID_MESA);
246         EXPECT_EQ((char *)0, str) << invalid_renderer_indices[i];
247         EXPECT_FALSE(query_renderer_integer_called)
248            << invalid_renderer_indices[i];
249         EXPECT_FALSE(query_renderer_string_called)
250            << invalid_renderer_indices[i];
251      }
252   } else {
253      EXPECT_FALSE(got_sigsegv);
254   }
255}
256
257/**
258 * glXQueryCurrentRendererStringMESA will return error if there is no context
259 * current.  It will also not segfault.
260 */
261TEST_F(query_renderer_string_test, no_current_context)
262{
263   if (setjmp(jmp) == 0) {
264      const char *str =
265         glXQueryCurrentRendererStringMESA(GLX_RENDERER_VENDOR_ID_MESA);
266      EXPECT_EQ((char *)0, str);
267   } else {
268      EXPECT_FALSE(got_sigsegv);
269   }
270}
271
272/**
273 * glXQueryCurrentRendererIntegerMESA will return \c NULL if the
274 * query_render_string vtable entry is \c NULL.  It will also not segfault.
275 */
276TEST_F(query_renderer_integer_test, null_query_render_string)
277{
278   struct glx_screen_vtable vtable = {
279      NULL,
280      NULL,
281      NULL,
282      NULL
283   };
284
285   scr.vtable = &vtable;
286
287   if (setjmp(jmp) == 0) {
288      unsigned value = 0xDEADBEEF;
289      Bool success = glXQueryRendererIntegerMESA(&dpy, 0, 0,
290                                                 GLX_RENDERER_VENDOR_ID_MESA,
291                                                 &value);
292      EXPECT_FALSE(success);
293      EXPECT_EQ(0xDEADBEEF, value);
294   } else {
295      EXPECT_FALSE(got_sigsegv);
296   }
297}
298
299/**
300 * glXQueryCurrentRendererIntegerMESA will not call the screen
301 * query_render_string function with an invalid GLX enum value, and it will
302 * return NULL.
303 */
304TEST_F(query_renderer_integer_test, invalid_attribute)
305{
306   static const attribute_test_vector invalid_attributes[] = {
307      /* These values are just plain invalid for use with this extension.
308       */
309      E(0),
310      E(GLX_VENDOR),
311      E(GLX_VERSION),
312      E(GLX_EXTENSIONS),
313      E(GLX_RENDERER_VENDOR_ID_MESA + 0x10000),
314      E(GLX_RENDERER_DEVICE_ID_MESA + 0x10000),
315      E(GLX_RENDERER_VERSION_MESA + 0x10000),
316      E(GLX_RENDERER_ACCELERATED_MESA + 0x10000),
317      E(GLX_RENDERER_VIDEO_MEMORY_MESA + 0x10000),
318      E(GLX_RENDERER_UNIFIED_MEMORY_ARCHITECTURE_MESA + 0x10000),
319      E(GLX_RENDERER_PREFERRED_PROFILE_MESA + 0x10000),
320      E(GLX_RENDERER_OPENGL_CORE_PROFILE_VERSION_MESA + 0x10000),
321      E(GLX_RENDERER_OPENGL_COMPATIBILITY_PROFILE_VERSION_MESA + 0x10000),
322      E(GLX_RENDERER_OPENGL_ES_PROFILE_VERSION_MESA + 0x10000),
323      E(GLX_RENDERER_OPENGL_ES2_PROFILE_VERSION_MESA + 0x10000),
324   };
325
326   for (unsigned i = 0; i < ARRAY_SIZE(invalid_attributes); i++) {
327      query_renderer_integer_called = false;
328      query_renderer_string_called = false;
329
330      unsigned value = 0xDEADBEEF;
331      Bool success =
332         glXQueryRendererIntegerMESA(&dpy, 0, 0,
333                                     invalid_attributes[i].value,
334                                     &value);
335      EXPECT_FALSE(success) << invalid_attributes[i].string;
336      EXPECT_EQ(0xDEADBEEF, value) << invalid_attributes[i].string;
337      EXPECT_FALSE(query_renderer_integer_called)
338         << invalid_attributes[i].string;
339      EXPECT_FALSE(query_renderer_string_called)
340         << invalid_attributes[i].string;
341   }
342}
343
344/**
345 * glXQueryCurrentRendererIntegerMESA will not call GetGLXScreenConfigs if the
346 * display pointer is \c NULL.  It will also not segfault.
347 */
348TEST_F(query_renderer_integer_test, null_display_pointer)
349{
350   if (setjmp(jmp) == 0) {
351      GetGLXScreenConfigs_called = false;
352
353      unsigned value = 0xDEADBEEF;
354      Bool success =
355         glXQueryRendererIntegerMESA(NULL, 0, 0, GLX_RENDERER_VENDOR_ID_MESA,
356                                     &value);
357      EXPECT_FALSE(success);
358      EXPECT_EQ(0xDEADBEEF, value);
359      EXPECT_FALSE(GetGLXScreenConfigs_called);
360   } else {
361      EXPECT_FALSE(got_sigsegv);
362   }
363}
364
365/**
366 * glXQueryCurrentRendererIntegerMESA will return error if GetGLXScreenConfigs
367 * returns NULL.  It will also not segfault.
368 */
369TEST_F(query_renderer_integer_test, null_screen_pointer)
370{
371   psc = NULL;
372
373   if (setjmp(jmp) == 0) {
374      GetGLXScreenConfigs_called = false;
375
376      unsigned value = 0xDEADBEEF;
377      Bool success =
378         glXQueryRendererIntegerMESA(&dpy, 0, 0, GLX_RENDERER_VENDOR_ID_MESA,
379            &value);
380      EXPECT_FALSE(success);
381      EXPECT_EQ(0xDEADBEEF, value);
382      EXPECT_TRUE(GetGLXScreenConfigs_called);
383   } else {
384      EXPECT_FALSE(got_sigsegv);
385   }
386}
387
388/**
389 * glXQueryRendererIntegerMESA will not call the screen query_render_integer
390 * function if the renderer is invalid, and it will return NULL.
391 */
392TEST_F(query_renderer_integer_test, invalid_renderer_index)
393{
394   static const int invalid_renderer_indices[] = {
395      -1,
396      1,
397      999,
398   };
399
400   if (setjmp(jmp) == 0) {
401      for (unsigned i = 0; i < ARRAY_SIZE(invalid_renderer_indices); i++) {
402         unsigned value = 0xDEADBEEF;
403         Bool success =
404            glXQueryRendererIntegerMESA(&dpy, 0,
405                                        invalid_renderer_indices[i],
406                                        GLX_RENDERER_VENDOR_ID_MESA,
407                                        &value);
408         EXPECT_FALSE(success) << invalid_renderer_indices[i];
409         EXPECT_EQ(0xDEADBEEF, value) << invalid_renderer_indices[i];
410         EXPECT_FALSE(query_renderer_integer_called)
411            << invalid_renderer_indices[i];
412         EXPECT_FALSE(query_renderer_string_called)
413            << invalid_renderer_indices[i];
414      }
415   } else {
416      EXPECT_FALSE(got_sigsegv);
417   }
418}
419
420/**
421 * glXQueryCurrentRendererIntegerMESA will return error if there is no context
422 * current.  It will also not segfault.
423 */
424TEST_F(query_renderer_integer_test, no_current_context)
425{
426   if (setjmp(jmp) == 0) {
427      unsigned value = 0xDEADBEEF;
428      Bool success =
429         glXQueryCurrentRendererIntegerMESA(GLX_RENDERER_VENDOR_ID_MESA,
430                                            &value);
431      EXPECT_FALSE(success);
432      EXPECT_EQ(0xDEADBEEF, value);
433   } else {
434      EXPECT_FALSE(got_sigsegv);
435   }
436}
437