blob: bc8409447171e379f13d2279caa3ae2deb067a52 [file]
// Part of the Crubit project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "support/rstd/char.h"
#include <stdint.h>
#include <type_traits>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
namespace {
// Check that `rstd::Char` is trivially destructible, copyable, and moveable.
//
// There are no constructor-related checks, because well-formed-ness checks
// will make construction non-trivial. The FromAsciiLiteral, FromUtf32Literal,
// etc. tests ensure that `rstd::Char` provide test coverage for certain
// construction-related scenarios.
static_assert(std::is_trivially_destructible_v<rstd::Char>);
static_assert(std::is_trivially_copy_constructible_v<rstd::Char>);
static_assert(std::is_trivially_copy_assignable_v<rstd::Char>);
static_assert(std::is_trivially_move_constructible_v<rstd::Char>);
static_assert(std::is_trivially_move_assignable_v<rstd::Char>);
// Layout tests.
//
// https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#char
// documents that "Rust char is 32-bit wide and represents an unicode scalar
// value".
//
// We don't map Rust's `char` to C++ `char32_t` because
// - It may be wider than 32 bits - <internal link>/c/string/multibyte/char32_t says
// that "char32_t is an unsigned integer type used for 32-bit wide characters
// and is the same type as uint_least32_t. uint_least32_t is the smallest
// unsigned integer type with width of at least 32 bits"
// - It is problematic on MacOS - https://github.com/eqrion/cbindgen/issues/423
// points out that `uchar.h` is missing on that platform.
static_assert(sizeof(rstd::Char) == 4);
static_assert(alignof(rstd::Char) == 4);
static_assert(std::is_standard_layout_v<rstd::Char>);
// This test covers the following case from
// https://en.cppreference.com/w/cpp/language/character_literal:
//
// Ordinary character literal, e.g. 'a' or '\n' or '\13'. Such literal has type
// `char` and the value equal to either:
// - the representation of c-char in the execution character set (until C++23)
// - the corresponding code point from ordinary literal encoding (since C++23).
TEST(RsCharTest, FromAsciiLiteral) {
rstd::Char c = 'x';
EXPECT_EQ(0x78, static_cast<uint32_t>(c));
}
// This test covers the following case from
// https://en.cppreference.com/w/cpp/language/character_literal:
//
// UTF-8 character literal, e.g. u8'a'. Such literal has type `char` (until
// C++20) or `char8_t` (since C++20) and the value equal to ISO/IEC 10646 code
// point value of c-char, provided that the code point value is representable
// with a single UTF-8 code unit (that is, c-char is in the range 0x0-0x7F,
// inclusive).
TEST(RsCharTest, FromUtf8Literal) {
rstd::Char c = u8'x';
EXPECT_EQ(0x78, static_cast<uint32_t>(c));
}
// This test covers the following case from
// https://en.cppreference.com/w/cpp/language/character_literal:
//
// UTF-16 character literal, e.g. u'猫', but not u'🍌' (u'\U0001f34c'). Such
// literal has type `char16_t` and the value equal to ISO/IEC 10646 code point
// value of c-char, provided that the code point value is representable with a
// single UTF-16 code unit (that is, c-char is in the range 0x0-0xFFFF,
// inclusive).
TEST(RsCharTest, FromUtf16Literal) {
// Not testing `is_trivially_constructible`, because UTF-16 literals may
// fail Rust's well-formed-ness checks (e.g. they may represent only one
// part of a surrogate pair).
rstd::Char c = u'Ł';
EXPECT_EQ(0x141, static_cast<uint32_t>(c));
}
// This test covers the following case from
// https://en.cppreference.com/w/cpp/language/character_literal:
//
// UTF-32 character literal, e.g. U'猫' or U'🍌'. Such literal has type
// `char32_t` and the value equal to ISO/IEC 10646 code point value of c-char.
TEST(RsCharTest, FromUtf32Literal) {
// Not testing `is_trivially_constructible`, because UTF-32 literals may fail
// Rust's well-formed-ness checks (e.g. they may exceed the value of Rust's
// `std::char::MAX`).
rstd::Char c = U'🦀';
EXPECT_EQ(0x1F980, static_cast<uint32_t>(c));
}
// Test that `rstd::Char` values can be compared with other `rstd::Char` values.
TEST(RsCharTest, ComparisonWithAnotherRsChar) {
const rstd::Char a = 'a';
const rstd::Char b = 'b';
EXPECT_TRUE(a == a);
EXPECT_FALSE(a != a);
EXPECT_TRUE(a <= a);
EXPECT_FALSE(a < a);
EXPECT_TRUE(a >= a);
EXPECT_FALSE(a > a);
EXPECT_FALSE(a == b);
EXPECT_TRUE(a != b);
EXPECT_TRUE(a <= b);
EXPECT_TRUE(a < b);
EXPECT_FALSE(a >= b);
EXPECT_FALSE(a > b);
EXPECT_FALSE(b == a);
EXPECT_TRUE(b != a);
EXPECT_FALSE(b <= a);
EXPECT_FALSE(b < a);
EXPECT_TRUE(b >= a);
EXPECT_TRUE(b > a);
}
} // namespace