Squashed 'third_party/SPIRV-Tools/' content from commit d14db341b

git-subtree-dir: third_party/SPIRV-Tools
git-subtree-split: d14db341b834cfb3c574a258c331b3a6b1c2cbc5
diff --git a/test/c_interface_test.cpp b/test/c_interface_test.cpp
new file mode 100644
index 0000000..c644fb9
--- /dev/null
+++ b/test/c_interface_test.cpp
@@ -0,0 +1,299 @@
+// Copyright (c) 2016 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "gtest/gtest.h"
+#include "source/table.h"
+#include "spirv-tools/libspirv.h"
+
+namespace spvtools {
+namespace {
+
+// TODO(antiagainst): Use public C API for setting the consumer once exists.
+#ifndef SPIRV_TOOLS_SHAREDLIB
+void SetContextMessageConsumer(spv_context context, MessageConsumer consumer) {
+  spvtools::SetContextMessageConsumer(context, consumer);
+}
+#else
+void SetContextMessageConsumer(spv_context, MessageConsumer) {}
+#endif
+
+// The default consumer is a null std::function.
+TEST(CInterface, DefaultConsumerNullDiagnosticForValidInput) {
+  auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
+  const char input_text[] =
+      "OpCapability Shader\n"
+      "OpCapability Linkage\n"
+      "OpMemoryModel Logical GLSL450";
+
+  spv_binary binary = nullptr;
+  EXPECT_EQ(SPV_SUCCESS, spvTextToBinary(context, input_text,
+                                         sizeof(input_text), &binary, nullptr));
+
+  {
+    // Sadly the compiler don't allow me to feed binary directly to
+    // spvValidate().
+    spv_const_binary_t b{binary->code, binary->wordCount};
+    EXPECT_EQ(SPV_SUCCESS, spvValidate(context, &b, nullptr));
+  }
+
+  spv_text text = nullptr;
+  EXPECT_EQ(SPV_SUCCESS, spvBinaryToText(context, binary->code,
+                                         binary->wordCount, 0, &text, nullptr));
+
+  spvTextDestroy(text);
+  spvBinaryDestroy(binary);
+  spvContextDestroy(context);
+}
+
+// The default consumer is a null std::function.
+TEST(CInterface, DefaultConsumerNullDiagnosticForInvalidAssembling) {
+  auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
+  const char input_text[] = "%1 = OpName";
+
+  spv_binary binary = nullptr;
+  EXPECT_EQ(SPV_ERROR_INVALID_TEXT,
+            spvTextToBinary(context, input_text, sizeof(input_text), &binary,
+                            nullptr));
+  spvBinaryDestroy(binary);
+  spvContextDestroy(context);
+}
+
+// The default consumer is a null std::function.
+TEST(CInterface, DefaultConsumerNullDiagnosticForInvalidDiassembling) {
+  auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
+  const char input_text[] = "OpNop";
+
+  spv_binary binary = nullptr;
+  ASSERT_EQ(SPV_SUCCESS, spvTextToBinary(context, input_text,
+                                         sizeof(input_text), &binary, nullptr));
+  // Change OpNop to an invalid (wordcount|opcode) word.
+  binary->code[binary->wordCount - 1] = 0xffffffff;
+
+  spv_text text = nullptr;
+  EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
+            spvBinaryToText(context, binary->code, binary->wordCount, 0, &text,
+                            nullptr));
+
+  spvTextDestroy(text);
+  spvBinaryDestroy(binary);
+  spvContextDestroy(context);
+}
+
+// The default consumer is a null std::function.
+TEST(CInterface, DefaultConsumerNullDiagnosticForInvalidValidating) {
+  auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
+  const char input_text[] = "OpNop";
+
+  spv_binary binary = nullptr;
+  ASSERT_EQ(SPV_SUCCESS, spvTextToBinary(context, input_text,
+                                         sizeof(input_text), &binary, nullptr));
+
+  spv_const_binary_t b{binary->code, binary->wordCount};
+  EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, spvValidate(context, &b, nullptr));
+
+  spvBinaryDestroy(binary);
+  spvContextDestroy(context);
+}
+
+TEST(CInterface, SpecifyConsumerNullDiagnosticForAssembling) {
+  const char input_text[] = "%1 = OpName\n";
+
+  auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
+  int invocation = 0;
+  SetContextMessageConsumer(
+      context,
+      [&invocation](spv_message_level_t level, const char* source,
+                    const spv_position_t& position, const char* message) {
+        ++invocation;
+        EXPECT_EQ(SPV_MSG_ERROR, level);
+        // The error happens at scanning the begining of second line.
+        EXPECT_STREQ("input", source);
+        EXPECT_EQ(1u, position.line);
+        EXPECT_EQ(0u, position.column);
+        EXPECT_EQ(12u, position.index);
+        EXPECT_STREQ("Expected operand, found end of stream.", message);
+      });
+
+  spv_binary binary = nullptr;
+  EXPECT_EQ(SPV_ERROR_INVALID_TEXT,
+            spvTextToBinary(context, input_text, sizeof(input_text), &binary,
+                            nullptr));
+#ifndef SPIRV_TOOLS_SHAREDLIB
+  EXPECT_EQ(1, invocation);
+#endif
+  spvBinaryDestroy(binary);
+  spvContextDestroy(context);
+}
+
+TEST(CInterface, SpecifyConsumerNullDiagnosticForDisassembling) {
+  const char input_text[] = "OpNop";
+
+  auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
+  int invocation = 0;
+  SetContextMessageConsumer(
+      context,
+      [&invocation](spv_message_level_t level, const char* source,
+                    const spv_position_t& position, const char* message) {
+        ++invocation;
+        EXPECT_EQ(SPV_MSG_ERROR, level);
+        EXPECT_STREQ("input", source);
+        EXPECT_EQ(0u, position.line);
+        EXPECT_EQ(0u, position.column);
+        EXPECT_EQ(1u, position.index);
+        EXPECT_STREQ("Invalid opcode: 65535", message);
+      });
+
+  spv_binary binary = nullptr;
+  ASSERT_EQ(SPV_SUCCESS, spvTextToBinary(context, input_text,
+                                         sizeof(input_text), &binary, nullptr));
+  // Change OpNop to an invalid (wordcount|opcode) word.
+  binary->code[binary->wordCount - 1] = 0xffffffff;
+
+  spv_text text = nullptr;
+  EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
+            spvBinaryToText(context, binary->code, binary->wordCount, 0, &text,
+                            nullptr));
+#ifndef SPIRV_TOOLS_SHAREDLIB
+  EXPECT_EQ(1, invocation);
+#endif
+
+  spvTextDestroy(text);
+  spvBinaryDestroy(binary);
+  spvContextDestroy(context);
+}
+
+TEST(CInterface, SpecifyConsumerNullDiagnosticForValidating) {
+  const char input_text[] = "OpNop";
+
+  auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
+  int invocation = 0;
+  SetContextMessageConsumer(
+      context,
+      [&invocation](spv_message_level_t level, const char* source,
+                    const spv_position_t& position, const char* message) {
+        ++invocation;
+        EXPECT_EQ(SPV_MSG_ERROR, level);
+        EXPECT_STREQ("input", source);
+        EXPECT_EQ(0u, position.line);
+        EXPECT_EQ(0u, position.column);
+        // TODO(antiagainst): what validation reports is not a word offset here.
+        // It is inconsistent with diassembler. Should be fixed.
+        EXPECT_EQ(1u, position.index);
+        EXPECT_STREQ(
+            "Nop cannot appear before the memory model instruction\n"
+            "  OpNop\n",
+            message);
+      });
+
+  spv_binary binary = nullptr;
+  ASSERT_EQ(SPV_SUCCESS, spvTextToBinary(context, input_text,
+                                         sizeof(input_text), &binary, nullptr));
+
+  spv_const_binary_t b{binary->code, binary->wordCount};
+  EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, spvValidate(context, &b, nullptr));
+#ifndef SPIRV_TOOLS_SHAREDLIB
+  EXPECT_EQ(1, invocation);
+#endif
+
+  spvBinaryDestroy(binary);
+  spvContextDestroy(context);
+}
+
+// When having both a consumer and an diagnostic object, the diagnostic object
+// should take priority.
+TEST(CInterface, SpecifyConsumerSpecifyDiagnosticForAssembling) {
+  const char input_text[] = "%1 = OpName";
+
+  auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
+  int invocation = 0;
+  SetContextMessageConsumer(
+      context,
+      [&invocation](spv_message_level_t, const char*, const spv_position_t&,
+                    const char*) { ++invocation; });
+
+  spv_binary binary = nullptr;
+  spv_diagnostic diagnostic = nullptr;
+  EXPECT_EQ(SPV_ERROR_INVALID_TEXT,
+            spvTextToBinary(context, input_text, sizeof(input_text), &binary,
+                            &diagnostic));
+  EXPECT_EQ(0, invocation);  // Consumer should not be invoked at all.
+  EXPECT_STREQ("Expected operand, found end of stream.", diagnostic->error);
+
+  spvDiagnosticDestroy(diagnostic);
+  spvBinaryDestroy(binary);
+  spvContextDestroy(context);
+}
+
+TEST(CInterface, SpecifyConsumerSpecifyDiagnosticForDisassembling) {
+  const char input_text[] = "OpNop";
+
+  auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
+  int invocation = 0;
+  SetContextMessageConsumer(
+      context,
+      [&invocation](spv_message_level_t, const char*, const spv_position_t&,
+                    const char*) { ++invocation; });
+
+  spv_binary binary = nullptr;
+  ASSERT_EQ(SPV_SUCCESS, spvTextToBinary(context, input_text,
+                                         sizeof(input_text), &binary, nullptr));
+  // Change OpNop to an invalid (wordcount|opcode) word.
+  binary->code[binary->wordCount - 1] = 0xffffffff;
+
+  spv_diagnostic diagnostic = nullptr;
+  spv_text text = nullptr;
+  EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
+            spvBinaryToText(context, binary->code, binary->wordCount, 0, &text,
+                            &diagnostic));
+
+  EXPECT_EQ(0, invocation);  // Consumer should not be invoked at all.
+  EXPECT_STREQ("Invalid opcode: 65535", diagnostic->error);
+
+  spvTextDestroy(text);
+  spvDiagnosticDestroy(diagnostic);
+  spvBinaryDestroy(binary);
+  spvContextDestroy(context);
+}
+
+TEST(CInterface, SpecifyConsumerSpecifyDiagnosticForValidating) {
+  const char input_text[] = "OpNop";
+
+  auto context = spvContextCreate(SPV_ENV_UNIVERSAL_1_1);
+  int invocation = 0;
+  SetContextMessageConsumer(
+      context,
+      [&invocation](spv_message_level_t, const char*, const spv_position_t&,
+                    const char*) { ++invocation; });
+
+  spv_binary binary = nullptr;
+  ASSERT_EQ(SPV_SUCCESS, spvTextToBinary(context, input_text,
+                                         sizeof(input_text), &binary, nullptr));
+
+  spv_diagnostic diagnostic = nullptr;
+  spv_const_binary_t b{binary->code, binary->wordCount};
+  EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, spvValidate(context, &b, &diagnostic));
+
+  EXPECT_EQ(0, invocation);  // Consumer should not be invoked at all.
+  EXPECT_STREQ(
+      "Nop cannot appear before the memory model instruction\n"
+      "  OpNop\n",
+      diagnostic->error);
+
+  spvDiagnosticDestroy(diagnostic);
+  spvBinaryDestroy(binary);
+  spvContextDestroy(context);
+}
+
+}  // namespace
+}  // namespace spvtools