[ir][spirv-writer] Rework unit testing

Add a `Generate()` method to the base test helper that runs the SPIR-V
generator and validates the result with spirv-val. The full
disassembled module is then stored to `output_`.

Rewrite the `access` tests to use this method, instead of manually
invoking the PIMPL methods. Attach friendly names to variables and
results to allow the test to only check for a specific instruction.

Bug: tint:1906
Change-Id: I679ecbff46598d50777f5663d36c6c1235a3f5ff
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/139480
Reviewed-by: dan sinclair <dsinclair@google.com>
Commit-Queue: James Price <jrprice@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/src/tint/writer/spirv/ir/test_helper_ir.h b/src/tint/writer/spirv/ir/test_helper_ir.h
index 08f8246..debe5d8 100644
--- a/src/tint/writer/spirv/ir/test_helper_ir.h
+++ b/src/tint/writer/spirv/ir/test_helper_ir.h
@@ -16,8 +16,10 @@
 #define SRC_TINT_WRITER_SPIRV_IR_TEST_HELPER_IR_H_
 
 #include <string>
+#include <utility>
 
 #include "gtest/gtest.h"
+#include "spirv-tools/libspirv.hpp"
 #include "src/tint/ir/builder.h"
 #include "src/tint/ir/validate.h"
 #include "src/tint/writer/spirv/ir/generator_impl_ir.h"
@@ -54,6 +56,9 @@
     /// Validation errors
     std::string err_;
 
+    /// SPIR-V output.
+    std::string output_;
+
     /// @returns the error string from the validation
     std::string Error() const { return err_; }
 
@@ -67,6 +72,57 @@
         return true;
     }
 
+    /// Run the generator on the IR module and validate the result.
+    /// @returns true if generation and validation succeeded
+    bool Generate() {
+        if (!generator_.Generate()) {
+            err_ = generator_.Diagnostics().str();
+            return false;
+        }
+        if (!Validate()) {
+            return false;
+        }
+
+        output_ = Disassemble(generator_.Result(), SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
+        return true;
+    }
+
+    /// Validate the generated SPIR-V using the SPIR-V Tools Validator.
+    /// @returns true if validation succeeded, false otherwise
+    bool Validate() {
+        auto binary = generator_.Result();
+
+        std::string spv_errors;
+        auto msg_consumer = [&spv_errors](spv_message_level_t level, const char*,
+                                          const spv_position_t& position, const char* message) {
+            switch (level) {
+                case SPV_MSG_FATAL:
+                case SPV_MSG_INTERNAL_ERROR:
+                case SPV_MSG_ERROR:
+                    spv_errors +=
+                        "error: line " + std::to_string(position.index) + ": " + message + "\n";
+                    break;
+                case SPV_MSG_WARNING:
+                    spv_errors +=
+                        "warning: line " + std::to_string(position.index) + ": " + message + "\n";
+                    break;
+                case SPV_MSG_INFO:
+                    spv_errors +=
+                        "info: line " + std::to_string(position.index) + ": " + message + "\n";
+                    break;
+                case SPV_MSG_DEBUG:
+                    break;
+            }
+        };
+
+        spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_2);
+        tools.SetMessageConsumer(msg_consumer);
+
+        auto result = tools.Validate(binary);
+        err_ = std::move(spv_errors);
+        return result;
+    }
+
     /// @returns the disassembled types from the generated module.
     std::string DumpTypes() { return DumpInstructions(generator_.Module().Types()); }