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      E(GLX_RENDERER_ID_MESA),
175   };
176
177   for (unsigned i = 0; i < ARRAY_SIZE(invalid_attributes); i++) {
178      query_renderer_integer_called = false;
179      query_renderer_string_called = false;
180
181      const char *str =
182         glXQueryRendererStringMESA(&dpy, 0, 0, invalid_attributes[i].value);
183      EXPECT_EQ((char *)0, str) << invalid_attributes[i].string;
184      EXPECT_FALSE(query_renderer_integer_called)
185         << invalid_attributes[i].string;
186      EXPECT_FALSE(query_renderer_string_called)
187         << invalid_attributes[i].string;
188   }
189}
190
191/**
192 * glXQueryRendererStringMESA will not call GetGLXScreenConfigs if the display
193 * pointer is \c NULL.  It will also not segfault.
194 */
195TEST_F(query_renderer_string_test, null_display_pointer)
196{
197   if (setjmp(jmp) == 0) {
198      GetGLXScreenConfigs_called = false;
199
200      const char *str =
201         glXQueryRendererStringMESA(NULL, 0, 0, GLX_RENDERER_VENDOR_ID_MESA);
202      EXPECT_EQ((char *)0, str);
203      EXPECT_FALSE(GetGLXScreenConfigs_called);
204   } else {
205      EXPECT_FALSE(got_sigsegv);
206   }
207}
208
209/**
210 * glXQueryRendererStringMESA will return error if GetGLXScreenConfigs returns
211 * NULL.  It will also not segfault.
212 */
213TEST_F(query_renderer_string_test, null_screen_pointer)
214{
215   psc = NULL;
216
217   if (setjmp(jmp) == 0) {
218      GetGLXScreenConfigs_called = false;
219
220      const char *str =
221         glXQueryRendererStringMESA(&dpy, 0, 0, GLX_RENDERER_VENDOR_ID_MESA);
222      EXPECT_EQ((char *)0, str);
223      EXPECT_TRUE(GetGLXScreenConfigs_called);
224   } else {
225      EXPECT_FALSE(got_sigsegv);
226   }
227}
228
229/**
230 * glXQueryRendererStringMESA will not call the screen query_render_string
231 * function if the renderer is invalid, and it will return NULL.
232 */
233TEST_F(query_renderer_string_test, invalid_renderer_index)
234{
235   static const int invalid_renderer_indices[] = {
236      -1,
237      1,
238      999,
239   };
240
241   if (setjmp(jmp) == 0) {
242      for (unsigned i = 0; i < ARRAY_SIZE(invalid_renderer_indices); i++) {
243         const char *str =
244            glXQueryRendererStringMESA(&dpy, 0,
245                                       invalid_renderer_indices[i],
246                                       GLX_RENDERER_VENDOR_ID_MESA);
247         EXPECT_EQ((char *)0, str) << invalid_renderer_indices[i];
248         EXPECT_FALSE(query_renderer_integer_called)
249            << invalid_renderer_indices[i];
250         EXPECT_FALSE(query_renderer_string_called)
251            << invalid_renderer_indices[i];
252      }
253   } else {
254      EXPECT_FALSE(got_sigsegv);
255   }
256}
257
258/**
259 * glXQueryCurrentRendererStringMESA will return error if there is no context
260 * current.  It will also not segfault.
261 */
262TEST_F(query_renderer_string_test, no_current_context)
263{
264   if (setjmp(jmp) == 0) {
265      const char *str =
266         glXQueryCurrentRendererStringMESA(GLX_RENDERER_VENDOR_ID_MESA);
267      EXPECT_EQ((char *)0, str);
268   } else {
269      EXPECT_FALSE(got_sigsegv);
270   }
271}
272
273/**
274 * glXQueryCurrentRendererIntegerMESA will return \c NULL if the
275 * query_render_string vtable entry is \c NULL.  It will also not segfault.
276 */
277TEST_F(query_renderer_integer_test, null_query_render_string)
278{
279   struct glx_screen_vtable vtable = {
280      NULL,
281      NULL,
282      NULL,
283      NULL
284   };
285
286   scr.vtable = &vtable;
287
288   if (setjmp(jmp) == 0) {
289      unsigned value = 0xDEADBEEF;
290      Bool success = glXQueryRendererIntegerMESA(&dpy, 0, 0,
291                                                 GLX_RENDERER_VENDOR_ID_MESA,
292                                                 &value);
293      EXPECT_FALSE(success);
294      EXPECT_EQ(0xDEADBEEF, value);
295   } else {
296      EXPECT_FALSE(got_sigsegv);
297   }
298}
299
300/**
301 * glXQueryCurrentRendererIntegerMESA will not call the screen
302 * query_render_string function with an invalid GLX enum value, and it will
303 * return NULL.
304 */
305TEST_F(query_renderer_integer_test, invalid_attribute)
306{
307   static const attribute_test_vector invalid_attributes[] = {
308      /* These values are just plain invalid for use with this extension.
309       */
310      E(0),
311      E(GLX_VENDOR),
312      E(GLX_VERSION),
313      E(GLX_EXTENSIONS),
314      E(GLX_RENDERER_VENDOR_ID_MESA + 0x10000),
315      E(GLX_RENDERER_DEVICE_ID_MESA + 0x10000),
316      E(GLX_RENDERER_VERSION_MESA + 0x10000),
317      E(GLX_RENDERER_ACCELERATED_MESA + 0x10000),
318      E(GLX_RENDERER_VIDEO_MEMORY_MESA + 0x10000),
319      E(GLX_RENDERER_UNIFIED_MEMORY_ARCHITECTURE_MESA + 0x10000),
320      E(GLX_RENDERER_PREFERRED_PROFILE_MESA + 0x10000),
321      E(GLX_RENDERER_OPENGL_CORE_PROFILE_VERSION_MESA + 0x10000),
322      E(GLX_RENDERER_OPENGL_COMPATIBILITY_PROFILE_VERSION_MESA + 0x10000),
323      E(GLX_RENDERER_OPENGL_ES_PROFILE_VERSION_MESA + 0x10000),
324      E(GLX_RENDERER_OPENGL_ES2_PROFILE_VERSION_MESA + 0x10000),
325      E(GLX_RENDERER_ID_MESA + 0x10000),
326   };
327
328   for (unsigned i = 0; i < ARRAY_SIZE(invalid_attributes); i++) {
329      query_renderer_integer_called = false;
330      query_renderer_string_called = false;
331
332      unsigned value = 0xDEADBEEF;
333      Bool success =
334         glXQueryRendererIntegerMESA(&dpy, 0, 0,
335                                     invalid_attributes[i].value,
336                                     &value);
337      EXPECT_FALSE(success) << invalid_attributes[i].string;
338      EXPECT_EQ(0xDEADBEEF, value) << invalid_attributes[i].string;
339      EXPECT_FALSE(query_renderer_integer_called)
340         << invalid_attributes[i].string;
341      EXPECT_FALSE(query_renderer_string_called)
342         << invalid_attributes[i].string;
343   }
344}
345
346/**
347 * glXQueryCurrentRendererIntegerMESA will not call GetGLXScreenConfigs if the
348 * display pointer is \c NULL.  It will also not segfault.
349 */
350TEST_F(query_renderer_integer_test, null_display_pointer)
351{
352   if (setjmp(jmp) == 0) {
353      GetGLXScreenConfigs_called = false;
354
355      unsigned value = 0xDEADBEEF;
356      Bool success =
357         glXQueryRendererIntegerMESA(NULL, 0, 0, GLX_RENDERER_VENDOR_ID_MESA,
358                                     &value);
359      EXPECT_FALSE(success);
360      EXPECT_EQ(0xDEADBEEF, value);
361      EXPECT_FALSE(GetGLXScreenConfigs_called);
362   } else {
363      EXPECT_FALSE(got_sigsegv);
364   }
365}
366
367/**
368 * glXQueryCurrentRendererIntegerMESA will return error if GetGLXScreenConfigs
369 * returns NULL.  It will also not segfault.
370 */
371TEST_F(query_renderer_integer_test, null_screen_pointer)
372{
373   psc = NULL;
374
375   if (setjmp(jmp) == 0) {
376      GetGLXScreenConfigs_called = false;
377
378      unsigned value = 0xDEADBEEF;
379      Bool success =
380         glXQueryRendererIntegerMESA(&dpy, 0, 0, GLX_RENDERER_VENDOR_ID_MESA,
381            &value);
382      EXPECT_FALSE(success);
383      EXPECT_EQ(0xDEADBEEF, value);
384      EXPECT_TRUE(GetGLXScreenConfigs_called);
385   } else {
386      EXPECT_FALSE(got_sigsegv);
387   }
388}
389
390/**
391 * glXQueryRendererIntegerMESA will not call the screen query_render_integer
392 * function if the renderer is invalid, and it will return NULL.
393 */
394TEST_F(query_renderer_integer_test, invalid_renderer_index)
395{
396   static const int invalid_renderer_indices[] = {
397      -1,
398      1,
399      999,
400   };
401
402   if (setjmp(jmp) == 0) {
403      for (unsigned i = 0; i < ARRAY_SIZE(invalid_renderer_indices); i++) {
404         unsigned value = 0xDEADBEEF;
405         Bool success =
406            glXQueryRendererIntegerMESA(&dpy, 0,
407                                        invalid_renderer_indices[i],
408                                        GLX_RENDERER_VENDOR_ID_MESA,
409                                        &value);
410         EXPECT_FALSE(success) << invalid_renderer_indices[i];
411         EXPECT_EQ(0xDEADBEEF, value) << invalid_renderer_indices[i];
412         EXPECT_FALSE(query_renderer_integer_called)
413            << invalid_renderer_indices[i];
414         EXPECT_FALSE(query_renderer_string_called)
415            << invalid_renderer_indices[i];
416      }
417   } else {
418      EXPECT_FALSE(got_sigsegv);
419   }
420}
421
422/**
423 * glXQueryCurrentRendererIntegerMESA will return error if there is no context
424 * current.  It will also not segfault.
425 */
426TEST_F(query_renderer_integer_test, no_current_context)
427{
428   if (setjmp(jmp) == 0) {
429      unsigned value = 0xDEADBEEF;
430      Bool success =
431         glXQueryCurrentRendererIntegerMESA(GLX_RENDERER_VENDOR_ID_MESA,
432                                            &value);
433      EXPECT_FALSE(success);
434      EXPECT_EQ(0xDEADBEEF, value);
435   } else {
436      EXPECT_FALSE(got_sigsegv);
437   }
438}
439