blob: b800ab54314ade261d9bdc8e125c225ca1ac66b5 [file] [log] [blame]
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "common.h"
#include "test.h"
#include <inttypes.h>
#include <kj/compat/gtest.h>
namespace kj {
namespace {
KJ_TEST("kj::size() on native arrays") {
int arr[] = {12, 34, 56, 78};
size_t expected = 0;
for (size_t i: indices(arr)) {
KJ_EXPECT(i == expected++);
}
KJ_EXPECT(expected == 4u);
}
struct ImplicitToInt {
int i;
operator int() const {
return i;
}
};
struct Immovable {
Immovable() = default;
KJ_DISALLOW_COPY(Immovable);
};
struct CopyOrMove {
// Type that detects the difference between copy and move.
CopyOrMove(int i): i(i) {}
CopyOrMove(CopyOrMove&& other): i(other.i) { other.i = -1; }
CopyOrMove(const CopyOrMove&) = default;
int i;
};
TEST(Common, Maybe) {
{
Maybe<int> m = 123;
EXPECT_FALSE(m == nullptr);
EXPECT_TRUE(m != nullptr);
KJ_IF_MAYBE(v, m) {
EXPECT_EQ(123, *v);
} else {
ADD_FAILURE();
}
KJ_IF_MAYBE(v, mv(m)) {
EXPECT_EQ(123, *v);
} else {
ADD_FAILURE();
}
EXPECT_EQ(123, m.orDefault(456));
bool ranLazy = false;
EXPECT_EQ(123, m.orDefault([&] {
ranLazy = true;
return 456;
}));
EXPECT_FALSE(ranLazy);
KJ_IF_MAYBE(v, m) {
int notUsedForRef = 5;
const int& ref = m.orDefault([&]() -> int& { return notUsedForRef; });
EXPECT_EQ(ref, *v);
EXPECT_EQ(&ref, v);
const int& ref2 = m.orDefault([notUsed = 5]() -> int { return notUsed; });
EXPECT_NE(&ref, &ref2);
EXPECT_EQ(ref2, 123);
} else {
ADD_FAILURE();
}
}
{
Maybe<int> empty;
int defaultValue = 5;
auto& ref1 = empty.orDefault([&defaultValue]() -> int& {
return defaultValue;
});
EXPECT_EQ(&ref1, &defaultValue);
auto ref2 = empty.orDefault([&]() -> int { return defaultValue; });
EXPECT_NE(&ref2, &defaultValue);
}
{
Maybe<int> m = 0;
EXPECT_FALSE(m == nullptr);
EXPECT_TRUE(m != nullptr);
KJ_IF_MAYBE(v, m) {
EXPECT_EQ(0, *v);
} else {
ADD_FAILURE();
}
KJ_IF_MAYBE(v, mv(m)) {
EXPECT_EQ(0, *v);
} else {
ADD_FAILURE();
}
EXPECT_EQ(0, m.orDefault(456));
bool ranLazy = false;
EXPECT_EQ(0, m.orDefault([&] {
ranLazy = true;
return 456;
}));
EXPECT_FALSE(ranLazy);
}
{
Maybe<int> m = nullptr;
EXPECT_TRUE(m == nullptr);
EXPECT_FALSE(m != nullptr);
KJ_IF_MAYBE(v, m) {
ADD_FAILURE();
EXPECT_EQ(0, *v); // avoid unused warning
}
KJ_IF_MAYBE(v, mv(m)) {
ADD_FAILURE();
EXPECT_EQ(0, *v); // avoid unused warning
}
EXPECT_EQ(456, m.orDefault(456));
bool ranLazy = false;
EXPECT_EQ(456, m.orDefault([&] {
ranLazy = true;
return 456;
}));
EXPECT_TRUE(ranLazy);
}
int i = 234;
{
Maybe<int&> m = i;
EXPECT_FALSE(m == nullptr);
EXPECT_TRUE(m != nullptr);
KJ_IF_MAYBE(v, m) {
EXPECT_EQ(&i, v);
} else {
ADD_FAILURE();
}
KJ_IF_MAYBE(v, mv(m)) {
EXPECT_EQ(&i, v);
} else {
ADD_FAILURE();
}
EXPECT_EQ(234, m.orDefault(456));
}
{
Maybe<int&> m = nullptr;
EXPECT_TRUE(m == nullptr);
EXPECT_FALSE(m != nullptr);
KJ_IF_MAYBE(v, m) {
ADD_FAILURE();
EXPECT_EQ(0, *v); // avoid unused warning
}
KJ_IF_MAYBE(v, mv(m)) {
ADD_FAILURE();
EXPECT_EQ(0, *v); // avoid unused warning
}
EXPECT_EQ(456, m.orDefault(456));
}
{
Maybe<int&> m = &i;
EXPECT_FALSE(m == nullptr);
EXPECT_TRUE(m != nullptr);
KJ_IF_MAYBE(v, m) {
EXPECT_EQ(&i, v);
} else {
ADD_FAILURE();
}
KJ_IF_MAYBE(v, mv(m)) {
EXPECT_EQ(&i, v);
} else {
ADD_FAILURE();
}
EXPECT_EQ(234, m.orDefault(456));
}
{
const Maybe<int&> m2 = &i;
Maybe<const int&> m = m2;
EXPECT_FALSE(m == nullptr);
EXPECT_TRUE(m != nullptr);
KJ_IF_MAYBE(v, m) {
EXPECT_EQ(&i, v);
} else {
ADD_FAILURE();
}
KJ_IF_MAYBE(v, mv(m)) {
EXPECT_EQ(&i, v);
} else {
ADD_FAILURE();
}
EXPECT_EQ(234, m.orDefault(456));
}
{
Maybe<int&> m = implicitCast<int*>(nullptr);
EXPECT_TRUE(m == nullptr);
EXPECT_FALSE(m != nullptr);
KJ_IF_MAYBE(v, m) {
ADD_FAILURE();
EXPECT_EQ(0, *v); // avoid unused warning
}
KJ_IF_MAYBE(v, mv(m)) {
ADD_FAILURE();
EXPECT_EQ(0, *v); // avoid unused warning
}
EXPECT_EQ(456, m.orDefault(456));
}
{
Maybe<int> mi = i;
Maybe<int&> m = mi;
EXPECT_FALSE(m == nullptr);
EXPECT_TRUE(m != nullptr);
KJ_IF_MAYBE(v, m) {
EXPECT_EQ(&KJ_ASSERT_NONNULL(mi), v);
} else {
ADD_FAILURE();
}
KJ_IF_MAYBE(v, mv(m)) {
EXPECT_EQ(&KJ_ASSERT_NONNULL(mi), v);
} else {
ADD_FAILURE();
}
EXPECT_EQ(234, m.orDefault(456));
}
{
Maybe<int> mi = nullptr;
Maybe<int&> m = mi;
EXPECT_TRUE(m == nullptr);
KJ_IF_MAYBE(v, m) {
KJ_FAIL_EXPECT(*v);
}
}
{
const Maybe<int> mi = i;
Maybe<const int&> m = mi;
EXPECT_FALSE(m == nullptr);
EXPECT_TRUE(m != nullptr);
KJ_IF_MAYBE(v, m) {
EXPECT_EQ(&KJ_ASSERT_NONNULL(mi), v);
} else {
ADD_FAILURE();
}
KJ_IF_MAYBE(v, mv(m)) {
EXPECT_EQ(&KJ_ASSERT_NONNULL(mi), v);
} else {
ADD_FAILURE();
}
EXPECT_EQ(234, m.orDefault(456));
}
{
const Maybe<int> mi = nullptr;
Maybe<const int&> m = mi;
EXPECT_TRUE(m == nullptr);
KJ_IF_MAYBE(v, m) {
KJ_FAIL_EXPECT(*v);
}
}
{
// Verify orDefault() works with move-only types.
Maybe<kj::String> m = nullptr;
kj::String s = kj::mv(m).orDefault(kj::str("foo"));
EXPECT_EQ("foo", s);
EXPECT_EQ("foo", kj::mv(m).orDefault([] {
return kj::str("foo");
}));
}
{
// Test a case where an implicit conversion didn't used to happen correctly.
Maybe<ImplicitToInt> m(ImplicitToInt { 123 });
Maybe<uint> m2(m);
Maybe<uint> m3(kj::mv(m));
KJ_IF_MAYBE(v, m2) {
EXPECT_EQ(123, *v);
} else {
ADD_FAILURE();
}
KJ_IF_MAYBE(v, m3) {
EXPECT_EQ(123, *v);
} else {
ADD_FAILURE();
}
}
{
// Test usage of immovable types.
Maybe<Immovable> m;
KJ_EXPECT(m == nullptr);
m.emplace();
KJ_EXPECT(m != nullptr);
m = nullptr;
KJ_EXPECT(m == nullptr);
}
{
// Test that initializing Maybe<T> from Maybe<T&>&& does a copy, not a move.
CopyOrMove x(123);
Maybe<CopyOrMove&> m(x);
Maybe<CopyOrMove> m2 = kj::mv(m);
KJ_EXPECT(m == nullptr); // m is moved out of and cleared
KJ_EXPECT(x.i == 123); // but what m *referenced* was not moved out of
KJ_EXPECT(KJ_ASSERT_NONNULL(m2).i == 123); // m2 is a copy of what m referenced
}
{
// Test that a moved-out-of Maybe<T> is left empty after move constructor.
Maybe<int> m = 123;
KJ_EXPECT(m != nullptr);
Maybe<int> n(kj::mv(m));
KJ_EXPECT(m == nullptr);
KJ_EXPECT(n != nullptr);
}
{
// Test that a moved-out-of Maybe<T> is left empty after move constructor.
Maybe<int> m = 123;
KJ_EXPECT(m != nullptr);
Maybe<int> n = kj::mv(m);
KJ_EXPECT(m == nullptr);
KJ_EXPECT(n != nullptr);
}
{
// Test that a moved-out-of Maybe<T&> is left empty when moved to a Maybe<T>.
int x = 123;
Maybe<int&> m = x;
KJ_EXPECT(m != nullptr);
Maybe<int> n(kj::mv(m));
KJ_EXPECT(m == nullptr);
KJ_EXPECT(n != nullptr);
}
{
// Test that a moved-out-of Maybe<T&> is left empty when moved to another Maybe<T&>.
int x = 123;
Maybe<int&> m = x;
KJ_EXPECT(m != nullptr);
Maybe<int&> n(kj::mv(m));
KJ_EXPECT(m == nullptr);
KJ_EXPECT(n != nullptr);
}
{
Maybe<int> m1 = 123;
Maybe<int> m2 = 123;
Maybe<int> m3 = 456;
Maybe<int> m4 = nullptr;
Maybe<int> m5 = nullptr;
KJ_EXPECT(m1 == m2);
KJ_EXPECT(m1 != m3);
KJ_EXPECT(m1 != m4);
KJ_EXPECT(m4 == m5);
KJ_EXPECT(m4 != m1);
}
}
TEST(Common, MaybeConstness) {
int i;
Maybe<int&> mi = i;
const Maybe<int&> cmi = mi;
// const Maybe<int&> cmi2 = cmi; // shouldn't compile! Transitive const violation.
KJ_IF_MAYBE(i2, cmi) {
EXPECT_EQ(&i, i2);
} else {
ADD_FAILURE();
}
Maybe<const int&> mci = mi;
const Maybe<const int&> cmci = mci;
const Maybe<const int&> cmci2 = cmci;
KJ_IF_MAYBE(i2, cmci2) {
EXPECT_EQ(&i, i2);
} else {
ADD_FAILURE();
}
}
#if __GNUC__
TEST(Common, MaybeUnwrapOrReturn) {
{
auto func = [](Maybe<int> i) -> int {
int& j = KJ_UNWRAP_OR_RETURN(i, -1);
KJ_EXPECT(&j == &KJ_ASSERT_NONNULL(i));
return j + 2;
};
KJ_EXPECT(func(123) == 125);
KJ_EXPECT(func(nullptr) == -1);
}
{
auto func = [&](Maybe<String> maybe) -> int {
String str = KJ_UNWRAP_OR_RETURN(kj::mv(maybe), -1);
return str.parseAs<int>();
};
KJ_EXPECT(func(kj::str("123")) == 123);
KJ_EXPECT(func(nullptr) == -1);
}
// Test void return.
{
int val = 0;
auto func = [&](Maybe<int> i) {
val = KJ_UNWRAP_OR_RETURN(i);
};
func(123);
KJ_EXPECT(val == 123);
val = 321;
func(nullptr);
KJ_EXPECT(val == 321);
}
// Test KJ_UNWRAP_OR
{
bool wasNull = false;
auto func = [&](Maybe<int> i) -> int {
int& j = KJ_UNWRAP_OR(i, {
wasNull = true;
return -1;
});
KJ_EXPECT(&j == &KJ_ASSERT_NONNULL(i));
return j + 2;
};
KJ_EXPECT(func(123) == 125);
KJ_EXPECT(!wasNull);
KJ_EXPECT(func(nullptr) == -1);
KJ_EXPECT(wasNull);
}
{
bool wasNull = false;
auto func = [&](Maybe<String> maybe) -> int {
String str = KJ_UNWRAP_OR(kj::mv(maybe), {
wasNull = true;
return -1;
});
return str.parseAs<int>();
};
KJ_EXPECT(func(kj::str("123")) == 123);
KJ_EXPECT(!wasNull);
KJ_EXPECT(func(nullptr) == -1);
KJ_EXPECT(wasNull);
}
// Test void return.
{
int val = 0;
auto func = [&](Maybe<int> i) {
val = KJ_UNWRAP_OR(i, {
return;
});
};
func(123);
KJ_EXPECT(val == 123);
val = 321;
func(nullptr);
KJ_EXPECT(val == 321);
}
}
#endif
class Foo {
public:
KJ_DISALLOW_COPY(Foo);
virtual ~Foo() {}
protected:
Foo() = default;
};
class Bar: public Foo {
public:
Bar() = default;
KJ_DISALLOW_COPY(Bar);
virtual ~Bar() {}
};
class Baz: public Foo {
public:
Baz() = delete;
KJ_DISALLOW_COPY(Baz);
virtual ~Baz() {}
};
TEST(Common, Downcast) {
Bar bar;
Foo& foo = bar;
EXPECT_EQ(&bar, &downcast<Bar>(foo));
#if defined(KJ_DEBUG) && !KJ_NO_RTTI
KJ_EXPECT_THROW_MESSAGE("Value cannot be downcast", downcast<Baz>(foo));
#endif
#if KJ_NO_RTTI
EXPECT_TRUE(dynamicDowncastIfAvailable<Bar>(foo) == nullptr);
EXPECT_TRUE(dynamicDowncastIfAvailable<Baz>(foo) == nullptr);
#else
KJ_IF_MAYBE(m, dynamicDowncastIfAvailable<Bar>(foo)) {
EXPECT_EQ(&bar, m);
} else {
KJ_FAIL_ASSERT("Dynamic downcast returned null.");
}
EXPECT_TRUE(dynamicDowncastIfAvailable<Baz>(foo) == nullptr);
#endif
}
TEST(Common, MinMax) {
EXPECT_EQ(5, kj::min(5, 9));
EXPECT_EQ(5, kj::min(9, 5));
EXPECT_EQ(5, kj::min(5, 5));
EXPECT_EQ(9, kj::max(5, 9));
EXPECT_EQ(9, kj::max(9, 5));
EXPECT_EQ(5, kj::min(5, 5));
// Hey look, we can handle the types mismatching. Eat your heart out, std.
EXPECT_EQ(5, kj::min(5, 'a'));
EXPECT_EQ(5, kj::min('a', 5));
EXPECT_EQ('a', kj::max(5, 'a'));
EXPECT_EQ('a', kj::max('a', 5));
EXPECT_EQ('a', kj::min(1234567890123456789ll, 'a'));
EXPECT_EQ('a', kj::min('a', 1234567890123456789ll));
EXPECT_EQ(1234567890123456789ll, kj::max(1234567890123456789ll, 'a'));
EXPECT_EQ(1234567890123456789ll, kj::max('a', 1234567890123456789ll));
}
TEST(Common, MinMaxValue) {
EXPECT_EQ(0x7f, int8_t(maxValue));
EXPECT_EQ(0xffu, uint8_t(maxValue));
EXPECT_EQ(0x7fff, int16_t(maxValue));
EXPECT_EQ(0xffffu, uint16_t(maxValue));
EXPECT_EQ(0x7fffffff, int32_t(maxValue));
EXPECT_EQ(0xffffffffu, uint32_t(maxValue));
EXPECT_EQ(0x7fffffffffffffffll, int64_t(maxValue));
EXPECT_EQ(0xffffffffffffffffull, uint64_t(maxValue));
EXPECT_EQ(-0x80, int8_t(minValue));
EXPECT_EQ(0, uint8_t(minValue));
EXPECT_EQ(-0x8000, int16_t(minValue));
EXPECT_EQ(0, uint16_t(minValue));
EXPECT_EQ(-0x80000000, int32_t(minValue));
EXPECT_EQ(0, uint32_t(minValue));
EXPECT_EQ(-0x8000000000000000ll, int64_t(minValue));
EXPECT_EQ(0, uint64_t(minValue));
double f = inf();
EXPECT_TRUE(f * 2 == f);
f = nan();
EXPECT_FALSE(f == f);
// `char`'s signedness is platform-specific.
EXPECT_LE(char(minValue), '\0');
EXPECT_GE(char(maxValue), '\x7f');
}
TEST(Common, Defer) {
uint i = 0;
uint j = 1;
bool k = false;
{
KJ_DEFER(++i);
KJ_DEFER(j += 3; k = true);
EXPECT_EQ(0u, i);
EXPECT_EQ(1u, j);
EXPECT_FALSE(k);
}
EXPECT_EQ(1u, i);
EXPECT_EQ(4u, j);
EXPECT_TRUE(k);
}
TEST(Common, CanConvert) {
static_assert(canConvert<long, int>(), "failure");
static_assert(!canConvert<long, void*>(), "failure");
struct Super {};
struct Sub: public Super {};
static_assert(canConvert<Sub, Super>(), "failure");
static_assert(!canConvert<Super, Sub>(), "failure");
static_assert(canConvert<Sub*, Super*>(), "failure");
static_assert(!canConvert<Super*, Sub*>(), "failure");
static_assert(canConvert<void*, const void*>(), "failure");
static_assert(!canConvert<const void*, void*>(), "failure");
}
TEST(Common, ArrayAsBytes) {
uint32_t raw[] = { 0x12345678u, 0x9abcdef0u };
ArrayPtr<uint32_t> array = raw;
ASSERT_EQ(2, array.size());
EXPECT_EQ(0x12345678u, array[0]);
EXPECT_EQ(0x9abcdef0u, array[1]);
{
ArrayPtr<byte> bytes = array.asBytes();
ASSERT_EQ(8, bytes.size());
if (bytes[0] == '\x12') {
// big-endian
EXPECT_EQ(0x12u, bytes[0]);
EXPECT_EQ(0x34u, bytes[1]);
EXPECT_EQ(0x56u, bytes[2]);
EXPECT_EQ(0x78u, bytes[3]);
EXPECT_EQ(0x9au, bytes[4]);
EXPECT_EQ(0xbcu, bytes[5]);
EXPECT_EQ(0xdeu, bytes[6]);
EXPECT_EQ(0xf0u, bytes[7]);
} else {
// little-endian
EXPECT_EQ(0x12u, bytes[3]);
EXPECT_EQ(0x34u, bytes[2]);
EXPECT_EQ(0x56u, bytes[1]);
EXPECT_EQ(0x78u, bytes[0]);
EXPECT_EQ(0x9au, bytes[7]);
EXPECT_EQ(0xbcu, bytes[6]);
EXPECT_EQ(0xdeu, bytes[5]);
EXPECT_EQ(0xf0u, bytes[4]);
}
}
{
ArrayPtr<char> chars = array.asChars();
ASSERT_EQ(8, chars.size());
if (chars[0] == '\x12') {
// big-endian
EXPECT_EQ('\x12', chars[0]);
EXPECT_EQ('\x34', chars[1]);
EXPECT_EQ('\x56', chars[2]);
EXPECT_EQ('\x78', chars[3]);
EXPECT_EQ('\x9a', chars[4]);
EXPECT_EQ('\xbc', chars[5]);
EXPECT_EQ('\xde', chars[6]);
EXPECT_EQ('\xf0', chars[7]);
} else {
// little-endian
EXPECT_EQ('\x12', chars[3]);
EXPECT_EQ('\x34', chars[2]);
EXPECT_EQ('\x56', chars[1]);
EXPECT_EQ('\x78', chars[0]);
EXPECT_EQ('\x9a', chars[7]);
EXPECT_EQ('\xbc', chars[6]);
EXPECT_EQ('\xde', chars[5]);
EXPECT_EQ('\xf0', chars[4]);
}
}
ArrayPtr<const uint32_t> constArray = array;
{
ArrayPtr<const byte> bytes = constArray.asBytes();
ASSERT_EQ(8, bytes.size());
if (bytes[0] == '\x12') {
// big-endian
EXPECT_EQ(0x12u, bytes[0]);
EXPECT_EQ(0x34u, bytes[1]);
EXPECT_EQ(0x56u, bytes[2]);
EXPECT_EQ(0x78u, bytes[3]);
EXPECT_EQ(0x9au, bytes[4]);
EXPECT_EQ(0xbcu, bytes[5]);
EXPECT_EQ(0xdeu, bytes[6]);
EXPECT_EQ(0xf0u, bytes[7]);
} else {
// little-endian
EXPECT_EQ(0x12u, bytes[3]);
EXPECT_EQ(0x34u, bytes[2]);
EXPECT_EQ(0x56u, bytes[1]);
EXPECT_EQ(0x78u, bytes[0]);
EXPECT_EQ(0x9au, bytes[7]);
EXPECT_EQ(0xbcu, bytes[6]);
EXPECT_EQ(0xdeu, bytes[5]);
EXPECT_EQ(0xf0u, bytes[4]);
}
}
{
ArrayPtr<const char> chars = constArray.asChars();
ASSERT_EQ(8, chars.size());
if (chars[0] == '\x12') {
// big-endian
EXPECT_EQ('\x12', chars[0]);
EXPECT_EQ('\x34', chars[1]);
EXPECT_EQ('\x56', chars[2]);
EXPECT_EQ('\x78', chars[3]);
EXPECT_EQ('\x9a', chars[4]);
EXPECT_EQ('\xbc', chars[5]);
EXPECT_EQ('\xde', chars[6]);
EXPECT_EQ('\xf0', chars[7]);
} else {
// little-endian
EXPECT_EQ('\x12', chars[3]);
EXPECT_EQ('\x34', chars[2]);
EXPECT_EQ('\x56', chars[1]);
EXPECT_EQ('\x78', chars[0]);
EXPECT_EQ('\x9a', chars[7]);
EXPECT_EQ('\xbc', chars[6]);
EXPECT_EQ('\xde', chars[5]);
EXPECT_EQ('\xf0', chars[4]);
}
}
}
KJ_TEST("ArrayPtr operator ==") {
KJ_EXPECT(ArrayPtr<const int>({123, 456}) == ArrayPtr<const int>({123, 456}));
KJ_EXPECT(!(ArrayPtr<const int>({123, 456}) != ArrayPtr<const int>({123, 456})));
KJ_EXPECT(ArrayPtr<const int>({123, 456}) != ArrayPtr<const int>({123, 321}));
KJ_EXPECT(ArrayPtr<const int>({123, 456}) != ArrayPtr<const int>({123}));
KJ_EXPECT(ArrayPtr<const int>({123, 456}) == ArrayPtr<const short>({123, 456}));
KJ_EXPECT(!(ArrayPtr<const int>({123, 456}) != ArrayPtr<const short>({123, 456})));
KJ_EXPECT(ArrayPtr<const int>({123, 456}) != ArrayPtr<const short>({123, 321}));
KJ_EXPECT(ArrayPtr<const int>({123, 456}) != ArrayPtr<const short>({123}));
KJ_EXPECT((ArrayPtr<const StringPtr>({"foo", "bar"}) ==
ArrayPtr<const char* const>({"foo", "bar"})));
KJ_EXPECT(!(ArrayPtr<const StringPtr>({"foo", "bar"}) !=
ArrayPtr<const char* const>({"foo", "bar"})));
KJ_EXPECT((ArrayPtr<const StringPtr>({"foo", "bar"}) !=
ArrayPtr<const char* const>({"foo", "baz"})));
KJ_EXPECT((ArrayPtr<const StringPtr>({"foo", "bar"}) !=
ArrayPtr<const char* const>({"foo"})));
}
KJ_TEST("kj::range()") {
uint expected = 5;
for (uint i: range(5, 10)) {
KJ_EXPECT(i == expected++);
}
KJ_EXPECT(expected == 10);
expected = 0;
for (uint i: range(0, 8)) {
KJ_EXPECT(i == expected++);
}
KJ_EXPECT(expected == 8);
}
KJ_TEST("kj::defer()") {
bool executed;
// rvalue reference
{
executed = false;
auto deferred = kj::defer([&executed]() {
executed = true;
});
KJ_EXPECT(!executed);
}
KJ_EXPECT(executed);
// lvalue reference
auto executor = [&executed]() {
executed = true;
};
{
executed = false;
auto deferred = kj::defer(executor);
KJ_EXPECT(!executed);
}
KJ_EXPECT(executed);
}
} // namespace
} // namespace kj