Skip to content

Commit

Permalink
[C++]: refactor struct nullable field cast tests, add tests for slicing
Browse files Browse the repository at this point in the history
  • Loading branch information
NickCrews committed Feb 10, 2025
1 parent 0458d56 commit ce00550
Showing 1 changed file with 65 additions and 68 deletions.
133 changes: 65 additions & 68 deletions cpp/src/arrow/compute/kernels/scalar_cast_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2900,95 +2900,92 @@ TEST(Cast, StructToBiggerNullableStruct) {
TEST(Cast, StructToDifferentNullabilityStruct) {
{
// OK to go from non-nullable to nullable...
std::vector<std::shared_ptr<Field>> fields_src_non_nullable = {
std::vector<std::shared_ptr<Field>> fields_src = {
std::make_shared<Field>("a", int8(), false),
std::make_shared<Field>("b", int8(), false),
std::make_shared<Field>("c", int8(), false)};
std::shared_ptr<Array> a_src_non_nullable, b_src_non_nullable, c_src_non_nullable;
a_src_non_nullable = ArrayFromJSON(int8(), "[11, 23, 56]");
b_src_non_nullable = ArrayFromJSON(int8(), "[32, 46, 37]");
c_src_non_nullable = ArrayFromJSON(int8(), "[95, 11, 44]");
ASSERT_OK_AND_ASSIGN(
auto src_non_nullable,
StructArray::Make({a_src_non_nullable, b_src_non_nullable, c_src_non_nullable},
fields_src_non_nullable));

std::shared_ptr<Array> a_dest_nullable, b_dest_nullable, c_dest_nullable;
a_dest_nullable = ArrayFromJSON(int64(), "[11, 23, 56]");
b_dest_nullable = ArrayFromJSON(int64(), "[32, 46, 37]");
c_dest_nullable = ArrayFromJSON(int64(), "[95, 11, 44]");

std::vector<std::shared_ptr<Field>> fields_dest1_nullable = {
std::vector<std::shared_ptr<Array>> arrays_src = {
ArrayFromJSON(int8(), "[11, 23, 56]"),
ArrayFromJSON(int8(), "[32, 46, 37]"),
ArrayFromJSON(int8(), "[95, 11, 44]"),
};
ASSERT_OK_AND_ASSIGN(auto src, StructArray::Make(arrays_src, fields_src));

std::vector<std::shared_ptr<Field>> fields_dest = {
std::make_shared<Field>("a", int64(), true),
std::make_shared<Field>("b", int64(), true),
std::make_shared<Field>("c", int64(), true)};
ASSERT_OK_AND_ASSIGN(
auto dest1_nullable,
StructArray::Make({a_dest_nullable, b_dest_nullable, c_dest_nullable},
fields_dest1_nullable));
CheckCast(src_non_nullable, dest1_nullable);

std::vector<std::shared_ptr<Field>> fields_dest2_nullable = {
std::make_shared<Field>("a", int64(), true),
std::make_shared<Field>("c", int64(), true)};
ASSERT_OK_AND_ASSIGN(
auto dest2_nullable,
StructArray::Make({a_dest_nullable, c_dest_nullable}, fields_dest2_nullable));
CheckCast(src_non_nullable, dest2_nullable);

std::vector<std::shared_ptr<Field>> fields_dest3_nullable = {
std::make_shared<Field>("b", int64(), true)};
ASSERT_OK_AND_ASSIGN(auto dest3_nullable,
StructArray::Make({b_dest_nullable}, fields_dest3_nullable));
CheckCast(src_non_nullable, dest3_nullable);
std::make_shared<Field>("c", int64(), true),
};
std::vector<std::shared_ptr<Array>> arrays_dest = {
ArrayFromJSON(int64(), "[11, 23, 56]"),
ArrayFromJSON(int64(), "[32, 46, 37]"),
ArrayFromJSON(int64(), "[95, 11, 44]"),
};
ASSERT_OK_AND_ASSIGN(auto dest, StructArray::Make(arrays_dest, fields_dest));
CheckCast(src, dest);

std::vector<std::shared_ptr<Field>> fields_dest_ac = {fields_dest[0], fields_dest[2]};
std::vector<std::shared_ptr<Array>> arrays_dest_ac = {arrays_dest[0], arrays_dest[2]};
ASSERT_OK_AND_ASSIGN(auto dest_ac, StructArray::Make(arrays_dest_ac, fields_dest_ac));
CheckCast(src, dest_ac);

std::vector<std::shared_ptr<Field>> fields_dest_b = {fields_dest[1]};
std::vector<std::shared_ptr<Array>> arrays_dest_b = {arrays_dest[1]};
ASSERT_OK_AND_ASSIGN(auto dest_b, StructArray::Make(arrays_dest_b, fields_dest_b));
CheckCast(src, dest_b);
}
{
// But when going from nullable to non-nullable, all data must be non-null...
std::vector<std::shared_ptr<Field>> fields_src_nullable = {
std::vector<std::shared_ptr<Field>> fields_src = {
std::make_shared<Field>("a", int8(), true),
std::make_shared<Field>("b", int8(), true),
std::make_shared<Field>("c", int8(), true)};
std::shared_ptr<Array> a_src_nullable, b_src_nullable, c_src_nullable;
a_src_nullable = ArrayFromJSON(int8(), "[1, null, 5]");
b_src_nullable = ArrayFromJSON(int8(), "[3, 4, null]");
c_src_nullable = ArrayFromJSON(int8(), "[9, 11, 44]");
ASSERT_OK_AND_ASSIGN(
auto src_nullable,
StructArray::Make({a_src_nullable, b_src_nullable, c_src_nullable},
fields_src_nullable));

std::vector<std::shared_ptr<Field>> fields_dest1_non_nullable = {
std::vector<std::shared_ptr<Array>> arrays_src = {
ArrayFromJSON(int8(), "[1, null, 5]"),
ArrayFromJSON(int8(), "[3, 4, null]"),
ArrayFromJSON(int8(), "[9, 11, 44]"),
};
ASSERT_OK_AND_ASSIGN(auto src, StructArray::Make(arrays_src, fields_src));

std::vector<std::shared_ptr<Field>> fields_dest = {
std::make_shared<Field>("a", int64(), false),
std::make_shared<Field>("b", int64(), false),
std::make_shared<Field>("c", int64(), false)};
const auto dest1_non_nullable = arrow::struct_(fields_dest1_non_nullable);
const auto options1_non_nullable = CastOptions::Safe(dest1_non_nullable);
EXPECT_RAISES_WITH_MESSAGE_THAT(
Invalid,
::testing::HasSubstr("field 'a' of type int64 has nulls. Can't cast to field 'a' "
::testing::HasSubstr("field 'a' of type int8 has nulls. Can't cast to field 'a' "
"of non-nullable type int64"),
Cast(src_nullable, options1_non_nullable));
Cast(src, CastOptions::Safe(arrow::struct_(fields_dest))));

std::vector<std::shared_ptr<Field>> fields_dest2_non_nullable = {
std::make_shared<Field>("a", int64(), false),
std::make_shared<Field>("c", int64(), false)};
const auto dest2_non_nullable = arrow::struct_(fields_dest2_non_nullable);
const auto options2_non_nullable = CastOptions::Safe(dest2_non_nullable);
std::vector<std::shared_ptr<Field>> fields_dest_ac = {fields_dest[0], fields_dest[2]};
EXPECT_RAISES_WITH_MESSAGE_THAT(
Invalid,
::testing::HasSubstr("field 'a' of type int64 has nulls. Can't cast to field 'a' "
::testing::HasSubstr("field 'a' of type int8 has nulls. Can't cast to field 'a' "
"of non-nullable type int64"),
Cast(src_nullable, options2_non_nullable));

std::shared_ptr<Array> c_dest_no_nulls;
c_dest_no_nulls = ArrayFromJSON(int64(), "[9, 11, 44]");
std::vector<std::shared_ptr<Field>> fields_dest_no_nulls = {
std::make_shared<Field>("c", int64(), false)};
ASSERT_OK_AND_ASSIGN(auto dest_no_nulls,
StructArray::Make({c_dest_no_nulls}, fields_dest_no_nulls));
const auto options3_non_nullable =
CastOptions::Safe(arrow::struct_(fields_dest_no_nulls));
CheckCast(src_nullable, dest_no_nulls, options3_non_nullable);
Cast(src, CastOptions::Safe(arrow::struct_(fields_dest_ac))));

// if we only select a field with no nulls, it should be fine:
std::vector<std::shared_ptr<Field>> fields_dest_c = {fields_dest[2]};
std::vector<std::shared_ptr<Array>> arrays_dest_c = {
ArrayFromJSON(int64(), "[9, 11, 44]")};
ASSERT_OK_AND_ASSIGN(auto dest_c, StructArray::Make(arrays_dest_c, fields_dest_c));
CheckCast(src, dest_c);

// A slice that doesn't contain nulls is castable...
std::vector<std::shared_ptr<Array>> arrays_dest_0 = {
ArrayFromJSON(int64(), "[1]"),
ArrayFromJSON(int64(), "[3]"),
ArrayFromJSON(int64(), "[9]"),
};
ASSERT_OK_AND_ASSIGN(auto dest_0, StructArray::Make(arrays_dest_0, fields_dest));
CheckCast(src->Slice(0, 1), dest_0);

// ...but a slice that contains nulls will error.
EXPECT_RAISES_WITH_MESSAGE_THAT(
Invalid,
::testing::HasSubstr("field 'a' of type int8 has nulls. Can't cast to field 'a' "
"of non-nullable type int64"),
Cast(src->Slice(1, 3), CastOptions::Safe(arrow::struct_(fields_dest))));
}
}

Expand Down

0 comments on commit ce00550

Please sign in to comment.