Add lots more tests for dap::any.

Exercise copy, assign, moves.
diff --git a/src/any_test.cpp b/src/any_test.cpp
index 2028d8c..ab1ebb7 100644
--- a/src/any_test.cpp
+++ b/src/any_test.cpp
@@ -31,8 +31,52 @@
                     DAP_FIELD(i, "i"),
                     DAP_FIELD(n, "n"));
 
+inline bool operator==(const AnyTestObject& a, const AnyTestObject& b) {
+  return a.i == b.i && a.n == b.n;
+}
+
 }  // namespace dap
 
+namespace {
+
+template <typename T>
+struct TestValue {};
+
+template <>
+struct TestValue<dap::integer> {
+  static const dap::integer value;
+};
+template <>
+struct TestValue<dap::boolean> {
+  static const dap::boolean value;
+};
+template <>
+struct TestValue<dap::number> {
+  static const dap::number value;
+};
+template <>
+struct TestValue<dap::string> {
+  static const dap::string value;
+};
+template <>
+struct TestValue<dap::array<dap::string>> {
+  static const dap::array<dap::string> value;
+};
+template <>
+struct TestValue<dap::AnyTestObject> {
+  static const dap::AnyTestObject value;
+};
+
+const dap::integer TestValue<dap::integer>::value = 20;
+const dap::boolean TestValue<dap::boolean>::value = true;
+const dap::number TestValue<dap::number>::value = 123.45;
+const dap::string TestValue<dap::string>::value = "hello world";
+const dap::array<dap::string> TestValue<dap::array<dap::string>>::value = {
+    "one", "two", "three"};
+const dap::AnyTestObject TestValue<dap::AnyTestObject>::value = {10, 20.30};
+
+}  // namespace
+
 TEST(Any, EmptyConstruct) {
   dap::any any;
   ASSERT_TRUE(any.is<dap::null>());
@@ -105,32 +149,84 @@
   ASSERT_EQ(any.get<dap::AnyTestObject>().n, 3.0);
 }
 
-TEST(Any, Assign) {
-  dap::any any;
-  any = dap::integer(10);
-  ASSERT_TRUE(any.is<dap::integer>());
-  ASSERT_FALSE(any.is<dap::boolean>());
-  ASSERT_FALSE(any.is<dap::AnyTestObject>());
-  ASSERT_EQ(any.get<dap::integer>(), dap::integer(10));
-  any = dap::boolean(true);
-  ASSERT_FALSE(any.is<dap::integer>());
-  ASSERT_TRUE(any.is<dap::boolean>());
-  ASSERT_FALSE(any.is<dap::AnyTestObject>());
-  ASSERT_EQ(any.get<dap::boolean>(), dap::boolean(true));
-  any = dap::AnyTestObject{5, 3.0};
-  ASSERT_FALSE(any.is<dap::integer>());
-  ASSERT_FALSE(any.is<dap::boolean>());
-  ASSERT_TRUE(any.is<dap::AnyTestObject>());
-  ASSERT_EQ(any.get<dap::AnyTestObject>().i, 5);
-  ASSERT_EQ(any.get<dap::AnyTestObject>().n, 3.0);
-  any = dap::string("hello world");
-  ASSERT_FALSE(any.is<dap::integer>());
-  ASSERT_FALSE(any.is<dap::boolean>());
-  ASSERT_FALSE(any.is<dap::AnyTestObject>());
-  ASSERT_TRUE(any.is<dap::string>());
-  ASSERT_EQ(any.get<dap::string>(), dap::string("hello world"));
+template <typename T>
+class AnyT : public ::testing::Test {
+ protected:
+  void check(const dap::any& any, const T& expect) {
+    ASSERT_EQ(any.is<dap::integer>(), (std::is_same<T, dap::integer>::value));
+    ASSERT_EQ(any.is<dap::boolean>(), (std::is_same<T, dap::boolean>::value));
+    ASSERT_EQ(any.is<dap::number>(), (std::is_same<T, dap::number>::value));
+    ASSERT_EQ(any.is<dap::string>(), (std::is_same<T, dap::string>::value));
+    ASSERT_EQ(any.is<dap::array<dap::string>>(),
+              (std::is_same<T, dap::array<dap::string>>::value));
+    ASSERT_EQ(any.is<dap::AnyTestObject>(),
+              (std::is_same<T, dap::AnyTestObject>::value));
+
+    ASSERT_EQ(any.get<T>(), expect);
+  }
+};
+TYPED_TEST_SUITE_P(AnyT);
+
+TYPED_TEST_P(AnyT, CopyConstruct) {
+  auto val = TestValue<TypeParam>::value;
+  dap::any any(val);
+  this->check(any, val);
 }
 
+TYPED_TEST_P(AnyT, MoveConstruct) {
+  auto val = TestValue<TypeParam>::value;
+  dap::any any(std::move(val));
+  this->check(any, val);
+}
+
+TYPED_TEST_P(AnyT, Assign) {
+  auto val = TestValue<TypeParam>::value;
+  dap::any any;
+  any = val;
+  this->check(any, val);
+}
+
+TYPED_TEST_P(AnyT, MoveAssign) {
+  auto val = TestValue<TypeParam>::value;
+  dap::any any;
+  any = std::move(val);
+  this->check(any, val);
+}
+
+TYPED_TEST_P(AnyT, RepeatedAssign) {
+  dap::string str = "hello world";
+  auto val = TestValue<TypeParam>::value;
+  dap::any any;
+  any = str;
+  any = val;
+  this->check(any, val);
+}
+
+TYPED_TEST_P(AnyT, RepeatedMoveAssign) {
+  dap::string str = "hello world";
+  auto val = TestValue<TypeParam>::value;
+  dap::any any;
+  any = std::move(str);
+  any = std::move(val);
+  this->check(any, val);
+}
+
+REGISTER_TYPED_TEST_SUITE_P(AnyT,
+                            CopyConstruct,
+                            MoveConstruct,
+                            Assign,
+                            MoveAssign,
+                            RepeatedAssign,
+                            RepeatedMoveAssign);
+
+using AnyTypes = ::testing::Types<dap::integer,
+                                  dap::boolean,
+                                  dap::number,
+                                  dap::string,
+                                  dap::array<dap::string>,
+                                  dap::AnyTestObject>;
+INSTANTIATE_TYPED_TEST_SUITE_P(T, AnyT, AnyTypes);
+
 TEST(Any, Reset) {
   dap::any any(dap::integer(10));
   ASSERT_TRUE(any.is<dap::integer>());