blob: 0d3115cc5f4d9f65ea3e1b9b4ba841dd215eb4ec [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <limits>
#include "garnet/bin/zxdb/common/err.h"
#include "garnet/bin/zxdb/expr/cast.h"
#include "garnet/bin/zxdb/expr/expr_value.h"
#include "garnet/bin/zxdb/symbols/base_type.h"
#include "garnet/bin/zxdb/symbols/modified_type.h"
#include "garnet/bin/zxdb/symbols/type_test_support.h"
#include "gtest/gtest.h"
namespace zxdb {
TEST(Cast, Coerce) {
auto int32_type = MakeInt32Type();
auto uint32_type = MakeInt32Type();
auto int64_type = MakeInt64Type();
auto uint64_type = MakeInt64Type();
auto char_type =
fxl::MakeRefCounted<BaseType>(BaseType::kBaseTypeSignedChar, 1, "char");
auto bool_type =
fxl::MakeRefCounted<BaseType>(BaseType::kBaseTypeBoolean, 1, "bool");
auto float_type =
fxl::MakeRefCounted<BaseType>(BaseType::kBaseTypeFloat, 4, "float");
auto double_type =
fxl::MakeRefCounted<BaseType>(BaseType::kBaseTypeFloat, 8, "double");
ExprValue int32_one(int32_type, {1, 0, 0, 0}, ExprValueSource());
ExprValue int32_minus_one(int32_type, {0xff, 0xff, 0xff, 0xff},
ExprValueSource());
// Simple identity conversion.
ExprValue result;
Err err = CoerceValueTo(int32_one, int32_type, ExprValueSource(), &result);
EXPECT_FALSE(err.has_error());
EXPECT_EQ(int32_one, result);
// Signed/unsigned conversion, should just copy the bits (end up with
// 0xffffffff),
err = CoerceValueTo(int32_minus_one, uint32_type, ExprValueSource(), &result);
EXPECT_FALSE(err.has_error());
EXPECT_EQ(uint32_type.get(), result.type());
EXPECT_EQ(int32_minus_one.data(), result.data());
// Signed integer promotion.
err = CoerceValueTo(int32_minus_one, uint64_type, ExprValueSource(), &result);
EXPECT_FALSE(err.has_error());
EXPECT_EQ(uint64_type.get(), result.type());
EXPECT_EQ(std::numeric_limits<uint64_t>::max(), result.GetAs<uint64_t>());
// Integer truncation
err = CoerceValueTo(int32_minus_one, char_type, ExprValueSource(), &result);
EXPECT_FALSE(err.has_error());
EXPECT_EQ(char_type.get(), result.type());
EXPECT_EQ(-1, result.GetAs<int8_t>());
// Zero integer to boolean.
ExprValue int32_zero(int32_type, {0, 0, 0, 0}, ExprValueSource());
err = CoerceValueTo(int32_zero, bool_type, ExprValueSource(), &result);
EXPECT_FALSE(err.has_error());
EXPECT_EQ(bool_type.get(), result.type());
EXPECT_EQ(0, result.GetAs<int8_t>());
// Nonzero integer to boolean.
err = CoerceValueTo(int32_minus_one, bool_type, ExprValueSource(), &result);
EXPECT_FALSE(err.has_error());
EXPECT_EQ(bool_type.get(), result.type());
EXPECT_EQ(1, result.GetAs<int8_t>());
// Zero floating point to boolean.
ExprValue float_minus_zero(float_type, {0, 0, 0, 0x80}, ExprValueSource());
err = CoerceValueTo(float_minus_zero, bool_type, ExprValueSource(), &result);
EXPECT_FALSE(err.has_error());
EXPECT_EQ(0, result.GetAs<int8_t>());
// Nonzero floating point to boolean.
ExprValue float_one_third(float_type, {0xab, 0xaa, 0xaa, 0x3e},
ExprValueSource());
err = CoerceValueTo(float_one_third, bool_type, ExprValueSource(), &result);
EXPECT_FALSE(err.has_error());
EXPECT_EQ(1, result.GetAs<int8_t>());
// Float to signed.
ExprValue float_minus_two(float_type, {0x00, 0x00, 0x00, 0xc0},
ExprValueSource());
err = CoerceValueTo(float_minus_two, int32_type, ExprValueSource(), &result);
EXPECT_FALSE(err.has_error());
EXPECT_EQ(-2, result.GetAs<int32_t>());
// Float to unsigned.
err = CoerceValueTo(float_minus_two, uint64_type, ExprValueSource(), &result);
EXPECT_FALSE(err.has_error());
EXPECT_EQ(static_cast<uint64_t>(-2), result.GetAs<uint64_t>());
// Floating point promption.
err = CoerceValueTo(float_minus_two, double_type, ExprValueSource(), &result);
EXPECT_FALSE(err.has_error());
EXPECT_EQ(-2.0, result.GetAs<double>());
ExprValue double_minus_two = result;
// Floating point truncation.
err = CoerceValueTo(double_minus_two, float_type, ExprValueSource(), &result);
EXPECT_FALSE(err.has_error());
EXPECT_EQ(-2.0f, result.GetAs<float>());
// Pointer to integer with truncation.
auto ptr_to_double_type = fxl::MakeRefCounted<ModifiedType>(
Symbol::kTagPointerType, LazySymbol(double_type));
ExprValue ptr_value(ptr_to_double_type,
{0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12},
ExprValueSource());
err = CoerceValueTo(ptr_value, uint32_type, ExprValueSource(), &result);
EXPECT_FALSE(err.has_error());
EXPECT_EQ(0x9abcdef0, result.GetAs<uint32_t>());
ExprValue big_int_value = result;
// Integer to pointer with expansion.
err = CoerceValueTo(int32_minus_one, ptr_to_double_type, ExprValueSource(),
&result);
EXPECT_FALSE(err.has_error());
EXPECT_EQ(-1, result.GetAs<int64_t>());
}
} // namespace zxdb