spirv-fuzz: Cover protobuf message creation in tests (#4285)

The Transformation class tests did not cover the (trivial) ToMessage
methods of each transformation, nor the constructors that take a
protobuf message. This lac of coverage makes it hard to see which more
interesting pieces of code are not covered when looking at coverage
percentages. This change adapts the helper function for applying a
transformation and checking fresh ids so that it turns a
transformation into a protobuf message and back, thus covering
ToMessage and the protobuf constructor for every transformation. The
runtime overhead of doing this is very small.
diff --git a/test/fuzz/fuzz_test_util.cpp b/test/fuzz/fuzz_test_util.cpp
index 28d3f89..bf0a4ff 100644
--- a/test/fuzz/fuzz_test_util.cpp
+++ b/test/fuzz/fuzz_test_util.cpp
@@ -160,13 +160,19 @@
     const Transformation& transformation, opt::IRContext* ir_context,
     TransformationContext* transformation_context,
     const std::unordered_set<uint32_t>& issued_overflow_ids) {
+  // To ensure that we cover all ToMessage and message-based constructor methods
+  // in our tests, we turn this into a message and back into a transformation,
+  // and use the reconstructed transformation in the rest of the function.
+  auto message = transformation.ToMessage();
+  auto reconstructed_transformation = Transformation::FromMessage(message);
+
   opt::analysis::DefUseManager::IdToDefMap before_transformation =
       ir_context->get_def_use_mgr()->id_to_defs();
-  transformation.Apply(ir_context, transformation_context);
+  reconstructed_transformation->Apply(ir_context, transformation_context);
   opt::analysis::DefUseManager::IdToDefMap after_transformation =
       ir_context->get_def_use_mgr()->id_to_defs();
   std::unordered_set<uint32_t> fresh_ids_for_transformation =
-      transformation.GetFreshIds();
+      reconstructed_transformation->GetFreshIds();
   for (auto& entry : after_transformation) {
     uint32_t id = entry.first;
     bool introduced_by_transformation_message =