blob: dd221f0ae62216af9b1cd88c2dece880378945b9 [file] [log] [blame]
// Copyright 2019 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 <zircon/assert.h>
#include <range/range.h>
#include <zxtest/zxtest.h>
namespace range {
namespace {
TEST(LengthTest, One) {
auto x = Range<uint64_t>(5, 6);
EXPECT_EQ(x.Length(), 1);
}
TEST(LengthTest, MoreThanOne) {
auto x = Range<uint64_t>(5, 7);
EXPECT_EQ(x.Length(), 2);
}
TEST(LengthTest, Zero) {
auto x = Range<uint64_t>(2, 1);
EXPECT_EQ(x.Length(), 0);
}
TEST(EqualToOperatorTest, EqualRanges) {
auto x = Range<uint64_t>(5, 7);
auto y = Range<uint64_t>(5, 7);
EXPECT_EQ(x, y);
EXPECT_TRUE(x == y);
}
TEST(EqualToOperatorTest, DifferentLengths) {
auto x = Range<uint64_t>(5, 7);
auto y = Range<uint64_t>(5, 5);
EXPECT_FALSE(x == y);
}
TEST(EqualToOperatorTest, DifferentStarts) {
auto x = Range<uint64_t>(3, 5);
auto y = Range<uint64_t>(5, 7);
EXPECT_FALSE(x == y);
}
TEST(EqualToOperatorTest, DifferentStartsDifferentLengths) {
auto x = Range<uint64_t>(3, 5);
auto y = Range<uint64_t>(5, 6);
EXPECT_FALSE(x == y);
}
TEST(NotEqualToOperatorTest, EqualRanges) {
auto x = Range<uint64_t>(5, 7);
auto y = Range<uint64_t>(5, 7);
EXPECT_FALSE(x != y);
}
TEST(NotEqualToOperatorTest, DifferentLengths) {
auto x = Range<uint64_t>(5, 7);
auto y = Range<uint64_t>(5, 5);
EXPECT_NE(x, y);
EXPECT_TRUE(x != y);
}
TEST(NotEqualToOperatorTest, DifferentStarts) {
auto x = Range<uint64_t>(3, 5);
auto y = Range<uint64_t>(5, 7);
EXPECT_NE(x, y);
EXPECT_TRUE(x != y);
}
TEST(NotEqualToOperatorTest, DifferentStartsDifferentLengths) {
auto x = Range<uint64_t>(3, 5);
auto y = Range<uint64_t>(5, 6);
EXPECT_NE(x, y);
EXPECT_TRUE(x != y);
}
TEST(OverlapTest, NonOverlapAdjuscentRanges) {
// Two adjuscent but non-overlapping, ranges
auto x = Range<uint64_t>(0, 1);
auto y = Range<uint64_t>(1, 2);
ASSERT_TRUE(Adjacent(x, y));
ASSERT_TRUE(Adjacent(y, x));
EXPECT_FALSE(Overlap(x, y));
// Two adjuscent, non-overlapping, ranges in reverse order
EXPECT_FALSE(Overlap(y, x));
}
TEST(OverlapTest, NonOverlapingNonAdjuscentRanges) {
// Two non-overlapping ranges
auto x = Range<uint64_t>(5, 7);
auto y = Range<uint64_t>(9, 18);
ASSERT_FALSE(Adjacent(x, y));
ASSERT_FALSE(Adjacent(y, x));
EXPECT_FALSE(Overlap(x, y));
// Reverse the order
EXPECT_FALSE(Overlap(y, x));
}
TEST(OverlapTest, OverlapingByOneNumber) {
// Two ranges sharing just one number in common
auto x = Range<uint64_t>(0, 2);
auto y = Range<uint64_t>(1, 3);
EXPECT_TRUE(Overlap(x, y));
// Reverse the order
EXPECT_TRUE(Overlap(y, x));
}
TEST(OverlapTest, OverlapingByMultipleNumbers) {
// Two ranges sharing multiple numbers in common
auto x = Range<uint64_t>(0, 4);
auto y = Range<uint64_t>(2, 6);
EXPECT_TRUE(Overlap(x, y));
// Reverse the order
EXPECT_TRUE(Overlap(y, x));
}
TEST(OverlapTest, OneRangeContainsTheOther) {
// One range containing another
auto x = Range<uint64_t>(0, 9);
auto y = Range<uint64_t>(2, 5);
EXPECT_TRUE(Overlap(x, y));
// Reverse the order
EXPECT_TRUE(Overlap(y, x));
}
TEST(OverlapTest, RangeOverlapsWithItself) {
// Same range
auto x = Range<uint64_t>(0, 9);
EXPECT_TRUE(Overlap(x, x));
}
TEST(AdjacentTest, AdjacentRanges) {
auto x = Range<uint64_t>(1, 3);
auto y = Range<uint64_t>(3, 8);
ASSERT_FALSE(Overlap(x, y));
ASSERT_FALSE(Overlap(y, x));
EXPECT_TRUE(Adjacent(x, y));
EXPECT_TRUE(Adjacent(y, x));
}
TEST(AdjacentTest, NonAdjacentNonOverlapingRanges) {
auto x = Range<uint64_t>(1, 3);
auto y = Range<uint64_t>(5, 8);
ASSERT_FALSE(Overlap(x, y));
ASSERT_FALSE(Overlap(y, x));
EXPECT_FALSE(Adjacent(x, y));
EXPECT_FALSE(Adjacent(y, x));
}
TEST(AdjacentTest, NonAdjacentOverlapingRanges) {
auto x = Range<uint64_t>(1, 5);
auto y = Range<uint64_t>(4, 8);
EXPECT_TRUE(Overlap(x, y));
EXPECT_TRUE(Overlap(y, x));
EXPECT_FALSE(Adjacent(x, y));
EXPECT_FALSE(Adjacent(y, x));
}
TEST(MergableTest, AdjacentRanges) {
auto x = Range<uint64_t>(1, 3);
auto y = Range<uint64_t>(3, 8);
ASSERT_FALSE(Overlap(x, y));
ASSERT_FALSE(Overlap(y, x));
ASSERT_TRUE(Adjacent(x, y));
ASSERT_TRUE(Adjacent(y, x));
EXPECT_TRUE(Mergable(x, y));
// Reverse the order
EXPECT_TRUE(Mergable(y, x));
}
TEST(MergableTest, NonAdjacentNonOverlapingRanges) {
auto x = Range<uint64_t>(1, 3);
auto y = Range<uint64_t>(5, 8);
ASSERT_FALSE(Overlap(x, y));
ASSERT_FALSE(Overlap(y, x));
ASSERT_FALSE(Adjacent(x, y));
ASSERT_FALSE(Adjacent(y, x));
EXPECT_FALSE(Mergable(x, y));
// Reverse the order
EXPECT_FALSE(Mergable(y, x));
}
TEST(MergableTest, OverlapingRanges) {
auto x = Range<uint64_t>(1, 5);
auto y = Range<uint64_t>(4, 8);
ASSERT_TRUE(Overlap(x, y));
ASSERT_TRUE(Overlap(y, x));
ASSERT_FALSE(Adjacent(x, y));
ASSERT_FALSE(Adjacent(y, x));
EXPECT_TRUE(Mergable(x, y));
// Reverse the order
EXPECT_TRUE(Mergable(y, x));
}
TEST(MergeTest, MergeAdjacentRanges) {
auto x = Range<uint64_t>(1, 3);
auto y = Range<uint64_t>(3, 8);
ASSERT_TRUE(Adjacent(x, y));
ASSERT_TRUE(Adjacent(y, x));
ASSERT_FALSE(Overlap(x, y));
ASSERT_FALSE(Overlap(y, x));
ASSERT_TRUE(Mergable(x, y));
ASSERT_TRUE(Mergable(y, x));
auto merged = x;
ASSERT_OK(merged.Merge(y));
EXPECT_EQ(merged.Length(), x.Length() + y.Length());
EXPECT_EQ(merged.Start(), std::min(x.Start(), y.Start()));
EXPECT_EQ(merged.End(), std::max(x.End(), y.End()));
}
TEST(MergeTest, TryMergeNonAdjacentNonOverlapingRanges) {
auto x = Range<uint64_t>(1, 3);
auto y = Range<uint64_t>(5, 8);
ASSERT_FALSE(Adjacent(y, x));
ASSERT_FALSE(Adjacent(x, y));
ASSERT_FALSE(Overlap(y, x));
ASSERT_FALSE(Overlap(x, y));
ASSERT_FALSE(Mergable(x, y));
auto merged = x;
EXPECT_STATUS(ZX_ERR_OUT_OF_RANGE, merged.Merge(y));
// Reverse the order
merged = y;
EXPECT_STATUS(ZX_ERR_OUT_OF_RANGE, merged.Merge(x));
}
TEST(MergeTest, OverlapingRanges) {
auto x = Range<uint64_t>(1, 5);
auto y = Range<uint64_t>(2, 8);
auto result = Range<uint64_t>(1, 8);
ASSERT_FALSE(Adjacent(y, x));
ASSERT_FALSE(Adjacent(x, y));
ASSERT_TRUE(Overlap(y, x));
ASSERT_TRUE(Overlap(x, y));
auto merged = x;
ASSERT_OK(merged.Merge(y));
EXPECT_EQ(result, merged);
// Reverse the order
merged = y;
ASSERT_OK(merged.Merge(x));
EXPECT_EQ(result, merged);
}
TEST(MergeTest, OverlapingByOneNumber) {
// Two ranges sharing just one number in common
auto x = Range<uint64_t>(0, 2);
auto y = Range<uint64_t>(1, 3);
auto result = Range<uint64_t>(0, 3);
ASSERT_FALSE(Adjacent(x, y));
ASSERT_FALSE(Adjacent(y, x));
ASSERT_TRUE(Overlap(x, y));
ASSERT_TRUE(Overlap(y, x));
ASSERT_TRUE(Mergable(x, y));
ASSERT_TRUE(Mergable(y, x));
auto merged = x;
ASSERT_OK(merged.Merge(y));
EXPECT_EQ(merged, result);
// Reverse the order
merged = y;
ASSERT_OK(merged.Merge(x));
EXPECT_TRUE(merged == result);
}
TEST(MergeTest, OverlapingByMultipleNumbers) {
// Two ranges sharing multiple numbers in common
auto x = Range<uint64_t>(0, 3);
auto y = Range<uint64_t>(1, 5);
auto result = Range<uint64_t>(0, 5);
ASSERT_FALSE(Adjacent(x, y));
ASSERT_FALSE(Adjacent(y, x));
ASSERT_TRUE(Overlap(x, y));
ASSERT_TRUE(Overlap(y, x));
ASSERT_TRUE(Mergable(x, y));
ASSERT_TRUE(Mergable(y, x));
auto merged = x;
ASSERT_OK(merged.Merge(y));
EXPECT_EQ(merged, result);
// Reverse the order
merged = y;
ASSERT_OK(merged.Merge(x));
EXPECT_EQ(merged, result);
}
TEST(MergeTest, OneRangeContainsTheOther) {
// One range containing another
auto x = Range<uint64_t>(0, 9);
auto y = Range<uint64_t>(2, 5);
ASSERT_FALSE(Adjacent(x, y));
ASSERT_FALSE(Adjacent(y, x));
ASSERT_TRUE(Overlap(x, y));
ASSERT_TRUE(Overlap(y, x));
ASSERT_TRUE(Mergable(x, y));
ASSERT_TRUE(Mergable(y, x));
auto merged = x;
ASSERT_OK(merged.Merge(y));
EXPECT_EQ(merged, x);
// Reverse the order
merged = y;
ASSERT_OK(merged.Merge(x));
EXPECT_EQ(merged, x);
}
TEST(MergeTest, MergeWithItself) {
// Same range
auto x = Range<uint64_t>(0, 10);
ASSERT_FALSE(Adjacent(x, x));
ASSERT_TRUE(Overlap(x, x));
ASSERT_TRUE(Mergable(x, x));
ASSERT_TRUE(Mergable(x, x));
auto merged = x;
ASSERT_OK(merged.Merge(x));
EXPECT_EQ(merged, x);
}
TEST(ContainsTest, ContainingRange) {
ASSERT_TRUE(Contains(Range<uint64_t>(1, 10), Range<uint64_t>(4, 8)));
}
TEST(ContainsTest, SelfContained) {
ASSERT_TRUE(Contains(Range<uint64_t>(1, 10), Range<uint64_t>(1, 10)));
}
TEST(ContainsTest, ContainedLargerThanContainer) {
ASSERT_FALSE(Contains(Range<uint64_t>(4, 8), Range<uint64_t>(1, 10)));
}
TEST(ContainsTest, ContainerEndSmallerThanContainedEnd) {
ASSERT_FALSE(Contains(Range<uint64_t>(1, 10), Range<uint64_t>(5, 11)));
}
TEST(ContainsTest, ContainerStartLargerThanContainedStart) {
ASSERT_FALSE(Contains(Range<uint64_t>(4, 8), Range<uint64_t>(1, 5)));
}
TEST(CustomRangeTest, CustomKey) {
Range<uint32_t> range(0, 10);
EXPECT_EQ(0, range.Start());
EXPECT_EQ(10, range.End());
}
TEST(CustomRangeTest, CustomContainer) {
struct Container {
uint64_t Start() const { return start_; }
uint64_t End() const { return end_; }
uint64_t other_data_ = 0;
uint64_t start_ = 0;
uint64_t end_ = 0;
};
Container c = {};
c.start_ = 5;
c.end_ = 10;
Range<uint64_t, Container> range(std::move(c));
EXPECT_EQ(5, range.Start());
EXPECT_EQ(10, range.End());
c = range.release();
EXPECT_EQ(5, c.start_);
EXPECT_EQ(10, c.end_);
}
TEST(CustomRangeTest, CustomContainerTraits) {
struct Container {
// Note: No "Start()" or "End()" methods.
uint64_t start_ = 0;
uint64_t end_ = 0;
};
struct Traits {
static uint64_t Start(const Container& obj) { return obj.start_; }
static uint64_t End(const Container& obj) { return obj.end_; }
static zx_status_t Update(const Container* other, uint64_t start, uint64_t end,
Container* obj) {
obj->start_ = start;
obj->end_ = end;
return ZX_OK;
}
};
using RangeWithTraits = Range<uint64_t, Container, Traits>;
Container c = {};
c.start_ = 5;
c.end_ = 10;
RangeWithTraits range1(std::move(c));
EXPECT_EQ(5, range1.Start());
EXPECT_EQ(10, range1.End());
c = {};
c.start_ = 0;
c.end_ = 5;
RangeWithTraits range2(std::move(c));
EXPECT_TRUE(Adjacent(range1, range2));
ASSERT_OK(range1.Merge(range2));
c = range1.release();
// Observe that the ranges merged.
EXPECT_EQ(0, c.start_);
EXPECT_EQ(10, c.end_);
}
TEST(CustomRangeTest, RejectedMergesDoNotModifyRange) {
struct Container {
uint64_t start_ = 0;
uint64_t end_ = 0;
};
struct Traits {
static uint64_t Start(const Container& obj) { return obj.start_; }
static uint64_t End(const Container& obj) { return obj.end_; }
static zx_status_t Update(const Container* other, uint64_t start, uint64_t end,
Container* obj) {
return ZX_ERR_INTERNAL;
}
};
using RangeWithTraits = Range<uint64_t, Container, Traits>;
Container c1, c2 = {}, c3;
c1.start_ = 0;
c1.end_ = 5;
c2.start_ = 5;
c2.end_ = 10;
c3.start_ = 1;
c3.end_ = 3;
RangeWithTraits range1(std::move(c1));
RangeWithTraits range2(std::move(c2));
RangeWithTraits range3(std::move(c3));
EXPECT_TRUE(Adjacent(range1, range2));
EXPECT_TRUE(Mergable(range1, range2));
EXPECT_TRUE(Contains(range1, range3));
EXPECT_FALSE(Contains(range2, range3));
ASSERT_STATUS(ZX_ERR_INTERNAL, range1.Merge(range2));
EXPECT_EQ(0, range1.Start());
EXPECT_EQ(5, range1.End());
EXPECT_EQ(5, range2.Start());
EXPECT_EQ(10, range2.End());
}
} // namespace
} // namespace range