1// Copyright (c) 2016 Google Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include <vector>
16
17#include "gmock/gmock.h"
18#include "source/spirv_target_env.h"
19#include "test/unit_spirv.h"
20
21namespace spvtools {
22namespace {
23
24using ::testing::AnyOf;
25using ::testing::Eq;
26using ::testing::StartsWith;
27using ::testing::ValuesIn;
28
29using TargetEnvTest = ::testing::TestWithParam<spv_target_env>;
30TEST_P(TargetEnvTest, CreateContext) {
31  spv_target_env env = GetParam();
32  spv_context context = spvContextCreate(env);
33  ASSERT_NE(nullptr, context);
34  spvContextDestroy(context);  // Avoid leaking
35}
36
37TEST_P(TargetEnvTest, ValidDescription) {
38  const char* description = spvTargetEnvDescription(GetParam());
39  ASSERT_NE(nullptr, description);
40  ASSERT_THAT(description, StartsWith("SPIR-V "));
41}
42
43TEST_P(TargetEnvTest, ValidSpirvVersion) {
44  auto spirv_version = spvVersionForTargetEnv(GetParam());
45  ASSERT_THAT(spirv_version, AnyOf(0x10000, 0x10100, 0x10200, 0x10300));
46}
47
48INSTANTIATE_TEST_SUITE_P(AllTargetEnvs, TargetEnvTest,
49                         ValuesIn(spvtest::AllTargetEnvironments()));
50
51TEST(GetContextTest, InvalidTargetEnvProducesNull) {
52  // Use a value beyond the last valid enum value.
53  spv_context context = spvContextCreate(static_cast<spv_target_env>(30));
54  EXPECT_EQ(context, nullptr);
55}
56
57// A test case for parsing an environment string.
58struct ParseCase {
59  const char* input;
60  bool success;        // Expect to successfully parse?
61  spv_target_env env;  // The parsed environment, if successful.
62};
63
64using TargetParseTest = ::testing::TestWithParam<ParseCase>;
65
66TEST_P(TargetParseTest, Samples) {
67  spv_target_env env;
68  bool parsed = spvParseTargetEnv(GetParam().input, &env);
69  EXPECT_THAT(parsed, Eq(GetParam().success));
70  if (parsed) {
71    EXPECT_THAT(env, Eq(GetParam().env));
72  }
73}
74
75INSTANTIATE_TEST_SUITE_P(
76    TargetParsing, TargetParseTest,
77    ValuesIn(std::vector<ParseCase>{
78        {"spv1.0", true, SPV_ENV_UNIVERSAL_1_0},
79        {"spv1.1", true, SPV_ENV_UNIVERSAL_1_1},
80        {"spv1.2", true, SPV_ENV_UNIVERSAL_1_2},
81        {"spv1.3", true, SPV_ENV_UNIVERSAL_1_3},
82        {"vulkan1.0", true, SPV_ENV_VULKAN_1_0},
83        {"vulkan1.1", true, SPV_ENV_VULKAN_1_1},
84        {"vulkan1.2", true, SPV_ENV_VULKAN_1_2},
85        {"opencl2.1", true, SPV_ENV_OPENCL_2_1},
86        {"opencl2.2", true, SPV_ENV_OPENCL_2_2},
87        {"opengl4.0", true, SPV_ENV_OPENGL_4_0},
88        {"opengl4.1", true, SPV_ENV_OPENGL_4_1},
89        {"opengl4.2", true, SPV_ENV_OPENGL_4_2},
90        {"opengl4.3", true, SPV_ENV_OPENGL_4_3},
91        {"opengl4.5", true, SPV_ENV_OPENGL_4_5},
92        {"opencl1.2", true, SPV_ENV_OPENCL_1_2},
93        {"opencl1.2embedded", true, SPV_ENV_OPENCL_EMBEDDED_1_2},
94        {"opencl2.0", true, SPV_ENV_OPENCL_2_0},
95        {"opencl2.0embedded", true, SPV_ENV_OPENCL_EMBEDDED_2_0},
96        {"opencl2.1embedded", true, SPV_ENV_OPENCL_EMBEDDED_2_1},
97        {"opencl2.2embedded", true, SPV_ENV_OPENCL_EMBEDDED_2_2},
98        {"opencl2.3", false, SPV_ENV_UNIVERSAL_1_0},
99        {"opencl3.0", false, SPV_ENV_UNIVERSAL_1_0},
100        {"vulkan1.9", false, SPV_ENV_UNIVERSAL_1_0},
101        {"vulkan2.0", false, SPV_ENV_UNIVERSAL_1_0},
102        {nullptr, false, SPV_ENV_UNIVERSAL_1_0},
103        {"", false, SPV_ENV_UNIVERSAL_1_0},
104        {"abc", false, SPV_ENV_UNIVERSAL_1_0},
105    }));
106
107// A test case for parsing an environment string.
108struct ParseVulkanCase {
109  uint32_t vulkan;
110  uint32_t spirv;
111  bool success;        // Expect to successfully parse?
112  spv_target_env env;  // The parsed environment, if successful.
113};
114
115using TargetParseVulkanTest = ::testing::TestWithParam<ParseVulkanCase>;
116
117TEST_P(TargetParseVulkanTest, Samples) {
118  spv_target_env env;
119  bool parsed = spvParseVulkanEnv(GetParam().vulkan, GetParam().spirv, &env);
120  EXPECT_THAT(parsed, Eq(GetParam().success));
121  if (parsed) {
122    EXPECT_THAT(env, Eq(GetParam().env));
123  }
124}
125
126#define VK(MAJ, MIN) ((MAJ << 22) | (MIN << 12))
127#define SPV(MAJ, MIN) ((MAJ << 16) | (MIN << 8))
128INSTANTIATE_TEST_SUITE_P(
129    TargetVulkanParsing, TargetParseVulkanTest,
130    ValuesIn(std::vector<ParseVulkanCase>{
131        // Vulkan 1.0 cases
132        {VK(1, 0), SPV(1, 0), true, SPV_ENV_VULKAN_1_0},
133        {VK(1, 0), SPV(1, 1), true, SPV_ENV_VULKAN_1_1},
134        {VK(1, 0), SPV(1, 2), true, SPV_ENV_VULKAN_1_1},
135        {VK(1, 0), SPV(1, 3), true, SPV_ENV_VULKAN_1_1},
136        {VK(1, 0), SPV(1, 4), true, SPV_ENV_VULKAN_1_1_SPIRV_1_4},
137        {VK(1, 0), SPV(1, 5), true, SPV_ENV_VULKAN_1_2},
138        {VK(1, 0), SPV(1, 6), true, SPV_ENV_VULKAN_1_3},
139        {VK(1, 0), SPV(1, 7), false, SPV_ENV_UNIVERSAL_1_0},
140        // Vulkan 1.1 cases
141        {VK(1, 1), SPV(1, 0), true, SPV_ENV_VULKAN_1_1},
142        {VK(1, 1), SPV(1, 1), true, SPV_ENV_VULKAN_1_1},
143        {VK(1, 1), SPV(1, 2), true, SPV_ENV_VULKAN_1_1},
144        {VK(1, 1), SPV(1, 3), true, SPV_ENV_VULKAN_1_1},
145        {VK(1, 1), SPV(1, 4), true, SPV_ENV_VULKAN_1_1_SPIRV_1_4},
146        {VK(1, 1), SPV(1, 5), true, SPV_ENV_VULKAN_1_2},
147        {VK(1, 1), SPV(1, 6), true, SPV_ENV_VULKAN_1_3},
148        {VK(1, 1), SPV(1, 7), false, SPV_ENV_UNIVERSAL_1_0},
149        // Vulkan 1.2 cases
150        {VK(1, 2), SPV(1, 0), true, SPV_ENV_VULKAN_1_2},
151        {VK(1, 2), SPV(1, 1), true, SPV_ENV_VULKAN_1_2},
152        {VK(1, 2), SPV(1, 2), true, SPV_ENV_VULKAN_1_2},
153        {VK(1, 2), SPV(1, 3), true, SPV_ENV_VULKAN_1_2},
154        {VK(1, 2), SPV(1, 4), true, SPV_ENV_VULKAN_1_2},
155        {VK(1, 2), SPV(1, 5), true, SPV_ENV_VULKAN_1_2},
156        {VK(1, 2), SPV(1, 6), true, SPV_ENV_VULKAN_1_3},
157        {VK(1, 2), SPV(1, 7), false, SPV_ENV_UNIVERSAL_1_0},
158        // Vulkan 1.3 cases
159        {VK(1, 3), SPV(1, 0), true, SPV_ENV_VULKAN_1_3},
160        {VK(1, 3), SPV(1, 1), true, SPV_ENV_VULKAN_1_3},
161        {VK(1, 3), SPV(1, 2), true, SPV_ENV_VULKAN_1_3},
162        {VK(1, 3), SPV(1, 3), true, SPV_ENV_VULKAN_1_3},
163        {VK(1, 3), SPV(1, 4), true, SPV_ENV_VULKAN_1_3},
164        {VK(1, 3), SPV(1, 5), true, SPV_ENV_VULKAN_1_3},
165        {VK(1, 3), SPV(1, 6), true, SPV_ENV_VULKAN_1_3},
166        {VK(1, 3), SPV(1, 7), false, SPV_ENV_UNIVERSAL_1_0},
167        // Vulkan 2.0 cases
168        {VK(2, 0), SPV(1, 0), false, SPV_ENV_UNIVERSAL_1_0},
169        // Vulkan 99.0 cases
170        {VK(99, 0), SPV(1, 0), false, SPV_ENV_UNIVERSAL_1_0},
171    }));
172
173}  // namespace
174}  // namespace spvtools
175