/* * Copyright (c) 2021, Jan de Visser * Copyright (c) 2022, Tim Flynn * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include TEST_CASE(null_value) { SQL::Value v(SQL::SQLType::Null); EXPECT_EQ(v.type(), SQL::SQLType::Null); EXPECT_EQ(v.to_deprecated_string(), "(null)"sv); EXPECT(!v.to_bool().has_value()); EXPECT(!v.to_int().has_value()); EXPECT(!v.to_int().has_value()); EXPECT(!v.to_double().has_value()); } TEST_CASE(assign_null) { SQL::Value v("Test"); EXPECT_EQ(v.type(), SQL::SQLType::Text); EXPECT(!v.is_null()); v = SQL::Value(); EXPECT_EQ(v.type(), SQL::SQLType::Null); EXPECT(v.is_null()); } TEST_CASE(text_value) { { SQL::Value v(SQL::SQLType::Text); EXPECT_EQ(v.type(), SQL::SQLType::Text); EXPECT(v.is_null()); v = "Test"sv; EXPECT_EQ(v.type(), SQL::SQLType::Text); EXPECT_EQ(v.to_deprecated_string(), "Test"sv); } { SQL::Value v(DeprecatedString("String Test"sv)); EXPECT_EQ(v.type(), SQL::SQLType::Text); EXPECT_EQ(v.to_deprecated_string(), "String Test"sv); v = DeprecatedString("String Test 2"sv); EXPECT_EQ(v.type(), SQL::SQLType::Text); EXPECT_EQ(v.to_deprecated_string(), "String Test 2"sv); } { SQL::Value v("const char * Test"); EXPECT_EQ(v.type(), SQL::SQLType::Text); EXPECT_EQ(v.to_deprecated_string(), "const char * Test"sv); v = "const char * Test 2"; EXPECT_EQ(v.type(), SQL::SQLType::Text); EXPECT_EQ(v.to_deprecated_string(), "const char * Test 2"sv); } } TEST_CASE(text_value_to_other_types) { { SQL::Value v("42"); EXPECT_EQ(v.type(), SQL::SQLType::Text); EXPECT(v.to_int().has_value()); EXPECT_EQ(v.to_int().value(), 42); EXPECT(v.to_double().has_value()); EXPECT((v.to_double().value() - 42.0) < NumericLimits().epsilon()); } { SQL::Value v("true"); EXPECT_EQ(v.type(), SQL::SQLType::Text); EXPECT(v.to_bool().has_value()); EXPECT(v.to_bool().value()); } { SQL::Value v("false"); EXPECT_EQ(v.type(), SQL::SQLType::Text); EXPECT(v.to_bool().has_value()); EXPECT(!v.to_bool().value()); } { SQL::Value v("foo"); EXPECT_EQ(v.type(), SQL::SQLType::Text); EXPECT(!v.to_bool().has_value()); EXPECT(!v.to_int().has_value()); EXPECT(!v.to_int().has_value()); EXPECT(!v.to_double().has_value()); } { SQL::Value v("3.14"); EXPECT_EQ(v.type(), SQL::SQLType::Text); EXPECT(v.to_double().has_value()); EXPECT((v.to_double().value() - 3.14) < NumericLimits().epsilon()); } } TEST_CASE(assign_int_to_text_value) { SQL::Value v(SQL::SQLType::Text); EXPECT_EQ(v.type(), SQL::SQLType::Text); EXPECT(v.is_null()); v = 42; EXPECT_EQ(v.type(), SQL::SQLType::Integer); EXPECT_EQ(v, 42); } TEST_CASE(serialize_text_value) { SQL::Value v("Test"); EXPECT_EQ(v.type(), SQL::SQLType::Text); EXPECT_EQ(v, "Test"sv); SQL::Serializer serializer; serializer.serialize(v); serializer.rewind(); auto v2 = serializer.deserialize(); EXPECT_EQ(v2.type(), SQL::SQLType::Text); EXPECT_EQ(v2, "Test"sv); EXPECT_EQ(v2, v); } TEST_CASE(integer_value) { { SQL::Value v(SQL::SQLType::Integer); EXPECT_EQ(v.type(), SQL::SQLType::Integer); EXPECT(v.is_null()); v = 42; EXPECT_EQ(v.type(), SQL::SQLType::Integer); EXPECT(v.to_int().has_value()); EXPECT_EQ(v.to_int().value(), 42); EXPECT_EQ(v.to_deprecated_string(), "42"sv); EXPECT(v.to_double().has_value()); EXPECT((v.to_double().value() - 42.0) < NumericLimits().epsilon()); EXPECT(v.to_bool().has_value()); EXPECT(v.to_bool().value()); } { SQL::Value v(0); EXPECT_EQ(v.type(), SQL::SQLType::Integer); EXPECT(v.to_int().has_value()); EXPECT_EQ(v.to_int().value(), 0); EXPECT(v.to_bool().has_value()); EXPECT(!v.to_bool().value()); } { SQL::Value v(42); EXPECT_EQ(v.type(), SQL::SQLType::Integer); EXPECT(v.to_int().has_value()); EXPECT_EQ(v.to_int().value(), 42); } { SQL::Value text("42"); SQL::Value integer(SQL::SQLType::Integer); integer = text; EXPECT(integer.to_int().has_value()); EXPECT_EQ(integer.to_int().value(), 42); } } TEST_CASE(serialize_int_value) { SQL::Value v(42); EXPECT_EQ(v.type(), SQL::SQLType::Integer); EXPECT_EQ(v, 42); SQL::Serializer serializer; serializer.serialize(v); serializer.rewind(); auto v2 = serializer.deserialize(); EXPECT_EQ(v2.type(), SQL::SQLType::Integer); EXPECT_EQ(v2, 42); EXPECT_EQ(v2, v); } TEST_CASE(serialize_downsized_int_value) { auto run_test_for_value = [](auto value) { using T = decltype(value); SQL::Value v(value); SQL::Serializer serializer; serializer.serialize(v); serializer.rewind(); auto type_flags = serializer.deserialize(); auto type_data = type_flags & 0xf0; auto type = static_cast(type_flags & 0x0f); EXPECT_NE(type_data, 0); EXPECT_EQ(type, SQL::SQLType::Integer); auto deserialized = serializer.deserialize(); EXPECT_EQ(deserialized, value); }; run_test_for_value(NumericLimits::min()); run_test_for_value(NumericLimits::max()); run_test_for_value(NumericLimits::min()); run_test_for_value(NumericLimits::max()); run_test_for_value(NumericLimits::min()); run_test_for_value(NumericLimits::max()); run_test_for_value(NumericLimits::min()); run_test_for_value(NumericLimits::max()); run_test_for_value(NumericLimits::min()); run_test_for_value(NumericLimits::max()); run_test_for_value(NumericLimits::min()); run_test_for_value(NumericLimits::max()); run_test_for_value(NumericLimits::min()); run_test_for_value(NumericLimits::max()); run_test_for_value(NumericLimits::min()); run_test_for_value(NumericLimits::max()); } TEST_CASE(float_value) { { SQL::Value v(SQL::SQLType::Float); EXPECT_EQ(v.type(), SQL::SQLType::Float); EXPECT(v.is_null()); v = 3.14; EXPECT_EQ(v.type(), SQL::SQLType::Float); EXPECT(v.to_double().has_value()); EXPECT((v.to_double().value() - 3.14) < NumericLimits().epsilon()); EXPECT(v.to_int().has_value()); EXPECT_EQ(v.to_int().value(), 3); EXPECT_EQ(v.to_deprecated_string(), "3.14"); EXPECT(v.to_bool().has_value()); EXPECT(v.to_bool().value()); v = 0.0; EXPECT_EQ(v.type(), SQL::SQLType::Float); EXPECT(v.to_double().has_value()); EXPECT(v.to_double().value() < NumericLimits().epsilon()); EXPECT(v.to_int().has_value()); EXPECT_EQ(v.to_int().value(), 0); EXPECT_EQ(v.to_deprecated_string(), "0"sv); EXPECT(v.to_bool().has_value()); EXPECT(!v.to_bool().value()); } { SQL::Value v(3.14); EXPECT_EQ(v.type(), SQL::SQLType::Float); EXPECT((v.to_double().value() - 3.14) < NumericLimits().epsilon()); } { SQL::Value v(3.51); EXPECT_EQ(v.type(), SQL::SQLType::Float); EXPECT(v.to_int().has_value()); EXPECT_EQ(v.to_int().value(), 4); } { SQL::Value v(-3.14); EXPECT_EQ(v.type(), SQL::SQLType::Float); EXPECT(v.to_int().has_value()); EXPECT_EQ(v.to_int().value(), -3); } { SQL::Value v(-3.51); EXPECT_EQ(v.type(), SQL::SQLType::Float); EXPECT(v.to_int().has_value()); EXPECT_EQ(v.to_int().value(), -4); } } TEST_CASE(serialize_float_value) { SQL::Value v(3.14); EXPECT_EQ(v.type(), SQL::SQLType::Float); EXPECT(v.to_double().value() - 3.14 < NumericLimits().epsilon()); SQL::Serializer serializer; serializer.serialize(v); serializer.rewind(); auto v2 = serializer.deserialize(); EXPECT_EQ(v2.type(), SQL::SQLType::Float); EXPECT((v.to_double().value() - 3.14) < NumericLimits().epsilon()); EXPECT_EQ(v2, v); } TEST_CASE(copy_value) { SQL::Value text("42"); SQL::Value copy(text); EXPECT_EQ(copy, "42"sv); } TEST_CASE(to_int) { SQL::Value text("42"); SQL::Value integer(42); EXPECT_EQ(text, integer); EXPECT_EQ(integer, text); SQL::Value int_64 { static_cast(123) }; EXPECT_EQ(int_64.to_int(), 123); EXPECT_EQ(int_64.to_int(), 123); EXPECT_EQ(int_64.to_int(), 123); EXPECT_EQ(int_64.to_int(), 123u); EXPECT_EQ(int_64.to_int(), 123u); EXPECT_EQ(int_64.to_int(), 123u); EXPECT_EQ(int_64.to_int(), 123u); SQL::Value uint_64 { static_cast(123) }; EXPECT_EQ(uint_64.to_int(), 123); EXPECT_EQ(uint_64.to_int(), 123); EXPECT_EQ(uint_64.to_int(), 123); EXPECT_EQ(uint_64.to_int(), 123); EXPECT_EQ(uint_64.to_int(), 123u); EXPECT_EQ(uint_64.to_int(), 123u); EXPECT_EQ(uint_64.to_int(), 123u); } TEST_CASE(to_int_failures) { SQL::Value large_int_64 { NumericLimits::max() }; EXPECT(!large_int_64.to_int().has_value()); EXPECT(!large_int_64.to_int().has_value()); EXPECT(!large_int_64.to_int().has_value()); EXPECT(!large_int_64.to_int().has_value()); EXPECT(!large_int_64.to_int().has_value()); EXPECT(!large_int_64.to_int().has_value()); SQL::Value large_int_32 { NumericLimits::max() }; EXPECT(!large_int_32.to_int().has_value()); EXPECT(!large_int_32.to_int().has_value()); EXPECT(!large_int_32.to_int().has_value()); EXPECT(!large_int_32.to_int().has_value()); SQL::Value small_int_64 { NumericLimits::min() }; EXPECT(!small_int_64.to_int().has_value()); EXPECT(!small_int_64.to_int().has_value()); EXPECT(!small_int_64.to_int().has_value()); EXPECT(!small_int_64.to_int().has_value()); EXPECT(!small_int_64.to_int().has_value()); EXPECT(!small_int_64.to_int().has_value()); EXPECT(!small_int_64.to_int().has_value()); SQL::Value small_int_32 { NumericLimits::min() }; EXPECT(!small_int_32.to_int().has_value()); EXPECT(!small_int_32.to_int().has_value()); EXPECT(!small_int_32.to_int().has_value()); EXPECT(!small_int_32.to_int().has_value()); EXPECT(!small_int_32.to_int().has_value()); EXPECT(!small_int_32.to_int().has_value()); SQL::Value large_uint_64 { NumericLimits::max() }; EXPECT(!large_uint_64.to_int().has_value()); EXPECT(!large_uint_64.to_int().has_value()); EXPECT(!large_uint_64.to_int().has_value()); EXPECT(!large_uint_64.to_int().has_value()); EXPECT(!large_uint_64.to_int().has_value()); EXPECT(!large_uint_64.to_int().has_value()); EXPECT(!large_uint_64.to_int().has_value()); SQL::Value large_uint_32 { NumericLimits::max() }; EXPECT(!large_uint_32.to_int().has_value()); EXPECT(!large_uint_32.to_int().has_value()); EXPECT(!large_uint_32.to_int().has_value()); EXPECT(!large_uint_32.to_int().has_value()); } TEST_CASE(bool_value) { { SQL::Value v(SQL::SQLType::Boolean); EXPECT_EQ(v.type(), SQL::SQLType::Boolean); EXPECT(v.is_null()); v = true; EXPECT_EQ(v.type(), SQL::SQLType::Boolean); EXPECT(v.to_bool().has_value()); EXPECT(v.to_bool().value()); EXPECT(v.to_int().has_value()); EXPECT_EQ(v.to_int().value(), 1); EXPECT_EQ(v.to_deprecated_string(), "true"sv); EXPECT(v.to_double().has_value()); EXPECT((v.to_double().value() - 1.0) < NumericLimits().epsilon()); } { SQL::Value v(false); EXPECT_EQ(v.type(), SQL::SQLType::Boolean); EXPECT(v.to_bool().has_value()); EXPECT(!v.to_bool().value()); EXPECT(v.to_int().has_value()); EXPECT_EQ(v.to_int().value(), 0); EXPECT_EQ(v.to_deprecated_string(), "false"sv); EXPECT(v.to_double().has_value()); EXPECT(v.to_double().value() < NumericLimits().epsilon()); } { SQL::Value v(true); EXPECT_EQ(v.type(), SQL::SQLType::Boolean); EXPECT(v.to_bool().has_value()); EXPECT(v.to_bool().value()); EXPECT(v.to_int().has_value()); EXPECT_EQ(v.to_int().value(), 1); EXPECT_EQ(v.to_deprecated_string(), "true"sv); EXPECT(v.to_double().has_value()); EXPECT((v.to_double().value() - 1.0) < NumericLimits().epsilon()); } } TEST_CASE(serialize_boolean_value) { SQL::Value v(true); EXPECT_EQ(v.type(), SQL::SQLType::Boolean); EXPECT_EQ(v.to_bool(), true); SQL::Serializer serializer; serializer.serialize(v); serializer.rewind(); auto v2 = serializer.deserialize(); EXPECT_EQ(v2.type(), SQL::SQLType::Boolean); EXPECT_EQ(v2.to_bool(), true); EXPECT_EQ(v, v2); } TEST_CASE(tuple_value) { NonnullRefPtr descriptor = adopt_ref(*new SQL::TupleDescriptor); descriptor->append({ "schema", "table", "col1", SQL::SQLType::Text, SQL::Order::Ascending }); descriptor->append({ "schema", "table", "col2", SQL::SQLType::Integer, SQL::Order::Descending }); auto v = MUST(SQL::Value::create_tuple(move(descriptor))); Vector values; values.empend("Test"); values.empend(42); MUST(v.assign_tuple(values)); auto values2 = v.to_vector(); EXPECT(values2.has_value()); EXPECT_EQ(values, values2.value()); } TEST_CASE(copy_tuple_value) { NonnullRefPtr descriptor = adopt_ref(*new SQL::TupleDescriptor); descriptor->append({ "schema", "table", "col1", SQL::SQLType::Text, SQL::Order::Ascending }); descriptor->append({ "schema", "table", "col2", SQL::SQLType::Integer, SQL::Order::Descending }); auto v = MUST(SQL::Value::create_tuple(move(descriptor))); Vector values; values.empend("Test"); values.empend(42); MUST(v.assign_tuple(values)); auto values2 = v; EXPECT_EQ(values2.type(), v.type()); EXPECT_EQ(v.type(), SQL::SQLType::Tuple); EXPECT_EQ(values, values2.to_vector().value()); } TEST_CASE(tuple_value_wrong_type) { NonnullRefPtr descriptor = adopt_ref(*new SQL::TupleDescriptor); descriptor->append({ "schema", "table", "col1", SQL::SQLType::Text, SQL::Order::Ascending }); auto v = MUST(SQL::Value::create_tuple(move(descriptor))); Vector values; values.empend(42); auto result = v.assign_tuple(move(values)); EXPECT(result.is_error()); } TEST_CASE(tuple_value_too_many_values) { NonnullRefPtr descriptor = adopt_ref(*new SQL::TupleDescriptor); descriptor->append({ "schema", "table", "col1", SQL::SQLType::Text, SQL::Order::Ascending }); auto v = MUST(SQL::Value::create_tuple(move(descriptor))); Vector values; values.empend("Test"); values.empend(42); auto result = v.assign_tuple(move(values)); EXPECT(result.is_error()); } TEST_CASE(tuple_value_not_enough_values) { NonnullRefPtr descriptor = adopt_ref(*new SQL::TupleDescriptor); descriptor->append({ "schema", "table", "col1", SQL::SQLType::Text, SQL::Order::Ascending }); descriptor->append({ "schema", "table", "col2", SQL::SQLType::Integer, SQL::Order::Ascending }); auto v = MUST(SQL::Value::create_tuple(move(descriptor))); Vector values; values.empend("Test"); MUST(v.assign_tuple(values)); EXPECT_EQ(v.type(), SQL::SQLType::Tuple); auto values_opt = v.to_vector(); EXPECT(values_opt.has_value()); EXPECT_EQ(values_opt.value().size(), 2u); auto col2 = values_opt.value()[1]; EXPECT_EQ(col2.type(), SQL::SQLType::Integer); } TEST_CASE(serialize_tuple_value) { NonnullRefPtr descriptor = adopt_ref(*new SQL::TupleDescriptor); descriptor->append({ "schema", "table", "col1", SQL::SQLType::Text, SQL::Order::Ascending }); descriptor->append({ "schema", "table", "col2", SQL::SQLType::Integer, SQL::Order::Descending }); auto v = MUST(SQL::Value::create_tuple(move(descriptor))); Vector values; values.empend("Test"); values.empend(42); MUST(v.assign_tuple(values)); SQL::Serializer serializer; serializer.serialize(v); serializer.rewind(); auto v2 = serializer.deserialize(); EXPECT_EQ(v2.type(), SQL::SQLType::Tuple); EXPECT_EQ(v, v2); } TEST_CASE(order_text_values) { SQL::Value v1(SQL::SQLType::Text); v1 = "Test_A"; SQL::Value v2(SQL::SQLType::Text); v2 = "Test_B"; EXPECT(v1 <= v2); EXPECT(v1 < v2); EXPECT(v2 >= v1); EXPECT(v2 > v1); } TEST_CASE(order_int_values) { SQL::Value v1(SQL::SQLType::Integer); v1 = 12; SQL::Value v2(SQL::SQLType::Integer); v2 = 42; EXPECT(v1 <= v2); EXPECT(v1 < v2); EXPECT(v2 >= v1); EXPECT(v2 > v1); } TEST_CASE(tuple) { NonnullRefPtr descriptor = adopt_ref(*new SQL::TupleDescriptor); descriptor->append({ "schema", "table", "col1", SQL::SQLType::Text, SQL::Order::Ascending }); descriptor->append({ "schema", "table", "col2", SQL::SQLType::Integer, SQL::Order::Descending }); SQL::Tuple tuple(descriptor); tuple["col1"] = "Test"; tuple["col2"] = 42; EXPECT_EQ(tuple[0], "Test"sv); EXPECT_EQ(tuple[1], 42); } TEST_CASE(serialize_tuple) { NonnullRefPtr descriptor = adopt_ref(*new SQL::TupleDescriptor); descriptor->append({ "schema", "table", "col1", SQL::SQLType::Text, SQL::Order::Ascending }); descriptor->append({ "schema", "table", "col2", SQL::SQLType::Integer, SQL::Order::Descending }); SQL::Tuple tuple(descriptor); tuple["col1"] = "Test"; tuple["col2"] = 42; EXPECT_EQ(tuple[0], "Test"sv); EXPECT_EQ(tuple[1], 42); SQL::Serializer serializer; serializer.serialize(tuple); serializer.rewind(); auto tuple2 = serializer.deserialize(); EXPECT_EQ(tuple2[0], "Test"sv); EXPECT_EQ(tuple2[1], 42); } TEST_CASE(copy_tuple) { NonnullRefPtr descriptor = adopt_ref(*new SQL::TupleDescriptor); descriptor->append({ "schema", "table", "col1", SQL::SQLType::Text, SQL::Order::Ascending }); descriptor->append({ "schema", "table", "col2", SQL::SQLType::Integer, SQL::Order::Descending }); SQL::Tuple tuple(descriptor); tuple["col1"] = "Test"; tuple["col2"] = 42; SQL::Tuple copy; copy = tuple; EXPECT_EQ(tuple, copy); SQL::Tuple copy_2(copy); EXPECT_EQ(tuple, copy_2); } TEST_CASE(compare_tuples) { NonnullRefPtr descriptor = adopt_ref(*new SQL::TupleDescriptor); descriptor->append({ "schema", "table", "col1", SQL::SQLType::Text, SQL::Order::Ascending }); descriptor->append({ "schema", "table", "col2", SQL::SQLType::Integer, SQL::Order::Descending }); SQL::Tuple tuple1(descriptor); tuple1["col1"] = "Test"; tuple1["col2"] = 42; SQL::Tuple tuple2(descriptor); tuple2["col1"] = "Test"; tuple2["col2"] = 12; SQL::Tuple tuple3(descriptor); tuple3["col1"] = "Text"; tuple3["col2"] = 12; EXPECT(tuple1 <= tuple2); EXPECT(tuple1 < tuple2); EXPECT(tuple2 >= tuple1); EXPECT(tuple2 > tuple1); EXPECT(tuple1 <= tuple3); EXPECT(tuple1 < tuple3); EXPECT(tuple3 >= tuple1); EXPECT(tuple3 > tuple1); } TEST_CASE(add) { { SQL::Value value1 { 21 }; SQL::Value value2 { 42 }; auto result = value1.add(value2); EXPECT(!result.is_error()); EXPECT_EQ(result.value().type(), SQL::SQLType::Integer); EXPECT_EQ(result.value(), 63); } { SQL::Value value1 { 21 }; SQL::Value value2 { static_cast(42) }; auto result = value1.add(value2); EXPECT(!result.is_error()); EXPECT_EQ(result.value().type(), SQL::SQLType::Integer); EXPECT_EQ(result.value(), 63); } { SQL::Value value1 { static_cast(21) }; SQL::Value value2 { 42 }; auto result = value1.add(value2); EXPECT(!result.is_error()); EXPECT_EQ(result.value().type(), SQL::SQLType::Integer); EXPECT_EQ(result.value(), 63); } { SQL::Value value1 { static_cast(21) }; SQL::Value value2 { 42 }; auto result = value1.add(value2); EXPECT(!result.is_error()); EXPECT_EQ(result.value().type(), SQL::SQLType::Integer); EXPECT_EQ(result.value(), 63); } { SQL::Value value1 { static_cast(21.5) }; SQL::Value value2 { 42 }; auto result = value1.add(value2); EXPECT(!result.is_error()); EXPECT_EQ(result.value().type(), SQL::SQLType::Float); EXPECT((result.value().to_double().value() - 63.5) < NumericLimits().epsilon()); } } TEST_CASE(add_error) { { // Fails to coerce value2 to the signedness of value1. SQL::Value value1 { 1 }; SQL::Value value2 { NumericLimits::max() }; auto result = value1.add(value2); EXPECT(result.is_error()); EXPECT_EQ(result.error().error(), SQL::SQLErrorCode::IntegerOverflow); } { // Fails to coerce value2 to the signedness of value1. SQL::Value value1 { static_cast(1) }; SQL::Value value2 { -1 }; auto result = value1.add(value2); EXPECT(result.is_error()); EXPECT_EQ(result.error().error(), SQL::SQLErrorCode::IntegerOverflow); } { // The operation itself would overflow. SQL::Value value1 { static_cast(1) }; SQL::Value value2 { NumericLimits::max() }; auto result = value1.add(value2); EXPECT(result.is_error()); EXPECT_EQ(result.error().error(), SQL::SQLErrorCode::IntegerOverflow); } { // Cannot convert value to a number. SQL::Value value1 { 1 }; SQL::Value value2 { "foo"sv }; auto result = value1.add(value2); EXPECT(result.is_error()); EXPECT_EQ(result.error().error(), SQL::SQLErrorCode::NumericOperatorTypeMismatch); } } TEST_CASE(subtract) { { SQL::Value value1 { 21 }; SQL::Value value2 { 42 }; auto result = value1.subtract(value2); EXPECT(!result.is_error()); EXPECT_EQ(result.value().type(), SQL::SQLType::Integer); EXPECT_EQ(result.value(), -21); } { SQL::Value value1 { 21 }; SQL::Value value2 { static_cast(42) }; auto result = value1.subtract(value2); EXPECT(!result.is_error()); EXPECT_EQ(result.value().type(), SQL::SQLType::Integer); EXPECT_EQ(result.value(), -21); } { SQL::Value value1 { static_cast(42) }; SQL::Value value2 { 21 }; auto result = value1.subtract(value2); EXPECT(!result.is_error()); EXPECT_EQ(result.value().type(), SQL::SQLType::Integer); EXPECT_EQ(result.value(), 21); } { SQL::Value value1 { static_cast(21) }; SQL::Value value2 { 42 }; auto result = value1.subtract(value2); EXPECT(!result.is_error()); EXPECT_EQ(result.value().type(), SQL::SQLType::Integer); EXPECT_EQ(result.value(), -21); } { SQL::Value value1 { static_cast(21.5) }; SQL::Value value2 { 42 }; auto result = value1.subtract(value2); EXPECT(!result.is_error()); EXPECT_EQ(result.value().type(), SQL::SQLType::Float); EXPECT((result.value().to_double().value() - 20.5) < NumericLimits().epsilon()); } } TEST_CASE(subtract_error) { { // Fails to coerce value2 to the signedness of value1. SQL::Value value1 { 1 }; SQL::Value value2 { NumericLimits::max() }; auto result = value1.subtract(value2); EXPECT(result.is_error()); EXPECT_EQ(result.error().error(), SQL::SQLErrorCode::IntegerOverflow); } { // Fails to coerce value2 to the signedness of value1. SQL::Value value1 { static_cast(1) }; SQL::Value value2 { -1 }; auto result = value1.subtract(value2); EXPECT(result.is_error()); EXPECT_EQ(result.error().error(), SQL::SQLErrorCode::IntegerOverflow); } { // The operation itself would overflow. SQL::Value value1 { static_cast(0) }; SQL::Value value2 { static_cast(1) }; auto result = value1.subtract(value2); EXPECT(result.is_error()); EXPECT_EQ(result.error().error(), SQL::SQLErrorCode::IntegerOverflow); } { // Cannot convert value to a number. SQL::Value value1 { 1 }; SQL::Value value2 { "foo"sv }; auto result = value1.subtract(value2); EXPECT(result.is_error()); EXPECT_EQ(result.error().error(), SQL::SQLErrorCode::NumericOperatorTypeMismatch); } } TEST_CASE(multiply) { { SQL::Value value1 { 2 }; SQL::Value value2 { 21 }; auto result = value1.multiply(value2); EXPECT(!result.is_error()); EXPECT_EQ(result.value().type(), SQL::SQLType::Integer); EXPECT_EQ(result.value(), 42); } { SQL::Value value1 { 2 }; SQL::Value value2 { static_cast(21) }; auto result = value1.multiply(value2); EXPECT(!result.is_error()); EXPECT_EQ(result.value().type(), SQL::SQLType::Integer); EXPECT_EQ(result.value(), 42); } { SQL::Value value1 { static_cast(2) }; SQL::Value value2 { 21 }; auto result = value1.multiply(value2); EXPECT(!result.is_error()); EXPECT_EQ(result.value().type(), SQL::SQLType::Integer); EXPECT_EQ(result.value(), 42); } { SQL::Value value1 { static_cast(2) }; SQL::Value value2 { 21 }; auto result = value1.multiply(value2); EXPECT(!result.is_error()); EXPECT_EQ(result.value().type(), SQL::SQLType::Integer); EXPECT_EQ(result.value(), 42); } { SQL::Value value1 { static_cast(2.5) }; SQL::Value value2 { 21 }; auto result = value1.multiply(value2); EXPECT(!result.is_error()); EXPECT_EQ(result.value().type(), SQL::SQLType::Float); EXPECT((result.value().to_double().value() - 52.5) < NumericLimits().epsilon()); } } TEST_CASE(multiply_error) { { // Fails to coerce value2 to the signedness of value1. SQL::Value value1 { 1 }; SQL::Value value2 { NumericLimits::max() }; auto result = value1.multiply(value2); EXPECT(result.is_error()); EXPECT_EQ(result.error().error(), SQL::SQLErrorCode::IntegerOverflow); } { // Fails to coerce value2 to the signedness of value1. SQL::Value value1 { static_cast(1) }; SQL::Value value2 { -1 }; auto result = value1.multiply(value2); EXPECT(result.is_error()); EXPECT_EQ(result.error().error(), SQL::SQLErrorCode::IntegerOverflow); } { // The operation itself would overflow. SQL::Value value1 { NumericLimits::max() }; SQL::Value value2 { 2 }; auto result = value1.multiply(value2); EXPECT(result.is_error()); EXPECT_EQ(result.error().error(), SQL::SQLErrorCode::IntegerOverflow); } { // Cannot convert value to a number. SQL::Value value1 { 1 }; SQL::Value value2 { "foo"sv }; auto result = value1.multiply(value2); EXPECT(result.is_error()); EXPECT_EQ(result.error().error(), SQL::SQLErrorCode::NumericOperatorTypeMismatch); } } TEST_CASE(divide) { { SQL::Value value1 { 42 }; SQL::Value value2 { -2 }; auto result = value1.divide(value2); EXPECT(!result.is_error()); EXPECT_EQ(result.value().type(), SQL::SQLType::Integer); EXPECT_EQ(result.value(), -21); } { SQL::Value value1 { 42 }; SQL::Value value2 { static_cast(2) }; auto result = value1.divide(value2); EXPECT(!result.is_error()); EXPECT_EQ(result.value().type(), SQL::SQLType::Integer); EXPECT_EQ(result.value(), 21); } { SQL::Value value1 { static_cast(42) }; SQL::Value value2 { 2 }; auto result = value1.divide(value2); EXPECT(!result.is_error()); EXPECT_EQ(result.value().type(), SQL::SQLType::Integer); EXPECT_EQ(result.value(), 21); } { SQL::Value value1 { static_cast(42) }; SQL::Value value2 { 2 }; auto result = value1.divide(value2); EXPECT(!result.is_error()); EXPECT_EQ(result.value().type(), SQL::SQLType::Integer); EXPECT_EQ(result.value(), 21); } { SQL::Value value1 { static_cast(43) }; SQL::Value value2 { 2 }; auto result = value1.divide(value2); EXPECT(!result.is_error()); EXPECT_EQ(result.value().type(), SQL::SQLType::Float); EXPECT((result.value().to_double().value() - 21.5) < NumericLimits().epsilon()); } } TEST_CASE(divide_error) { { // The operation itself would overflow. SQL::Value value1 { 1 }; SQL::Value value2 { 0 }; auto result = value1.divide(value2); EXPECT(result.is_error()); EXPECT_EQ(result.error().error(), SQL::SQLErrorCode::IntegerOverflow); } { // Cannot convert value to a number. SQL::Value value1 { 1 }; SQL::Value value2 { "foo"sv }; auto result = value1.divide(value2); EXPECT(result.is_error()); EXPECT_EQ(result.error().error(), SQL::SQLErrorCode::NumericOperatorTypeMismatch); } } TEST_CASE(modulo) { { SQL::Value value1 { 21 }; SQL::Value value2 { 2 }; auto result = value1.modulo(value2); EXPECT(!result.is_error()); EXPECT_EQ(result.value().type(), SQL::SQLType::Integer); EXPECT_EQ(result.value(), 1); } { SQL::Value value1 { 21 }; SQL::Value value2 { static_cast(2) }; auto result = value1.modulo(value2); EXPECT(!result.is_error()); EXPECT_EQ(result.value().type(), SQL::SQLType::Integer); EXPECT_EQ(result.value(), 1); } { SQL::Value value1 { static_cast(21) }; SQL::Value value2 { 2 }; auto result = value1.modulo(value2); EXPECT(!result.is_error()); EXPECT_EQ(result.value().type(), SQL::SQLType::Integer); EXPECT_EQ(result.value(), 1); } { SQL::Value value1 { static_cast(21) }; SQL::Value value2 { 2 }; auto result = value1.modulo(value2); EXPECT(!result.is_error()); EXPECT_EQ(result.value().type(), SQL::SQLType::Integer); EXPECT_EQ(result.value(), 1); } } TEST_CASE(modulo_error) { { // Fails to coerce value2 to the signedness of value1. SQL::Value value1 { 1 }; SQL::Value value2 { NumericLimits::max() }; auto result = value1.modulo(value2); EXPECT(result.is_error()); EXPECT_EQ(result.error().error(), SQL::SQLErrorCode::IntegerOverflow); } { // Fails to coerce value2 to the signedness of value1. SQL::Value value1 { static_cast(1) }; SQL::Value value2 { -1 }; auto result = value1.modulo(value2); EXPECT(result.is_error()); EXPECT_EQ(result.error().error(), SQL::SQLErrorCode::IntegerOverflow); } { // The operation itself would overflow. SQL::Value value1 { 21 }; SQL::Value value2 { 0 }; auto result = value1.modulo(value2); EXPECT(result.is_error()); EXPECT_EQ(result.error().error(), SQL::SQLErrorCode::IntegerOverflow); } { // Cannot convert value to an integer. SQL::Value value1 { 1 }; SQL::Value value2 { "foo"sv }; auto result = value1.modulo(value2); EXPECT(result.is_error()); EXPECT_EQ(result.error().error(), SQL::SQLErrorCode::NumericOperatorTypeMismatch); } { // Cannot convert value to an integer. SQL::Value value1 { static_cast(21.5) }; SQL::Value value2 { 2 }; auto result = value1.modulo(value2); EXPECT(result.is_error()); EXPECT_EQ(result.error().error(), SQL::SQLErrorCode::NumericOperatorTypeMismatch); } } TEST_CASE(shift_left) { { SQL::Value value1 { 0b0011'0000 }; SQL::Value value2 { 2 }; auto result = value1.shift_left(value2); EXPECT(!result.is_error()); EXPECT_EQ(result.value().type(), SQL::SQLType::Integer); EXPECT_EQ(result.value(), 0b1100'0000); } { SQL::Value value1 { 0b0011'0000 }; SQL::Value value2 { static_cast(2) }; auto result = value1.shift_left(value2); EXPECT(!result.is_error()); EXPECT_EQ(result.value().type(), SQL::SQLType::Integer); EXPECT_EQ(result.value(), 0b1100'0000); } { SQL::Value value1 { static_cast(0b0011'0000) }; SQL::Value value2 { 2 }; auto result = value1.shift_left(value2); EXPECT(!result.is_error()); EXPECT_EQ(result.value().type(), SQL::SQLType::Integer); EXPECT_EQ(result.value(), 0b1100'0000); } { SQL::Value value1 { static_cast(0b0011'0000) }; SQL::Value value2 { 2 }; auto result = value1.shift_left(value2); EXPECT(!result.is_error()); EXPECT_EQ(result.value().type(), SQL::SQLType::Integer); EXPECT_EQ(result.value(), 0b1100'0000); } } TEST_CASE(shift_left_error) { { // Fails to coerce value2 to the signedness of value1. SQL::Value value1 { 1 }; SQL::Value value2 { NumericLimits::max() }; auto result = value1.shift_left(value2); EXPECT(result.is_error()); EXPECT_EQ(result.error().error(), SQL::SQLErrorCode::IntegerOverflow); } { // Fails to coerce value2 to the signedness of value1. SQL::Value value1 { static_cast(1) }; SQL::Value value2 { -1 }; auto result = value1.shift_left(value2); EXPECT(result.is_error()); EXPECT_EQ(result.error().error(), SQL::SQLErrorCode::IntegerOverflow); } { // The operation itself would overflow. SQL::Value value1 { 21 }; SQL::Value value2 { -1 }; auto result = value1.shift_left(value2); EXPECT(result.is_error()); EXPECT_EQ(result.error().error(), SQL::SQLErrorCode::IntegerOverflow); } { // The operation itself would overflow. SQL::Value value1 { 21 }; SQL::Value value2 { 64 }; auto result = value1.shift_left(value2); EXPECT(result.is_error()); EXPECT_EQ(result.error().error(), SQL::SQLErrorCode::IntegerOverflow); } { // Cannot convert value to an integer. SQL::Value value1 { 1 }; SQL::Value value2 { "foo"sv }; auto result = value1.shift_left(value2); EXPECT(result.is_error()); EXPECT_EQ(result.error().error(), SQL::SQLErrorCode::NumericOperatorTypeMismatch); } { // Cannot convert value to an integer. SQL::Value value1 { static_cast(21.5) }; SQL::Value value2 { 2 }; auto result = value1.shift_left(value2); EXPECT(result.is_error()); EXPECT_EQ(result.error().error(), SQL::SQLErrorCode::NumericOperatorTypeMismatch); } } TEST_CASE(shift_right) { { SQL::Value value1 { 0b0011'0000 }; SQL::Value value2 { 2 }; auto result = value1.shift_right(value2); EXPECT(!result.is_error()); EXPECT_EQ(result.value().type(), SQL::SQLType::Integer); EXPECT_EQ(result.value(), 0b0000'1100); } { SQL::Value value1 { 0b0011'0000 }; SQL::Value value2 { static_cast(2) }; auto result = value1.shift_right(value2); EXPECT(!result.is_error()); EXPECT_EQ(result.value().type(), SQL::SQLType::Integer); EXPECT_EQ(result.value(), 0b0000'1100); } { SQL::Value value1 { static_cast(0b0011'0000) }; SQL::Value value2 { 2 }; auto result = value1.shift_right(value2); EXPECT(!result.is_error()); EXPECT_EQ(result.value().type(), SQL::SQLType::Integer); EXPECT_EQ(result.value(), 0b0000'1100); } { SQL::Value value1 { static_cast(0b0011'0000) }; SQL::Value value2 { 2 }; auto result = value1.shift_right(value2); EXPECT(!result.is_error()); EXPECT_EQ(result.value().type(), SQL::SQLType::Integer); EXPECT_EQ(result.value(), 0b0000'1100); } } TEST_CASE(shift_right_error) { { // Fails to coerce value2 to the signedness of value1. SQL::Value value1 { 1 }; SQL::Value value2 { NumericLimits::max() }; auto result = value1.shift_right(value2); EXPECT(result.is_error()); EXPECT_EQ(result.error().error(), SQL::SQLErrorCode::IntegerOverflow); } { // Fails to coerce value2 to the signedness of value1. SQL::Value value1 { static_cast(1) }; SQL::Value value2 { -1 }; auto result = value1.shift_right(value2); EXPECT(result.is_error()); EXPECT_EQ(result.error().error(), SQL::SQLErrorCode::IntegerOverflow); } { // The operation itself would overflow. SQL::Value value1 { 21 }; SQL::Value value2 { -1 }; auto result = value1.shift_right(value2); EXPECT(result.is_error()); EXPECT_EQ(result.error().error(), SQL::SQLErrorCode::IntegerOverflow); } { // The operation itself would overflow. SQL::Value value1 { 21 }; SQL::Value value2 { 64 }; auto result = value1.shift_right(value2); EXPECT(result.is_error()); EXPECT_EQ(result.error().error(), SQL::SQLErrorCode::IntegerOverflow); } { // Cannot convert value to an integer. SQL::Value value1 { 1 }; SQL::Value value2 { "foo"sv }; auto result = value1.shift_right(value2); EXPECT(result.is_error()); EXPECT_EQ(result.error().error(), SQL::SQLErrorCode::NumericOperatorTypeMismatch); } { // Cannot convert value to an integer. SQL::Value value1 { static_cast(21.5) }; SQL::Value value2 { 2 }; auto result = value1.shift_right(value2); EXPECT(result.is_error()); EXPECT_EQ(result.error().error(), SQL::SQLErrorCode::NumericOperatorTypeMismatch); } }