[fidl][compatibility] Add more types to the test

This adds tests for:
 - bits, tables and xunions in a struct
 - arrays of every type
 - vectors of every type
 - tables of every type
 - xunions of every type

The new tests are disabled for dart until they can be added to topaz.

Some tests are disabled for Rust and LLCPP because they currently fail.

FIDL-610

Change-Id: Ie409ce5110f66ac1d2695b41e7c46e905d9ba7c6
diff --git a/garnet/bin/fidl_compatibility_test/compatibility_test.cc b/garnet/bin/fidl_compatibility_test/compatibility_test.cc
index 6f5b2a3..8cfe92f 100644
--- a/garnet/bin/fidl_compatibility_test/compatibility_test.cc
+++ b/garnet/bin/fidl_compatibility_test/compatibility_test.cc
@@ -23,10 +23,19 @@
 #include "src/lib/fxl/strings/utf_codecs.h"
 
 using fidl::VectorPtr;
+using fidl::test::compatibility::AllTypesTable;
+using fidl::test::compatibility::AllTypesXunion;
+using fidl::test::compatibility::ArraysStruct;
 using fidl::test::compatibility::Struct;
+using fidl::test::compatibility::this_is_a_struct;
+using fidl::test::compatibility::this_is_a_table;
+using fidl::test::compatibility::this_is_a_union;
+using fidl::test::compatibility::this_is_a_xunion;
+using fidl::test::compatibility::VectorsStruct;
 using std::string;
 
 namespace {
+
 // Want a size small enough that it doesn't get too big to transmit but
 // large enough to exercise interesting code paths.
 constexpr uint8_t kArbitraryVectorSize = 3;
@@ -36,6 +45,148 @@
 constexpr char kUsage[] =
     ("Usage:\n  fidl_compatibility_test foo_server bar_server\n");
 
+class DataGenerator {
+ public:
+  DataGenerator(int seed) : rand_engine_(seed) {}
+
+  template <typename T>
+  T choose(T a, T b) {
+    if (next<bool>()) {
+      return a;
+    } else {
+      return b;
+    }
+  }
+
+  template <typename T>
+  std::enable_if_t<std::is_integral_v<T>, T> next() {
+    return std::uniform_int_distribution<T>{}(rand_engine_);
+  }
+
+  template <typename T>
+  std::enable_if_t<std::is_floating_point_v<T>, T> next() {
+    return std::uniform_real_distribution<T>{}(rand_engine_);
+  }
+
+  template <typename T>
+  std::enable_if_t<std::is_same_v<T, std::string>, T> next(
+      size_t count = kArbitraryConstant) {
+    std::string random_string;
+    random_string.reserve(count);
+    do {
+      // Generate a random 32 bit unsigned int to use a the code point.
+      uint32_t code_point = next<uint32_t>();
+      // Mask the random number so that it can be encoded into the number of
+      // bytes remaining.
+      size_t remaining = count - random_string.size();
+      if (remaining == 1) {
+        code_point &= 0x7F;
+      } else if (remaining == 2) {
+        code_point &= 0x7FF;
+      } else if (remaining == 3) {
+        code_point &= 0xFFFF;
+      } else {
+        // Mask to fall within the general range of code points.
+        code_point &= 0x1FFFFF;
+      }
+      // Check that it's really a valid code point, otherwise try again.
+      if (!fxl::IsValidCodepoint(code_point)) {
+        continue;
+      }
+      // Add the character to the random string.
+      fxl::WriteUnicodeCharacter(code_point, &random_string);
+      FXL_CHECK(random_string.size() <= count);
+    } while (random_string.size() < count);
+    return random_string;
+  }
+
+  template <typename T>
+  std::enable_if_t<std::is_same_v<T, fidl::StringPtr>, T> next(
+      size_t count = kArbitraryConstant) {
+    return nullable<fidl::StringPtr>(
+        fidl::StringPtr(), [this, count]() -> fidl::StringPtr {
+          return fidl::StringPtr(next<std::string>(count));
+        });
+  }
+
+  template <typename T>
+  std::enable_if_t<std::is_same_v<T, zx::handle>, T> next(
+      bool nullable = false) {
+    if (!nullable || next<bool>()) {
+      zx_handle_t raw_event;
+      const zx_status_t status = zx_event_create(0u, &raw_event);
+      // Can't use gtest ASSERT_EQ because we're in a non-void function.
+      ZX_ASSERT_MSG(status == ZX_OK, "status = %d", status);
+      return zx::handle(raw_event);
+    } else {
+      return zx::handle(0);
+    }
+  }
+
+  template <typename T>
+  std::enable_if_t<std::is_same_v<T, this_is_a_struct>, T> next() {
+    this_is_a_struct value{};
+    value.s = next<std::string>();
+    return value;
+  }
+
+  template <typename T>
+  std::enable_if_t<std::is_same_v<T, std::unique_ptr<this_is_a_struct>>, T>
+  next() {
+    return nullable<std::unique_ptr<this_is_a_struct>>(nullptr, [this]() {
+      return std::make_unique<this_is_a_struct>(next<this_is_a_struct>());
+    });
+  }
+
+  template <typename T>
+  std::enable_if_t<std::is_same_v<T, this_is_a_table>, T> next() {
+    this_is_a_table value{};
+    value.set_s(next<std::string>());
+    return value;
+  }
+
+  template <typename T>
+  std::enable_if_t<std::is_same_v<T, this_is_a_union>, T> next() {
+    this_is_a_union value{};
+    if (next<bool>()) {
+      value.set_b(next<bool>());
+    } else {
+      value.set_s(next<std::string>());
+    }
+    return value;
+  }
+
+  template <typename T>
+  std::enable_if_t<std::is_same_v<T, std::unique_ptr<this_is_a_union>>, T>
+  next() {
+    return nullable<std::unique_ptr<this_is_a_union>>(nullptr, [this]() {
+      return std::make_unique<this_is_a_union>(next<this_is_a_union>());
+    });
+  }
+
+  template <typename T>
+  std::enable_if_t<std::is_same_v<T, this_is_a_xunion>, T> next() {
+    this_is_a_xunion value{};
+    if (next<bool>()) {
+      value.set_b(next<bool>());
+    } else {
+      value.set_s(next<std::string>());
+    }
+    return value;
+  }
+
+ private:
+  std::default_random_engine rand_engine_;
+  template <typename T>
+  T nullable(T null_value, std::function<T(void)> generate_value) {
+    if (next<bool>()) {
+      return generate_value();
+    } else {
+      return null_value;
+    }
+  }
+};
+
 zx::handle Handle() {
   zx_handle_t raw_event;
   const zx_status_t status = zx_event_create(0u, &raw_event);
@@ -424,6 +575,13 @@
   EXPECT_EQ(a.u32_enum, b.u32_enum);
   EXPECT_EQ(a.u64_enum, b.u64_enum);
 
+  // bits
+  EXPECT_EQ(a.default_bits, b.default_bits);
+  EXPECT_EQ(a.u8_bits, b.u8_bits);
+  EXPECT_EQ(a.u16_bits, b.u16_bits);
+  EXPECT_EQ(a.u32_bits, b.u32_bits);
+  EXPECT_EQ(a.u64_bits, b.u64_bits);
+
   // structs
   EXPECT_EQ(a.structs.s.s, b.structs.s.s);
   EXPECT_EQ(a.structs.nullable_s, b.structs.nullable_s);
@@ -438,18 +596,16 @@
   EXPECT_EQ(a.unions.nullable_u->is_b(), b.unions.nullable_u->is_b());
   EXPECT_EQ(a.unions.nullable_u->b(), b.unions.nullable_u->b());
 
+  // tables and xunions
+  EXPECT_TRUE(fidl::Equals(a.table, b.table));
+  EXPECT_TRUE(fidl::Equals(a.xunion_, b.xunion_));
+
   // bool
   EXPECT_EQ(a.b, b.b);
 }
 
-std::string RandomUTF8(size_t count) {
-  // Prepare randomness.
-  std::default_random_engine rand_engine;
-  // Using randomness to avoid having to come up with varied values by hand.
-  // Seed deterministically so that this function's outputs are predictable.
-  rand_engine.seed(count);
+std::string RandomUTF8(size_t count, std::default_random_engine& rand_engine) {
   std::uniform_int_distribution<uint32_t> uint32_distribution;
-
   std::string random_string;
   random_string.reserve(count);
   do {
@@ -479,7 +635,7 @@
   return random_string;
 }
 
-void Initialize(Struct* s) {
+void InitializeStruct(Struct* s) {
   // Prepare randomness.
   std::default_random_engine rand_engine;
   // Using randomness to avoid having to come up with varied values by hand.
@@ -497,8 +653,8 @@
   std::uniform_real_distribution<float> float_distribution;
   std::uniform_real_distribution<double> double_distribution;
   std::string random_string =
-      RandomUTF8(fidl::test::compatibility::strings_size);
-  std::string random_short_string = RandomUTF8(kArbitraryConstant);
+      RandomUTF8(fidl::test::compatibility::strings_size, rand_engine);
+  std::string random_short_string = RandomUTF8(kArbitraryConstant, rand_engine);
 
   // primitive_types
   s->primitive_types.b = bool_distribution(rand_engine);
@@ -893,18 +1049,351 @@
   s->u32_enum = fidl::test::compatibility::u32_enum::kThree;
   s->u64_enum = fidl::test::compatibility::u64_enum::kFour;
 
+  // bits
+  s->default_bits = fidl::test::compatibility::default_bits::kOne;
+  s->u8_bits = fidl::test::compatibility::u8_bits::kOne;
+  s->u16_bits = fidl::test::compatibility::u16_bits::kTwo;
+  s->u32_bits = fidl::test::compatibility::u32_bits::kThree;
+  s->u64_bits = fidl::test::compatibility::u64_bits::kFour;
+
   // structs
   s->structs.s.s = fidl::StringPtr(random_string);
 
   // unions
   s->unions.u.set_s(fidl::StringPtr(random_string));
-  s->unions.nullable_u = fidl::test::compatibility::this_is_a_union::New();
+  s->unions.nullable_u = this_is_a_union::New();
   s->unions.nullable_u->set_b(bool_distribution(rand_engine));
 
+  s->table.set_s(random_string);
+  s->xunion_.set_s(random_string);
+
   // bool
   s->b = bool_distribution(rand_engine);
 }
 
+void InitializeArraysStruct(ArraysStruct* value, DataGenerator& gen) {
+  for (uint32_t i = 0; i < fidl::test::compatibility::arrays_size; i++) {
+    value->bools[i] = gen.next<bool>();
+    value->int8s[i] = gen.next<int8_t>();
+    value->int16s[i] = gen.next<int16_t>();
+    value->int32s[i] = gen.next<int32_t>();
+    value->uint8s[i] = gen.next<uint8_t>();
+    value->uint16s[i] = gen.next<uint16_t>();
+    value->uint32s[i] = gen.next<uint32_t>();
+    value->uint64s[i] = gen.next<uint64_t>();
+    value->float32s[i] = gen.next<float>();
+    value->float64s[i] = gen.next<double>();
+
+    value->enums[i] =
+        gen.choose(fidl::test::compatibility::default_enum::kOne,
+                   fidl::test::compatibility::default_enum::kZero);
+    value->bits[i] = gen.choose(fidl::test::compatibility::default_bits::kOne,
+                                fidl::test::compatibility::default_bits::kTwo);
+
+    value->handles[i] = gen.next<zx::handle>();
+    value->nullable_handles[i] = gen.next<zx::handle>(true);
+
+    value->strings[i] = gen.next<std::string>();
+    value->nullable_strings[i] = gen.next<fidl::StringPtr>();
+
+    value->structs[i] = gen.next<this_is_a_struct>();
+    value->nullable_structs[i] = gen.next<std::unique_ptr<this_is_a_struct>>();
+    if (gen.next<bool>()) {
+      value->nullable_structs[i] = std::make_unique<this_is_a_struct>();
+      value->nullable_structs[i]->s = gen.next<std::string>();
+    }
+
+    value->unions[i] = gen.next<this_is_a_union>();
+    value->nullable_unions[i] = gen.next<std::unique_ptr<this_is_a_union>>();
+
+    for (size_t j = 0; j < fidl::test::compatibility::arrays_size; j++) {
+      value->arrays[i][j] = gen.next<uint32_t>();
+      value->vectors[i].push_back(gen.next<uint32_t>());
+    }
+
+    if (gen.next<bool>()) {
+      for (size_t j = 0; j < fidl::test::compatibility::arrays_size; j++) {
+        value->nullable_vectors[i].push_back(gen.next<uint32_t>());
+      }
+    }
+
+    value->tables[i] = gen.next<this_is_a_table>();
+    value->xunions[i] = gen.next<this_is_a_xunion>();
+  }
+}
+
+void ExpectArraysStructEq(const ArraysStruct& a, const ArraysStruct& b) {
+  EXPECT_TRUE(fidl::Equals(a.bools, b.bools));
+  EXPECT_TRUE(fidl::Equals(a.int8s, b.int8s));
+  EXPECT_TRUE(fidl::Equals(a.int16s, b.int16s));
+  EXPECT_TRUE(fidl::Equals(a.int32s, b.int32s));
+  EXPECT_TRUE(fidl::Equals(a.int64s, b.int64s));
+  EXPECT_TRUE(fidl::Equals(a.uint8s, b.uint8s));
+  EXPECT_TRUE(fidl::Equals(a.uint16s, b.uint16s));
+  EXPECT_TRUE(fidl::Equals(a.uint32s, b.uint32s));
+  EXPECT_TRUE(fidl::Equals(a.uint64s, b.uint64s));
+  EXPECT_TRUE(fidl::Equals(a.float32s, b.float32s));
+  EXPECT_TRUE(fidl::Equals(a.float64s, b.float64s));
+  EXPECT_TRUE(fidl::Equals(a.enums, b.enums));
+  EXPECT_TRUE(fidl::Equals(a.bits, b.bits));
+  EXPECT_EQ(a.handles.size(), b.handles.size());
+  EXPECT_EQ(a.nullable_handles.size(), b.nullable_handles.size());
+  EXPECT_EQ(a.handles.size(), a.nullable_handles.size());
+  for (size_t i = 0; i < a.handles.size(); i++) {
+    EXPECT_TRUE(HandlesEq(a.handles[i], b.handles[i]));
+    EXPECT_TRUE(HandlesEq(a.nullable_handles[i], b.nullable_handles[i]));
+  }
+  EXPECT_TRUE(fidl::Equals(a.strings, b.strings));
+  EXPECT_TRUE(fidl::Equals(a.nullable_strings, b.nullable_strings));
+  EXPECT_TRUE(fidl::Equals(a.structs, b.structs));
+  EXPECT_TRUE(fidl::Equals(a.nullable_structs, b.nullable_structs));
+  EXPECT_TRUE(fidl::Equals(a.unions, b.unions));
+  EXPECT_TRUE(fidl::Equals(a.nullable_unions, b.nullable_unions));
+  EXPECT_TRUE(fidl::Equals(a.arrays, b.arrays));
+  EXPECT_TRUE(fidl::Equals(a.vectors, b.vectors));
+  EXPECT_TRUE(fidl::Equals(a.nullable_vectors, b.nullable_vectors));
+  EXPECT_TRUE(fidl::Equals(a.tables, b.tables));
+  EXPECT_TRUE(fidl::Equals(a.xunions, b.xunions));
+}
+
+void InitializeVectorsStruct(VectorsStruct* value, DataGenerator& gen) {
+  for (uint32_t i = 0; i < fidl::test::compatibility::arrays_size; i++) {
+    value->bools.push_back(gen.next<bool>());
+    value->int8s.push_back(gen.next<int8_t>());
+    value->int16s.push_back(gen.next<int16_t>());
+    value->int32s.push_back(gen.next<int32_t>());
+    value->int64s.push_back(gen.next<int64_t>());
+    value->uint8s.push_back(gen.next<uint8_t>());
+    value->uint16s.push_back(gen.next<uint16_t>());
+    value->uint32s.push_back(gen.next<uint32_t>());
+    value->uint64s.push_back(gen.next<uint64_t>());
+    value->float32s.push_back(gen.next<float>());
+    value->float64s.push_back(gen.next<double>());
+
+    value->enums.push_back(
+        gen.choose(fidl::test::compatibility::default_enum::kOne,
+                   fidl::test::compatibility::default_enum::kZero));
+    value->bits.push_back(
+        gen.choose(fidl::test::compatibility::default_bits::kOne,
+                   fidl::test::compatibility::default_bits::kTwo));
+
+    value->handles.push_back(gen.next<zx::handle>());
+    value->nullable_handles.push_back(gen.next<zx::handle>(true));
+
+    value->strings.push_back(gen.next<std::string>());
+    value->nullable_strings.push_back(gen.next<fidl::StringPtr>());
+
+    value->structs.push_back(this_is_a_struct{});
+    value->structs[i].s = gen.next<std::string>();
+    if (gen.next<bool>()) {
+      value->nullable_structs.push_back(std::make_unique<this_is_a_struct>());
+      value->nullable_structs.back()->s = gen.next<std::string>();
+    }
+
+    value->unions.push_back(gen.next<this_is_a_union>());
+    value->nullable_unions.push_back(
+        gen.next<std::unique_ptr<this_is_a_union>>());
+
+    value->arrays.push_back(
+        std::array<uint32_t, fidl::test::compatibility::vectors_size>{});
+    value->vectors.push_back(std::vector<uint32_t>{});
+    for (size_t j = 0; j < fidl::test::compatibility::vectors_size; j++) {
+      value->arrays.back()[j] = gen.next<uint32_t>();
+      value->vectors.back().push_back(gen.next<uint32_t>());
+    }
+
+    value->nullable_vectors.push_back(fidl::VectorPtr<uint32_t>());
+    if (gen.next<bool>()) {
+      for (size_t j = 0; j < fidl::test::compatibility::vectors_size; j++) {
+        value->nullable_vectors.back().push_back(gen.next<uint32_t>());
+      }
+    } else {
+      value->nullable_vectors.back().reset();
+    }
+
+    value->tables.push_back(gen.next<this_is_a_table>());
+    value->xunions.push_back(gen.next<this_is_a_xunion>());
+  }
+}
+
+void ExpectVectorsStructEq(const VectorsStruct& a, const VectorsStruct& b) {
+  EXPECT_TRUE(fidl::Equals(a.bools, b.bools));
+  EXPECT_TRUE(fidl::Equals(a.int8s, b.int8s));
+  EXPECT_TRUE(fidl::Equals(a.int16s, b.int16s));
+  EXPECT_TRUE(fidl::Equals(a.int32s, b.int32s));
+  EXPECT_TRUE(fidl::Equals(a.int64s, b.int64s));
+  EXPECT_TRUE(fidl::Equals(a.uint8s, b.uint8s));
+  EXPECT_TRUE(fidl::Equals(a.uint16s, b.uint16s));
+  EXPECT_TRUE(fidl::Equals(a.uint32s, b.uint32s));
+  EXPECT_TRUE(fidl::Equals(a.uint64s, b.uint64s));
+  EXPECT_TRUE(fidl::Equals(a.float32s, b.float32s));
+  EXPECT_TRUE(fidl::Equals(a.float64s, b.float64s));
+  EXPECT_TRUE(fidl::Equals(a.enums, b.enums));
+  EXPECT_TRUE(fidl::Equals(a.bits, b.bits));
+  EXPECT_EQ(a.handles.size(), b.handles.size());
+  EXPECT_EQ(a.nullable_handles.size(), b.nullable_handles.size());
+  EXPECT_EQ(a.handles.size(), a.nullable_handles.size());
+  for (size_t i = 0; i < a.handles.size(); i++) {
+    EXPECT_TRUE(HandlesEq(a.handles[i], b.handles[i]));
+    EXPECT_TRUE(HandlesEq(a.nullable_handles[i], b.nullable_handles[i]));
+  }
+  EXPECT_TRUE(fidl::Equals(a.strings, b.strings));
+  EXPECT_TRUE(fidl::Equals(a.nullable_strings, b.nullable_strings));
+  EXPECT_TRUE(fidl::Equals(a.structs, b.structs));
+  EXPECT_TRUE(fidl::Equals(a.nullable_structs, b.nullable_structs));
+  EXPECT_TRUE(fidl::Equals(a.unions, b.unions));
+  EXPECT_TRUE(fidl::Equals(a.nullable_unions, b.nullable_unions));
+  EXPECT_TRUE(fidl::Equals(a.arrays, b.arrays));
+  EXPECT_TRUE(fidl::Equals(a.vectors, b.vectors));
+  EXPECT_TRUE(fidl::Equals(a.nullable_vectors, b.nullable_vectors));
+  EXPECT_TRUE(fidl::Equals(a.tables, b.tables));
+  EXPECT_TRUE(fidl::Equals(a.xunions, b.xunions));
+}
+
+void InitializeAllTypesTable(AllTypesTable* value, DataGenerator& gen) {
+  value->set_bool_member(gen.next<bool>());
+  value->set_int8_member(gen.next<int8_t>());
+  value->set_int16_member(gen.next<int16_t>());
+  value->set_int32_member(gen.next<int32_t>());
+  value->set_int64_member(gen.next<int64_t>());
+  value->set_uint8_member(gen.next<uint8_t>());
+  value->set_uint16_member(gen.next<uint16_t>());
+  value->set_uint32_member(gen.next<uint32_t>());
+  value->set_uint64_member(gen.next<uint64_t>());
+  value->set_float32_member(gen.next<float>());
+  value->set_float64_member(gen.next<double>());
+  value->set_enum_member(
+      gen.choose(fidl::test::compatibility::default_enum::kOne,
+                 fidl::test::compatibility::default_enum::kZero));
+  value->set_bits_member(
+      gen.choose(fidl::test::compatibility::default_bits::kOne,
+                 fidl::test::compatibility::default_bits::kTwo));
+  value->set_handle_member(gen.next<zx::handle>());
+  value->set_string_member(gen.next<std::string>());
+  value->set_struct_member(gen.next<this_is_a_struct>());
+  value->set_union_member(gen.next<this_is_a_union>());
+
+  std::array<uint32_t, fidl::test::compatibility::arrays_size> array;
+  for (size_t i = 0; i < array.size(); i++) {
+    array[i] = gen.next<uint32_t>();
+  }
+  value->set_array_member(array);
+
+  std::vector<uint32_t> vector;
+  for (size_t i = 0; i < kArbitraryVectorSize; i++) {
+    vector.push_back(gen.next<uint32_t>());
+  }
+  value->set_vector_member(vector);
+
+  value->set_table_member(gen.next<this_is_a_table>());
+  value->set_xunion_member(gen.next<this_is_a_xunion>());
+}
+
+void ExpectAllTypesTableEq(const AllTypesTable& a, const AllTypesTable& b) {
+  EXPECT_TRUE(fidl::Equals(a.bool_member(), b.bool_member()));
+  EXPECT_TRUE(fidl::Equals(a.int8_member(), b.int8_member()));
+  EXPECT_TRUE(fidl::Equals(a.int16_member(), b.int16_member()));
+  EXPECT_TRUE(fidl::Equals(a.int32_member(), b.int32_member()));
+  EXPECT_TRUE(fidl::Equals(a.int64_member(), b.int64_member()));
+  EXPECT_TRUE(fidl::Equals(a.uint8_member(), b.uint8_member()));
+  EXPECT_TRUE(fidl::Equals(a.uint16_member(), b.uint16_member()));
+  EXPECT_TRUE(fidl::Equals(a.uint32_member(), b.uint32_member()));
+  EXPECT_TRUE(fidl::Equals(a.uint64_member(), b.uint64_member()));
+  EXPECT_TRUE(fidl::Equals(a.float32_member(), b.float32_member()));
+  EXPECT_TRUE(fidl::Equals(a.float64_member(), b.float64_member()));
+  EXPECT_TRUE(fidl::Equals(a.enum_member(), b.enum_member()));
+  EXPECT_TRUE(fidl::Equals(a.bits_member(), b.bits_member()));
+  EXPECT_TRUE(HandlesEq(a.handle_member(), b.handle_member()));
+  EXPECT_TRUE(fidl::Equals(a.string_member(), b.string_member()));
+  EXPECT_TRUE(fidl::Equals(a.struct_member(), b.struct_member()));
+  EXPECT_TRUE(fidl::Equals(a.union_member(), b.union_member()));
+  EXPECT_TRUE(fidl::Equals(a.array_member(), b.array_member()));
+  EXPECT_TRUE(fidl::Equals(a.vector_member(), b.vector_member()));
+  EXPECT_TRUE(fidl::Equals(a.table_member(), b.table_member()));
+  EXPECT_TRUE(fidl::Equals(a.xunion_member(), b.xunion_member()));
+}
+
+void InitializeAllTypesXunions(std::vector<AllTypesXunion>* value,
+                               DataGenerator& gen) {
+  for (size_t i = 1; true; i++) {
+    AllTypesXunion xu{};
+    switch (i) {
+      case 1:
+        xu.set_bool_member(gen.next<bool>());
+        break;
+      case 2:
+        xu.set_int8_member(gen.next<int8_t>());
+        break;
+      case 3:
+        xu.set_int16_member(gen.next<int16_t>());
+        break;
+      case 4:
+        xu.set_int32_member(gen.next<int32_t>());
+        break;
+      case 5:
+        xu.set_int64_member(gen.next<int64_t>());
+        break;
+      case 6:
+        xu.set_uint8_member(gen.next<uint8_t>());
+        break;
+      case 7:
+        xu.set_uint16_member(gen.next<uint16_t>());
+        break;
+      case 8:
+        xu.set_uint32_member(gen.next<uint32_t>());
+        break;
+      case 9:
+        xu.set_uint64_member(gen.next<uint64_t>());
+        break;
+      case 10:
+        xu.set_float32_member(gen.next<float>());
+        break;
+      case 11:
+        xu.set_float64_member(gen.next<double>());
+        break;
+      case 12:
+        xu.set_enum_member(
+            gen.choose(fidl::test::compatibility::default_enum::kOne,
+                       fidl::test::compatibility::default_enum::kZero));
+        break;
+      case 13:
+        xu.set_bits_member(
+            gen.choose(fidl::test::compatibility::default_bits::kOne,
+                       fidl::test::compatibility::default_bits::kTwo));
+        break;
+      case 14:
+        xu.set_handle_member(gen.next<zx::handle>());
+        break;
+      case 15:
+        xu.set_string_member(gen.next<std::string>());
+        break;
+      case 16:
+        xu.set_struct_member(gen.next<this_is_a_struct>());
+        break;
+      case 17:
+        xu.set_union_member(gen.next<this_is_a_union>());
+        break;
+      default:
+        EXPECT_EQ(i, 18UL);
+        return;
+    }
+    value->push_back(std::move(xu));
+  }
+}
+
+void ExpectAllTypesXunionsEq(const std::vector<AllTypesXunion>& a,
+                             const std::vector<AllTypesXunion>& b) {
+  EXPECT_EQ(a.size(), b.size());
+  for (size_t i = 0; i < a.size(); i++) {
+    if (a[i].is_handle_member()) {
+      EXPECT_TRUE(b[i].is_handle_member());
+      EXPECT_TRUE(HandlesEq(a[i].handle_member(), b[i].handle_member()));
+    } else {
+      EXPECT_TRUE(fidl::Equals(a[i], b[i]));
+    }
+  }
+}
+
 class CompatibilityTest
     : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
  protected:
@@ -925,20 +1414,29 @@
 using TestBody = std::function<void(async::Loop& loop,
                                     fidl::test::compatibility::EchoPtr& proxy,
                                     const std::string& server_url)>;
+using AllowServer = std::function<bool(const std::string& server_url)>;
 
-void ForAllServers(TestBody body) {
+void ForSomeServers(AllowServer allow, TestBody body) {
   for (auto const& proxy_url : servers) {
+    if (!allow(proxy_url)) {
+      continue;
+    }
     for (auto const& server_url : servers) {
+      if (!allow(server_url)) {
+        continue;
+      }
       std::cerr << proxy_url << " <-> " << server_url << std::endl;
       async::Loop loop(&kAsyncLoopConfigAttachToThread);
       fidl::test::compatibility::EchoClientApp proxy;
       bool test_completed = false;
-      proxy.echo().set_error_handler([&proxy_url, &loop, &test_completed](zx_status_t status) {
-        if (!test_completed) {
-          loop.Quit();
-          FAIL() << "Connection to " << proxy_url << " failed unexpectedly: " << status;
-        }
-      });
+      proxy.echo().set_error_handler(
+          [&proxy_url, &loop, &test_completed](zx_status_t status) {
+            if (!test_completed) {
+              loop.Quit();
+              FAIL() << "Connection to " << proxy_url
+                     << " failed unexpectedly: " << status;
+            }
+          });
       proxy.Start(proxy_url);
 
       body(loop, proxy.echo(), server_url);
@@ -947,11 +1445,26 @@
   }
 }
 
+void ForAllServers(TestBody body) {
+  ForSomeServers([](const std::string& _) { return true; }, body);
+}
+
+AllowServer Exclude(std::initializer_list<const char*> substrings) {
+  return [substrings](const std::string& server_url) {
+    for (auto substring : substrings) {
+      if (server_url.find(substring) != std::string::npos) {
+        return false;
+      }
+    }
+    return true;
+  };
+}
+
 TEST(Compatibility, EchoStruct) {
   ForAllServers([](async::Loop& loop, fidl::test::compatibility::EchoPtr& proxy,
                    const std::string& server_url) {
     Struct sent;
-    Initialize(&sent);
+    InitializeStruct(&sent);
 
     Struct sent_clone;
     sent.Clone(&sent_clone);
@@ -971,26 +1484,155 @@
 }
 
 TEST(Compatibility, EchoStructNoRetval) {
-  ForAllServers([](async::Loop& loop, fidl::test::compatibility::EchoPtr& proxy,
-                   const std::string& server_url) {
-    Struct sent;
-    Initialize(&sent);
+  ForSomeServers(
+      // See: FIDL-644
+      Exclude({"rust"}),
+      [](async::Loop& loop, fidl::test::compatibility::EchoPtr& proxy,
+         const std::string& server_url) {
+        Struct sent;
+        InitializeStruct(&sent);
 
-    Struct sent_clone;
-    sent.Clone(&sent_clone);
-    fidl::test::compatibility::Struct resp_clone;
-    bool event_received = false;
-    proxy.events().EchoEvent = [&loop, &resp_clone,
-                                &event_received](Struct resp) {
-      resp.Clone(&resp_clone);
-      event_received = true;
-      loop.Quit();
-    };
-    proxy->EchoStructNoRetVal(std::move(sent), server_url);
-    loop.Run();
-    ASSERT_TRUE(event_received);
-    ExpectEq(sent_clone, resp_clone);
-  });
+        Struct sent_clone;
+        sent.Clone(&sent_clone);
+        fidl::test::compatibility::Struct resp_clone;
+        bool event_received = false;
+        proxy.events().EchoEvent = [&loop, &resp_clone,
+                                    &event_received](Struct resp) {
+          resp.Clone(&resp_clone);
+          event_received = true;
+          loop.Quit();
+        };
+        proxy->EchoStructNoRetVal(std::move(sent), server_url);
+        loop.Run();
+        ASSERT_TRUE(event_received);
+        ExpectEq(sent_clone, resp_clone);
+      });
+}
+
+TEST(Compatibility, EchoArrays) {
+  ForSomeServers(
+      Exclude({"dart"}),
+      [](async::Loop& loop, fidl::test::compatibility::EchoPtr& proxy,
+         const std::string& server_url) {
+        // Using randomness to avoid having to come up with varied values by
+        // hand. Seed deterministically so that this function's outputs are
+        // predictable.
+        DataGenerator generator(0xF1D7);
+
+        ArraysStruct sent;
+        InitializeArraysStruct(&sent, generator);
+
+        ArraysStruct sent_clone;
+        sent.Clone(&sent_clone);
+        ArraysStruct resp_clone;
+        bool called_back = false;
+        proxy->EchoArrays(
+            std::move(sent), server_url,
+            [&loop, &resp_clone, &called_back](ArraysStruct resp) {
+              ASSERT_EQ(ZX_OK, resp.Clone(&resp_clone));
+              called_back = true;
+              loop.Quit();
+            });
+
+        loop.Run();
+        ASSERT_TRUE(called_back);
+        ExpectArraysStructEq(sent_clone, resp_clone);
+      });
+}
+
+TEST(Compatibility, EchoVectors) {
+  ForSomeServers(
+      Exclude({"dart"}),
+      [](async::Loop& loop, fidl::test::compatibility::EchoPtr& proxy,
+         const std::string& server_url) {
+        // Using randomness to avoid having to come up with varied values by
+        // hand. Seed deterministically so that this function's outputs are
+        // predictable.
+        DataGenerator generator(0x1234);
+
+        VectorsStruct sent;
+        InitializeVectorsStruct(&sent, generator);
+
+        VectorsStruct sent_clone;
+        sent.Clone(&sent_clone);
+        VectorsStruct resp_clone;
+        bool called_back = false;
+        proxy->EchoVectors(
+            std::move(sent), server_url,
+            [&loop, &resp_clone, &called_back](VectorsStruct resp) {
+              ASSERT_EQ(ZX_OK, resp.Clone(&resp_clone));
+              called_back = true;
+              loop.Quit();
+            });
+
+        loop.Run();
+        ASSERT_TRUE(called_back);
+        ExpectVectorsStructEq(sent_clone, resp_clone);
+      });
+}
+
+TEST(Compatibility, EchoTable) {
+  ForSomeServers(
+      // See: FIDL-644, FIDL-645
+      Exclude({"dart", "llcpp", "rust"}),
+      [](async::Loop& loop, fidl::test::compatibility::EchoPtr& proxy,
+         const std::string& server_url) {
+        // Using randomness to avoid having to come up with varied values by
+        // hand. Seed deterministically so that this function's outputs are
+        // predictable.
+        DataGenerator generator(0x1234);
+
+        AllTypesTable sent;
+        InitializeAllTypesTable(&sent, generator);
+
+        AllTypesTable sent_clone;
+        sent.Clone(&sent_clone);
+        AllTypesTable resp_clone;
+        bool called_back = false;
+        proxy->EchoTable(
+            std::move(sent), server_url,
+            [&loop, &resp_clone, &called_back](AllTypesTable resp) {
+              ASSERT_EQ(ZX_OK, resp.Clone(&resp_clone));
+              called_back = true;
+              loop.Quit();
+            });
+
+        loop.Run();
+        ASSERT_TRUE(called_back);
+        ExpectAllTypesTableEq(sent_clone, resp_clone);
+      });
+}
+
+TEST(Compatibility, EchoXunions) {
+  ForSomeServers(
+      // See: FIDL-645
+      Exclude({"dart", "llcpp"}),
+      [](async::Loop& loop, fidl::test::compatibility::EchoPtr& proxy,
+         const std::string& server_url) {
+        // Using randomness to avoid having to come up with varied values by
+        // hand. Seed deterministically so that this function's outputs are
+        // predictable.
+        DataGenerator generator(0x1234);
+
+        std::vector<AllTypesXunion> sent;
+        InitializeAllTypesXunions(&sent, generator);
+
+        std::vector<AllTypesXunion> sent_clone;
+        fidl::Clone(sent, &sent_clone);
+        std::vector<AllTypesXunion> resp_clone;
+        bool called_back = false;
+        proxy->EchoXunions(std::move(sent), server_url,
+                           [&loop, &resp_clone,
+                            &called_back](std::vector<AllTypesXunion> resp) {
+                             ASSERT_EQ(ZX_OK, fidl::Clone(resp, &resp_clone));
+                             called_back = true;
+                             loop.Quit();
+                           });
+
+        loop.Run();
+        ASSERT_TRUE(called_back);
+        ExpectAllTypesXunionsEq(sent_clone, resp_clone);
+      });
 }
 
 }  // namespace
diff --git a/garnet/bin/fidl_compatibility_test/compatibility_test_server_cpp.cc b/garnet/bin/fidl_compatibility_test/compatibility_test_server_cpp.cc
index d637762..353f354 100644
--- a/garnet/bin/fidl_compatibility_test/compatibility_test_server_cpp.cc
+++ b/garnet/bin/fidl_compatibility_test/compatibility_test_server_cpp.cc
@@ -10,6 +10,7 @@
 #include <lib/zx/channel.h>
 #include <src/lib/fxl/logging.h>
 #include <zircon/types.h>
+
 #include <cstdlib>
 #include <string>
 
@@ -33,11 +34,13 @@
     if (!forward_to_server.empty()) {
       EchoClientApp app;
       bool failed = false;
-      app.echo().set_error_handler([this, &forward_to_server, &failed](zx_status_t status) {
-        failed = true;
-        loop_->Quit();
-        FXL_LOG(ERROR) << "error communicating with " << forward_to_server << ": " << status;
-      });
+      app.echo().set_error_handler(
+          [this, &forward_to_server, &failed](zx_status_t status) {
+            failed = true;
+            loop_->Quit();
+            FXL_LOG(ERROR) << "error communicating with " << forward_to_server
+                           << ": " << status;
+          });
       app.Start(forward_to_server);
       bool called_back = false;
       app.echo()->EchoStruct(std::move(value), "",
@@ -59,10 +62,12 @@
                           std::string forward_to_server) override {
     if (!forward_to_server.empty()) {
       std::unique_ptr<EchoClientApp> app(new EchoClientApp);
-      app->echo().set_error_handler([this, &forward_to_server](zx_status_t status) {
-        loop_->Quit();
-        FXL_LOG(ERROR) << "error communicating with " << forward_to_server << ": " << status;
-      });
+      app->echo().set_error_handler(
+          [this, &forward_to_server](zx_status_t status) {
+            loop_->Quit();
+            FXL_LOG(ERROR) << "error communicating with " << forward_to_server
+                           << ": " << status;
+          });
       app->Start(forward_to_server);
       app->echo().events().EchoEvent = [this](Struct resp) {
         this->HandleEchoEvent(std::move(resp));
@@ -78,6 +83,127 @@
     }
   }
 
+  void EchoArrays(ArraysStruct value, std::string forward_to_server,
+                  EchoArraysCallback callback) override {
+    if (!forward_to_server.empty()) {
+      EchoClientApp app;
+      bool failed = false;
+      app.echo().set_error_handler(
+          [this, &forward_to_server, &failed](zx_status_t status) {
+            failed = true;
+            loop_->Quit();
+            FXL_LOG(ERROR) << "error communicating with " << forward_to_server
+                           << ": " << status;
+          });
+      app.Start(forward_to_server);
+      bool called_back = false;
+      app.echo()->EchoArrays(
+          std::move(value), "",
+          [this, &called_back, &callback](ArraysStruct resp) {
+            called_back = true;
+            callback(std::move(resp));
+            loop_->Quit();
+          });
+      while (!called_back && !failed) {
+        loop_->Run();
+      }
+      loop_->ResetQuit();
+    } else {
+      callback(std::move(value));
+    }
+  }
+
+  void EchoVectors(VectorsStruct value, std::string forward_to_server,
+                   EchoVectorsCallback callback) override {
+    if (!forward_to_server.empty()) {
+      EchoClientApp app;
+      bool failed = false;
+      app.echo().set_error_handler(
+          [this, &forward_to_server, &failed](zx_status_t status) {
+            failed = true;
+            loop_->Quit();
+            FXL_LOG(ERROR) << "error communicating with " << forward_to_server
+                           << ": " << status;
+          });
+      app.Start(forward_to_server);
+      bool called_back = false;
+      app.echo()->EchoVectors(
+          std::move(value), "",
+          [this, &called_back, &callback](VectorsStruct resp) {
+            called_back = true;
+            callback(std::move(resp));
+            loop_->Quit();
+          });
+      while (!called_back && !failed) {
+        loop_->Run();
+      }
+      loop_->ResetQuit();
+    } else {
+      callback(std::move(value));
+    }
+  }
+
+  void EchoTable(AllTypesTable value, std::string forward_to_server,
+                 EchoTableCallback callback) override {
+    if (!forward_to_server.empty()) {
+      EchoClientApp app;
+      bool failed = false;
+      app.echo().set_error_handler(
+          [this, &forward_to_server, &failed](zx_status_t status) {
+            failed = true;
+            loop_->Quit();
+            FXL_LOG(ERROR) << "error communicating with " << forward_to_server
+                           << ": " << status;
+          });
+      app.Start(forward_to_server);
+      bool called_back = false;
+      app.echo()->EchoTable(
+          std::move(value), "",
+          [this, &called_back, &callback](AllTypesTable resp) {
+            called_back = true;
+            callback(std::move(resp));
+            loop_->Quit();
+          });
+      while (!called_back && !failed) {
+        loop_->Run();
+      }
+      loop_->ResetQuit();
+    } else {
+      callback(std::move(value));
+    }
+  }
+
+  void EchoXunions(std::vector<AllTypesXunion> value,
+                   std::string forward_to_server,
+                   EchoXunionsCallback callback) override {
+    if (!forward_to_server.empty()) {
+      EchoClientApp app;
+      bool failed = false;
+      app.echo().set_error_handler(
+          [this, &forward_to_server, &failed](zx_status_t status) {
+            failed = true;
+            loop_->Quit();
+            FXL_LOG(ERROR) << "error communicating with " << forward_to_server
+                           << ": " << status;
+          });
+      app.Start(forward_to_server);
+      bool called_back = false;
+      app.echo()->EchoXunions(
+          std::move(value), "",
+          [this, &called_back, &callback](std::vector<AllTypesXunion> resp) {
+            called_back = true;
+            callback(std::move(resp));
+            loop_->Quit();
+          });
+      while (!called_back && !failed) {
+        loop_->Run();
+      }
+      loop_->ResetQuit();
+    } else {
+      callback(std::move(value));
+    }
+  }
+
  private:
   void HandleEchoEvent(Struct value) {
     for (const auto& binding : bindings_.bindings()) {
diff --git a/garnet/bin/fidl_compatibility_test/compatibility_test_server_llcpp.cc b/garnet/bin/fidl_compatibility_test/compatibility_test_server_llcpp.cc
index 7349147..4fd3838 100644
--- a/garnet/bin/fidl_compatibility_test/compatibility_test_server_llcpp.cc
+++ b/garnet/bin/fidl_compatibility_test/compatibility_test_server_llcpp.cc
@@ -33,15 +33,14 @@
       ::fidl::BytePart request_buffer, Struct value,
       ::fidl::StringView forward_to_server, ::fidl::BytePart response_buffer,
       Struct* out_value) {
-    return client_.EchoStruct(std::move(request_buffer),
-                              std::move(value), forward_to_server,
-                              std::move(response_buffer),
+    return client_.EchoStruct(std::move(request_buffer), std::move(value),
+                              forward_to_server, std::move(response_buffer),
                               out_value);
   }
 
-  zx_status_t EchoStructNoRetVal(
-      Struct value, ::fidl::StringView forward_to_server,
-      Echo::EventHandlers event_handlers) {
+  zx_status_t EchoStructNoRetVal(Struct value,
+                                 ::fidl::StringView forward_to_server,
+                                 Echo::EventHandlers event_handlers) {
     auto status =
         client_.EchoStructNoRetVal(std::move(value), forward_to_server);
     if (status != ZX_OK) {
@@ -50,6 +49,42 @@
     return client_.HandleEvents(std::move(event_handlers));
   }
 
+  ::fidl::DecodeResult<Echo::EchoArraysResponse> EchoArrays(
+      ::fidl::BytePart request_buffer, ArraysStruct value,
+      ::fidl::StringView forward_to_server, ::fidl::BytePart response_buffer,
+      ArraysStruct* out_value) {
+    return client_.EchoArrays(std::move(request_buffer), std::move(value),
+                              forward_to_server, std::move(response_buffer),
+                              out_value);
+  }
+
+  ::fidl::DecodeResult<Echo::EchoVectorsResponse> EchoVectors(
+      ::fidl::BytePart request_buffer, VectorsStruct value,
+      ::fidl::StringView forward_to_server, ::fidl::BytePart response_buffer,
+      VectorsStruct* out_value) {
+    return client_.EchoVectors(std::move(request_buffer), std::move(value),
+                               forward_to_server, std::move(response_buffer),
+                               out_value);
+  }
+
+  ::fidl::DecodeResult<Echo::EchoTableResponse> EchoTable(
+      ::fidl::BytePart request_buffer, AllTypesTable value,
+      ::fidl::StringView forward_to_server, ::fidl::BytePart response_buffer,
+      AllTypesTable* out_value) {
+    return client_.EchoTable(std::move(request_buffer), std::move(value),
+                             forward_to_server, std::move(response_buffer),
+                             out_value);
+  }
+
+  ::fidl::DecodeResult<Echo::EchoXunionsResponse> EchoXunions(
+      ::fidl::BytePart request_buffer, ::fidl::VectorView<AllTypesXunion> value,
+      ::fidl::StringView forward_to_server, ::fidl::BytePart response_buffer,
+      ::fidl::VectorView<AllTypesXunion>* out_value) {
+    return client_.EchoXunions(std::move(request_buffer), std::move(value),
+                               forward_to_server, std::move(response_buffer),
+                               out_value);
+  }
+
   EchoClientApp(const EchoClientApp&) = delete;
   EchoClientApp& operator=(const EchoClientApp&) = delete;
 
@@ -99,8 +134,7 @@
           ::fidl::BytePart(&response_buffer[0],
                            static_cast<uint32_t>(response_buffer.size())),
           &out_value);
-      ZX_ASSERT_MSG(result.status == ZX_OK,
-                    "Forwarding failed: %s",
+      ZX_ASSERT_MSG(result.status == ZX_OK, "Forwarding failed: %s",
                     result.error);
       completer.Reply(std::move(out_value));
     }
@@ -112,29 +146,117 @@
     if (forward_to_server.empty()) {
       auto status = Echo::SendEchoEventEvent(zx::unowned_channel(channel_),
                                              std::move(value));
-      ZX_ASSERT_MSG(status == ZX_OK,
-                    "Replying with event failed: %s",
+      ZX_ASSERT_MSG(status == ZX_OK, "Replying with event failed: %s",
                     zx_status_get_string(status));
     } else {
       EchoClientApp app(forward_to_server);
       zx_status_t status = app.EchoStructNoRetVal(
           std::move(value), ::fidl::StringView{0, ""},
-          Echo::EventHandlers{
-              .echo_event = [&](Struct value) {
-                  return Echo::SendEchoEventEvent(zx::unowned_channel(channel_),
-                                                  std::move(value));
-              },
-              .unknown = [] {
-                  ZX_PANIC("Received unexpected event");
-                  return ZX_ERR_INVALID_ARGS;
-              }
-          });
-      ZX_ASSERT_MSG(status == ZX_OK,
-                    "Replying with event failed: %s",
+          Echo::EventHandlers{.echo_event =
+                                  [&](Struct value) {
+                                    return Echo::SendEchoEventEvent(
+                                        zx::unowned_channel(channel_),
+                                        std::move(value));
+                                  },
+                              .unknown =
+                                  [] {
+                                    ZX_PANIC("Received unexpected event");
+                                    return ZX_ERR_INVALID_ARGS;
+                                  }});
+      ZX_ASSERT_MSG(status == ZX_OK, "Replying with event failed: %s",
                     zx_status_get_string(status));
     }
   }
 
+  void EchoArrays(ArraysStruct value, ::fidl::StringView forward_to_server,
+                  EchoArraysCompleter::Sync completer) override {
+    if (forward_to_server.empty()) {
+      completer.Reply(std::move(value));
+    } else {
+      std::vector<uint8_t> request_buffer(ZX_CHANNEL_MAX_MSG_BYTES);
+      std::vector<uint8_t> response_buffer(ZX_CHANNEL_MAX_MSG_BYTES);
+      EchoClientApp app(forward_to_server);
+      ArraysStruct out_value;
+      auto result = app.EchoArrays(
+          ::fidl::BytePart(&request_buffer[0],
+                           static_cast<uint32_t>(request_buffer.size())),
+          std::move(value), ::fidl::StringView{0, ""},
+          ::fidl::BytePart(&response_buffer[0],
+                           static_cast<uint32_t>(response_buffer.size())),
+          &out_value);
+      ZX_ASSERT_MSG(result.status == ZX_OK, "Forwarding failed: %s",
+                    result.error);
+      completer.Reply(std::move(out_value));
+    }
+  }
+
+  void EchoVectors(VectorsStruct value, ::fidl::StringView forward_to_server,
+                   EchoVectorsCompleter::Sync completer) override {
+    if (forward_to_server.empty()) {
+      completer.Reply(std::move(value));
+    } else {
+      std::vector<uint8_t> request_buffer(ZX_CHANNEL_MAX_MSG_BYTES);
+      std::vector<uint8_t> response_buffer(ZX_CHANNEL_MAX_MSG_BYTES);
+      EchoClientApp app(forward_to_server);
+      VectorsStruct out_value;
+      auto result = app.EchoVectors(
+          ::fidl::BytePart(&request_buffer[0],
+                           static_cast<uint32_t>(request_buffer.size())),
+          std::move(value), ::fidl::StringView{0, ""},
+          ::fidl::BytePart(&response_buffer[0],
+                           static_cast<uint32_t>(response_buffer.size())),
+          &out_value);
+      ZX_ASSERT_MSG(result.status == ZX_OK, "Forwarding failed: %s",
+                    result.error);
+      completer.Reply(std::move(out_value));
+    }
+  }
+
+  void EchoTable(AllTypesTable value, ::fidl::StringView forward_to_server,
+                 EchoTableCompleter::Sync completer) override {
+    if (forward_to_server.empty()) {
+      completer.Reply(std::move(value));
+    } else {
+      std::vector<uint8_t> request_buffer(ZX_CHANNEL_MAX_MSG_BYTES);
+      std::vector<uint8_t> response_buffer(ZX_CHANNEL_MAX_MSG_BYTES);
+      EchoClientApp app(forward_to_server);
+      AllTypesTable out_value;
+      auto result = app.EchoTable(
+          ::fidl::BytePart(&request_buffer[0],
+                           static_cast<uint32_t>(request_buffer.size())),
+          std::move(value), ::fidl::StringView{0, ""},
+          ::fidl::BytePart(&response_buffer[0],
+                           static_cast<uint32_t>(response_buffer.size())),
+          &out_value);
+      ZX_ASSERT_MSG(result.status == ZX_OK, "Forwarding failed: %s",
+                    result.error);
+      completer.Reply(std::move(out_value));
+    }
+  }
+
+  void EchoXunions(fidl::VectorView<AllTypesXunion> value,
+                   ::fidl::StringView forward_to_server,
+                   EchoXunionsCompleter::Sync completer) override {
+    if (forward_to_server.empty()) {
+      completer.Reply(std::move(value));
+    } else {
+      std::vector<uint8_t> request_buffer(ZX_CHANNEL_MAX_MSG_BYTES);
+      std::vector<uint8_t> response_buffer(ZX_CHANNEL_MAX_MSG_BYTES);
+      EchoClientApp app(forward_to_server);
+      fidl::VectorView<AllTypesXunion> out_value;
+      auto result = app.EchoXunions(
+          ::fidl::BytePart(&request_buffer[0],
+                           static_cast<uint32_t>(request_buffer.size())),
+          std::move(value), ::fidl::StringView{0, ""},
+          ::fidl::BytePart(&response_buffer[0],
+                           static_cast<uint32_t>(response_buffer.size())),
+          &out_value);
+      ZX_ASSERT_MSG(result.status == ZX_OK, "Forwarding failed: %s",
+                    result.error);
+      completer.Reply(std::move(out_value));
+    }
+  }
+
  private:
   zx::unowned_channel channel_;
 };
diff --git a/garnet/bin/fidl_compatibility_test/compatibility_test_server_rust.rs b/garnet/bin/fidl_compatibility_test/compatibility_test_server_rust.rs
index 7764ecc..46b8959 100644
--- a/garnet/bin/fidl_compatibility_test/compatibility_test_server_rust.rs
+++ b/garnet/bin/fidl_compatibility_test/compatibility_test_server_rust.rs
@@ -8,61 +8,112 @@
 use {
     failure::{format_err, Error, ResultExt},
     fidl_fidl_test_compatibility::{
-        EchoEvent,
-        EchoMarker,
-        EchoProxy,
-        EchoRequest,
-        EchoRequestStream,
+        EchoEvent, EchoMarker, EchoProxy, EchoRequest, EchoRequestStream,
     },
     fidl_fuchsia_sys::LauncherProxy,
     fuchsia_async as fasync,
     fuchsia_component::{
-        client::{App, launcher, launch},
+        client::{launch, launcher, App},
         server::ServiceFs,
     },
     futures::{StreamExt, TryStreamExt},
 };
 
-fn launch_and_connect_to_echo(launcher: &LauncherProxy, url: String) -> Result<(EchoProxy, App), Error> {
+fn launch_and_connect_to_echo(
+    launcher: &LauncherProxy,
+    url: String,
+) -> Result<(EchoProxy, App), Error> {
     let app = launch(&launcher, url, None)?;
     let echo = app.connect_to_service::<EchoMarker>()?;
     Ok((echo, app))
 }
 
 async fn echo_server(stream: EchoRequestStream, launcher: &LauncherProxy) -> Result<(), Error> {
-    let handler = move |request| Box::pin(async move {
-        match request {
-            EchoRequest::EchoStruct { mut value, forward_to_server, responder } => {
-                if !forward_to_server.is_empty() {
-                    let (echo, app) = launch_and_connect_to_echo(launcher, forward_to_server)
-                        .context("Error connecting to proxy")?;
-                    value = await!(echo.echo_struct(&mut value, ""))
-                        .context("Error calling echo_struct on proxy")?;
-                    drop(app);
+    let handler = move |request| {
+        Box::pin(async move {
+            match request {
+                EchoRequest::EchoStruct { mut value, forward_to_server, responder } => {
+                    if !forward_to_server.is_empty() {
+                        let (echo, app) = launch_and_connect_to_echo(launcher, forward_to_server)
+                            .context("Error connecting to proxy")?;
+                        value = await!(echo.echo_struct(&mut value, ""))
+                            .context("Error calling echo_struct on proxy")?;
+                        drop(app);
+                    }
+                    responder.send(&mut value).context("Error responding")?;
                 }
-                responder.send(&mut value)
-                    .context("Error responding")?;
-            }
-            EchoRequest::EchoStructNoRetVal { mut value, forward_to_server, control_handle } => {
-                if !forward_to_server.is_empty() {
-                    let (echo, app) = launch_and_connect_to_echo(launcher, forward_to_server)
-                        .context("Error connecting to proxy")?;
-                    echo.echo_struct_no_ret_val(&mut value, "")
-                        .context("Error sending echo_struct_no_ret_val to proxy")?;
-                    let mut event_stream = echo.take_event_stream();
-                    let EchoEvent::EchoEvent { value: response_val } =
-                        await!(event_stream.try_next())
-                            .context("Error getting event response from proxy")?
-                            .ok_or_else(|| format_err!("Proxy sent no events"))?;
-                    value = response_val;
-                    drop(app);
+                EchoRequest::EchoStructNoRetVal {
+                    mut value,
+                    forward_to_server,
+                    control_handle,
+                } => {
+                    if !forward_to_server.is_empty() {
+                        let (echo, app) = launch_and_connect_to_echo(launcher, forward_to_server)
+                            .context("Error connecting to proxy")?;
+                        echo.echo_struct_no_ret_val(&mut value, "")
+                            .context("Error sending echo_struct_no_ret_val to proxy")?;
+                        let mut event_stream = echo.take_event_stream();
+                        let EchoEvent::EchoEvent { value: response_val } =
+                            await!(event_stream.try_next())
+                                .context("Error getting event response from proxy")?
+                                .ok_or_else(|| format_err!("Proxy sent no events"))?;
+                        value = response_val;
+                        drop(app);
+                    }
+                    control_handle
+                        .send_echo_event(&mut value)
+                        .context("Error responding with event")?;
                 }
-                control_handle.send_echo_event(&mut value)
-                    .context("Error responding with event")?;
+                EchoRequest::EchoArrays { mut value, forward_to_server, responder } => {
+                    if !forward_to_server.is_empty() {
+                        let (echo, app) = launch_and_connect_to_echo(launcher, forward_to_server)
+                            .context("Error connecting to proxy")?;
+                        value = await!(echo.echo_arrays(&mut value, ""))
+                            .context("Error calling echo_arrays on proxy")?;
+                        drop(app);
+                    }
+                    responder.send(&mut value).context("Error responding")?;
+                }
+                EchoRequest::EchoVectors { mut value, forward_to_server, responder } => {
+                    if !forward_to_server.is_empty() {
+                        let (echo, app) = launch_and_connect_to_echo(launcher, forward_to_server)
+                            .context("Error connecting to proxy")?;
+                        value = await!(echo.echo_vectors(&mut value, ""))
+                            .context("Error calling echo_vectors on proxy")?;
+                        drop(app);
+                    }
+                    responder.send(&mut value).context("Error responding")?;
+                }
+                EchoRequest::EchoTable { value: _, forward_to_server: _, responder: _ } => {
+                    // Enabling this blows the stack.
+                }
+                /*
+                EchoRequest::EchoTable { mut value, forward_to_server, responder } => {
+                    if !forward_to_server.is_empty() {
+                        let (echo, app) = launch_and_connect_to_echo(launcher, forward_to_server)
+                            .context("Error connecting to proxy")?;
+                        value = await!(echo.echo_table(value, ""))
+                            .context("Error calling echo_table on proxy")?;
+                        drop(app);
+                    }
+                    responder.send(value)
+                        .context("Error responding")?;
+                }
+                */
+                EchoRequest::EchoXunions { mut value, forward_to_server, responder } => {
+                    if !forward_to_server.is_empty() {
+                        let (echo, app) = launch_and_connect_to_echo(launcher, forward_to_server)
+                            .context("Error connecting to proxy")?;
+                        value = await!(echo.echo_xunions(&mut value.iter_mut(), ""))
+                            .context("Error calling echo_xunions on proxy")?;
+                        drop(app);
+                    }
+                    responder.send(&mut value.iter_mut()).context("Error responding")?;
+                }
             }
-        }
-        Ok(())
-    });
+            Ok(())
+        })
+    };
 
     let handle_requests_fut = stream
         .err_into() // change error type from fidl::Error to failure::Error
@@ -76,13 +127,14 @@
     let launcher = launcher().context("Error connecting to application launcher")?;
 
     let mut fs = ServiceFs::new_local();
-    fs.dir("public")
-        .add_fidl_service(|stream| stream);
+    fs.dir("public").add_fidl_service(|stream| stream);
     fs.take_and_serve_directory_handle().context("Error serving directory handle")?;
 
-    let serve_fut = fs.for_each_concurrent(None /* max concurrent connections */, |stream| async {
-        if let Err(e) = await!(echo_server(stream, &launcher)) {
-            eprintln!("Closing echo server {:?}", e);
+    let serve_fut = fs.for_each_concurrent(None /* max concurrent connections */, |stream| {
+        async {
+            if let Err(e) = await!(echo_server(stream, &launcher)) {
+                eprintln!("Closing echo server {:?}", e);
+            }
         }
     });
 
diff --git a/garnet/bin/fidl_compatibility_test/golang/compatibility_test_server_go.go b/garnet/bin/fidl_compatibility_test/golang/compatibility_test_server_go.go
index 5471e26..fdee4dd 100644
--- a/garnet/bin/fidl_compatibility_test/golang/compatibility_test_server_go.go
+++ b/garnet/bin/fidl_compatibility_test/golang/compatibility_test_server_go.go
@@ -52,21 +52,20 @@
 }
 
 func (echo *echoImpl) EchoStruct(value compatibility.Struct, forwardURL string) (compatibility.Struct, error) {
-	if forwardURL != "" {
-		echoInterface, err := echo.getServer(forwardURL)
-		if err != nil {
-			log.Printf("Connecting to %s failed: %s", forwardURL, err)
-			return compatibility.Struct{}, err
-		}
-		response, err := echoInterface.EchoStruct(value, "")
-		if err != nil {
-			log.Printf("EchoStruct failed: %s", err)
-			return compatibility.Struct{}, err
-		}
-		return response, nil
+	if forwardURL == "" {
+		return value, nil
 	}
-
-	return value, nil
+	echoInterface, err := echo.getServer(forwardURL)
+	if err != nil {
+		log.Printf("Connecting to %s failed: %s", forwardURL, err)
+		return compatibility.Struct{}, err
+	}
+	response, err := echoInterface.EchoStruct(value, "")
+	if err != nil {
+		log.Printf("EchoStruct failed: %s", err)
+		return compatibility.Struct{}, err
+	}
+	return response, nil
 }
 
 func (echo *echoImpl) EchoStructNoRetVal(value compatibility.Struct, forwardURL string) error {
@@ -102,6 +101,76 @@
 	return nil
 }
 
+func (echo *echoImpl) EchoArrays(value compatibility.ArraysStruct, forwardURL string) (compatibility.ArraysStruct, error) {
+	if forwardURL == "" {
+		return value, nil
+	}
+	echoInterface, err := echo.getServer(forwardURL)
+	if err != nil {
+		log.Printf("Connecting to %s failed: %s", forwardURL, err)
+		return compatibility.ArraysStruct{}, err
+	}
+	response, err := echoInterface.EchoArrays(value, "")
+	if err != nil {
+		log.Printf("EchoArrays failed: %s", err)
+		return compatibility.ArraysStruct{}, err
+	}
+	return response, nil
+}
+
+func (echo *echoImpl) EchoVectors(value compatibility.VectorsStruct, forwardURL string) (compatibility.VectorsStruct, error) {
+	if forwardURL == "" {
+		return value, nil
+	}
+	echoInterface, err := echo.getServer(forwardURL)
+	if err != nil {
+		log.Printf("Connecting to %s failed: %s", forwardURL, err)
+		return compatibility.VectorsStruct{}, err
+	}
+	response, err := echoInterface.EchoVectors(value, "")
+	if err != nil {
+		log.Printf("EchoVectors failed: %s", err)
+		return compatibility.VectorsStruct{}, err
+	}
+	return response, nil
+}
+
+func (echo *echoImpl) EchoTable(value compatibility.AllTypesTable, forwardURL string) (compatibility.AllTypesTable, error) {
+	if forwardURL == "" {
+		return value, nil
+	}
+	echoInterface, err := echo.getServer(forwardURL)
+	if err != nil {
+		log.Printf("Connecting to %s failed: %s", forwardURL, err)
+		return compatibility.AllTypesTable{}, err
+	}
+	response, err := echoInterface.EchoTable(value, "")
+	if err != nil {
+		log.Printf("EchoTable failed: %s", err)
+		return compatibility.AllTypesTable{}, err
+	}
+	return response, nil
+
+}
+
+func (echo *echoImpl) EchoXunions(value []compatibility.AllTypesXunion, forwardURL string) ([]compatibility.AllTypesXunion, error) {
+	if forwardURL == "" {
+		return value, nil
+	}
+	echoInterface, err := echo.getServer(forwardURL)
+	if err != nil {
+		log.Printf("Connecting to %s failed: %s", forwardURL, err)
+		return nil, err
+	}
+	response, err := echoInterface.EchoXunions(value, "")
+	if err != nil {
+		log.Printf("EchoXunions failed: %s", err)
+		return nil, err
+	}
+	return response, nil
+
+}
+
 var echoService compatibility.EchoService
 
 func main() {
diff --git a/garnet/public/lib/fidl/compatibility_test/BUILD.gn b/garnet/public/lib/fidl/compatibility_test/BUILD.gn
index 5494e82..84715ad 100644
--- a/garnet/public/lib/fidl/compatibility_test/BUILD.gn
+++ b/garnet/public/lib/fidl/compatibility_test/BUILD.gn
@@ -9,7 +9,7 @@
   name = "fidl.test.compatibility"
 
   sources = [
-    "compatibility_test_service.fidl",
+    "compatibility_service.test.fidl",
   ]
 }
 
diff --git a/garnet/public/lib/fidl/compatibility_test/compatibility_test_service.fidl b/garnet/public/lib/fidl/compatibility_test/compatibility_service.test.fidl
similarity index 68%
rename from garnet/public/lib/fidl/compatibility_test/compatibility_test_service.fidl
rename to garnet/public/lib/fidl/compatibility_test/compatibility_service.test.fidl
index 7c222ac8..3ef0873 100644
--- a/garnet/public/lib/fidl/compatibility_test/compatibility_test_service.fidl
+++ b/garnet/public/lib/fidl/compatibility_test/compatibility_service.test.fidl
@@ -16,6 +16,15 @@
     bool b;
 };
 
+table this_is_a_table {
+    1: string s;
+};
+
+xunion this_is_a_xunion {
+    string s;
+    bool b;
+};
+
 struct primitive_types {
     bool b;
     int8 i8;
@@ -333,6 +342,44 @@
     kSeven = 7;
     kEight = 8;
 };
+bits default_bits {
+    kOne = 1;
+    kTwo = 2;
+};
+bits u8_bits:uint8 {
+    kOne = 1;
+    kTwo = 2;
+    kThree = 4;
+    kFour = 8;
+    kFive = 16;
+};
+bits u16_bits:uint16 {
+    kOne = 1;
+    kTwo = 2;
+    kThree = 4;
+    kFour = 8;
+    kFive = 16;
+    kSix = 32;
+};
+bits u32_bits:uint32 {
+    kOne = 1;
+    kTwo = 2;
+    kThree = 4;
+    kFour = 8;
+    kFive = 16;
+    kSix = 32;
+    kSeven = 64;
+};
+bits u64_bits:uint64 {
+    kOne = 1;
+    kTwo = 2;
+    kThree = 4;
+    kFour = 8;
+    kFive = 16;
+    kSix = 32;
+    kSeven = 64;
+    kEight = 128;
+};
 
 struct structs {
     this_is_a_struct s;
@@ -363,11 +410,128 @@
     u16_enum u16_enum;
     u32_enum u32_enum;
     u64_enum u64_enum;
+    default_bits default_bits;
+    u8_bits u8_bits;
+    u16_bits u16_bits;
+    u32_bits u32_bits;
+    u64_bits u64_bits;
     structs structs;
     unions unions;
+    this_is_a_table table;
+    this_is_a_xunion xunion;
     bool b;
 };
 
+// This struct contains arrays of all different kinds of FIDL types.
+struct ArraysStruct {
+    array<bool>:arrays_size bools;
+    array<int8>:arrays_size int8s;
+    array<int16>:arrays_size int16s;
+    array<int32>:arrays_size int32s;
+    array<int64>:arrays_size int64s;
+    array<uint8>:arrays_size uint8s;
+    array<uint16>:arrays_size uint16s;
+    array<uint32>:arrays_size uint32s;
+    array<uint64>:arrays_size uint64s;
+    array<float32>:arrays_size float32s;
+    array<float64>:arrays_size float64s;
+    array<default_enum>:arrays_size enums;
+    array<default_bits>:arrays_size bits;
+    array<handle>:arrays_size handles;
+    array<handle?>:arrays_size nullable_handles;
+    array<string>:arrays_size strings;
+    array<string?>:arrays_size nullable_strings;
+    array<this_is_a_struct>:arrays_size structs;
+    array<this_is_a_struct?>:arrays_size nullable_structs;
+    array<this_is_a_union>:arrays_size unions;
+    array<this_is_a_union?>:arrays_size nullable_unions;
+    array<array<uint32>:arrays_size>:arrays_size arrays;
+    array<vector<uint32>>:arrays_size vectors;
+    array<vector<uint32>?>:arrays_size nullable_vectors;
+    array<this_is_a_table>:arrays_size tables;
+    array<this_is_a_xunion>:arrays_size xunions;
+};
+
+// This struct contains vectors of all different kinds of FIDL types.
+struct VectorsStruct {
+    vector<bool>:vectors_size bools;
+    vector<int8>:vectors_size int8s;
+    vector<int16>:vectors_size int16s;
+    vector<int32>:vectors_size int32s;
+    vector<int64>:vectors_size int64s;
+    vector<uint8>:vectors_size uint8s;
+    vector<uint16>:vectors_size uint16s;
+    vector<uint32>:vectors_size uint32s;
+    vector<uint64>:vectors_size uint64s;
+    vector<float32>:vectors_size float32s;
+    vector<float64>:vectors_size float64s;
+    vector<default_enum>:vectors_size enums;
+    vector<default_bits>:vectors_size bits;
+    vector<handle>:vectors_size handles;
+    vector<handle?>:vectors_size nullable_handles;
+    vector<string>:vectors_size strings;
+    vector<string?>:vectors_size nullable_strings;
+    vector<this_is_a_struct>:vectors_size structs;
+    vector<this_is_a_struct?>:vectors_size nullable_structs;
+    vector<this_is_a_union>:vectors_size unions;
+    vector<this_is_a_union?>:vectors_size nullable_unions;
+    vector<array<uint32>:vectors_size>:vectors_size arrays;
+    vector<vector<uint32>>:vectors_size vectors;
+    vector<vector<uint32>?>:vectors_size nullable_vectors;
+    vector<this_is_a_table>:vectors_size tables;
+    vector<this_is_a_xunion>:vectors_size xunions;
+};
+
+// This table has members all different FIDL types.
+table AllTypesTable {
+    1: bool bool_member;
+    2: int8 int8_member;
+    3: int16 int16_member;
+    4: int32 int32_member;
+    5: int64 int64_member;
+    6: uint8 uint8_member;
+    7: uint16 uint16_member;
+    8: uint32 uint32_member;
+    9: uint64 uint64_member;
+    10: float32 float32_member;
+    11: float64 float64_member;
+    12: default_enum enum_member;
+    13: default_bits bits_member;
+    14: handle handle_member;
+    15: string string_member;
+    16: this_is_a_struct struct_member;
+    17: this_is_a_union union_member;
+    18: array<uint32>:arrays_size array_member;
+    19: vector<uint32> vector_member;
+    20: this_is_a_table table_member;
+    21: this_is_a_xunion xunion_member;
+};
+
+// This xunion has members all different FIDL types.
+xunion AllTypesXunion {
+    bool bool_member;
+    int8 int8_member;
+    int16 int16_member;
+    int32 int32_member;
+    int64 int64_member;
+    uint8 uint8_member;
+    uint16 uint16_member;
+    uint32 uint32_member;
+    uint64 uint64_member;
+    float32 float32_member;
+    float64 float64_member;
+    default_enum enum_member;
+    default_bits bits_member;
+    handle handle_member;
+    string string_member;
+    this_is_a_struct struct_member;
+    this_is_a_union union_member;
+    array<uint32>:arrays_size array_member;
+    vector<uint32> vector_member;
+    this_is_a_table table_member;
+    this_is_a_xunion xunion_member;
+};
+
 [Discoverable]
 protocol Echo {
     // If |forward_to_server| is empty, just returns |value|.
@@ -380,4 +544,16 @@
     // response, rather than a return value.
     EchoStructNoRetVal(Struct value, string forward_to_server);
     -> EchoEvent(Struct value);
+
+    [Transitional]
+    EchoArrays(ArraysStruct value, string forward_to_server) -> (ArraysStruct value);
+
+    [Transitional]
+    EchoVectors(VectorsStruct value, string forward_to_server) -> (VectorsStruct value);
+
+    [Transitional]
+    EchoTable(AllTypesTable value, string forward_to_server) -> (AllTypesTable value);
+
+    [Transitional]
+    EchoXunions(vector<AllTypesXunion> value, string forward_to_server) -> (vector<AllTypesXunion> value);
 };