one-of-test.c++ (6023B)
1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors 2 // Licensed under the MIT License: 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining a copy 5 // of this software and associated documentation files (the "Software"), to deal 6 // in the Software without restriction, including without limitation the rights 7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 // copies of the Software, and to permit persons to whom the Software is 9 // furnished to do so, subject to the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included in 12 // all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 // THE SOFTWARE. 21 22 #include "one-of.h" 23 #include "string.h" 24 #include <kj/compat/gtest.h> 25 26 namespace kj { 27 28 TEST(OneOf, Basic) { 29 OneOf<int, float, String> var; 30 31 EXPECT_FALSE(var.is<int>()); 32 EXPECT_FALSE(var.is<float>()); 33 EXPECT_FALSE(var.is<String>()); 34 EXPECT_TRUE(var.tryGet<int>() == nullptr); 35 EXPECT_TRUE(var.tryGet<float>() == nullptr); 36 EXPECT_TRUE(var.tryGet<String>() == nullptr); 37 38 var.init<int>(123); 39 40 EXPECT_TRUE(var.is<int>()); 41 EXPECT_FALSE(var.is<float>()); 42 EXPECT_FALSE(var.is<String>()); 43 44 EXPECT_EQ(123, var.get<int>()); 45 #if !KJ_NO_EXCEPTIONS && defined(KJ_DEBUG) 46 EXPECT_ANY_THROW(var.get<float>()); 47 EXPECT_ANY_THROW(var.get<String>()); 48 #endif 49 50 EXPECT_EQ(123, KJ_ASSERT_NONNULL(var.tryGet<int>())); 51 EXPECT_TRUE(var.tryGet<float>() == nullptr); 52 EXPECT_TRUE(var.tryGet<String>() == nullptr); 53 54 var.init<String>(kj::str("foo")); 55 56 EXPECT_FALSE(var.is<int>()); 57 EXPECT_FALSE(var.is<float>()); 58 EXPECT_TRUE(var.is<String>()); 59 60 EXPECT_EQ("foo", var.get<String>()); 61 62 EXPECT_TRUE(var.tryGet<int>() == nullptr); 63 EXPECT_TRUE(var.tryGet<float>() == nullptr); 64 EXPECT_EQ("foo", KJ_ASSERT_NONNULL(var.tryGet<String>())); 65 66 OneOf<int, float, String> var2 = kj::mv(var); 67 EXPECT_EQ("", var.get<String>()); 68 EXPECT_EQ("foo", var2.get<String>()); 69 70 var = kj::mv(var2); 71 EXPECT_EQ("foo", var.get<String>()); 72 EXPECT_EQ("", var2.get<String>()); 73 74 auto canCompile KJ_UNUSED = [&]() { 75 var.allHandled<3>(); 76 // var.allHandled<2>(); // doesn't compile 77 }; 78 } 79 80 TEST(OneOf, Copy) { 81 OneOf<int, float, const char*> var; 82 83 OneOf<int, float, const char*> var2 = var; 84 EXPECT_FALSE(var2.is<int>()); 85 EXPECT_FALSE(var2.is<float>()); 86 EXPECT_FALSE(var2.is<const char*>()); 87 88 var.init<int>(123); 89 90 var2 = var; 91 EXPECT_TRUE(var2.is<int>()); 92 EXPECT_EQ(123, var2.get<int>()); 93 94 var.init<const char*>("foo"); 95 96 var2 = var; 97 EXPECT_TRUE(var2.is<const char*>()); 98 EXPECT_STREQ("foo", var2.get<const char*>()); 99 } 100 101 TEST(OneOf, Switch) { 102 OneOf<int, float, const char*> var; 103 var = "foo"; 104 uint count = 0; 105 106 { 107 KJ_SWITCH_ONEOF(var) { 108 KJ_CASE_ONEOF(i, int) { 109 KJ_FAIL_ASSERT("expected char*, got int", i); 110 } 111 KJ_CASE_ONEOF(s, const char*) { 112 KJ_EXPECT(kj::StringPtr(s) == "foo"); 113 ++count; 114 } 115 KJ_CASE_ONEOF(n, float) { 116 KJ_FAIL_ASSERT("expected char*, got float", n); 117 } 118 } 119 } 120 121 KJ_EXPECT(count == 1); 122 123 { 124 KJ_SWITCH_ONEOF(kj::cp(var)) { 125 KJ_CASE_ONEOF(i, int) { 126 KJ_FAIL_ASSERT("expected char*, got int", i); 127 } 128 KJ_CASE_ONEOF(s, const char*) { 129 KJ_EXPECT(kj::StringPtr(s) == "foo"); 130 } 131 KJ_CASE_ONEOF(n, float) { 132 KJ_FAIL_ASSERT("expected char*, got float", n); 133 } 134 } 135 } 136 137 { 138 // At one time this failed to compile. 139 const auto& constVar = var; 140 KJ_SWITCH_ONEOF(constVar) { 141 KJ_CASE_ONEOF(i, int) { 142 KJ_FAIL_ASSERT("expected char*, got int", i); 143 } 144 KJ_CASE_ONEOF(s, const char*) { 145 KJ_EXPECT(kj::StringPtr(s) == "foo"); 146 } 147 KJ_CASE_ONEOF(n, float) { 148 KJ_FAIL_ASSERT("expected char*, got float", n); 149 } 150 } 151 } 152 } 153 154 TEST(OneOf, Maybe) { 155 Maybe<OneOf<int, float>> var; 156 var = OneOf<int, float>(123); 157 158 KJ_IF_MAYBE(v, var) { 159 // At one time this failed to compile. Note that a Maybe<OneOf<...>> isn't necessarily great 160 // style -- you might be better off with an explicit OneOf<Empty, ...>. Nevertheless, it should 161 // compile. 162 KJ_SWITCH_ONEOF(*v) { 163 KJ_CASE_ONEOF(i, int) { 164 KJ_EXPECT(i == 123); 165 } 166 KJ_CASE_ONEOF(n, float) { 167 KJ_FAIL_ASSERT("expected int, got float", n); 168 } 169 } 170 } 171 } 172 173 KJ_TEST("OneOf copy/move from alternative variants") { 174 { 175 // Test const copy. 176 const OneOf<int, float> src = 23.5f; 177 OneOf<int, bool, float> dst = src; 178 KJ_ASSERT(dst.is<float>()); 179 KJ_EXPECT(dst.get<float>() == 23.5); 180 } 181 182 { 183 // Test case that requires non-const copy. 184 int arr[3] = {1, 2, 3}; 185 OneOf<int, ArrayPtr<int>> src = ArrayPtr<int>(arr); 186 OneOf<int, bool, ArrayPtr<int>> dst = src; 187 KJ_ASSERT(dst.is<ArrayPtr<int>>()); 188 KJ_EXPECT(dst.get<ArrayPtr<int>>().begin() == arr); 189 KJ_EXPECT(dst.get<ArrayPtr<int>>().size() == kj::size(arr)); 190 } 191 192 { 193 // Test move. 194 OneOf<int, String> src = kj::str("foo"); 195 OneOf<int, bool, String> dst = kj::mv(src); 196 KJ_ASSERT(dst.is<String>()); 197 KJ_EXPECT(dst.get<String>() == "foo"); 198 199 String s = kj::mv(dst).get<String>(); 200 KJ_EXPECT(s == "foo"); 201 } 202 203 { 204 // We can still have nested OneOfs. 205 OneOf<int, float> src = 23.5f; 206 OneOf<bool, OneOf<int, float>> dst = src; 207 KJ_ASSERT((dst.is<OneOf<int, float>>())); 208 KJ_ASSERT((dst.get<OneOf<int, float>>().is<float>())); 209 KJ_EXPECT((dst.get<OneOf<int, float>>().get<float>() == 23.5)); 210 } 211 } 212 213 } // namespace kj