first commit
This commit is contained in:
commit
5893b00dd2
1669 changed files with 1982740 additions and 0 deletions
452
libraries/M5Utility/test/MurmurHash3.cpp
Normal file
452
libraries/M5Utility/test/MurmurHash3.cpp
Normal file
|
|
@ -0,0 +1,452 @@
|
|||
/*
|
||||
MurmurHash3 by
|
||||
https://github.com/aappleby/smhasher/blob/master/src/MurmurHash3.cpp
|
||||
|
||||
Modified by M5Stack
|
||||
*/
|
||||
//-----------------------------------------------------------------------------
|
||||
// MurmurHash3 was written by Austin Appleby, and is placed in the public
|
||||
// domain. The author hereby disclaims copyright to this source code.
|
||||
|
||||
// Note - The x86 and x64 versions do _not_ produce the same results, as the
|
||||
// algorithms are optimized for their respective platforms. You can still
|
||||
// compile and run any of them on any platform, but your performance with the
|
||||
// non-native version will be less than optimal.
|
||||
|
||||
#include "MurmurHash3.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Platform-specific functions and macros
|
||||
|
||||
// Microsoft Visual Studio
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#define ROTL32(x, y) _rotl(x, y)
|
||||
#define ROTL64(x, y) _rotl64(x, y)
|
||||
|
||||
#define BIG_CONSTANT(x) (x)
|
||||
|
||||
// Other compilers
|
||||
|
||||
#else // defined(_MSC_VER)
|
||||
|
||||
inline uint32_t rotl32(uint32_t x, int8_t r)
|
||||
{
|
||||
return (x << r) | (x >> (32 - r));
|
||||
}
|
||||
|
||||
inline uint64_t rotl64(uint64_t x, int8_t r)
|
||||
{
|
||||
return (x << r) | (x >> (64 - r));
|
||||
}
|
||||
|
||||
#define ROTL32(x, y) rotl32(x, y)
|
||||
#define ROTL64(x, y) rotl64(x, y)
|
||||
|
||||
#define BIG_CONSTANT(x) (x##LLU)
|
||||
|
||||
#endif // !defined(_MSC_VER)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Block read - if your platform needs to do endian-swapping or can only
|
||||
// handle aligned reads, do the conversion here
|
||||
|
||||
uint32_t getblock32(const uint32_t *p, int i)
|
||||
{
|
||||
return p[i];
|
||||
}
|
||||
|
||||
uint64_t getblock64(const uint64_t *p, int i)
|
||||
{
|
||||
return p[i];
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Finalization mix - force all bits of a hash block to avalanche
|
||||
|
||||
uint32_t fmix32(uint32_t h)
|
||||
{
|
||||
h ^= h >> 16;
|
||||
h *= 0x85ebca6b;
|
||||
h ^= h >> 13;
|
||||
h *= 0xc2b2ae35;
|
||||
h ^= h >> 16;
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
//----------
|
||||
|
||||
uint64_t fmix64(uint64_t k)
|
||||
{
|
||||
k ^= k >> 33;
|
||||
k *= BIG_CONSTANT(0xff51afd7ed558ccd);
|
||||
k ^= k >> 33;
|
||||
k *= BIG_CONSTANT(0xc4ceb9fe1a85ec53);
|
||||
k ^= k >> 33;
|
||||
|
||||
return k;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// objsize: 0x0-0x15f: 351
|
||||
|
||||
void MurmurHash3_x86_32(const void *key, int len, uint32_t seed, void *out)
|
||||
{
|
||||
const uint8_t *data = (const uint8_t *)key;
|
||||
const int nblocks = len / 4;
|
||||
|
||||
uint32_t h1 = seed;
|
||||
|
||||
const uint32_t c1 = 0xcc9e2d51;
|
||||
const uint32_t c2 = 0x1b873593;
|
||||
|
||||
//----------
|
||||
// body
|
||||
|
||||
const uint32_t *blocks = (const uint32_t *)(data + nblocks * 4);
|
||||
|
||||
for (int i = -nblocks; i; i++) {
|
||||
uint32_t k1 = getblock32(blocks, i);
|
||||
|
||||
k1 *= c1;
|
||||
k1 = ROTL32(k1, 15);
|
||||
k1 *= c2;
|
||||
|
||||
h1 ^= k1;
|
||||
h1 = ROTL32(h1, 13);
|
||||
h1 = h1 * 5 + 0xe6546b64;
|
||||
}
|
||||
|
||||
//----------
|
||||
// tail
|
||||
|
||||
const uint8_t *tail = (const uint8_t *)(data + nblocks * 4);
|
||||
|
||||
uint32_t k1 = 0;
|
||||
|
||||
switch (len & 3) {
|
||||
case 3:
|
||||
k1 ^= tail[2] << 16;
|
||||
/* Falls through. */
|
||||
case 2:
|
||||
k1 ^= tail[1] << 8;
|
||||
/* Falls through. */
|
||||
case 1:
|
||||
k1 ^= tail[0];
|
||||
k1 *= c1;
|
||||
k1 = ROTL32(k1, 15);
|
||||
k1 *= c2;
|
||||
h1 ^= k1;
|
||||
};
|
||||
|
||||
//----------
|
||||
// finalization
|
||||
|
||||
h1 ^= len;
|
||||
|
||||
h1 = fmix32(h1);
|
||||
|
||||
*(uint32_t *)out = h1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// objsize: 0x160-0x4bb: 859
|
||||
|
||||
void MurmurHash3_x86_128(const void *key, const int len, uint32_t seed, void *out)
|
||||
{
|
||||
const uint8_t *data = (const uint8_t *)key;
|
||||
const int nblocks = len / 16;
|
||||
|
||||
uint32_t h1 = seed;
|
||||
uint32_t h2 = seed;
|
||||
uint32_t h3 = seed;
|
||||
uint32_t h4 = seed;
|
||||
|
||||
const uint32_t c1 = 0x239b961b;
|
||||
const uint32_t c2 = 0xab0e9789;
|
||||
const uint32_t c3 = 0x38b34ae5;
|
||||
const uint32_t c4 = 0xa1e38b93;
|
||||
|
||||
//----------
|
||||
// body
|
||||
|
||||
const uint32_t *blocks = (const uint32_t *)(data + nblocks * 16);
|
||||
|
||||
for (int i = -nblocks; i; i++) {
|
||||
uint32_t k1 = getblock32(blocks, i * 4 + 0);
|
||||
uint32_t k2 = getblock32(blocks, i * 4 + 1);
|
||||
uint32_t k3 = getblock32(blocks, i * 4 + 2);
|
||||
uint32_t k4 = getblock32(blocks, i * 4 + 3);
|
||||
|
||||
k1 *= c1;
|
||||
k1 = ROTL32(k1, 15);
|
||||
k1 *= c2;
|
||||
h1 ^= k1;
|
||||
|
||||
h1 = ROTL32(h1, 19);
|
||||
h1 += h2;
|
||||
h1 = h1 * 5 + 0x561ccd1b;
|
||||
|
||||
k2 *= c2;
|
||||
k2 = ROTL32(k2, 16);
|
||||
k2 *= c3;
|
||||
h2 ^= k2;
|
||||
|
||||
h2 = ROTL32(h2, 17);
|
||||
h2 += h3;
|
||||
h2 = h2 * 5 + 0x0bcaa747;
|
||||
|
||||
k3 *= c3;
|
||||
k3 = ROTL32(k3, 17);
|
||||
k3 *= c4;
|
||||
h3 ^= k3;
|
||||
|
||||
h3 = ROTL32(h3, 15);
|
||||
h3 += h4;
|
||||
h3 = h3 * 5 + 0x96cd1c35;
|
||||
|
||||
k4 *= c4;
|
||||
k4 = ROTL32(k4, 18);
|
||||
k4 *= c1;
|
||||
h4 ^= k4;
|
||||
|
||||
h4 = ROTL32(h4, 13);
|
||||
h4 += h1;
|
||||
h4 = h4 * 5 + 0x32ac3b17;
|
||||
}
|
||||
|
||||
//----------
|
||||
// tail
|
||||
|
||||
const uint8_t *tail = (const uint8_t *)(data + nblocks * 16);
|
||||
|
||||
uint32_t k1 = 0;
|
||||
uint32_t k2 = 0;
|
||||
uint32_t k3 = 0;
|
||||
uint32_t k4 = 0;
|
||||
|
||||
switch (len & 15) {
|
||||
case 15:
|
||||
k4 ^= tail[14] << 16;
|
||||
/* Falls through. */
|
||||
case 14:
|
||||
k4 ^= tail[13] << 8;
|
||||
/* Falls through. */
|
||||
case 13:
|
||||
k4 ^= tail[12] << 0;
|
||||
k4 *= c4;
|
||||
k4 = ROTL32(k4, 18);
|
||||
k4 *= c1;
|
||||
h4 ^= k4;
|
||||
/* Falls through. */
|
||||
case 12:
|
||||
k3 ^= tail[11] << 24;
|
||||
/* Falls through. */
|
||||
case 11:
|
||||
k3 ^= tail[10] << 16;
|
||||
/* Falls through. */
|
||||
case 10:
|
||||
k3 ^= tail[9] << 8;
|
||||
/* Falls through. */
|
||||
case 9:
|
||||
k3 ^= tail[8] << 0;
|
||||
k3 *= c3;
|
||||
k3 = ROTL32(k3, 17);
|
||||
k3 *= c4;
|
||||
h3 ^= k3;
|
||||
/* Falls through. */
|
||||
case 8:
|
||||
k2 ^= tail[7] << 24;
|
||||
/* Falls through. */
|
||||
case 7:
|
||||
k2 ^= tail[6] << 16;
|
||||
/* Falls through. */
|
||||
case 6:
|
||||
k2 ^= tail[5] << 8;
|
||||
/* Falls through. */
|
||||
case 5:
|
||||
k2 ^= tail[4] << 0;
|
||||
k2 *= c2;
|
||||
k2 = ROTL32(k2, 16);
|
||||
k2 *= c3;
|
||||
h2 ^= k2;
|
||||
/* Falls through. */
|
||||
case 4:
|
||||
k1 ^= tail[3] << 24;
|
||||
/* Falls through. */
|
||||
case 3:
|
||||
k1 ^= tail[2] << 16;
|
||||
/* Falls through. */
|
||||
case 2:
|
||||
k1 ^= tail[1] << 8;
|
||||
/* Falls through. */
|
||||
case 1:
|
||||
k1 ^= tail[0] << 0;
|
||||
k1 *= c1;
|
||||
k1 = ROTL32(k1, 15);
|
||||
k1 *= c2;
|
||||
h1 ^= k1;
|
||||
};
|
||||
|
||||
//----------
|
||||
// finalization
|
||||
|
||||
h1 ^= len;
|
||||
h2 ^= len;
|
||||
h3 ^= len;
|
||||
h4 ^= len;
|
||||
|
||||
h1 += h2;
|
||||
h1 += h3;
|
||||
h1 += h4;
|
||||
h2 += h1;
|
||||
h3 += h1;
|
||||
h4 += h1;
|
||||
|
||||
h1 = fmix32(h1);
|
||||
h2 = fmix32(h2);
|
||||
h3 = fmix32(h3);
|
||||
h4 = fmix32(h4);
|
||||
|
||||
h1 += h2;
|
||||
h1 += h3;
|
||||
h1 += h4;
|
||||
h2 += h1;
|
||||
h3 += h1;
|
||||
h4 += h1;
|
||||
|
||||
((uint32_t *)out)[0] = h1;
|
||||
((uint32_t *)out)[1] = h2;
|
||||
((uint32_t *)out)[2] = h3;
|
||||
((uint32_t *)out)[3] = h4;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// objsize: 0x500-0x7bb: 699
|
||||
|
||||
void MurmurHash3_x64_128(const void *key, const int len, const uint32_t seed, void *out)
|
||||
{
|
||||
const uint8_t *data = (const uint8_t *)key;
|
||||
const int nblocks = len / 16;
|
||||
|
||||
uint64_t h1 = seed;
|
||||
uint64_t h2 = seed;
|
||||
|
||||
const uint64_t c1 = BIG_CONSTANT(0x87c37b91114253d5);
|
||||
const uint64_t c2 = BIG_CONSTANT(0x4cf5ad432745937f);
|
||||
|
||||
//----------
|
||||
// body
|
||||
|
||||
const uint64_t *blocks = (const uint64_t *)(data);
|
||||
|
||||
for (int i = 0; i < nblocks; i++) {
|
||||
uint64_t k1 = getblock64(blocks, i * 2 + 0);
|
||||
uint64_t k2 = getblock64(blocks, i * 2 + 1);
|
||||
|
||||
k1 *= c1;
|
||||
k1 = ROTL64(k1, 31);
|
||||
k1 *= c2;
|
||||
h1 ^= k1;
|
||||
|
||||
h1 = ROTL64(h1, 27);
|
||||
h1 += h2;
|
||||
h1 = h1 * 5 + 0x52dce729;
|
||||
|
||||
k2 *= c2;
|
||||
k2 = ROTL64(k2, 33);
|
||||
k2 *= c1;
|
||||
h2 ^= k2;
|
||||
|
||||
h2 = ROTL64(h2, 31);
|
||||
h2 += h1;
|
||||
h2 = h2 * 5 + 0x38495ab5;
|
||||
}
|
||||
|
||||
//----------
|
||||
// tail
|
||||
|
||||
const uint8_t *tail = (const uint8_t *)(data + nblocks * 16);
|
||||
|
||||
uint64_t k1 = 0;
|
||||
uint64_t k2 = 0;
|
||||
|
||||
switch (len & 15) {
|
||||
case 15:
|
||||
k2 ^= ((uint64_t)tail[14]) << 48;
|
||||
/* Falls through. */
|
||||
case 14:
|
||||
k2 ^= ((uint64_t)tail[13]) << 40;
|
||||
/* Falls through. */
|
||||
case 13:
|
||||
k2 ^= ((uint64_t)tail[12]) << 32;
|
||||
/* Falls through. */
|
||||
case 12:
|
||||
k2 ^= ((uint64_t)tail[11]) << 24;
|
||||
/* Falls through. */
|
||||
case 11:
|
||||
k2 ^= ((uint64_t)tail[10]) << 16;
|
||||
/* Falls through. */
|
||||
case 10:
|
||||
k2 ^= ((uint64_t)tail[9]) << 8;
|
||||
/* Falls through. */
|
||||
case 9:
|
||||
k2 ^= ((uint64_t)tail[8]) << 0;
|
||||
k2 *= c2;
|
||||
k2 = ROTL64(k2, 33);
|
||||
k2 *= c1;
|
||||
h2 ^= k2;
|
||||
/* Falls through. */
|
||||
case 8:
|
||||
k1 ^= ((uint64_t)tail[7]) << 56;
|
||||
/* Falls through. */
|
||||
case 7:
|
||||
k1 ^= ((uint64_t)tail[6]) << 48;
|
||||
/* Falls through. */
|
||||
case 6:
|
||||
k1 ^= ((uint64_t)tail[5]) << 40;
|
||||
/* Falls through. */
|
||||
case 5:
|
||||
k1 ^= ((uint64_t)tail[4]) << 32;
|
||||
/* Falls through. */
|
||||
case 4:
|
||||
k1 ^= ((uint64_t)tail[3]) << 24;
|
||||
/* Falls through. */
|
||||
case 3:
|
||||
k1 ^= ((uint64_t)tail[2]) << 16;
|
||||
/* Falls through. */
|
||||
case 2:
|
||||
k1 ^= ((uint64_t)tail[1]) << 8;
|
||||
/* Falls through. */
|
||||
case 1:
|
||||
k1 ^= ((uint64_t)tail[0]) << 0;
|
||||
k1 *= c1;
|
||||
k1 = ROTL64(k1, 31);
|
||||
k1 *= c2;
|
||||
h1 ^= k1;
|
||||
};
|
||||
|
||||
//----------
|
||||
// finalization
|
||||
|
||||
h1 ^= len;
|
||||
h2 ^= len;
|
||||
|
||||
h1 += h2;
|
||||
h2 += h1;
|
||||
|
||||
h1 = fmix64(h1);
|
||||
h2 = fmix64(h2);
|
||||
|
||||
h1 += h2;
|
||||
h2 += h1;
|
||||
|
||||
((uint64_t *)out)[0] = h1;
|
||||
((uint64_t *)out)[1] = h2;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
26
libraries/M5Utility/test/MurmurHash3.h
Normal file
26
libraries/M5Utility/test/MurmurHash3.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
MurmurHash3 by
|
||||
https://github.com/aappleby/smhasher/blob/master/src/MurmurHash3.hpp
|
||||
|
||||
Modified by M5Stack
|
||||
*/
|
||||
//-----------------------------------------------------------------------------
|
||||
// MurmurHash3 was written by Austin Appleby, and is placed in the public
|
||||
// domain. The author hereby disclaims copyright to this source code.
|
||||
|
||||
#ifndef _MURMURHASH3_H_
|
||||
#define _MURMURHASH3_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void MurmurHash3_x86_32(const void* key, int len, uint32_t seed, void* out);
|
||||
|
||||
void MurmurHash3_x86_128(const void* key, int len, uint32_t seed, void* out);
|
||||
|
||||
void MurmurHash3_x64_128(const void* key, int len, uint32_t seed, void* out);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#endif // _MURMURHASH3_H_
|
||||
58
libraries/M5Utility/test/common_main.cpp
Normal file
58
libraries/M5Utility/test/common_main.cpp
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
/*
|
||||
main for UnitTest on native
|
||||
*/
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
// C++ version
|
||||
#if __cplusplus >= 202002L
|
||||
#pragma message "C++20 or later"
|
||||
#elif __cplusplus >= 201703L
|
||||
#pragma message "C++17 or later"
|
||||
#elif __cplusplus >= 201402L
|
||||
#pragma message "C++14 or later"
|
||||
#elif __cplusplus >= 201103L
|
||||
#pragma message "C++11 or later"
|
||||
#else
|
||||
#error "Need C++11 or later"
|
||||
#endif
|
||||
// Compiler
|
||||
#if defined(__clang__)
|
||||
#pragma message "Clang"
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma message "MSVC"
|
||||
#elif defined(__BORLANDC__)
|
||||
#pragma message "BORLANDC"
|
||||
#elif defined(__MINGW32__) || defined(__MINGW64__)
|
||||
#pragma message "MINGW"
|
||||
#elif defined(__INTEL_COMPILER)
|
||||
#pragma message "ICC"
|
||||
#elif defined(__GNUG__)
|
||||
#pragma message "GCC"
|
||||
#else
|
||||
#pragma message "Unknown compiler"
|
||||
#endif
|
||||
|
||||
/*
|
||||
For native test, this main() is used.
|
||||
For embedded test, overwrite by main() in library.
|
||||
*/
|
||||
__attribute__((weak)) int main(int argc, char **argv)
|
||||
{
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
|
||||
#ifdef GTEST_FILTER
|
||||
::testing::GTEST_FLAG(filter) = GTEST_FILTER;
|
||||
#endif
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-result"
|
||||
RUN_ALL_TESTS();
|
||||
#pragma GCC diagnostic pop
|
||||
// Always return zero-code and allow PlatformIO to parse results
|
||||
return 0;
|
||||
}
|
||||
473
libraries/M5Utility/test/container_test.cpp
Normal file
473
libraries/M5Utility/test/container_test.cpp
Normal file
|
|
@ -0,0 +1,473 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
/*
|
||||
UnitTest for M5Utility
|
||||
*/
|
||||
#include <gtest/gtest.h>
|
||||
#include <M5Utility.hpp>
|
||||
#include <M5Unified.hpp>
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace m5::container;
|
||||
|
||||
void cb_basic_test()
|
||||
{
|
||||
SCOPED_TRACE("Basic");
|
||||
|
||||
FixedCircularBuffer<int, 4> rbuf;
|
||||
|
||||
EXPECT_TRUE(rbuf.empty());
|
||||
EXPECT_FALSE(rbuf.full());
|
||||
EXPECT_EQ(rbuf.capacity(), 4U);
|
||||
EXPECT_EQ(rbuf.size(), 0U);
|
||||
EXPECT_FALSE(rbuf.front());
|
||||
EXPECT_FALSE(rbuf.back());
|
||||
EXPECT_FALSE(rbuf.at(0));
|
||||
EXPECT_FALSE(rbuf.at(1));
|
||||
EXPECT_FALSE(rbuf.at(2));
|
||||
EXPECT_FALSE(rbuf.at(3));
|
||||
|
||||
// H
|
||||
// | | | | 1 |
|
||||
// T
|
||||
rbuf.push_front(1);
|
||||
EXPECT_FALSE(rbuf.empty());
|
||||
EXPECT_FALSE(rbuf.full());
|
||||
EXPECT_EQ(rbuf.size(), 1U);
|
||||
EXPECT_EQ(rbuf[0], 1);
|
||||
EXPECT_EQ(rbuf.front(), 1);
|
||||
EXPECT_EQ(rbuf.back(), 1);
|
||||
// M5_LOGW("1> %zu/%zu/%u", rbuf._head, rbuf._tail, rbuf._full);
|
||||
|
||||
// H
|
||||
// | | | | |
|
||||
// T
|
||||
auto r = rbuf.front();
|
||||
EXPECT_TRUE(r);
|
||||
int v = *r;
|
||||
rbuf.pop_front();
|
||||
EXPECT_EQ(v, 1);
|
||||
EXPECT_TRUE(rbuf.empty());
|
||||
EXPECT_FALSE(rbuf.full());
|
||||
EXPECT_EQ(rbuf.size(), 0U);
|
||||
EXPECT_FALSE(rbuf.front());
|
||||
EXPECT_FALSE(rbuf.back());
|
||||
// M5_LOGW("2> %zu/%zu/%u", rbuf._head, rbuf._tail, rbuf._full);
|
||||
|
||||
// H
|
||||
// | 2 | | | |
|
||||
// T
|
||||
rbuf.push_back(2);
|
||||
EXPECT_FALSE(rbuf.empty());
|
||||
EXPECT_FALSE(rbuf.full());
|
||||
EXPECT_EQ(rbuf.size(), 1U);
|
||||
EXPECT_EQ(rbuf[0], 2);
|
||||
EXPECT_EQ(rbuf.front(), 2);
|
||||
EXPECT_EQ(rbuf.back(), 2);
|
||||
// M5_LOGW("3> %zu/%zu/%u", rbuf._head, rbuf._tail, rbuf._full);
|
||||
|
||||
// H
|
||||
// | | | | |
|
||||
// T
|
||||
r = rbuf.back();
|
||||
EXPECT_TRUE(r);
|
||||
v = *r;
|
||||
rbuf.pop_back();
|
||||
EXPECT_EQ(v, 2);
|
||||
EXPECT_TRUE(rbuf.empty());
|
||||
EXPECT_FALSE(rbuf.full());
|
||||
EXPECT_EQ(rbuf.size(), 0U);
|
||||
EXPECT_FALSE(rbuf.front());
|
||||
EXPECT_FALSE(rbuf.back());
|
||||
// M5_LOGW("3> %zu/%zu/%u", rbuf._head, rbuf._tail, rbuf._full);
|
||||
|
||||
// H
|
||||
// | 4 | 5 | 6 | 3 |
|
||||
// T
|
||||
rbuf.push_front(3); // to front
|
||||
EXPECT_FALSE(rbuf.empty());
|
||||
EXPECT_FALSE(rbuf.full());
|
||||
EXPECT_EQ(rbuf.size(), 1U);
|
||||
EXPECT_EQ(rbuf.front(), 3);
|
||||
EXPECT_EQ(rbuf.back(), 3);
|
||||
|
||||
rbuf.push_back(4); // to back
|
||||
EXPECT_FALSE(rbuf.empty());
|
||||
EXPECT_FALSE(rbuf.full());
|
||||
EXPECT_EQ(rbuf.size(), 2U);
|
||||
EXPECT_EQ(rbuf.front(), 3);
|
||||
EXPECT_EQ(rbuf.back(), 4);
|
||||
|
||||
rbuf.push_back(5); // to back
|
||||
EXPECT_FALSE(rbuf.empty());
|
||||
EXPECT_FALSE(rbuf.full());
|
||||
EXPECT_EQ(rbuf.size(), 3U);
|
||||
EXPECT_EQ(rbuf.front(), 3);
|
||||
EXPECT_EQ(rbuf.back(), 5);
|
||||
|
||||
rbuf.push_front(6); // to front
|
||||
EXPECT_FALSE(rbuf.empty());
|
||||
EXPECT_TRUE(rbuf.full());
|
||||
EXPECT_EQ(rbuf.size(), 4U);
|
||||
EXPECT_EQ(rbuf[0], 6);
|
||||
EXPECT_EQ(rbuf[1], 3);
|
||||
EXPECT_EQ(rbuf[2], 4);
|
||||
EXPECT_EQ(rbuf[3], 5);
|
||||
EXPECT_EQ(rbuf.front(), 6);
|
||||
EXPECT_EQ(rbuf.back(), 5);
|
||||
// M5_LOGW("4> %zu/%zu/%u", rbuf._head, rbuf._tail, rbuf._full);
|
||||
|
||||
// H
|
||||
// | 4 | 7 | 6 | 3 |
|
||||
// T
|
||||
rbuf.push_front(7);
|
||||
EXPECT_FALSE(rbuf.empty());
|
||||
EXPECT_TRUE(rbuf.full());
|
||||
EXPECT_EQ(rbuf.size(), 4U);
|
||||
EXPECT_EQ(rbuf[0], 7);
|
||||
EXPECT_EQ(rbuf[1], 6);
|
||||
EXPECT_EQ(rbuf[2], 3);
|
||||
EXPECT_EQ(rbuf[3], 4);
|
||||
EXPECT_EQ(rbuf.front(), 7);
|
||||
EXPECT_EQ(rbuf.back(), 4);
|
||||
// M5_LOGW("5> %zu/%zu/%u", rbuf._head, rbuf._tail, rbuf._full);
|
||||
|
||||
// H
|
||||
// | 4 | 8 | 6 | 3 |
|
||||
// T
|
||||
rbuf.push_back(8);
|
||||
EXPECT_FALSE(rbuf.empty());
|
||||
EXPECT_TRUE(rbuf.full());
|
||||
EXPECT_EQ(rbuf.size(), 4U);
|
||||
EXPECT_EQ(rbuf[0], 6);
|
||||
EXPECT_EQ(rbuf[1], 3);
|
||||
EXPECT_EQ(rbuf[2], 4);
|
||||
EXPECT_EQ(rbuf[3], 8);
|
||||
EXPECT_EQ(rbuf.front(), 6);
|
||||
EXPECT_EQ(rbuf.back(), 8);
|
||||
// M5_LOGW("5> %zu/%zu/%u", rbuf._head, rbuf._tail, rbuf._full);
|
||||
|
||||
// H
|
||||
// | | | | |
|
||||
// T
|
||||
rbuf.pop_back();
|
||||
EXPECT_EQ(rbuf.back(), 4);
|
||||
rbuf.pop_back();
|
||||
EXPECT_EQ(rbuf.back(), 3);
|
||||
rbuf.pop_back();
|
||||
EXPECT_EQ(rbuf.back(), 6);
|
||||
rbuf.pop_back();
|
||||
EXPECT_TRUE(rbuf.empty());
|
||||
EXPECT_FALSE(rbuf.full());
|
||||
EXPECT_EQ(rbuf.size(), 0U);
|
||||
EXPECT_FALSE(rbuf.front());
|
||||
EXPECT_FALSE(rbuf.back());
|
||||
// M5_LOGW("6> %zu/%zu/%u", rbuf._head, rbuf._tail, rbuf._full);
|
||||
|
||||
// H
|
||||
// | 11| 12| 13| 10 |
|
||||
// T
|
||||
rbuf.push_back(9);
|
||||
rbuf.push_back(10);
|
||||
rbuf.push_back(11);
|
||||
rbuf.push_back(12);
|
||||
rbuf.push_back(13);
|
||||
EXPECT_FALSE(rbuf.empty());
|
||||
EXPECT_TRUE(rbuf.full());
|
||||
EXPECT_EQ(rbuf.size(), 4U);
|
||||
EXPECT_EQ(rbuf[0], 10);
|
||||
EXPECT_EQ(rbuf[1], 11);
|
||||
EXPECT_EQ(rbuf[2], 12);
|
||||
EXPECT_EQ(rbuf[3], 13);
|
||||
EXPECT_EQ(rbuf.front(), 10);
|
||||
EXPECT_EQ(rbuf.back(), 13);
|
||||
// M5_LOGW("7> %zu/%zu/%u", rbuf._head, rbuf._tail, rbuf._full);
|
||||
|
||||
// H
|
||||
// | | | 13| |
|
||||
// T
|
||||
rbuf.pop_front();
|
||||
EXPECT_EQ(rbuf.front(), 11);
|
||||
EXPECT_EQ(rbuf.back(), 13);
|
||||
rbuf.pop_front();
|
||||
EXPECT_EQ(rbuf.front(), 12);
|
||||
EXPECT_EQ(rbuf.back(), 13);
|
||||
rbuf.pop_front();
|
||||
EXPECT_FALSE(rbuf.empty());
|
||||
EXPECT_FALSE(rbuf.full());
|
||||
EXPECT_EQ(rbuf.size(), 1U);
|
||||
EXPECT_EQ(rbuf.front(), 13);
|
||||
EXPECT_EQ(rbuf.back(), 13);
|
||||
// M5_LOGW("8> %zu/%zu/%u", rbuf._head, rbuf._tail, rbuf._full);
|
||||
|
||||
// H
|
||||
// | | | | |
|
||||
// T
|
||||
rbuf.clear();
|
||||
EXPECT_TRUE(rbuf.empty());
|
||||
EXPECT_FALSE(rbuf.full());
|
||||
EXPECT_EQ(rbuf.size(), 0U);
|
||||
EXPECT_FALSE(rbuf.front());
|
||||
EXPECT_FALSE(rbuf.back());
|
||||
// M5_LOGW("9> %zu/%zu/%u", rbuf._head, rbuf._tail, rbuf._full);
|
||||
|
||||
// H
|
||||
// |111|111|111|111|
|
||||
// T
|
||||
rbuf.fill(111);
|
||||
EXPECT_TRUE(rbuf.full());
|
||||
EXPECT_EQ(rbuf.size(), 4U);
|
||||
EXPECT_EQ(rbuf[0], 111);
|
||||
EXPECT_EQ(rbuf[1], 111);
|
||||
EXPECT_EQ(rbuf[2], 111);
|
||||
EXPECT_EQ(rbuf[3], 111);
|
||||
EXPECT_EQ(rbuf.front(), 111);
|
||||
EXPECT_EQ(rbuf.back(), 111);
|
||||
// M5_LOGW("A> %zu/%zu/%u", rbuf._head, rbuf._tail, rbuf._full);
|
||||
}
|
||||
|
||||
void cb_constructor_test()
|
||||
{
|
||||
SCOPED_TRACE("Constructor");
|
||||
|
||||
std::vector<int> table(100);
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
table[i] = i;
|
||||
}
|
||||
|
||||
{
|
||||
FixedCircularBuffer<int, 8> rbuf(2U, 52);
|
||||
EXPECT_FALSE(rbuf.empty());
|
||||
EXPECT_FALSE(rbuf.full());
|
||||
EXPECT_EQ(rbuf.capacity(), 8U);
|
||||
EXPECT_EQ(rbuf.size(), 2U);
|
||||
EXPECT_EQ(rbuf[0], 52);
|
||||
EXPECT_EQ(rbuf[1], 52);
|
||||
}
|
||||
{
|
||||
FixedCircularBuffer<int, 8> rbuf(100U, 52);
|
||||
EXPECT_FALSE(rbuf.empty());
|
||||
EXPECT_TRUE(rbuf.full());
|
||||
EXPECT_EQ(rbuf.capacity(), 8U);
|
||||
EXPECT_EQ(rbuf.size(), 8U);
|
||||
EXPECT_EQ(rbuf.front(), 52);
|
||||
EXPECT_EQ(rbuf.back(), 52);
|
||||
}
|
||||
|
||||
{
|
||||
FixedCircularBuffer<int, 10> rbuf2({9, 8, 7, 6, 5});
|
||||
EXPECT_FALSE(rbuf2.empty());
|
||||
EXPECT_FALSE(rbuf2.full());
|
||||
EXPECT_EQ(rbuf2.capacity(), 10U);
|
||||
EXPECT_EQ(rbuf2.size(), 5U);
|
||||
EXPECT_EQ(rbuf2[0], 9);
|
||||
EXPECT_EQ(rbuf2[1], 8);
|
||||
EXPECT_EQ(rbuf2[2], 7);
|
||||
EXPECT_EQ(rbuf2[3], 6);
|
||||
EXPECT_EQ(rbuf2[4], 5);
|
||||
}
|
||||
{
|
||||
FixedCircularBuffer<int, 8> rbuf2(table.begin(), table.end());
|
||||
EXPECT_FALSE(rbuf2.empty());
|
||||
EXPECT_TRUE(rbuf2.full());
|
||||
EXPECT_EQ(rbuf2.capacity(), 8U);
|
||||
EXPECT_EQ(rbuf2.size(), 8U);
|
||||
EXPECT_EQ(rbuf2.front(), 100 - 8);
|
||||
EXPECT_EQ(rbuf2.back(), 99);
|
||||
}
|
||||
|
||||
FixedCircularBuffer<float, 3> rbuf3 = {1.1f, 2.2f, 3.3f};
|
||||
EXPECT_FALSE(rbuf3.empty());
|
||||
EXPECT_TRUE(rbuf3.full());
|
||||
EXPECT_EQ(rbuf3.capacity(), 3U);
|
||||
EXPECT_EQ(rbuf3.size(), 3U);
|
||||
EXPECT_FLOAT_EQ(rbuf3[0], 1.1f);
|
||||
EXPECT_FLOAT_EQ(rbuf3[1], 2.2f);
|
||||
EXPECT_FLOAT_EQ(rbuf3[2], 3.3f);
|
||||
}
|
||||
|
||||
void cb_read()
|
||||
{
|
||||
SCOPED_TRACE("Read");
|
||||
|
||||
FixedCircularBuffer<int, 128> rb;
|
||||
int buf[128] = {};
|
||||
size_t rcnt = 0;
|
||||
|
||||
// empty
|
||||
rcnt = rb.read(buf, 64);
|
||||
EXPECT_EQ(rcnt, 0U);
|
||||
|
||||
// fill
|
||||
for (size_t i = 0; i < rb.capacity(); ++i) {
|
||||
rb.push_back(i);
|
||||
}
|
||||
EXPECT_EQ(rb.size(), 128U);
|
||||
|
||||
// read half
|
||||
rcnt = rb.read(buf, 64);
|
||||
EXPECT_EQ(rcnt, 64U);
|
||||
for (int i = 0; i < 64; ++i) {
|
||||
EXPECT_EQ(buf[i], i) << i;
|
||||
}
|
||||
|
||||
EXPECT_EQ(rb.size(), 128U);
|
||||
EXPECT_EQ(rb.front(), 0);
|
||||
EXPECT_EQ(rb.back(), 127);
|
||||
|
||||
// pop half
|
||||
for (int i = 0; i < 64; ++i) {
|
||||
rb.pop_front();
|
||||
}
|
||||
|
||||
// read
|
||||
rcnt = rb.read(buf, 64);
|
||||
EXPECT_EQ(rcnt, 64U);
|
||||
for (int i = 0; i < 64; ++i) {
|
||||
EXPECT_EQ(buf[i], i + 64) << (i + 64);
|
||||
}
|
||||
|
||||
EXPECT_EQ(rb.size(), 64U);
|
||||
EXPECT_EQ(rb.front(), 64);
|
||||
EXPECT_EQ(rb.back(), 127);
|
||||
|
||||
// pop half
|
||||
for (int i = 0; i < 32; ++i) {
|
||||
rb.pop_front();
|
||||
}
|
||||
|
||||
// read
|
||||
rcnt = rb.read(buf, 64);
|
||||
EXPECT_EQ(rcnt, 32U);
|
||||
for (int i = 0; i < 32; ++i) {
|
||||
EXPECT_EQ(buf[i], i + 96) << (i + 96);
|
||||
}
|
||||
|
||||
EXPECT_EQ(rb.size(), 32U);
|
||||
EXPECT_EQ(rb.front(), 96);
|
||||
EXPECT_EQ(rb.back(), 127);
|
||||
|
||||
// push
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
rb.push_back(i + 128);
|
||||
}
|
||||
|
||||
// read
|
||||
rcnt = rb.read(buf, 64);
|
||||
EXPECT_EQ(rcnt, 64U);
|
||||
for (int i = 0; i < 64; ++i) {
|
||||
EXPECT_EQ(buf[i], i + 100) << (i + 100);
|
||||
}
|
||||
|
||||
EXPECT_EQ(rb.size(), 128U);
|
||||
EXPECT_EQ(*rb.front(), 227 - 127);
|
||||
EXPECT_EQ(*rb.back(), 227);
|
||||
}
|
||||
|
||||
void cb_iterator_test()
|
||||
{
|
||||
SCOPED_TRACE("Iterators");
|
||||
|
||||
FixedCircularBuffer<int, 4> rb = {0, 1, 2};
|
||||
FixedCircularBuffer<int, 6> rb2;
|
||||
|
||||
// empty
|
||||
EXPECT_EQ(rb2.begin(), rb2.end());
|
||||
EXPECT_EQ(rb2.rbegin(), rb2.rend());
|
||||
EXPECT_EQ(rb2.cbegin(), rb2.cend());
|
||||
EXPECT_EQ(rb2.crbegin(), rb2.crend());
|
||||
|
||||
//
|
||||
int c = 0;
|
||||
for (auto it = rb.begin(); it != rb.end(); ++it) {
|
||||
EXPECT_EQ(*it, c++);
|
||||
}
|
||||
c = 2;
|
||||
for (auto it = rb.rbegin(); it != rb.rend(); ++it) {
|
||||
EXPECT_EQ(*it, c--);
|
||||
}
|
||||
c = 0;
|
||||
for (auto it = rb.cbegin(); it != rb.cend(); ++it) {
|
||||
EXPECT_EQ(*it, c++);
|
||||
}
|
||||
c = 2;
|
||||
for (auto it = rb.crbegin(); it != rb.crend(); ++it) {
|
||||
EXPECT_EQ(*it, c--);
|
||||
}
|
||||
|
||||
//
|
||||
rb.clear();
|
||||
rb.push_back(9);
|
||||
rb.push_back(8);
|
||||
rb.push_back(7);
|
||||
rb.push_back(6);
|
||||
EXPECT_TRUE(rb.full());
|
||||
|
||||
c = 9;
|
||||
for (auto&& e : rb) {
|
||||
EXPECT_EQ(e, c--);
|
||||
}
|
||||
c = 6;
|
||||
for (auto it = rb.crbegin(); it != rb.crend(); ++it) {
|
||||
EXPECT_EQ(*it, c++);
|
||||
}
|
||||
|
||||
// make the rounds
|
||||
rb.push_back(5);
|
||||
rb.push_back(4);
|
||||
c = 7;
|
||||
for (auto&& e : rb) {
|
||||
EXPECT_EQ(e, c--);
|
||||
}
|
||||
c = 4;
|
||||
for (auto it = rb.crbegin(); it != rb.crend(); ++it) {
|
||||
EXPECT_EQ(*it, c++);
|
||||
}
|
||||
|
||||
c = 7;
|
||||
std::for_each(std::begin(rb), std::end(rb), [&c](const int& e) { EXPECT_EQ(e, c--); });
|
||||
#if __cplusplus >= 201402L
|
||||
// std::rbegin, rend require C++14 or later
|
||||
c = 4;
|
||||
std::for_each(std::rbegin(rb), std::rend(rb), [&c](const int& e) { EXPECT_EQ(e, c++); });
|
||||
#endif
|
||||
|
||||
c = 4;
|
||||
for (auto it = rb.cend(); it != rb.cbegin(); /**/) {
|
||||
--it;
|
||||
EXPECT_EQ(*it, c++);
|
||||
}
|
||||
c = 7;
|
||||
for (auto it = rb.rend(); it != rb.rbegin(); /**/) {
|
||||
--it;
|
||||
EXPECT_EQ(*it, c--);
|
||||
}
|
||||
|
||||
{
|
||||
auto it = rb.begin();
|
||||
EXPECT_EQ(*it++, 7);
|
||||
EXPECT_EQ(*it--, 6);
|
||||
EXPECT_EQ(*++it, 6);
|
||||
EXPECT_EQ(*--it, 7);
|
||||
|
||||
auto itr = rb.rbegin();
|
||||
EXPECT_EQ(*itr++, 4);
|
||||
EXPECT_EQ(*itr--, 5);
|
||||
EXPECT_EQ(*++itr, 5);
|
||||
EXPECT_EQ(*--itr, 4);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(Utility, CircularBuffer)
|
||||
{
|
||||
cb_basic_test();
|
||||
cb_constructor_test();
|
||||
cb_read();
|
||||
cb_iterator_test();
|
||||
}
|
||||
104
libraries/M5Utility/test/conversion_test.cpp
Normal file
104
libraries/M5Utility/test/conversion_test.cpp
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
/*
|
||||
UnitTest for M5Utility
|
||||
*/
|
||||
#include <gtest/gtest.h>
|
||||
#include <M5Utility.hpp>
|
||||
|
||||
TEST(Utility, Conversion)
|
||||
{
|
||||
{
|
||||
SCOPED_TRACE("8bit:4");
|
||||
std::pair<uint8_t, int8_t> table[] = {
|
||||
// zero
|
||||
{0x00, 0},
|
||||
// only sign bit
|
||||
{0x08, -8},
|
||||
// all bits
|
||||
{0x0F, -1},
|
||||
// all signed bits
|
||||
{0x07, 7},
|
||||
};
|
||||
for (auto&& e : table) {
|
||||
EXPECT_EQ(m5::utility::unsigned_to_signed<4>(e.first), e.second) << e.first;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
SCOPED_TRACE("8bit:8");
|
||||
std::pair<uint8_t, int8_t> table[] = {
|
||||
// zero
|
||||
{0, 0},
|
||||
// only sign bit
|
||||
{0x80, -128},
|
||||
// all bits
|
||||
{0xFF, -1},
|
||||
// all signed bits
|
||||
{0x7F, 127},
|
||||
};
|
||||
for (auto&& e : table) {
|
||||
EXPECT_EQ(m5::utility::unsigned_to_signed<8>(e.first), e.second) << e.first;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
SCOPED_TRACE("16bit:10");
|
||||
std::pair<uint16_t, int16_t> table[] = {
|
||||
// zero
|
||||
{0x0000, 0},
|
||||
// only sign bit
|
||||
{0x0200, -512},
|
||||
// all bits
|
||||
{0x03FF, -1},
|
||||
// all signed bits
|
||||
{0x01FF, 511},
|
||||
//
|
||||
{0x0100, 256},
|
||||
};
|
||||
for (auto&& e : table) {
|
||||
EXPECT_EQ(m5::utility::unsigned_to_signed<10>(e.first), e.second) << e.first;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
SCOPED_TRACE("32bit:20");
|
||||
std::pair<uint32_t, int32_t> table[] = {
|
||||
// zero
|
||||
{0x00000000, 0},
|
||||
// only sign bit
|
||||
{0x00080000, -524288},
|
||||
// all bits
|
||||
{0x000FFFFF, -1},
|
||||
// all signed bits
|
||||
{0x0007FFFF, 524287},
|
||||
//
|
||||
{0x00040000, 262144},
|
||||
};
|
||||
for (auto&& e : table) {
|
||||
EXPECT_EQ(m5::utility::unsigned_to_signed<20>(e.first), e.second) << e.first;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
SCOPED_TRACE("64bit:47");
|
||||
std::pair<uint64_t, int64_t> table[] = {
|
||||
// zero
|
||||
{0x0000000000000000ULL, 0},
|
||||
// only sign bit
|
||||
{0x0000400000000000ULL, -70368744177664LL},
|
||||
// all bits
|
||||
{0x00007FFFFFFFFFFFULL, -1LL},
|
||||
// all signed bits
|
||||
{0x00003FFFFFFFFFFFULL, 70368744177663LL},
|
||||
//
|
||||
{0x0000200000000000ULL, 35184372088832},
|
||||
};
|
||||
for (auto&& e : table) {
|
||||
EXPECT_EQ(m5::utility::unsigned_to_signed<47>(e.first), e.second) << e.second;
|
||||
}
|
||||
}
|
||||
}
|
||||
147
libraries/M5Utility/test/crc_test.cpp
Normal file
147
libraries/M5Utility/test/crc_test.cpp
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
/*
|
||||
UnitTest for M5Utility
|
||||
*/
|
||||
#include <gtest/gtest.h>
|
||||
#include <M5Utility.hpp>
|
||||
#include <M5Unified.hpp>
|
||||
|
||||
namespace {
|
||||
struct CRCType {
|
||||
const char* name;
|
||||
const uint32_t result;
|
||||
const uint32_t poly;
|
||||
const uint32_t init;
|
||||
const bool refIn;
|
||||
const bool refOut;
|
||||
const uint32_t xorout;
|
||||
};
|
||||
|
||||
// See also
|
||||
// https://crccalc.com/?crc=0123456789abcdef&method=crc8&datatype=hex&outtype=0
|
||||
CRCType crc8_table[] = {
|
||||
// name, result, poly, init, refIn, refOut, xorout
|
||||
{"CRC-8", 0x1E, 0x07, 0x00, false, false, 0x00}, {"CRC-8/CDMA2000", 0xF0, 0x9B, 0xFF, false, false, 0x00},
|
||||
{"CRC-8/DARC", 0x4E, 0x39, 0x00, true, true, 0x00}, {"CRC-8/DVB-S2", 0x7D, 0xD5, 0x00, false, false, 0x00},
|
||||
{"CRC-8/EBU", 0x17, 0x1D, 0xFF, true, true, 0x00}, {"CRC-8/I-CODE", 0x6C, 0x1D, 0xFD, false, false, 0x00},
|
||||
{"CRC-8/ITU", 0x4B, 0x07, 0x00, false, false, 0x55}, {"CRC-8/MAXIM", 0xDD, 0x31, 0x00, true, true, 0x00},
|
||||
{"CRC-8/ROHC", 0xFC, 0x07, 0xFF, true, true, 0x00}, {"CRC-8/WCDMA", 0x22, 0x9B, 0x00, true, true, 0x00},
|
||||
};
|
||||
|
||||
CRCType crc16_table[] = {
|
||||
// name, result, poly, init, refIn, refOut, xorout
|
||||
{"CRC-16/ARC", 0xF3A6, 0x8005, 0x0000, true, true, 0x0000},
|
||||
{"CRC-16/AUG-CCITT", 0x486C, 0x1021, 0x1D0F, false, false, 0x0000},
|
||||
{"CRC-16/BUYPASS", 0x2951, 0x8005, 0x0000, false, false, 0x0000},
|
||||
{"CRC-16/CCITT-FALSE", 0x986B, 0x1021, 0xFFFF, false, false, 0x0000},
|
||||
{"CRC-16/CDMA2000", 0x593C, 0xC867, 0xFFFF, false, false, 0x0000},
|
||||
{"CRC-16/DDS-110", 0x27B1, 0x8005, 0x800D, false, false, 0x0000},
|
||||
{"CRC-16/DECT-R", 0xE83B, 0x0589, 0x0000, false, false, 0x0001},
|
||||
{"CRC-16/DECT-X", 0xE83A, 0x0589, 0x0000, false, false, 0x0000},
|
||||
{"CRC-16/DNP", 0xDFCE, 0x3D65, 0x0000, true, true, 0xFFFF},
|
||||
{"CRC-16/EN-13757", 0x984F, 0x3D65, 0x0000, false, false, 0xFFFF},
|
||||
{"CRC-16/GENIBUS", 0x6794, 0x1021, 0xFFFF, false, false, 0xFFFF},
|
||||
{"CRC-16/KERMIT", 0x5A3C, 0x1021, 0x0000, true, true, 0x0000},
|
||||
{"CRC-16/MAXIM", 0x0C59, 0x8005, 0x0000, true, true, 0xFFFF},
|
||||
{"CRC-16/MCRF4XX", 0x26B0, 0x1021, 0xFFFF, true, true, 0x0000},
|
||||
{"CRC-16/MODBUS", 0xF8E6, 0x8005, 0xFFFF, true, true, 0x0000},
|
||||
{"CRC-16/RIELLO", 0x077C, 0x1021, 0xB2AA, true, true, 0x0000}, // 0x554D
|
||||
{"CRC-16/T10-DIF", 0x4FF0, 0x8BB7, 0x0000, false, false, 0x0000},
|
||||
{"CRC-16/TELEDISK", 0x3267, 0xA097, 0x0000, false, false, 0x0000},
|
||||
{"CRC-16/TMS37157", 0x5A4B, 0x1021, 0x89EC, true, true, 0x0000}, // 0x3791
|
||||
{"CRC-16/USB", 0x0719, 0x8005, 0xFFFF, true, true, 0xFFFF},
|
||||
{"CRC-16/X-25", 0xD94F, 0x1021, 0xFFFF, true, true, 0xFFFF},
|
||||
{"CRC-16/XMODEM", 0xA955, 0x1021, 0x0000, false, false, 0x0000},
|
||||
{"CRC-A", 0x0F06, 0x1021, 0xC6C6, true, true, 0x0000}, // 0x6363
|
||||
};
|
||||
|
||||
const std::vector<uint8_t> tdata = {
|
||||
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
|
||||
};
|
||||
|
||||
}; // namespace
|
||||
|
||||
using namespace m5::utility;
|
||||
|
||||
TEST(Utility, CRC8)
|
||||
{
|
||||
for (auto&& e : crc8_table) {
|
||||
SCOPED_TRACE(e.name);
|
||||
CRC8 crc(e.init, e.poly, e.refIn, e.refOut, e.xorout);
|
||||
auto v = crc.range(tdata.data(), tdata.size());
|
||||
auto u = crc.update(tdata.data(), tdata.size());
|
||||
EXPECT_EQ(v, e.result);
|
||||
EXPECT_EQ(crc.value(), e.result);
|
||||
EXPECT_EQ(u, crc.value());
|
||||
|
||||
v = crc.range(tdata.data(), tdata.size());
|
||||
u = crc.update(tdata.data(), tdata.size());
|
||||
EXPECT_EQ(v, e.result);
|
||||
EXPECT_NE(v, u);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Utility, CRC16)
|
||||
{
|
||||
for (auto&& e : crc16_table) {
|
||||
SCOPED_TRACE(e.name);
|
||||
CRC16 crc(e.init, e.poly, e.refIn, e.refOut, e.xorout);
|
||||
auto v = crc.update(tdata.data(), tdata.size());
|
||||
EXPECT_EQ(crc.value(), e.result);
|
||||
EXPECT_EQ(v, crc.value());
|
||||
}
|
||||
}
|
||||
|
||||
// Test whether calculation from the whole and calculation from split chunks are
|
||||
// equivalent
|
||||
TEST(Utility, Chunk)
|
||||
{
|
||||
constexpr uint8_t d8[32] = {0x04, 0x67, 0xfc, 0x4d, 0xf4, 0xe7, 0x9c, 0x3b, 0x05, 0xb8, 0xad,
|
||||
0x31, 0x97, 0xb1, 0x21, 0x72, 0x59, 0x5d, 0x80, 0x26, 0x66, 0x0c,
|
||||
0x12, 0xa9, 0x53, 0xa6, 0x70, 0x87, 0x91, 0x5d, 0xa4, 0x9a};
|
||||
;
|
||||
|
||||
// CRC8
|
||||
for (auto&& e : crc8_table) {
|
||||
SCOPED_TRACE(e.name);
|
||||
uint8_t crc_all = CRC8::calculate(d8, m5::stl::size(d8), e.init, e.poly, e.refIn, e.refOut, e.xorout);
|
||||
|
||||
CRC8 crc(e.init, e.poly, e.refIn, e.refOut, e.xorout);
|
||||
uint8_t crc_chunk{};
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
crc_chunk = crc.update(d8 + (i * 8), 8);
|
||||
// M5_LOGW("%s:i:%d:[%x/%x]", e.name, i, crc_chunk,
|
||||
// crc.range(d8 + (i * 8), 8));
|
||||
if (i == 0) {
|
||||
EXPECT_EQ(crc_chunk, crc.range(d8 + (i * 8), 8));
|
||||
} else {
|
||||
EXPECT_NE(crc_chunk, crc.range(d8 + (i * 8), 8));
|
||||
}
|
||||
}
|
||||
EXPECT_EQ(crc_all, crc_chunk);
|
||||
EXPECT_EQ(crc_all, crc.value());
|
||||
}
|
||||
|
||||
// CRC16
|
||||
for (auto&& e : crc16_table) {
|
||||
SCOPED_TRACE(e.name);
|
||||
uint16_t crc_all = CRC16::calculate(d8, m5::stl::size(d8), e.init, e.poly, e.refIn, e.refOut, e.xorout);
|
||||
|
||||
CRC16 crc(e.init, e.poly, e.refIn, e.refOut, e.xorout);
|
||||
uint16_t crc_chunk{};
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
crc_chunk = crc.update(d8 + (i * 8), 8);
|
||||
if (i == 0) {
|
||||
EXPECT_EQ(crc_chunk, crc.range(d8 + (i * 8), 8));
|
||||
} else {
|
||||
EXPECT_NE(crc_chunk, crc.range(d8 + (i * 8), 8));
|
||||
}
|
||||
}
|
||||
EXPECT_EQ(crc_all, crc_chunk);
|
||||
EXPECT_EQ(crc_all, crc_chunk);
|
||||
}
|
||||
}
|
||||
53
libraries/M5Utility/test/embedded/embedded_main.cpp
Normal file
53
libraries/M5Utility/test/embedded/embedded_main.cpp
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
/*
|
||||
main for UnitTest on embedded
|
||||
*/
|
||||
#include <gtest/gtest.h>
|
||||
#include <M5Unified.h>
|
||||
|
||||
#pragma message "Embedded setup/loop"
|
||||
|
||||
#if __has_include(<esp_idf_version.h>)
|
||||
#include <esp_idf_version.h>
|
||||
#else // esp_idf_version.h has been introduced in Arduino 1.0.5 (ESP-IDF3.3)
|
||||
#define ESP_IDF_VERSION_VAL(major, minor, patch) ((major << 16) | (minor << 8) | (patch))
|
||||
#define ESP_IDF_VERSION ESP_IDF_VERSION_VAL(3, 2, 0)
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
auto& lcd = M5.Display;
|
||||
}
|
||||
|
||||
void test()
|
||||
{
|
||||
lcd.fillRect(0, 0, lcd.width() >> 1, lcd.height(), RUN_ALL_TESTS() ? TFT_RED : TFT_GREEN);
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
M5.begin();
|
||||
|
||||
M5_LOGI("CPP %ld", __cplusplus);
|
||||
M5_LOGI("ESP-IDF Version %d.%d.%d", (ESP_IDF_VERSION >> 16) & 0xFF, (ESP_IDF_VERSION >> 8) & 0xFF,
|
||||
ESP_IDF_VERSION & 0xFF);
|
||||
M5_LOGI("Heap: %u", esp_get_free_heap_size());
|
||||
|
||||
lcd.clear(TFT_DARKGRAY);
|
||||
::testing::InitGoogleTest();
|
||||
|
||||
#ifdef GTEST_FILTER
|
||||
::testing::GTEST_FLAG(filter) = GTEST_FILTER;
|
||||
#endif
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
test();
|
||||
while (true) {
|
||||
delay(10000);
|
||||
}
|
||||
}
|
||||
19
libraries/M5Utility/test/expected/assertions.cpp
Normal file
19
libraries/M5Utility/test/expected/assertions.cpp
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#include <gtest/gtest.h>
|
||||
// #include <stdexcept>
|
||||
|
||||
// #define TL_ASSERT(cond) if (!(cond)) { throw std::runtime_error(std::string("assertion failure")); }
|
||||
|
||||
#include <m5_utility/stl/expected.hpp>
|
||||
#if 0
|
||||
TEST(Expected, Assertions) {
|
||||
m5::stl::expected<int,int> o1 = 42;
|
||||
EXPECT_ANY_THROW(o1.error());
|
||||
|
||||
m5::stl::expected<int,int> o2 {m5::stl::unexpect, 0};
|
||||
EXPECT_ANY_THROW(*o2);
|
||||
|
||||
struct foo { int bar; };
|
||||
m5::stl::expected<struct foo,int> o3 {m5::stl::unexpect, 0};
|
||||
EXPECT_ANY_THROW(o3->bar);
|
||||
}
|
||||
#endif
|
||||
86
libraries/M5Utility/test/expected/assignment.cpp
Normal file
86
libraries/M5Utility/test/expected/assignment.cpp
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <m5_utility/stl/expected.hpp>
|
||||
|
||||
TEST(Expected, Assignment)
|
||||
{
|
||||
m5::stl::expected<int, int> e1 = 42;
|
||||
m5::stl::expected<int, int> e2 = 17;
|
||||
m5::stl::expected<int, int> e3 = 21;
|
||||
m5::stl::expected<int, int> e4 = m5::stl::make_unexpected(42);
|
||||
m5::stl::expected<int, int> e5 = m5::stl::make_unexpected(17);
|
||||
m5::stl::expected<int, int> e6 = m5::stl::make_unexpected(21);
|
||||
|
||||
e1 = e2;
|
||||
EXPECT_TRUE(e1);
|
||||
EXPECT_TRUE(*e1 == 17);
|
||||
EXPECT_TRUE(e2);
|
||||
EXPECT_TRUE(*e2 == 17);
|
||||
|
||||
e1 = std::move(e2);
|
||||
EXPECT_TRUE(e1);
|
||||
EXPECT_TRUE(*e1 == 17);
|
||||
EXPECT_TRUE(e2);
|
||||
EXPECT_TRUE(*e2 == 17);
|
||||
|
||||
e1 = 42;
|
||||
EXPECT_TRUE(e1);
|
||||
EXPECT_TRUE(*e1 == 42);
|
||||
|
||||
auto unex = m5::stl::make_unexpected(12);
|
||||
e1 = unex;
|
||||
EXPECT_TRUE(!e1);
|
||||
EXPECT_TRUE(e1.error() == 12);
|
||||
|
||||
e1 = m5::stl::make_unexpected(42);
|
||||
EXPECT_TRUE(!e1);
|
||||
EXPECT_TRUE(e1.error() == 42);
|
||||
|
||||
e1 = e3;
|
||||
EXPECT_TRUE(e1);
|
||||
EXPECT_TRUE(*e1 == 21);
|
||||
|
||||
e4 = e5;
|
||||
EXPECT_TRUE(!e4);
|
||||
EXPECT_TRUE(e4.error() == 17);
|
||||
|
||||
e4 = std::move(e6);
|
||||
EXPECT_TRUE(!e4);
|
||||
EXPECT_TRUE(e4.error() == 21);
|
||||
|
||||
e4 = e1;
|
||||
EXPECT_TRUE(e4);
|
||||
EXPECT_TRUE(*e4 == 21);
|
||||
}
|
||||
|
||||
TEST(Expected, AssignmentDeletion)
|
||||
{
|
||||
struct has_all {
|
||||
has_all() = default;
|
||||
|
||||
has_all(const has_all &) = default;
|
||||
|
||||
has_all(has_all &&) noexcept = default;
|
||||
|
||||
has_all &operator=(const has_all &) = default;
|
||||
};
|
||||
|
||||
m5::stl::expected<has_all, has_all> e1 = {};
|
||||
m5::stl::expected<has_all, has_all> e2 = {};
|
||||
e1 = e2;
|
||||
|
||||
struct except_move {
|
||||
except_move() = default;
|
||||
|
||||
except_move(const except_move &) = default;
|
||||
|
||||
except_move(except_move &&) noexcept(false)
|
||||
{
|
||||
}
|
||||
|
||||
except_move &operator=(const except_move &) = default;
|
||||
};
|
||||
|
||||
// m5::stl::expected<except_move, except_move> e3 = {};
|
||||
// m5::stl::expected<except_move, except_move> e4 = {};
|
||||
// e3 = e4; //should not compile
|
||||
}
|
||||
218
libraries/M5Utility/test/expected/bases.cpp
Normal file
218
libraries/M5Utility/test/expected/bases.cpp
Normal file
|
|
@ -0,0 +1,218 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <m5_utility/stl/expected.hpp>
|
||||
#include <string>
|
||||
|
||||
// Old versions of GCC don't have the correct trait names. Could fix them up if needs be.
|
||||
#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && !defined(__clang__))
|
||||
// nothing for now
|
||||
#else
|
||||
TEST(Expected, Triviality)
|
||||
{
|
||||
EXPECT_TRUE((std::is_trivially_copy_constructible<m5::stl::expected<int, int> >::value));
|
||||
EXPECT_TRUE((std::is_trivially_copy_assignable<m5::stl::expected<int, int> >::value));
|
||||
EXPECT_TRUE((std::is_trivially_move_constructible<m5::stl::expected<int, int> >::value));
|
||||
EXPECT_TRUE((std::is_trivially_move_assignable<m5::stl::expected<int, int> >::value));
|
||||
EXPECT_TRUE((std::is_trivially_destructible<m5::stl::expected<int, int> >::value));
|
||||
|
||||
EXPECT_TRUE((std::is_trivially_copy_constructible<m5::stl::expected<void, int> >::value));
|
||||
EXPECT_TRUE((std::is_trivially_move_constructible<m5::stl::expected<void, int> >::value));
|
||||
EXPECT_TRUE((std::is_trivially_destructible<m5::stl::expected<void, int> >::value));
|
||||
|
||||
{
|
||||
struct T {
|
||||
T(const T&) = default;
|
||||
|
||||
T(T&&) = default;
|
||||
|
||||
T& operator=(const T&) = default;
|
||||
|
||||
T& operator=(T&&) = default;
|
||||
|
||||
~T() = default;
|
||||
};
|
||||
EXPECT_TRUE((std::is_trivially_copy_constructible<m5::stl::expected<T, int> >::value));
|
||||
EXPECT_TRUE((std::is_trivially_copy_assignable<m5::stl::expected<T, int> >::value));
|
||||
EXPECT_TRUE((std::is_trivially_move_constructible<m5::stl::expected<T, int> >::value));
|
||||
EXPECT_TRUE((std::is_trivially_move_assignable<m5::stl::expected<T, int> >::value));
|
||||
EXPECT_TRUE((std::is_trivially_destructible<m5::stl::expected<T, int> >::value));
|
||||
}
|
||||
|
||||
{
|
||||
struct T {
|
||||
T(const T&)
|
||||
{
|
||||
}
|
||||
T(T&&)
|
||||
{
|
||||
}
|
||||
T& operator=(const T&)
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
T& operator=(T&&)
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
~T()
|
||||
{
|
||||
}
|
||||
};
|
||||
EXPECT_TRUE(!(std::is_trivially_copy_constructible<m5::stl::expected<T, int> >::value));
|
||||
EXPECT_TRUE(!(std::is_trivially_copy_assignable<m5::stl::expected<T, int> >::value));
|
||||
EXPECT_TRUE(!(std::is_trivially_move_constructible<m5::stl::expected<T, int> >::value));
|
||||
EXPECT_TRUE(!(std::is_trivially_move_assignable<m5::stl::expected<T, int> >::value));
|
||||
EXPECT_TRUE(!(std::is_trivially_destructible<m5::stl::expected<T, int> >::value));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Expected, Deletion)
|
||||
{
|
||||
EXPECT_TRUE((std::is_copy_constructible<m5::stl::expected<int, int> >::value));
|
||||
EXPECT_TRUE((std::is_copy_assignable<m5::stl::expected<int, int> >::value));
|
||||
EXPECT_TRUE((std::is_move_constructible<m5::stl::expected<int, int> >::value));
|
||||
EXPECT_TRUE((std::is_move_assignable<m5::stl::expected<int, int> >::value));
|
||||
EXPECT_TRUE((std::is_destructible<m5::stl::expected<int, int> >::value));
|
||||
|
||||
{
|
||||
struct T {
|
||||
T() = default;
|
||||
};
|
||||
EXPECT_TRUE((std::is_default_constructible<m5::stl::expected<T, int> >::value));
|
||||
}
|
||||
|
||||
{
|
||||
struct T {
|
||||
T(int)
|
||||
{
|
||||
}
|
||||
};
|
||||
EXPECT_TRUE(!(std::is_default_constructible<m5::stl::expected<T, int> >::value));
|
||||
}
|
||||
|
||||
{
|
||||
struct T {
|
||||
T(const T&) = default;
|
||||
|
||||
T(T&&) = default;
|
||||
|
||||
T& operator=(const T&) = default;
|
||||
|
||||
T& operator=(T&&) = default;
|
||||
|
||||
~T() = default;
|
||||
};
|
||||
EXPECT_TRUE((std::is_copy_constructible<m5::stl::expected<T, int> >::value));
|
||||
EXPECT_TRUE((std::is_copy_assignable<m5::stl::expected<T, int> >::value));
|
||||
EXPECT_TRUE((std::is_move_constructible<m5::stl::expected<T, int> >::value));
|
||||
EXPECT_TRUE((std::is_move_assignable<m5::stl::expected<T, int> >::value));
|
||||
EXPECT_TRUE((std::is_destructible<m5::stl::expected<T, int> >::value));
|
||||
}
|
||||
|
||||
{
|
||||
struct T {
|
||||
T(const T&) = delete;
|
||||
|
||||
T(T&&) = delete;
|
||||
|
||||
T& operator=(const T&) = delete;
|
||||
|
||||
T& operator=(T&&) = delete;
|
||||
};
|
||||
EXPECT_TRUE(!(std::is_copy_constructible<m5::stl::expected<T, int> >::value));
|
||||
EXPECT_TRUE(!(std::is_copy_assignable<m5::stl::expected<T, int> >::value));
|
||||
EXPECT_TRUE((!std::is_move_constructible<m5::stl::expected<T, int> >::value));
|
||||
EXPECT_TRUE(!(std::is_move_assignable<m5::stl::expected<T, int> >::value));
|
||||
}
|
||||
|
||||
{
|
||||
struct T {
|
||||
T(const T&) = delete;
|
||||
|
||||
T(T&&) = default;
|
||||
|
||||
T& operator=(const T&) = delete;
|
||||
|
||||
T& operator=(T&&) = default;
|
||||
};
|
||||
EXPECT_TRUE(!(std::is_copy_constructible<m5::stl::expected<T, int> >::value));
|
||||
EXPECT_TRUE(!(std::is_copy_assignable<m5::stl::expected<T, int> >::value));
|
||||
EXPECT_TRUE((std::is_move_constructible<m5::stl::expected<T, int> >::value));
|
||||
EXPECT_TRUE((std::is_move_assignable<m5::stl::expected<T, int> >::value));
|
||||
}
|
||||
|
||||
{
|
||||
struct T {
|
||||
T(const T&) = default;
|
||||
|
||||
T(T&&) = delete;
|
||||
|
||||
T& operator=(const T&) = default;
|
||||
|
||||
T& operator=(T&&) = delete;
|
||||
};
|
||||
EXPECT_TRUE((std::is_copy_constructible<m5::stl::expected<T, int> >::value));
|
||||
EXPECT_TRUE((std::is_copy_assignable<m5::stl::expected<T, int> >::value));
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e;
|
||||
EXPECT_TRUE(std::is_default_constructible<decltype(e)>::value);
|
||||
EXPECT_TRUE(std::is_copy_constructible<decltype(e)>::value);
|
||||
EXPECT_TRUE(std::is_move_constructible<decltype(e)>::value);
|
||||
EXPECT_TRUE(std::is_copy_assignable<decltype(e)>::value);
|
||||
EXPECT_TRUE(std::is_move_assignable<decltype(e)>::value);
|
||||
EXPECT_TRUE(TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(decltype(e))::value);
|
||||
EXPECT_TRUE(TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(decltype(e))::value);
|
||||
#if !defined(TL_EXPECTED_GCC49)
|
||||
EXPECT_TRUE(std::is_trivially_move_constructible<decltype(e)>::value);
|
||||
EXPECT_TRUE(std::is_trivially_move_assignable<decltype(e)>::value);
|
||||
#endif
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, std::string> e;
|
||||
EXPECT_TRUE(std::is_default_constructible<decltype(e)>::value);
|
||||
EXPECT_TRUE(std::is_copy_constructible<decltype(e)>::value);
|
||||
EXPECT_TRUE(std::is_move_constructible<decltype(e)>::value);
|
||||
EXPECT_TRUE(std::is_copy_assignable<decltype(e)>::value);
|
||||
EXPECT_TRUE(std::is_move_assignable<decltype(e)>::value);
|
||||
EXPECT_TRUE(!TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(decltype(e))::value);
|
||||
EXPECT_TRUE(!TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(decltype(e))::value);
|
||||
#if !defined(TL_EXPECTED_GCC49)
|
||||
EXPECT_TRUE(!std::is_trivially_move_constructible<decltype(e)>::value);
|
||||
EXPECT_TRUE(!std::is_trivially_move_assignable<decltype(e)>::value);
|
||||
#endif
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<std::string, int> e;
|
||||
EXPECT_TRUE(std::is_default_constructible<decltype(e)>::value);
|
||||
EXPECT_TRUE(std::is_copy_constructible<decltype(e)>::value);
|
||||
EXPECT_TRUE(std::is_move_constructible<decltype(e)>::value);
|
||||
EXPECT_TRUE(std::is_copy_assignable<decltype(e)>::value);
|
||||
EXPECT_TRUE(std::is_move_assignable<decltype(e)>::value);
|
||||
EXPECT_TRUE(!TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(decltype(e))::value);
|
||||
EXPECT_TRUE(!TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(decltype(e))::value);
|
||||
#if !defined(TL_EXPECTED_GCC49)
|
||||
EXPECT_TRUE(!std::is_trivially_move_constructible<decltype(e)>::value);
|
||||
EXPECT_TRUE(!std::is_trivially_move_assignable<decltype(e)>::value);
|
||||
#endif
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<std::string, std::string> e;
|
||||
EXPECT_TRUE(std::is_default_constructible<decltype(e)>::value);
|
||||
EXPECT_TRUE(std::is_copy_constructible<decltype(e)>::value);
|
||||
EXPECT_TRUE(std::is_move_constructible<decltype(e)>::value);
|
||||
EXPECT_TRUE(std::is_copy_assignable<decltype(e)>::value);
|
||||
EXPECT_TRUE(std::is_move_assignable<decltype(e)>::value);
|
||||
EXPECT_TRUE(!TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(decltype(e))::value);
|
||||
EXPECT_TRUE(!TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(decltype(e))::value);
|
||||
#if !defined(TL_EXPECTED_GCC49)
|
||||
EXPECT_TRUE(!std::is_trivially_move_constructible<decltype(e)>::value);
|
||||
EXPECT_TRUE(!std::is_trivially_move_assignable<decltype(e)>::value);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
7
libraries/M5Utility/test/expected/constexpr.cpp
Normal file
7
libraries/M5Utility/test/expected/constexpr.cpp
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <m5_utility/stl/expected.hpp>
|
||||
|
||||
TEST(Expected, Constexpr)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
136
libraries/M5Utility/test/expected/constructors.cpp
Normal file
136
libraries/M5Utility/test/expected/constructors.cpp
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <m5_utility/stl/expected.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
struct takes_init_and_variadic {
|
||||
std::vector<int> v;
|
||||
std::tuple<int, int> t;
|
||||
template <class... Args>
|
||||
takes_init_and_variadic(std::initializer_list<int> l, Args &&...args) : v(l), t(std::forward<Args>(args)...)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
TEST(Expected, Constructors)
|
||||
{
|
||||
{
|
||||
m5::stl::expected<int, int> e;
|
||||
EXPECT_TRUE(e);
|
||||
EXPECT_TRUE(e == 0);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e = m5::stl::make_unexpected(0);
|
||||
EXPECT_TRUE(!e);
|
||||
EXPECT_TRUE(e.error() == 0);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e(m5::stl::unexpect, 0);
|
||||
EXPECT_TRUE(!e);
|
||||
EXPECT_TRUE(e.error() == 0);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e(m5::stl::in_place, 42);
|
||||
EXPECT_TRUE(e);
|
||||
EXPECT_TRUE(e == 42);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<std::vector<int>, int> e(m5::stl::in_place, {0, 1});
|
||||
EXPECT_TRUE(e);
|
||||
EXPECT_TRUE((*e)[0] == 0);
|
||||
EXPECT_TRUE((*e)[1] == 1);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<std::tuple<int, int>, int> e(m5::stl::in_place, 0, 1);
|
||||
EXPECT_TRUE(e);
|
||||
EXPECT_TRUE(std::get<0>(*e) == 0);
|
||||
EXPECT_TRUE(std::get<1>(*e) == 1);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<takes_init_and_variadic, int> e(m5::stl::in_place, {0, 1}, 2, 3);
|
||||
EXPECT_TRUE(e);
|
||||
EXPECT_TRUE(e->v[0] == 0);
|
||||
EXPECT_TRUE(e->v[1] == 1);
|
||||
EXPECT_TRUE(std::get<0>(e->t) == 2);
|
||||
EXPECT_TRUE(std::get<1>(e->t) == 3);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e;
|
||||
EXPECT_TRUE(std::is_default_constructible<decltype(e)>::value);
|
||||
EXPECT_TRUE(std::is_copy_constructible<decltype(e)>::value);
|
||||
EXPECT_TRUE(std::is_move_constructible<decltype(e)>::value);
|
||||
EXPECT_TRUE(std::is_copy_assignable<decltype(e)>::value);
|
||||
EXPECT_TRUE(std::is_move_assignable<decltype(e)>::value);
|
||||
EXPECT_TRUE(TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(decltype(e))::value);
|
||||
EXPECT_TRUE(TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(decltype(e))::value);
|
||||
#if !defined(TL_EXPECTED_GCC49)
|
||||
EXPECT_TRUE(std::is_trivially_move_constructible<decltype(e)>::value);
|
||||
EXPECT_TRUE(std::is_trivially_move_assignable<decltype(e)>::value);
|
||||
#endif
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, std::string> e;
|
||||
EXPECT_TRUE(std::is_default_constructible<decltype(e)>::value);
|
||||
EXPECT_TRUE(std::is_copy_constructible<decltype(e)>::value);
|
||||
EXPECT_TRUE(std::is_move_constructible<decltype(e)>::value);
|
||||
EXPECT_TRUE(std::is_copy_assignable<decltype(e)>::value);
|
||||
EXPECT_TRUE(std::is_move_assignable<decltype(e)>::value);
|
||||
EXPECT_TRUE(!TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(decltype(e))::value);
|
||||
EXPECT_TRUE(!TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(decltype(e))::value);
|
||||
#if !defined(TL_EXPECTED_GCC49)
|
||||
EXPECT_TRUE(!std::is_trivially_move_constructible<decltype(e)>::value);
|
||||
EXPECT_TRUE(!std::is_trivially_move_assignable<decltype(e)>::value);
|
||||
#endif
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<std::string, int> e;
|
||||
EXPECT_TRUE(std::is_default_constructible<decltype(e)>::value);
|
||||
EXPECT_TRUE(std::is_copy_constructible<decltype(e)>::value);
|
||||
EXPECT_TRUE(std::is_move_constructible<decltype(e)>::value);
|
||||
EXPECT_TRUE(std::is_copy_assignable<decltype(e)>::value);
|
||||
EXPECT_TRUE(std::is_move_assignable<decltype(e)>::value);
|
||||
EXPECT_TRUE(!TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(decltype(e))::value);
|
||||
EXPECT_TRUE(!TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(decltype(e))::value);
|
||||
#if !defined(TL_EXPECTED_GCC49)
|
||||
EXPECT_TRUE(!std::is_trivially_move_constructible<decltype(e)>::value);
|
||||
EXPECT_TRUE(!std::is_trivially_move_assignable<decltype(e)>::value);
|
||||
#endif
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<std::string, std::string> e;
|
||||
EXPECT_TRUE(std::is_default_constructible<decltype(e)>::value);
|
||||
EXPECT_TRUE(std::is_copy_constructible<decltype(e)>::value);
|
||||
EXPECT_TRUE(std::is_move_constructible<decltype(e)>::value);
|
||||
EXPECT_TRUE(std::is_copy_assignable<decltype(e)>::value);
|
||||
EXPECT_TRUE(std::is_move_assignable<decltype(e)>::value);
|
||||
EXPECT_TRUE(!TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(decltype(e))::value);
|
||||
EXPECT_TRUE(!TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(decltype(e))::value);
|
||||
#if !defined(TL_EXPECTED_GCC49)
|
||||
EXPECT_TRUE(!std::is_trivially_move_constructible<decltype(e)>::value);
|
||||
EXPECT_TRUE(!std::is_trivially_move_assignable<decltype(e)>::value);
|
||||
#endif
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<void, int> e;
|
||||
EXPECT_TRUE(e);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<void, int> e(m5::stl::unexpect, 42);
|
||||
EXPECT_TRUE(!e);
|
||||
EXPECT_TRUE(e.error() == 42);
|
||||
}
|
||||
}
|
||||
51
libraries/M5Utility/test/expected/emplace.cpp
Normal file
51
libraries/M5Utility/test/expected/emplace.cpp
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <m5_utility/stl/expected.hpp>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
namespace {
|
||||
struct takes_init_and_variadic {
|
||||
std::vector<int> v;
|
||||
std::tuple<int, int> t;
|
||||
template <class... Args>
|
||||
takes_init_and_variadic(std::initializer_list<int> l, Args &&...args) : v(l), t(std::forward<Args>(args)...)
|
||||
{
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
TEST(Expected, Emplace)
|
||||
{
|
||||
{
|
||||
m5::stl::expected<std::unique_ptr<int>, int> e;
|
||||
e.emplace(new int{42});
|
||||
EXPECT_TRUE(e);
|
||||
EXPECT_TRUE(**e == 42);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<std::vector<int>, int> e;
|
||||
e.emplace({0, 1});
|
||||
EXPECT_TRUE(e);
|
||||
EXPECT_TRUE((*e)[0] == 0);
|
||||
EXPECT_TRUE((*e)[1] == 1);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<std::tuple<int, int>, int> e;
|
||||
e.emplace(2, 3);
|
||||
EXPECT_TRUE(e);
|
||||
EXPECT_TRUE(std::get<0>(*e) == 2);
|
||||
EXPECT_TRUE(std::get<1>(*e) == 3);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<::takes_init_and_variadic, int> e = m5::stl::make_unexpected(0);
|
||||
e.emplace({0, 1}, 2, 3);
|
||||
EXPECT_TRUE(e);
|
||||
EXPECT_TRUE(e->v[0] == 0);
|
||||
EXPECT_TRUE(e->v[1] == 1);
|
||||
EXPECT_TRUE(std::get<0>(e->t) == 2);
|
||||
EXPECT_TRUE(std::get<1>(e->t) == 3);
|
||||
}
|
||||
}
|
||||
832
libraries/M5Utility/test/expected/extensions.cpp
Normal file
832
libraries/M5Utility/test/expected/extensions.cpp
Normal file
|
|
@ -0,0 +1,832 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <m5_utility/stl/expected.hpp>
|
||||
|
||||
#define TOKENPASTE(x, y) x##y
|
||||
#define TOKENPASTE2(x, y) TOKENPASTE(x, y)
|
||||
#undef STATIC_REQUIRE
|
||||
#define STATIC_REQUIRE(e) \
|
||||
constexpr bool TOKENPASTE2(rqure, __LINE__) = e; \
|
||||
(void)TOKENPASTE2(rqure, __LINE__); \
|
||||
EXPECT_TRUE(e);
|
||||
|
||||
TEST(Expected, MapExtensions)
|
||||
{
|
||||
auto mul2 = [](int a) { return a * 2; };
|
||||
auto ret_void = [](int a) { (void)a; };
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e = 21;
|
||||
auto ret = e.map(mul2);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_TRUE(*ret == 42);
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e = 21;
|
||||
auto ret = e.map(mul2);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_TRUE(*ret == 42);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e = 21;
|
||||
auto ret = std::move(e).map(mul2);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_TRUE(*ret == 42);
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e = 21;
|
||||
auto ret = std::move(e).map(mul2);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_TRUE(*ret == 42);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = e.map(mul2);
|
||||
EXPECT_TRUE(!ret);
|
||||
EXPECT_TRUE(ret.error() == 21);
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = e.map(mul2);
|
||||
EXPECT_TRUE(!ret);
|
||||
EXPECT_TRUE(ret.error() == 21);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = std::move(e).map(mul2);
|
||||
EXPECT_TRUE(!ret);
|
||||
EXPECT_TRUE(ret.error() == 21);
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = std::move(e).map(mul2);
|
||||
EXPECT_TRUE(!ret);
|
||||
EXPECT_TRUE(ret.error() == 21);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e = 21;
|
||||
auto ret = e.map(ret_void);
|
||||
EXPECT_TRUE(ret);
|
||||
STATIC_REQUIRE((std::is_same<decltype(ret), m5::stl::expected<void, int>>::value));
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e = 21;
|
||||
auto ret = e.map(ret_void);
|
||||
EXPECT_TRUE(ret);
|
||||
STATIC_REQUIRE((std::is_same<decltype(ret), m5::stl::expected<void, int>>::value));
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e = 21;
|
||||
auto ret = std::move(e).map(ret_void);
|
||||
EXPECT_TRUE(ret);
|
||||
STATIC_REQUIRE((std::is_same<decltype(ret), m5::stl::expected<void, int>>::value));
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e = 21;
|
||||
auto ret = std::move(e).map(ret_void);
|
||||
EXPECT_TRUE(ret);
|
||||
STATIC_REQUIRE((std::is_same<decltype(ret), m5::stl::expected<void, int>>::value));
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = e.map(ret_void);
|
||||
EXPECT_TRUE(!ret);
|
||||
STATIC_REQUIRE((std::is_same<decltype(ret), m5::stl::expected<void, int>>::value));
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = e.map(ret_void);
|
||||
EXPECT_TRUE(!ret);
|
||||
STATIC_REQUIRE((std::is_same<decltype(ret), m5::stl::expected<void, int>>::value));
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = std::move(e).map(ret_void);
|
||||
EXPECT_TRUE(!ret);
|
||||
STATIC_REQUIRE((std::is_same<decltype(ret), m5::stl::expected<void, int>>::value));
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = std::move(e).map(ret_void);
|
||||
EXPECT_TRUE(!ret);
|
||||
STATIC_REQUIRE((std::is_same<decltype(ret), m5::stl::expected<void, int>>::value));
|
||||
}
|
||||
|
||||
// mapping functions which return references
|
||||
{
|
||||
m5::stl::expected<int, int> e(42);
|
||||
auto ret = e.map([](int& i) -> int& { return i; });
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_TRUE(ret == 42);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Expected, MapErrorExtensions)
|
||||
{
|
||||
auto mul2 = [](int a) { return a * 2; };
|
||||
auto ret_void = [](int a) { (void)a; };
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e = 21;
|
||||
auto ret = e.map_error(mul2);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_TRUE(*ret == 21);
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e = 21;
|
||||
auto ret = e.map_error(mul2);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_TRUE(*ret == 21);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e = 21;
|
||||
auto ret = std::move(e).map_error(mul2);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_TRUE(*ret == 21);
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e = 21;
|
||||
auto ret = std::move(e).map_error(mul2);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_TRUE(*ret == 21);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = e.map_error(mul2);
|
||||
EXPECT_TRUE(!ret);
|
||||
EXPECT_TRUE(ret.error() == 42);
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = e.map_error(mul2);
|
||||
EXPECT_TRUE(!ret);
|
||||
EXPECT_TRUE(ret.error() == 42);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = std::move(e).map_error(mul2);
|
||||
EXPECT_TRUE(!ret);
|
||||
EXPECT_TRUE(ret.error() == 42);
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = std::move(e).map_error(mul2);
|
||||
EXPECT_TRUE(!ret);
|
||||
EXPECT_TRUE(ret.error() == 42);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e = 21;
|
||||
auto ret = e.map_error(ret_void);
|
||||
EXPECT_TRUE(ret);
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e = 21;
|
||||
auto ret = e.map_error(ret_void);
|
||||
EXPECT_TRUE(ret);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e = 21;
|
||||
auto ret = std::move(e).map_error(ret_void);
|
||||
EXPECT_TRUE(ret);
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e = 21;
|
||||
auto ret = std::move(e).map_error(ret_void);
|
||||
EXPECT_TRUE(ret);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = e.map_error(ret_void);
|
||||
EXPECT_TRUE(!ret);
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = e.map_error(ret_void);
|
||||
EXPECT_TRUE(!ret);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = std::move(e).map_error(ret_void);
|
||||
EXPECT_TRUE(!ret);
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = std::move(e).map_error(ret_void);
|
||||
EXPECT_TRUE(!ret);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Expected, AndThenExtensions)
|
||||
{
|
||||
auto succeed = [](int a) {
|
||||
(void)a;
|
||||
return m5::stl::expected<int, int>(21 * 2);
|
||||
};
|
||||
auto fail = [](int a) {
|
||||
(void)a;
|
||||
return m5::stl::expected<int, int>(m5::stl::unexpect, 17);
|
||||
};
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e = 21;
|
||||
auto ret = e.and_then(succeed);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_TRUE(*ret == 42);
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e = 21;
|
||||
auto ret = e.and_then(succeed);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_TRUE(*ret == 42);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e = 21;
|
||||
auto ret = std::move(e).and_then(succeed);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_TRUE(*ret == 42);
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e = 21;
|
||||
auto ret = std::move(e).and_then(succeed);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_TRUE(*ret == 42);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e = 21;
|
||||
auto ret = e.and_then(fail);
|
||||
EXPECT_TRUE(!ret);
|
||||
EXPECT_TRUE(ret.error() == 17);
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e = 21;
|
||||
auto ret = e.and_then(fail);
|
||||
EXPECT_TRUE(!ret);
|
||||
EXPECT_TRUE(ret.error() == 17);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e = 21;
|
||||
auto ret = std::move(e).and_then(fail);
|
||||
EXPECT_TRUE(!ret);
|
||||
EXPECT_TRUE(ret.error() == 17);
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e = 21;
|
||||
auto ret = std::move(e).and_then(fail);
|
||||
EXPECT_TRUE(!ret);
|
||||
EXPECT_TRUE(ret.error() == 17);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = e.and_then(succeed);
|
||||
EXPECT_TRUE(!ret);
|
||||
EXPECT_TRUE(ret.error() == 21);
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = e.and_then(succeed);
|
||||
EXPECT_TRUE(!ret);
|
||||
EXPECT_TRUE(ret.error() == 21);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = std::move(e).and_then(succeed);
|
||||
EXPECT_TRUE(!ret);
|
||||
EXPECT_TRUE(ret.error() == 21);
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = std::move(e).and_then(succeed);
|
||||
EXPECT_TRUE(!ret);
|
||||
EXPECT_TRUE(ret.error() == 21);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = e.and_then(fail);
|
||||
EXPECT_TRUE(!ret);
|
||||
EXPECT_TRUE(ret.error() == 21);
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = e.and_then(fail);
|
||||
EXPECT_TRUE(!ret);
|
||||
EXPECT_TRUE(ret.error() == 21);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = std::move(e).and_then(fail);
|
||||
EXPECT_TRUE(!ret);
|
||||
EXPECT_TRUE(ret.error() == 21);
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = std::move(e).and_then(fail);
|
||||
EXPECT_TRUE(!ret);
|
||||
EXPECT_TRUE(ret.error() == 21);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Expected, or_else)
|
||||
{
|
||||
using eptr = std::unique_ptr<int>;
|
||||
auto succeed = [](int a) {
|
||||
(void)a;
|
||||
return m5::stl::expected<int, int>(21 * 2);
|
||||
};
|
||||
auto succeedptr = [](eptr e) {
|
||||
(void)e;
|
||||
return m5::stl::expected<int, eptr>(21 * 2);
|
||||
};
|
||||
auto fail = [](int a) {
|
||||
(void)a;
|
||||
return m5::stl::expected<int, int>(m5::stl::unexpect, 17);
|
||||
};
|
||||
auto failptr = [](eptr e) {
|
||||
*e = 17;
|
||||
return m5::stl::expected<int, eptr>(m5::stl::unexpect, std::move(e));
|
||||
};
|
||||
auto failvoid = [](int) {};
|
||||
auto failvoidptr = [](const eptr&) { /* don't consume */ };
|
||||
auto consumeptr = [](eptr) {};
|
||||
auto make_u_int = [](int n) { return std::unique_ptr<int>(new int(n)); };
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e = 21;
|
||||
auto ret = e.or_else(succeed);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_TRUE(*ret == 21);
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e = 21;
|
||||
auto ret = e.or_else(succeed);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_TRUE(*ret == 21);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e = 21;
|
||||
auto ret = std::move(e).or_else(succeed);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_TRUE(*ret == 21);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, eptr> e = 21;
|
||||
auto ret = std::move(e).or_else(succeedptr);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_TRUE(*ret == 21);
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e = 21;
|
||||
auto ret = std::move(e).or_else(succeed);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_TRUE(*ret == 21);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e = 21;
|
||||
auto ret = e.or_else(fail);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_TRUE(*ret == 21);
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e = 21;
|
||||
auto ret = e.or_else(fail);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_TRUE(*ret == 21);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e = 21;
|
||||
auto ret = std::move(e).or_else(fail);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_TRUE(ret == 21);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, eptr> e = 21;
|
||||
auto ret = std::move(e).or_else(failptr);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_TRUE(ret == 21);
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e = 21;
|
||||
auto ret = std::move(e).or_else(fail);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_TRUE(*ret == 21);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = e.or_else(succeed);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_TRUE(*ret == 42);
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = e.or_else(succeed);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_TRUE(*ret == 42);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = std::move(e).or_else(succeed);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_TRUE(*ret == 42);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, eptr> e(m5::stl::unexpect, make_u_int(21));
|
||||
auto ret = std::move(e).or_else(succeedptr);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_TRUE(*ret == 42);
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = std::move(e).or_else(succeed);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_TRUE(*ret == 42);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = e.or_else(fail);
|
||||
EXPECT_TRUE(!ret);
|
||||
EXPECT_TRUE(ret.error() == 17);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = e.or_else(failvoid);
|
||||
EXPECT_TRUE(!ret);
|
||||
EXPECT_TRUE(ret.error() == 21);
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = e.or_else(fail);
|
||||
EXPECT_TRUE(!ret);
|
||||
EXPECT_TRUE(ret.error() == 17);
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = e.or_else(failvoid);
|
||||
EXPECT_TRUE(!ret);
|
||||
EXPECT_TRUE(ret.error() == 21);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = std::move(e).or_else(fail);
|
||||
EXPECT_TRUE(!ret);
|
||||
EXPECT_TRUE(ret.error() == 17);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = std::move(e).or_else(failvoid);
|
||||
EXPECT_TRUE(!ret);
|
||||
EXPECT_TRUE(ret.error() == 21);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, eptr> e(m5::stl::unexpect, make_u_int(21));
|
||||
auto ret = std::move(e).or_else(failvoidptr);
|
||||
EXPECT_TRUE(!ret);
|
||||
EXPECT_TRUE(*ret.error() == 21);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, eptr> e(m5::stl::unexpect, make_u_int(21));
|
||||
auto ret = std::move(e).or_else(consumeptr);
|
||||
EXPECT_TRUE(!ret);
|
||||
EXPECT_TRUE(ret.error() == nullptr);
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = std::move(e).or_else(fail);
|
||||
EXPECT_TRUE(!ret);
|
||||
EXPECT_TRUE(ret.error() == 17);
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = std::move(e).or_else(failvoid);
|
||||
EXPECT_TRUE(!ret);
|
||||
EXPECT_TRUE(ret.error() == 21);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Expected, TransformExtensions)
|
||||
{
|
||||
auto mul2 = [](int a) { return a * 2; };
|
||||
auto ret_void = [](int a) { (void)a; };
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e = 21;
|
||||
auto ret = e.transform(mul2);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_TRUE(*ret == 42);
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e = 21;
|
||||
auto ret = e.transform(mul2);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_TRUE(*ret == 42);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e = 21;
|
||||
auto ret = std::move(e).transform(mul2);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_TRUE(*ret == 42);
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e = 21;
|
||||
auto ret = std::move(e).transform(mul2);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_TRUE(*ret == 42);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = e.transform(mul2);
|
||||
EXPECT_TRUE(!ret);
|
||||
EXPECT_TRUE(ret.error() == 21);
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = e.transform(mul2);
|
||||
EXPECT_TRUE(!ret);
|
||||
EXPECT_TRUE(ret.error() == 21);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = std::move(e).transform(mul2);
|
||||
EXPECT_TRUE(!ret);
|
||||
EXPECT_TRUE(ret.error() == 21);
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = std::move(e).transform(mul2);
|
||||
EXPECT_TRUE(!ret);
|
||||
EXPECT_TRUE(ret.error() == 21);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e = 21;
|
||||
auto ret = e.transform(ret_void);
|
||||
EXPECT_TRUE(ret);
|
||||
STATIC_REQUIRE((std::is_same<decltype(ret), m5::stl::expected<void, int>>::value));
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e = 21;
|
||||
auto ret = e.transform(ret_void);
|
||||
EXPECT_TRUE(ret);
|
||||
STATIC_REQUIRE((std::is_same<decltype(ret), m5::stl::expected<void, int>>::value));
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e = 21;
|
||||
auto ret = std::move(e).transform(ret_void);
|
||||
EXPECT_TRUE(ret);
|
||||
STATIC_REQUIRE((std::is_same<decltype(ret), m5::stl::expected<void, int>>::value));
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e = 21;
|
||||
auto ret = std::move(e).transform(ret_void);
|
||||
EXPECT_TRUE(ret);
|
||||
STATIC_REQUIRE((std::is_same<decltype(ret), m5::stl::expected<void, int>>::value));
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = e.transform(ret_void);
|
||||
EXPECT_TRUE(!ret);
|
||||
STATIC_REQUIRE((std::is_same<decltype(ret), m5::stl::expected<void, int>>::value));
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = e.transform(ret_void);
|
||||
EXPECT_TRUE(!ret);
|
||||
STATIC_REQUIRE((std::is_same<decltype(ret), m5::stl::expected<void, int>>::value));
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = std::move(e).transform(ret_void);
|
||||
EXPECT_TRUE(!ret);
|
||||
STATIC_REQUIRE((std::is_same<decltype(ret), m5::stl::expected<void, int>>::value));
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = std::move(e).transform(ret_void);
|
||||
EXPECT_TRUE(!ret);
|
||||
STATIC_REQUIRE((std::is_same<decltype(ret), m5::stl::expected<void, int>>::value));
|
||||
}
|
||||
|
||||
// mapping functions which return references
|
||||
{
|
||||
m5::stl::expected<int, int> e(42);
|
||||
auto ret = e.transform([](int& i) -> int& { return i; });
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_TRUE(ret == 42);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Expected, TransformErrorExtensions)
|
||||
{
|
||||
auto mul2 = [](int a) { return a * 2; };
|
||||
auto ret_void = [](int a) { (void)a; };
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e = 21;
|
||||
auto ret = e.transform_error(mul2);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_TRUE(*ret == 21);
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e = 21;
|
||||
auto ret = e.transform_error(mul2);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_TRUE(*ret == 21);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e = 21;
|
||||
auto ret = std::move(e).transform_error(mul2);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_TRUE(*ret == 21);
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e = 21;
|
||||
auto ret = std::move(e).transform_error(mul2);
|
||||
EXPECT_TRUE(ret);
|
||||
EXPECT_TRUE(*ret == 21);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = e.transform_error(mul2);
|
||||
EXPECT_TRUE(!ret);
|
||||
EXPECT_TRUE(ret.error() == 42);
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = e.transform_error(mul2);
|
||||
EXPECT_TRUE(!ret);
|
||||
EXPECT_TRUE(ret.error() == 42);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = std::move(e).transform_error(mul2);
|
||||
EXPECT_TRUE(!ret);
|
||||
EXPECT_TRUE(ret.error() == 42);
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = std::move(e).transform_error(mul2);
|
||||
EXPECT_TRUE(!ret);
|
||||
EXPECT_TRUE(ret.error() == 42);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e = 21;
|
||||
auto ret = e.transform_error(ret_void);
|
||||
EXPECT_TRUE(ret);
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e = 21;
|
||||
auto ret = e.transform_error(ret_void);
|
||||
EXPECT_TRUE(ret);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e = 21;
|
||||
auto ret = std::move(e).transform_error(ret_void);
|
||||
EXPECT_TRUE(ret);
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e = 21;
|
||||
auto ret = std::move(e).transform_error(ret_void);
|
||||
EXPECT_TRUE(ret);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = e.transform_error(ret_void);
|
||||
EXPECT_TRUE(!ret);
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = e.transform_error(ret_void);
|
||||
EXPECT_TRUE(!ret);
|
||||
}
|
||||
|
||||
{
|
||||
m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = std::move(e).transform_error(ret_void);
|
||||
EXPECT_TRUE(!ret);
|
||||
}
|
||||
|
||||
{
|
||||
const m5::stl::expected<int, int> e(m5::stl::unexpect, 21);
|
||||
auto ret = std::move(e).transform_error(ret_void);
|
||||
EXPECT_TRUE(!ret);
|
||||
}
|
||||
}
|
||||
|
||||
struct S {
|
||||
int x;
|
||||
};
|
||||
|
||||
struct F {
|
||||
int x;
|
||||
};
|
||||
|
||||
TEST(Expected, issue14)
|
||||
{
|
||||
auto res = m5::stl::expected<S, F>{m5::stl::unexpect, F{}};
|
||||
|
||||
res.map_error([](F f) { (void)f; });
|
||||
}
|
||||
|
||||
TEST(Expected, issue32)
|
||||
{
|
||||
int i = 0;
|
||||
m5::stl::expected<void, int> a;
|
||||
a.map([&i] { i = 42; });
|
||||
EXPECT_TRUE(i == 42);
|
||||
|
||||
auto x = a.map([] { return 42; });
|
||||
EXPECT_TRUE(*x == 42);
|
||||
}
|
||||
256
libraries/M5Utility/test/expected/issues.cpp
Normal file
256
libraries/M5Utility/test/expected/issues.cpp
Normal file
|
|
@ -0,0 +1,256 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <m5_utility/stl/expected.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
using std::string;
|
||||
|
||||
m5::stl::expected<int, string> getInt3(int val)
|
||||
{
|
||||
return val;
|
||||
}
|
||||
|
||||
m5::stl::expected<int, string> getInt2(int val)
|
||||
{
|
||||
return val;
|
||||
}
|
||||
|
||||
m5::stl::expected<int, string> getInt1()
|
||||
{
|
||||
return getInt2(5).and_then(getInt3);
|
||||
}
|
||||
|
||||
TEST(Expected, Issue1)
|
||||
{
|
||||
getInt1();
|
||||
}
|
||||
|
||||
m5::stl::expected<int, int> operation1()
|
||||
{
|
||||
return 42;
|
||||
}
|
||||
|
||||
m5::stl::expected<std::string, int> operation2(int const val)
|
||||
{
|
||||
(void)val;
|
||||
return "Bananas";
|
||||
}
|
||||
|
||||
TEST(Expected, Issue17)
|
||||
{
|
||||
auto const intermediate_result = operation1();
|
||||
|
||||
intermediate_result.and_then(operation2);
|
||||
}
|
||||
|
||||
struct a { /* empty */
|
||||
};
|
||||
|
||||
struct b : a { /* empty */
|
||||
};
|
||||
|
||||
auto doit() -> m5::stl::expected<std::unique_ptr<b>, int>
|
||||
{
|
||||
return m5::stl::make_unexpected(0);
|
||||
}
|
||||
|
||||
TEST(Expected, Issue23)
|
||||
{
|
||||
m5::stl::expected<std::unique_ptr<a>, int> msg = doit();
|
||||
EXPECT_TRUE(!msg.has_value());
|
||||
}
|
||||
|
||||
TEST(Expected, Issue26)
|
||||
{
|
||||
m5::stl::expected<a, int> exp = m5::stl::expected<b, int>(m5::stl::unexpect, 0);
|
||||
EXPECT_TRUE(!exp.has_value());
|
||||
}
|
||||
|
||||
struct foo {
|
||||
foo() = default;
|
||||
foo(const foo &) = delete;
|
||||
foo(foo &&) noexcept {};
|
||||
};
|
||||
|
||||
TEST(Expected, Issue29)
|
||||
{
|
||||
std::vector<foo> v;
|
||||
v.emplace_back();
|
||||
m5::stl::expected<std::vector<foo>, int> ov = std::move(v);
|
||||
EXPECT_TRUE(ov->size() == 1);
|
||||
}
|
||||
|
||||
m5::stl::expected<int, std::string> error()
|
||||
{
|
||||
return m5::stl::make_unexpected(std::string("error1 "));
|
||||
}
|
||||
std::string maperror(std::string s)
|
||||
{
|
||||
return s + "maperror ";
|
||||
}
|
||||
|
||||
TEST(Expected, Issue30)
|
||||
{
|
||||
error().map_error(maperror);
|
||||
}
|
||||
|
||||
struct i31 {
|
||||
int i;
|
||||
};
|
||||
TEST(Expected, Issue31)
|
||||
{
|
||||
const m5::stl::expected<i31, int> a = i31{42};
|
||||
(void)a->i;
|
||||
|
||||
m5::stl::expected<void, std::string> result;
|
||||
m5::stl::expected<void, std::string> result2 = result;
|
||||
result2 = result;
|
||||
}
|
||||
|
||||
TEST(Expected, Issue33)
|
||||
{
|
||||
m5::stl::expected<void, int> res{m5::stl::unexpect, 0};
|
||||
EXPECT_TRUE(!res);
|
||||
res = res.map_error([](int i) {
|
||||
(void)i;
|
||||
return 42;
|
||||
});
|
||||
EXPECT_TRUE(res.error() == 42);
|
||||
}
|
||||
|
||||
m5::stl::expected<void, std::string> voidWork()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
m5::stl::expected<int, std::string> work2()
|
||||
{
|
||||
return 42;
|
||||
}
|
||||
void errorhandling(std::string)
|
||||
{
|
||||
}
|
||||
|
||||
TEST(Expected, Issue34)
|
||||
{
|
||||
m5::stl::expected<int, std::string> result = voidWork().and_then(work2);
|
||||
result.map_error([&](std::string result) { errorhandling(result); });
|
||||
}
|
||||
|
||||
struct non_copyable {
|
||||
non_copyable(non_copyable &&) = default;
|
||||
non_copyable(non_copyable const &) = delete;
|
||||
non_copyable() = default;
|
||||
};
|
||||
|
||||
TEST(Expected, Issue42)
|
||||
{
|
||||
m5::stl::expected<non_copyable, int>{}.map([](non_copyable) {});
|
||||
}
|
||||
|
||||
TEST(Expected, Issue43)
|
||||
{
|
||||
auto result = m5::stl::expected<void, std::string>{};
|
||||
result = m5::stl::make_unexpected(std::string{"foo"});
|
||||
}
|
||||
|
||||
#if !(__GNUC__ <= 5)
|
||||
#include <memory>
|
||||
|
||||
using MaybeDataPtr = m5::stl::expected<int, std::unique_ptr<int>>;
|
||||
|
||||
MaybeDataPtr test(int i) noexcept
|
||||
{
|
||||
return std::move(i);
|
||||
}
|
||||
|
||||
MaybeDataPtr test2(int i) noexcept
|
||||
{
|
||||
return std::move(i);
|
||||
}
|
||||
|
||||
TEST(Expected, Issue49)
|
||||
{
|
||||
auto m = test(10).and_then(test2);
|
||||
}
|
||||
#endif
|
||||
|
||||
m5::stl::expected<int, std::unique_ptr<std::string>> func()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
TEST(Expected, Issue61)
|
||||
{
|
||||
EXPECT_TRUE(func().value() == 1);
|
||||
}
|
||||
|
||||
struct move_tracker {
|
||||
int moved = 0;
|
||||
|
||||
move_tracker() = default;
|
||||
|
||||
move_tracker(move_tracker const &other) noexcept {};
|
||||
move_tracker(move_tracker &&orig) noexcept : moved(orig.moved + 1)
|
||||
{
|
||||
}
|
||||
|
||||
move_tracker &operator=(move_tracker const &other) noexcept
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
move_tracker &operator=(move_tracker &&orig) noexcept
|
||||
{
|
||||
moved = orig.moved + 1;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
TEST(Expected, Issue122)
|
||||
{
|
||||
m5::stl::expected<move_tracker, int> res;
|
||||
res.emplace();
|
||||
EXPECT_TRUE(res.value().moved == 0);
|
||||
}
|
||||
|
||||
#ifdef __cpp_deduction_guides
|
||||
TEST(Expected, Issue89)
|
||||
{
|
||||
auto s = m5::stl::unexpected("Some string");
|
||||
EXPECT_TRUE(s.value() == std::string("Some string"));
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
struct SS {
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
SS(int i) : i(i)
|
||||
{
|
||||
}
|
||||
SS(int i, int j) : i(i), j(j)
|
||||
{
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
TEST(Expected, Issue107)
|
||||
{
|
||||
m5::stl::expected<int, SS> ex1(m5::stl::unexpect, 2);
|
||||
m5::stl::expected<int, SS> ex2(m5::stl::unexpect, 2, 2);
|
||||
|
||||
EXPECT_TRUE(ex1.error().i == 2);
|
||||
EXPECT_TRUE(ex1.error().j == 0);
|
||||
EXPECT_TRUE(ex2.error().i == 2);
|
||||
EXPECT_TRUE(ex2.error().j == 2);
|
||||
}
|
||||
|
||||
TEST(Expected, Issue129)
|
||||
{
|
||||
m5::stl::expected<std::unique_ptr<int>, int> x1{std::unique_ptr<int>(new int(4))};
|
||||
m5::stl::expected<std::unique_ptr<int>, int> y1{std::unique_ptr<int>(new int(2))};
|
||||
x1 = std::move(y1);
|
||||
|
||||
EXPECT_TRUE(**x1 == 2);
|
||||
}
|
||||
7
libraries/M5Utility/test/expected/noexcept.cpp
Normal file
7
libraries/M5Utility/test/expected/noexcept.cpp
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <m5_utility/stl/expected.hpp>
|
||||
|
||||
TEST(Expected, Noexcept)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
44
libraries/M5Utility/test/expected/observers.cpp
Normal file
44
libraries/M5Utility/test/expected/observers.cpp
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <m5_utility/stl/expected.hpp>
|
||||
|
||||
struct move_detector {
|
||||
move_detector() = default;
|
||||
move_detector(move_detector &&rhs)
|
||||
{
|
||||
rhs.been_moved = true;
|
||||
}
|
||||
bool been_moved = false;
|
||||
};
|
||||
|
||||
TEST(Expected, Observers)
|
||||
{
|
||||
m5::stl::expected<int, int> o1 = 42;
|
||||
m5::stl::expected<int, int> o2{m5::stl::unexpect, 0};
|
||||
const m5::stl::expected<int, int> o3 = 42;
|
||||
|
||||
EXPECT_TRUE(*o1 == 42);
|
||||
EXPECT_TRUE(*o1 == o1.value());
|
||||
EXPECT_TRUE(o2.value_or(42) == 42);
|
||||
EXPECT_TRUE(o2.error() == 0);
|
||||
EXPECT_TRUE(o3.value() == 42);
|
||||
auto success = std::is_same<decltype(o1.value()), int &>::value;
|
||||
EXPECT_TRUE(success);
|
||||
success = std::is_same<decltype(o3.value()), const int &>::value;
|
||||
EXPECT_TRUE(success);
|
||||
success = std::is_same<decltype(std::move(o1).value()), int &&>::value;
|
||||
EXPECT_TRUE(success);
|
||||
|
||||
#ifndef TL_EXPECTED_NO_CONSTRR
|
||||
success = std::is_same<decltype(std::move(o3).value()), const int &&>::value;
|
||||
EXPECT_TRUE(success);
|
||||
#endif
|
||||
|
||||
m5::stl::expected<move_detector, int> o4{m5::stl::in_place};
|
||||
move_detector o5 = std::move(o4).value();
|
||||
EXPECT_TRUE(o4->been_moved);
|
||||
EXPECT_TRUE(!o5.been_moved);
|
||||
|
||||
// Add by GOB
|
||||
EXPECT_TRUE(o1.error_or(52) == 52);
|
||||
EXPECT_TRUE(o2.error_or(52) == 0);
|
||||
}
|
||||
18
libraries/M5Utility/test/expected/relops.cpp
Normal file
18
libraries/M5Utility/test/expected/relops.cpp
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <m5_utility/stl/expected.hpp>
|
||||
|
||||
TEST(Expected, RelationalOperators)
|
||||
{
|
||||
m5::stl::expected<int, int> o1 = 42;
|
||||
m5::stl::expected<int, int> o2{m5::stl::unexpect, 0};
|
||||
const m5::stl::expected<int, int> o3 = 42;
|
||||
|
||||
EXPECT_TRUE(o1 == o1);
|
||||
EXPECT_TRUE(o1 != o2);
|
||||
EXPECT_TRUE(o1 == o3);
|
||||
EXPECT_TRUE(o3 == o3);
|
||||
|
||||
m5::stl::expected<void, int> o6;
|
||||
|
||||
EXPECT_TRUE(o6 == o6);
|
||||
}
|
||||
126
libraries/M5Utility/test/expected/swap.cpp
Normal file
126
libraries/M5Utility/test/expected/swap.cpp
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <m5_utility/stl/expected.hpp>
|
||||
|
||||
struct no_throw {
|
||||
no_throw(std::string i) : i(i)
|
||||
{
|
||||
}
|
||||
std::string i;
|
||||
};
|
||||
struct canthrow_move {
|
||||
canthrow_move(std::string i) : i(i)
|
||||
{
|
||||
}
|
||||
canthrow_move(canthrow_move const &) = default;
|
||||
canthrow_move(canthrow_move &&other) noexcept(false) : i(other.i)
|
||||
{
|
||||
}
|
||||
canthrow_move &operator=(canthrow_move &&) = default;
|
||||
std::string i;
|
||||
};
|
||||
|
||||
bool should_throw = false;
|
||||
|
||||
#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
|
||||
struct willthrow_move {
|
||||
willthrow_move(std::string i) : i(i)
|
||||
{
|
||||
}
|
||||
willthrow_move(willthrow_move const &) = default;
|
||||
willthrow_move(willthrow_move &&other) : i(other.i)
|
||||
{
|
||||
if (should_throw) throw 0;
|
||||
}
|
||||
willthrow_move &operator=(willthrow_move &&) = default;
|
||||
std::string i;
|
||||
};
|
||||
#endif // TL_EXPECTED_EXCEPTIONS_ENABLED
|
||||
|
||||
static_assert(m5::stl::detail::is_swappable<no_throw>::value, "");
|
||||
|
||||
template <class T1, class T2>
|
||||
void swap_test()
|
||||
{
|
||||
std::string s1 = "abcdefghijklmnopqrstuvwxyz";
|
||||
std::string s2 = "zyxwvutsrqponmlkjihgfedcba";
|
||||
|
||||
m5::stl::expected<T1, T2> a{s1};
|
||||
m5::stl::expected<T1, T2> b{s2};
|
||||
swap(a, b);
|
||||
EXPECT_TRUE(a->i == s2);
|
||||
EXPECT_TRUE(b->i == s1);
|
||||
|
||||
a = s1;
|
||||
b = m5::stl::unexpected<T2>(s2);
|
||||
swap(a, b);
|
||||
EXPECT_TRUE(a.error().i == s2);
|
||||
EXPECT_TRUE(b->i == s1);
|
||||
|
||||
a = m5::stl::unexpected<T2>(s1);
|
||||
b = s2;
|
||||
swap(a, b);
|
||||
EXPECT_TRUE(a->i == s2);
|
||||
EXPECT_TRUE(b.error().i == s1);
|
||||
|
||||
a = m5::stl::unexpected<T2>(s1);
|
||||
b = m5::stl::unexpected<T2>(s2);
|
||||
swap(a, b);
|
||||
EXPECT_TRUE(a.error().i == s2);
|
||||
EXPECT_TRUE(b.error().i == s1);
|
||||
|
||||
a = s1;
|
||||
b = s2;
|
||||
a.swap(b);
|
||||
EXPECT_TRUE(a->i == s2);
|
||||
EXPECT_TRUE(b->i == s1);
|
||||
|
||||
a = s1;
|
||||
b = m5::stl::unexpected<T2>(s2);
|
||||
a.swap(b);
|
||||
EXPECT_TRUE(a.error().i == s2);
|
||||
EXPECT_TRUE(b->i == s1);
|
||||
|
||||
a = m5::stl::unexpected<T2>(s1);
|
||||
b = s2;
|
||||
a.swap(b);
|
||||
EXPECT_TRUE(a->i == s2);
|
||||
EXPECT_TRUE(b.error().i == s1);
|
||||
|
||||
a = m5::stl::unexpected<T2>(s1);
|
||||
b = m5::stl::unexpected<T2>(s2);
|
||||
a.swap(b);
|
||||
EXPECT_TRUE(a.error().i == s2);
|
||||
EXPECT_TRUE(b.error().i == s1);
|
||||
}
|
||||
|
||||
#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED
|
||||
TEST(Expected, swap)
|
||||
{
|
||||
{
|
||||
SCOPED_TRACE("no_throw no-throw");
|
||||
swap_test<no_throw, no_throw>();
|
||||
}
|
||||
{
|
||||
SCOPED_TRACE("no_throw canthrow");
|
||||
swap_test<no_throw, canthrow_move>();
|
||||
}
|
||||
{
|
||||
SCOPED_TRACE("canthrow no_throw");
|
||||
swap_test<canthrow_move, no_throw>();
|
||||
}
|
||||
|
||||
std::string s1 = "abcdefghijklmnopqrstuvwxyz";
|
||||
std::string s2 = "zyxwvutsrqponmlkjihgfedcbaxxx";
|
||||
m5::stl::expected<no_throw, willthrow_move> a{s1};
|
||||
m5::stl::expected<no_throw, willthrow_move> b{m5::stl::unexpect, s2};
|
||||
should_throw = 1;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// this seems to break catch on GCC and Clang
|
||||
EXPECT_TRUE_THROWS(swap(a, b));
|
||||
#endif
|
||||
|
||||
EXPECT_TRUE(a->i == s1);
|
||||
EXPECT_TRUE(b.error().i == s2);
|
||||
}
|
||||
#endif // TL_EXPECTED_EXCEPTIONS_ENABLED
|
||||
23
libraries/M5Utility/test/expected_test.cpp
Normal file
23
libraries/M5Utility/test/expected_test.cpp
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
/*
|
||||
UnitTest for M5Utility
|
||||
|
||||
Each split by test_filter creates a separate binary. So they are combined by including cpp.
|
||||
Note that the /optional files are not compiled directly if not set to test_filter
|
||||
*/
|
||||
#include "expected/assertions.cpp"
|
||||
#include "expected/assignment.cpp"
|
||||
#include "expected/bases.cpp"
|
||||
#include "expected/constexpr.cpp"
|
||||
#include "expected/constructors.cpp"
|
||||
#include "expected/emplace.cpp"
|
||||
#include "expected/extensions.cpp"
|
||||
#include "expected/issues.cpp"
|
||||
#include "expected/noexcept.cpp"
|
||||
#include "expected/observers.cpp"
|
||||
#include "expected/relops.cpp"
|
||||
#include "expected/swap.cpp"
|
||||
18
libraries/M5Utility/test/helper.hpp
Normal file
18
libraries/M5Utility/test/helper.hpp
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
/*
|
||||
UnitTest for M5Utility
|
||||
*/
|
||||
#ifndef TEST_HEKPER_HPP
|
||||
#define TEST_HEKPER_HPP
|
||||
|
||||
// catch2 STATIC_REQUIRE
|
||||
#define STATIC_EXPECT_TRUE(constexpr_cond) \
|
||||
do { \
|
||||
static_assert((constexpr_cond), "Occurrence of compile-time assertion"); \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
22
libraries/M5Utility/test/math_test.cpp
Normal file
22
libraries/M5Utility/test/math_test.cpp
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
/*
|
||||
UnitTest for M5Utility
|
||||
*/
|
||||
#include <gtest/gtest.h>
|
||||
#include <M5Utility.hpp>
|
||||
|
||||
TEST(Utility, is_powerof2)
|
||||
{
|
||||
EXPECT_FALSE(m5::math::is_powerof2(0));
|
||||
EXPECT_TRUE(m5::math::is_powerof2(1));
|
||||
EXPECT_TRUE(m5::math::is_powerof2(2));
|
||||
EXPECT_FALSE(m5::math::is_powerof2(3));
|
||||
|
||||
constexpr auto b = m5::math::is_powerof2(-1);
|
||||
EXPECT_FALSE(b);
|
||||
EXPECT_FALSE(m5::math::is_powerof2(-2));
|
||||
}
|
||||
31
libraries/M5Utility/test/misc_test.cpp
Normal file
31
libraries/M5Utility/test/misc_test.cpp
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
/*
|
||||
UnitTest for M5Utility
|
||||
*/
|
||||
#include <gtest/gtest.h>
|
||||
#include <M5Utility.hpp>
|
||||
|
||||
using namespace m5::utility;
|
||||
|
||||
TEST(Utility, reverseBitOrder)
|
||||
{
|
||||
EXPECT_EQ(reverseBitOrder((uint8_t)0), 0);
|
||||
EXPECT_EQ(reverseBitOrder((uint16_t)0), 0);
|
||||
|
||||
EXPECT_EQ(reverseBitOrder((uint8_t)0xFF), 0xFF);
|
||||
EXPECT_EQ(reverseBitOrder((uint16_t)0xFFFF), 0xFFFF);
|
||||
|
||||
EXPECT_EQ(reverseBitOrder((uint8_t)0x0F), 0xF0);
|
||||
EXPECT_EQ(reverseBitOrder((uint16_t)0xFF00), 0x00FF);
|
||||
|
||||
EXPECT_EQ(reverseBitOrder((uint8_t)0x4C), 0x32);
|
||||
EXPECT_EQ(reverseBitOrder((uint16_t)0x4C4C), 0x3232);
|
||||
|
||||
EXPECT_EQ(reverseBitOrder((uint8_t)0x8E), 0x71);
|
||||
EXPECT_EQ(reverseBitOrder((uint8_t)0x65), 0xA6);
|
||||
EXPECT_EQ(reverseBitOrder((uint16_t)0x8E65), 0xA671);
|
||||
}
|
||||
101
libraries/M5Utility/test/mmh3_test.cpp
Normal file
101
libraries/M5Utility/test/mmh3_test.cpp
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
/*
|
||||
UnitTest for M5Utility
|
||||
*/
|
||||
#include <gtest/gtest.h>
|
||||
#include <random>
|
||||
#include <M5Utility.hpp>
|
||||
#include "MurmurHash3.h" // from https://github.com/rurban/smhasher/tree/master (public domain)
|
||||
|
||||
#if defined(ARDUINO)
|
||||
#include <WString.h>
|
||||
using string_t = String;
|
||||
#else
|
||||
#include <cstring>
|
||||
using string_t = std::string;
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
auto rng = std::default_random_engine{};
|
||||
|
||||
string_t make_random_str()
|
||||
{
|
||||
constexpr char dic[] =
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"0123456789"
|
||||
"!#$%&()=-~^|@[{]}:;+*,.<>/?_";
|
||||
|
||||
string_t s;
|
||||
size_t len = 1 + (rng() & 31);
|
||||
while (len--) {
|
||||
s += dic[rng() % (sizeof(dic) / sizeof(dic[0]) - 1)];
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
using test_pair_t = std::pair<const char*, uint32_t>;
|
||||
|
||||
test_pair_t test_pairs[] = {
|
||||
{"", 0},
|
||||
{"M5Stack", 0x8c97d1e0U},
|
||||
{"M5Stack is a leading provider of IoT solutions.", 0x1a1eca6dU},
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(MurmurHash3, endianness)
|
||||
{
|
||||
using namespace m5::utility::mmh3;
|
||||
|
||||
constexpr char tst[] = "M5ST";
|
||||
auto big = str2uint32<false>(tst);
|
||||
auto little = str2uint32<true>(tst);
|
||||
|
||||
EXPECT_EQ(big, 0x4d355354U);
|
||||
EXPECT_EQ(little, 0x5453354dU);
|
||||
}
|
||||
|
||||
// User-defined literals "_mmh3"
|
||||
TEST(MurmurHash3, user_defined_literals)
|
||||
{
|
||||
using namespace m5::utility::mmh3;
|
||||
|
||||
constexpr auto h0 = ""_mmh3;
|
||||
constexpr auto h1 = "M5Stack"_mmh3;
|
||||
constexpr auto h2 = "M5Stack is a leading provider of IoT solutions."_mmh3;
|
||||
|
||||
EXPECT_EQ(h0, 0U);
|
||||
EXPECT_EQ(h1, 0x8c97d1e0U);
|
||||
EXPECT_EQ(h2, 0x1a1eca6dU);
|
||||
}
|
||||
|
||||
// Verification of value correctness
|
||||
TEST(MurmurHash3, verify)
|
||||
{
|
||||
for (auto&& e : test_pairs) {
|
||||
auto& s = e.first;
|
||||
auto h = m5::utility::mmh3::calculate(s);
|
||||
uint32_t h2{};
|
||||
MurmurHash3_x86_32(s, strlen(s), 0, &h2);
|
||||
|
||||
EXPECT_EQ(e.second, h) << '[' << s << "] len:" << strlen(s);
|
||||
EXPECT_EQ(h, h2) << '[' << s << "] len:" << strlen(s);
|
||||
}
|
||||
|
||||
constexpr int count = 10000;
|
||||
for (int i = 0; i < count; ++i) {
|
||||
string_t s = make_random_str();
|
||||
size_t len = strlen(s.c_str());
|
||||
uint32_t h1{};
|
||||
MurmurHash3_x86_32(s.c_str(), len, 0, &h1);
|
||||
uint32_t h2 = m5::utility::mmh3::calculate(s.c_str());
|
||||
|
||||
EXPECT_EQ(h1, h2) << '[' << s.c_str() << "] len:" << strlen(s.c_str());
|
||||
}
|
||||
}
|
||||
72
libraries/M5Utility/test/optional/assignment.cpp
Normal file
72
libraries/M5Utility/test/optional/assignment.cpp
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <m5_utility/stl/optional.hpp>
|
||||
|
||||
TEST(Optional, Assignment)
|
||||
{
|
||||
m5::stl::optional<int> o1 = 42;
|
||||
m5::stl::optional<int> o2 = 12;
|
||||
m5::stl::optional<int> o3;
|
||||
|
||||
o1 = o1;
|
||||
EXPECT_TRUE(*o1 == 42);
|
||||
|
||||
o1 = o2;
|
||||
EXPECT_TRUE(*o1 == 12);
|
||||
|
||||
o1 = o3;
|
||||
EXPECT_TRUE(!o1);
|
||||
|
||||
o1 = 42;
|
||||
EXPECT_TRUE(*o1 == 42);
|
||||
|
||||
o1 = m5::stl::nullopt;
|
||||
EXPECT_TRUE(!o1);
|
||||
|
||||
o1 = std::move(o2);
|
||||
EXPECT_TRUE(*o1 == 12);
|
||||
|
||||
m5::stl::optional<short> o4 = 42;
|
||||
|
||||
o1 = o4;
|
||||
EXPECT_TRUE(*o1 == 42);
|
||||
|
||||
o1 = std::move(o4);
|
||||
EXPECT_TRUE(*o1 == 42);
|
||||
}
|
||||
|
||||
TEST(Optional, AssignmentReference)
|
||||
{
|
||||
auto i = 42;
|
||||
auto j = 12;
|
||||
|
||||
m5::stl::optional<int&> o1 = i;
|
||||
m5::stl::optional<int&> o2 = j;
|
||||
m5::stl::optional<int&> o3;
|
||||
|
||||
o1 = o1;
|
||||
EXPECT_TRUE(*o1 == 42);
|
||||
EXPECT_TRUE(&*o1 == &i);
|
||||
|
||||
o1 = o2;
|
||||
EXPECT_TRUE(*o1 == 12);
|
||||
|
||||
o1 = o3;
|
||||
EXPECT_TRUE(!o1);
|
||||
|
||||
auto k = 42;
|
||||
o1 = k;
|
||||
EXPECT_TRUE(*o1 == 42);
|
||||
EXPECT_TRUE(*o1 == i);
|
||||
EXPECT_TRUE(*o1 == k);
|
||||
EXPECT_TRUE(&*o1 != &i);
|
||||
EXPECT_TRUE(&*o1 == &k);
|
||||
|
||||
k = 12;
|
||||
EXPECT_TRUE(*o1 == 12);
|
||||
|
||||
o1 = m5::stl::nullopt;
|
||||
EXPECT_TRUE(!o1);
|
||||
|
||||
o1 = std::move(o2);
|
||||
EXPECT_TRUE(*o1 == 12);
|
||||
}
|
||||
136
libraries/M5Utility/test/optional/bases.cpp
Normal file
136
libraries/M5Utility/test/optional/bases.cpp
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <m5_utility/stl/optional.hpp>
|
||||
|
||||
// Old versions of GCC don't have the correct trait names. Could fix them up if needs be.
|
||||
#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && !defined(__clang__))
|
||||
// nothing for now
|
||||
#else
|
||||
TEST(Optional, Triviality)
|
||||
{
|
||||
EXPECT_TRUE(std::is_trivially_copy_constructible<m5::stl::optional<int> >::value);
|
||||
EXPECT_TRUE(std::is_trivially_copy_assignable<m5::stl::optional<int> >::value);
|
||||
EXPECT_TRUE(std::is_trivially_move_constructible<m5::stl::optional<int> >::value);
|
||||
EXPECT_TRUE(std::is_trivially_move_assignable<m5::stl::optional<int> >::value);
|
||||
EXPECT_TRUE(std::is_trivially_destructible<m5::stl::optional<int> >::value);
|
||||
|
||||
{
|
||||
struct T {
|
||||
T(const T&) = default;
|
||||
|
||||
T(T&&) = default;
|
||||
|
||||
T& operator=(const T&) = default;
|
||||
|
||||
T& operator=(T&&) = default;
|
||||
|
||||
~T() = default;
|
||||
};
|
||||
EXPECT_TRUE(std::is_trivially_copy_constructible<m5::stl::optional<T> >::value);
|
||||
EXPECT_TRUE(std::is_trivially_copy_assignable<m5::stl::optional<T> >::value);
|
||||
EXPECT_TRUE(std::is_trivially_move_constructible<m5::stl::optional<T> >::value);
|
||||
EXPECT_TRUE(std::is_trivially_move_assignable<m5::stl::optional<T> >::value);
|
||||
EXPECT_TRUE(std::is_trivially_destructible<m5::stl::optional<T> >::value);
|
||||
}
|
||||
|
||||
{
|
||||
struct T {
|
||||
T(const T&)
|
||||
{
|
||||
}
|
||||
T(T&&)
|
||||
{
|
||||
}
|
||||
T& operator=(const T&)
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
T& operator=(T&&)
|
||||
{
|
||||
return *this;
|
||||
};
|
||||
~T()
|
||||
{
|
||||
}
|
||||
};
|
||||
EXPECT_TRUE(!std::is_trivially_copy_constructible<m5::stl::optional<T> >::value);
|
||||
EXPECT_TRUE(!std::is_trivially_copy_assignable<m5::stl::optional<T> >::value);
|
||||
EXPECT_TRUE(!std::is_trivially_move_constructible<m5::stl::optional<T> >::value);
|
||||
EXPECT_TRUE(!std::is_trivially_move_assignable<m5::stl::optional<T> >::value);
|
||||
EXPECT_TRUE(!std::is_trivially_destructible<m5::stl::optional<T> >::value);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Optional, Deletion)
|
||||
{
|
||||
EXPECT_TRUE(std::is_copy_constructible<m5::stl::optional<int> >::value);
|
||||
EXPECT_TRUE(std::is_copy_assignable<m5::stl::optional<int> >::value);
|
||||
EXPECT_TRUE(std::is_move_constructible<m5::stl::optional<int> >::value);
|
||||
EXPECT_TRUE(std::is_move_assignable<m5::stl::optional<int> >::value);
|
||||
EXPECT_TRUE(std::is_destructible<m5::stl::optional<int> >::value);
|
||||
|
||||
{
|
||||
struct T {
|
||||
T(const T&) = default;
|
||||
|
||||
T(T&&) = default;
|
||||
|
||||
T& operator=(const T&) = default;
|
||||
|
||||
T& operator=(T&&) = default;
|
||||
|
||||
~T() = default;
|
||||
};
|
||||
EXPECT_TRUE(std::is_copy_constructible<m5::stl::optional<T> >::value);
|
||||
EXPECT_TRUE(std::is_copy_assignable<m5::stl::optional<T> >::value);
|
||||
EXPECT_TRUE(std::is_move_constructible<m5::stl::optional<T> >::value);
|
||||
EXPECT_TRUE(std::is_move_assignable<m5::stl::optional<T> >::value);
|
||||
EXPECT_TRUE(std::is_destructible<m5::stl::optional<T> >::value);
|
||||
}
|
||||
|
||||
{
|
||||
struct T {
|
||||
T(const T&) = delete;
|
||||
|
||||
T(T&&) = delete;
|
||||
|
||||
T& operator=(const T&) = delete;
|
||||
|
||||
T& operator=(T&&) = delete;
|
||||
};
|
||||
EXPECT_TRUE(!std::is_copy_constructible<m5::stl::optional<T> >::value);
|
||||
EXPECT_TRUE(!std::is_copy_assignable<m5::stl::optional<T> >::value);
|
||||
EXPECT_TRUE(!std::is_move_constructible<m5::stl::optional<T> >::value);
|
||||
EXPECT_TRUE(!std::is_move_assignable<m5::stl::optional<T> >::value);
|
||||
}
|
||||
|
||||
{
|
||||
struct T {
|
||||
T(const T&) = delete;
|
||||
|
||||
T(T&&) = default;
|
||||
|
||||
T& operator=(const T&) = delete;
|
||||
|
||||
T& operator=(T&&) = default;
|
||||
};
|
||||
EXPECT_TRUE(!std::is_copy_constructible<m5::stl::optional<T> >::value);
|
||||
EXPECT_TRUE(!std::is_copy_assignable<m5::stl::optional<T> >::value);
|
||||
EXPECT_TRUE(std::is_move_constructible<m5::stl::optional<T> >::value);
|
||||
EXPECT_TRUE(std::is_move_assignable<m5::stl::optional<T> >::value);
|
||||
}
|
||||
|
||||
{
|
||||
struct T {
|
||||
T(const T&) = default;
|
||||
|
||||
T(T&&) = delete;
|
||||
|
||||
T& operator=(const T&) = default;
|
||||
|
||||
T& operator=(T&&) = delete;
|
||||
};
|
||||
EXPECT_TRUE(std::is_copy_constructible<m5::stl::optional<T> >::value);
|
||||
EXPECT_TRUE(std::is_copy_assignable<m5::stl::optional<T> >::value);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
44
libraries/M5Utility/test/optional/constexpr.cpp
Normal file
44
libraries/M5Utility/test/optional/constexpr.cpp
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <m5_utility/stl/optional.hpp>
|
||||
#include "helper.hpp"
|
||||
|
||||
TEST(Optional, Constexpr)
|
||||
{
|
||||
#if !defined(TL_OPTIONAL_MSVC2015) && defined(TL_OPTIONAL_CXX14)
|
||||
{
|
||||
SCOPED_TRACE("empty construct");
|
||||
constexpr m5::stl::optional<int> o2{};
|
||||
constexpr m5::stl::optional<int> o3 = {};
|
||||
constexpr m5::stl::optional<int> o4 = m5::stl::nullopt;
|
||||
constexpr m5::stl::optional<int> o5 = {m5::stl::nullopt};
|
||||
constexpr m5::stl::optional<int> o6(m5::stl::nullopt);
|
||||
|
||||
STATIC_EXPECT_TRUE(!o2);
|
||||
STATIC_EXPECT_TRUE(!o3);
|
||||
STATIC_EXPECT_TRUE(!o4);
|
||||
STATIC_EXPECT_TRUE(!o5);
|
||||
STATIC_EXPECT_TRUE(!o6);
|
||||
}
|
||||
{
|
||||
SCOPED_TRACE("value construct");
|
||||
constexpr m5::stl::optional<int> o1 = 42;
|
||||
constexpr m5::stl::optional<int> o2{42};
|
||||
constexpr m5::stl::optional<int> o3(42);
|
||||
constexpr m5::stl::optional<int> o4 = {42};
|
||||
constexpr int i = 42;
|
||||
constexpr m5::stl::optional<int> o5 = std::move(i);
|
||||
constexpr m5::stl::optional<int> o6{std::move(i)};
|
||||
constexpr m5::stl::optional<int> o7(std::move(i));
|
||||
constexpr m5::stl::optional<int> o8 = {std::move(i)};
|
||||
|
||||
STATIC_EXPECT_TRUE(*o1 == 42);
|
||||
STATIC_EXPECT_TRUE(*o2 == 42);
|
||||
STATIC_EXPECT_TRUE(*o3 == 42);
|
||||
STATIC_EXPECT_TRUE(*o4 == 42);
|
||||
STATIC_EXPECT_TRUE(*o5 == 42);
|
||||
STATIC_EXPECT_TRUE(*o6 == 42);
|
||||
STATIC_EXPECT_TRUE(*o7 == 42);
|
||||
STATIC_EXPECT_TRUE(*o8 == 42);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
69
libraries/M5Utility/test/optional/constructors.cpp
Normal file
69
libraries/M5Utility/test/optional/constructors.cpp
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <m5_utility/stl/optional.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace constructor {
|
||||
struct foo {
|
||||
foo() = default;
|
||||
|
||||
foo(foo &) = delete;
|
||||
|
||||
foo(foo &&) noexcept
|
||||
{
|
||||
}
|
||||
};
|
||||
} // namespace constructor
|
||||
|
||||
TEST(Optional, Constructors)
|
||||
{
|
||||
m5::stl::optional<int> o1;
|
||||
EXPECT_TRUE(!o1);
|
||||
|
||||
m5::stl::optional<int> o2 = m5::stl::nullopt;
|
||||
EXPECT_TRUE(!o2);
|
||||
|
||||
m5::stl::optional<int> o3 = 42;
|
||||
EXPECT_TRUE(*o3 == 42);
|
||||
|
||||
m5::stl::optional<int> o4 = o3;
|
||||
EXPECT_TRUE(*o4 == 42);
|
||||
|
||||
m5::stl::optional<int> o5 = o1;
|
||||
EXPECT_TRUE(!o5);
|
||||
|
||||
m5::stl::optional<int> o6 = std::move(o3);
|
||||
EXPECT_TRUE(*o6 == 42);
|
||||
|
||||
m5::stl::optional<short> o7 = 42;
|
||||
EXPECT_TRUE(*o7 == 42);
|
||||
|
||||
m5::stl::optional<int> o8 = o7;
|
||||
EXPECT_TRUE(*o8 == 42);
|
||||
|
||||
m5::stl::optional<int> o9 = std::move(o7);
|
||||
EXPECT_TRUE(*o9 == 42);
|
||||
|
||||
{
|
||||
m5::stl::optional<int &> o;
|
||||
EXPECT_TRUE(!o);
|
||||
|
||||
m5::stl::optional<int &> oo = o;
|
||||
EXPECT_TRUE(!oo);
|
||||
}
|
||||
|
||||
{
|
||||
auto i = 42;
|
||||
m5::stl::optional<int &> o = i;
|
||||
EXPECT_TRUE(o);
|
||||
EXPECT_TRUE(*o == 42);
|
||||
|
||||
m5::stl::optional<int &> oo = o;
|
||||
EXPECT_TRUE(oo);
|
||||
EXPECT_TRUE(*oo == 42);
|
||||
}
|
||||
|
||||
std::vector<constructor::foo> v;
|
||||
v.emplace_back();
|
||||
m5::stl::optional<std::vector<constructor::foo>> ov = std::move(v);
|
||||
EXPECT_TRUE(ov->size() == 1);
|
||||
}
|
||||
27
libraries/M5Utility/test/optional/emplace.cpp
Normal file
27
libraries/M5Utility/test/optional/emplace.cpp
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <m5_utility/stl/optional.hpp>
|
||||
#include <utility>
|
||||
#include <tuple>
|
||||
|
||||
TEST(Optional, Emplace)
|
||||
{
|
||||
m5::stl::optional<std::pair<std::pair<int, int>, std::pair<double, double>>> i;
|
||||
i.emplace(std::piecewise_construct, std::make_tuple(0, 2), std::make_tuple(3, 4));
|
||||
EXPECT_TRUE(i->first.first == 0);
|
||||
EXPECT_TRUE(i->first.second == 2);
|
||||
EXPECT_TRUE(i->second.first == 3);
|
||||
EXPECT_TRUE(i->second.second == 4);
|
||||
}
|
||||
|
||||
struct A {
|
||||
A()
|
||||
{
|
||||
throw std::exception();
|
||||
}
|
||||
};
|
||||
|
||||
TEST(Optional, EmplaceWithException)
|
||||
{
|
||||
m5::stl::optional<A> a;
|
||||
EXPECT_ANY_THROW(a.emplace());
|
||||
}
|
||||
501
libraries/M5Utility/test/optional/extensions.cpp
Normal file
501
libraries/M5Utility/test/optional/extensions.cpp
Normal file
|
|
@ -0,0 +1,501 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <m5_utility/stl/optional.hpp>
|
||||
#include <string>
|
||||
#include "helper.hpp"
|
||||
|
||||
constexpr int get_int(int)
|
||||
{
|
||||
return 42;
|
||||
}
|
||||
TL_OPTIONAL_11_CONSTEXPR m5::stl::optional<int> get_opt_int(int)
|
||||
{
|
||||
return 42;
|
||||
}
|
||||
|
||||
// What is Clang Format up to?!
|
||||
TEST(Optional, Monadic)
|
||||
{
|
||||
{ // lhs is empty
|
||||
SCOPED_TRACE("map");
|
||||
m5::stl::optional<int> o1;
|
||||
auto o1r = o1.map([](int i) { return i + 2; });
|
||||
STATIC_EXPECT_TRUE((std::is_same<decltype(o1r), m5::stl::optional<int>>::value));
|
||||
EXPECT_TRUE(!o1r);
|
||||
|
||||
// lhs has value
|
||||
m5::stl::optional<int> o2 = 40;
|
||||
auto o2r = o2.map([](int i) { return i + 2; });
|
||||
STATIC_EXPECT_TRUE((std::is_same<decltype(o2r), m5::stl::optional<int>>::value));
|
||||
EXPECT_TRUE(o2r.value() == 42);
|
||||
|
||||
struct rval_call_map {
|
||||
double operator()(int) &&
|
||||
{
|
||||
return 42.0;
|
||||
};
|
||||
};
|
||||
|
||||
// ensure that function object is forwarded
|
||||
m5::stl::optional<int> o3 = 42;
|
||||
auto o3r = o3.map(rval_call_map{});
|
||||
STATIC_EXPECT_TRUE((std::is_same<decltype(o3r), m5::stl::optional<double>>::value));
|
||||
EXPECT_TRUE(o3r.value() == 42);
|
||||
|
||||
// ensure that lhs is forwarded
|
||||
m5::stl::optional<int> o4 = 40;
|
||||
auto o4r = std::move(o4).map([](int &&i) { return i + 2; });
|
||||
STATIC_EXPECT_TRUE((std::is_same<decltype(o4r), m5::stl::optional<int>>::value));
|
||||
EXPECT_TRUE(o4r.value() == 42);
|
||||
|
||||
// ensure that lhs is const-propagated
|
||||
const m5::stl::optional<int> o5 = 40;
|
||||
auto o5r = o5.map([](const int &i) { return i + 2; });
|
||||
STATIC_EXPECT_TRUE((std::is_same<decltype(o5r), m5::stl::optional<int>>::value));
|
||||
EXPECT_TRUE(o5r.value() == 42);
|
||||
|
||||
// test void return
|
||||
m5::stl::optional<int> o7 = 40;
|
||||
auto f7 = [](const int &) { return; };
|
||||
auto o7r = o7.map(f7);
|
||||
STATIC_EXPECT_TRUE((std::is_same<decltype(o7r), m5::stl::optional<m5::stl::monostate>>::value));
|
||||
EXPECT_TRUE(o7r.has_value());
|
||||
|
||||
// test each overload in turn
|
||||
m5::stl::optional<int> o8 = 42;
|
||||
auto o8r = o8.map([](int) { return 42; });
|
||||
EXPECT_TRUE(*o8r == 42);
|
||||
|
||||
m5::stl::optional<int> o9 = 42;
|
||||
auto o9r = o9.map([](int) { return; });
|
||||
EXPECT_TRUE(o9r);
|
||||
|
||||
m5::stl::optional<int> o12 = 42;
|
||||
auto o12r = std::move(o12).map([](int) { return 42; });
|
||||
EXPECT_TRUE(*o12r == 42);
|
||||
|
||||
m5::stl::optional<int> o13 = 42;
|
||||
auto o13r = std::move(o13).map([](int) { return; });
|
||||
EXPECT_TRUE(o13r);
|
||||
|
||||
const m5::stl::optional<int> o16 = 42;
|
||||
auto o16r = o16.map([](int) { return 42; });
|
||||
EXPECT_TRUE(*o16r == 42);
|
||||
|
||||
const m5::stl::optional<int> o17 = 42;
|
||||
auto o17r = o17.map([](int) { return; });
|
||||
EXPECT_TRUE(o17r);
|
||||
|
||||
const m5::stl::optional<int> o20 = 42;
|
||||
auto o20r = std::move(o20).map([](int) { return 42; });
|
||||
EXPECT_TRUE(*o20r == 42);
|
||||
|
||||
const m5::stl::optional<int> o21 = 42;
|
||||
auto o21r = std::move(o21).map([](int) { return; });
|
||||
EXPECT_TRUE(o21r);
|
||||
|
||||
m5::stl::optional<int> o24 = m5::stl::nullopt;
|
||||
auto o24r = o24.map([](int) { return 42; });
|
||||
EXPECT_TRUE(!o24r);
|
||||
|
||||
m5::stl::optional<int> o25 = m5::stl::nullopt;
|
||||
auto o25r = o25.map([](int) { return; });
|
||||
EXPECT_TRUE(!o25r);
|
||||
|
||||
m5::stl::optional<int> o28 = m5::stl::nullopt;
|
||||
auto o28r = std::move(o28).map([](int) { return 42; });
|
||||
EXPECT_TRUE(!o28r);
|
||||
|
||||
m5::stl::optional<int> o29 = m5::stl::nullopt;
|
||||
auto o29r = std::move(o29).map([](int) { return; });
|
||||
EXPECT_TRUE(!o29r);
|
||||
|
||||
const m5::stl::optional<int> o32 = m5::stl::nullopt;
|
||||
auto o32r = o32.map([](int) { return 42; });
|
||||
EXPECT_TRUE(!o32r);
|
||||
|
||||
const m5::stl::optional<int> o33 = m5::stl::nullopt;
|
||||
auto o33r = o33.map([](int) { return; });
|
||||
EXPECT_TRUE(!o33r);
|
||||
|
||||
const m5::stl::optional<int> o36 = m5::stl::nullopt;
|
||||
auto o36r = std::move(o36).map([](int) { return 42; });
|
||||
EXPECT_TRUE(!o36r);
|
||||
|
||||
const m5::stl::optional<int> o37 = m5::stl::nullopt;
|
||||
auto o37r = std::move(o37).map([](int) { return; });
|
||||
EXPECT_TRUE(!o37r);
|
||||
|
||||
// callable which returns a reference
|
||||
m5::stl::optional<int> o38 = 42;
|
||||
auto o38r = o38.map([](int &i) -> const int &{ return i; });
|
||||
EXPECT_TRUE(o38r);
|
||||
EXPECT_TRUE(*o38r == 42);
|
||||
|
||||
int i = 42;
|
||||
m5::stl::optional<int &> o39 = i;
|
||||
o39.map([](int &x) { x = 12; });
|
||||
EXPECT_TRUE(i == 12);
|
||||
}
|
||||
{
|
||||
SCOPED_TRACE("map constexpr");
|
||||
#if !defined(_MSC_VER) && defined(TL_OPTIONAL_CXX14)
|
||||
// test each overload in turn
|
||||
constexpr m5::stl::optional<int> o16 = 42;
|
||||
constexpr auto o16r = o16.map(get_int);
|
||||
STATIC_EXPECT_TRUE(*o16r == 42);
|
||||
|
||||
constexpr m5::stl::optional<int> o20 = 42;
|
||||
constexpr auto o20r = std::move(o20).map(get_int);
|
||||
STATIC_EXPECT_TRUE(*o20r == 42);
|
||||
|
||||
constexpr m5::stl::optional<int> o32 = m5::stl::nullopt;
|
||||
constexpr auto o32r = o32.map(get_int);
|
||||
STATIC_EXPECT_TRUE(!o32r);
|
||||
constexpr m5::stl::optional<int> o36 = m5::stl::nullopt;
|
||||
constexpr auto o36r = std::move(o36).map(get_int);
|
||||
STATIC_EXPECT_TRUE(!o36r);
|
||||
#endif
|
||||
}
|
||||
{ // lhs is empty
|
||||
SCOPED_TRACE("transform");
|
||||
m5::stl::optional<int> o1;
|
||||
auto o1r = o1.transform([](int i) { return i + 2; });
|
||||
STATIC_EXPECT_TRUE((std::is_same<decltype(o1r), m5::stl::optional<int>>::value));
|
||||
EXPECT_TRUE(!o1r);
|
||||
|
||||
// lhs has value
|
||||
m5::stl::optional<int> o2 = 40;
|
||||
auto o2r = o2.transform([](int i) { return i + 2; });
|
||||
STATIC_EXPECT_TRUE((std::is_same<decltype(o2r), m5::stl::optional<int>>::value));
|
||||
EXPECT_TRUE(o2r.value() == 42);
|
||||
|
||||
struct rval_call_transform {
|
||||
double operator()(int) &&
|
||||
{
|
||||
return 42.0;
|
||||
};
|
||||
};
|
||||
|
||||
// ensure that function object is forwarded
|
||||
m5::stl::optional<int> o3 = 42;
|
||||
auto o3r = o3.transform(rval_call_transform{});
|
||||
STATIC_EXPECT_TRUE((std::is_same<decltype(o3r), m5::stl::optional<double>>::value));
|
||||
EXPECT_TRUE(o3r.value() == 42);
|
||||
|
||||
// ensure that lhs is forwarded
|
||||
m5::stl::optional<int> o4 = 40;
|
||||
auto o4r = std::move(o4).transform([](int &&i) { return i + 2; });
|
||||
STATIC_EXPECT_TRUE((std::is_same<decltype(o4r), m5::stl::optional<int>>::value));
|
||||
EXPECT_TRUE(o4r.value() == 42);
|
||||
|
||||
// ensure that lhs is const-propagated
|
||||
const m5::stl::optional<int> o5 = 40;
|
||||
auto o5r = o5.transform([](const int &i) { return i + 2; });
|
||||
STATIC_EXPECT_TRUE((std::is_same<decltype(o5r), m5::stl::optional<int>>::value));
|
||||
EXPECT_TRUE(o5r.value() == 42);
|
||||
|
||||
// test void return
|
||||
m5::stl::optional<int> o7 = 40;
|
||||
auto f7 = [](const int &) { return; };
|
||||
auto o7r = o7.transform(f7);
|
||||
STATIC_EXPECT_TRUE((std::is_same<decltype(o7r), m5::stl::optional<m5::stl::monostate>>::value));
|
||||
EXPECT_TRUE(o7r.has_value());
|
||||
|
||||
// test each overload in turn
|
||||
m5::stl::optional<int> o8 = 42;
|
||||
auto o8r = o8.transform([](int) { return 42; });
|
||||
EXPECT_TRUE(*o8r == 42);
|
||||
|
||||
m5::stl::optional<int> o9 = 42;
|
||||
auto o9r = o9.transform([](int) { return; });
|
||||
EXPECT_TRUE(o9r);
|
||||
|
||||
m5::stl::optional<int> o12 = 42;
|
||||
auto o12r = std::move(o12).transform([](int) { return 42; });
|
||||
EXPECT_TRUE(*o12r == 42);
|
||||
|
||||
m5::stl::optional<int> o13 = 42;
|
||||
auto o13r = std::move(o13).transform([](int) { return; });
|
||||
EXPECT_TRUE(o13r);
|
||||
|
||||
const m5::stl::optional<int> o16 = 42;
|
||||
auto o16r = o16.transform([](int) { return 42; });
|
||||
EXPECT_TRUE(*o16r == 42);
|
||||
|
||||
const m5::stl::optional<int> o17 = 42;
|
||||
auto o17r = o17.transform([](int) { return; });
|
||||
EXPECT_TRUE(o17r);
|
||||
|
||||
const m5::stl::optional<int> o20 = 42;
|
||||
auto o20r = std::move(o20).transform([](int) { return 42; });
|
||||
EXPECT_TRUE(*o20r == 42);
|
||||
|
||||
const m5::stl::optional<int> o21 = 42;
|
||||
auto o21r = std::move(o21).transform([](int) { return; });
|
||||
EXPECT_TRUE(o21r);
|
||||
|
||||
m5::stl::optional<int> o24 = m5::stl::nullopt;
|
||||
auto o24r = o24.transform([](int) { return 42; });
|
||||
EXPECT_TRUE(!o24r);
|
||||
|
||||
m5::stl::optional<int> o25 = m5::stl::nullopt;
|
||||
auto o25r = o25.transform([](int) { return; });
|
||||
EXPECT_TRUE(!o25r);
|
||||
|
||||
m5::stl::optional<int> o28 = m5::stl::nullopt;
|
||||
auto o28r = std::move(o28).transform([](int) { return 42; });
|
||||
EXPECT_TRUE(!o28r);
|
||||
|
||||
m5::stl::optional<int> o29 = m5::stl::nullopt;
|
||||
auto o29r = std::move(o29).transform([](int) { return; });
|
||||
EXPECT_TRUE(!o29r);
|
||||
|
||||
const m5::stl::optional<int> o32 = m5::stl::nullopt;
|
||||
auto o32r = o32.transform([](int) { return 42; });
|
||||
EXPECT_TRUE(!o32r);
|
||||
|
||||
const m5::stl::optional<int> o33 = m5::stl::nullopt;
|
||||
auto o33r = o33.transform([](int) { return; });
|
||||
EXPECT_TRUE(!o33r);
|
||||
|
||||
const m5::stl::optional<int> o36 = m5::stl::nullopt;
|
||||
auto o36r = std::move(o36).transform([](int) { return 42; });
|
||||
EXPECT_TRUE(!o36r);
|
||||
|
||||
const m5::stl::optional<int> o37 = m5::stl::nullopt;
|
||||
auto o37r = std::move(o37).transform([](int) { return; });
|
||||
EXPECT_TRUE(!o37r);
|
||||
|
||||
// callable which returns a reference
|
||||
m5::stl::optional<int> o38 = 42;
|
||||
auto o38r = o38.transform([](int &i) -> const int &{ return i; });
|
||||
EXPECT_TRUE(o38r);
|
||||
EXPECT_TRUE(*o38r == 42);
|
||||
|
||||
int i = 42;
|
||||
m5::stl::optional<int &> o39 = i;
|
||||
o39.transform([](int &x) { x = 12; });
|
||||
EXPECT_TRUE(i == 12);
|
||||
}
|
||||
{
|
||||
SCOPED_TRACE("transform constexpr");
|
||||
#if !defined(_MSC_VER) && defined(TL_OPTIONAL_CXX14)
|
||||
// test each overload in turn
|
||||
constexpr m5::stl::optional<int> o16 = 42;
|
||||
constexpr auto o16r = o16.transform(get_int);
|
||||
STATIC_EXPECT_TRUE(*o16r == 42);
|
||||
|
||||
constexpr m5::stl::optional<int> o20 = 42;
|
||||
constexpr auto o20r = std::move(o20).transform(get_int);
|
||||
STATIC_EXPECT_TRUE(*o20r == 42);
|
||||
|
||||
constexpr m5::stl::optional<int> o32 = m5::stl::nullopt;
|
||||
constexpr auto o32r = o32.transform(get_int);
|
||||
STATIC_EXPECT_TRUE(!o32r);
|
||||
constexpr m5::stl::optional<int> o36 = m5::stl::nullopt;
|
||||
constexpr auto o36r = std::move(o36).transform(get_int);
|
||||
STATIC_EXPECT_TRUE(!o36r);
|
||||
#endif
|
||||
}
|
||||
{
|
||||
SCOPED_TRACE("and_then");
|
||||
|
||||
// lhs is empty
|
||||
m5::stl::optional<int> o1;
|
||||
auto o1r = o1.and_then([](int) { return m5::stl::optional<float>{42}; });
|
||||
STATIC_EXPECT_TRUE((std::is_same<decltype(o1r), m5::stl::optional<float>>::value));
|
||||
EXPECT_TRUE(!o1r);
|
||||
|
||||
// lhs has value
|
||||
m5::stl::optional<int> o2 = 12;
|
||||
auto o2r = o2.and_then([](int) { return m5::stl::optional<float>{42}; });
|
||||
STATIC_EXPECT_TRUE((std::is_same<decltype(o2r), m5::stl::optional<float>>::value));
|
||||
EXPECT_TRUE(o2r.value() == 42.f);
|
||||
|
||||
// lhs is empty, rhs returns empty
|
||||
m5::stl::optional<int> o3;
|
||||
auto o3r = o3.and_then([](int) { return m5::stl::optional<float>{}; });
|
||||
STATIC_EXPECT_TRUE((std::is_same<decltype(o3r), m5::stl::optional<float>>::value));
|
||||
EXPECT_TRUE(!o3r);
|
||||
|
||||
// rhs returns empty
|
||||
m5::stl::optional<int> o4 = 12;
|
||||
auto o4r = o4.and_then([](int) { return m5::stl::optional<float>{}; });
|
||||
STATIC_EXPECT_TRUE((std::is_same<decltype(o4r), m5::stl::optional<float>>::value));
|
||||
EXPECT_TRUE(!o4r);
|
||||
|
||||
struct rval_call_and_then {
|
||||
m5::stl::optional<double> operator()(int) &&
|
||||
{
|
||||
return m5::stl::optional<double>(42.0);
|
||||
};
|
||||
};
|
||||
|
||||
// ensure that function object is forwarded
|
||||
m5::stl::optional<int> o5 = 42;
|
||||
auto o5r = o5.and_then(rval_call_and_then{});
|
||||
STATIC_EXPECT_TRUE((std::is_same<decltype(o5r), m5::stl::optional<double>>::value));
|
||||
EXPECT_TRUE(o5r.value() == 42);
|
||||
|
||||
// ensure that lhs is forwarded
|
||||
m5::stl::optional<int> o6 = 42;
|
||||
auto o6r = std::move(o6).and_then([](int &&i) { return m5::stl::optional<double>(i); });
|
||||
STATIC_EXPECT_TRUE((std::is_same<decltype(o6r), m5::stl::optional<double>>::value));
|
||||
EXPECT_TRUE(o6r.value() == 42);
|
||||
|
||||
// ensure that function object is const-propagated
|
||||
const m5::stl::optional<int> o7 = 42;
|
||||
auto o7r = o7.and_then([](const int &i) { return m5::stl::optional<double>(i); });
|
||||
STATIC_EXPECT_TRUE((std::is_same<decltype(o7r), m5::stl::optional<double>>::value));
|
||||
EXPECT_TRUE(o7r.value() == 42);
|
||||
|
||||
// test each overload in turn
|
||||
m5::stl::optional<int> o8 = 42;
|
||||
auto o8r = o8.and_then([](int) { return m5::stl::make_optional(42); });
|
||||
EXPECT_TRUE(*o8r == 42);
|
||||
|
||||
m5::stl::optional<int> o9 = 42;
|
||||
auto o9r = std::move(o9).and_then([](int) { return m5::stl::make_optional(42); });
|
||||
EXPECT_TRUE(*o9r == 42);
|
||||
|
||||
const m5::stl::optional<int> o10 = 42;
|
||||
auto o10r = o10.and_then([](int) { return m5::stl::make_optional(42); });
|
||||
EXPECT_TRUE(*o10r == 42);
|
||||
|
||||
const m5::stl::optional<int> o11 = 42;
|
||||
auto o11r = std::move(o11).and_then([](int) { return m5::stl::make_optional(42); });
|
||||
EXPECT_TRUE(*o11r == 42);
|
||||
|
||||
m5::stl::optional<int> o16 = m5::stl::nullopt;
|
||||
auto o16r = o16.and_then([](int) { return m5::stl::make_optional(42); });
|
||||
EXPECT_TRUE(!o16r);
|
||||
|
||||
m5::stl::optional<int> o17 = m5::stl::nullopt;
|
||||
auto o17r = std::move(o17).and_then([](int) { return m5::stl::make_optional(42); });
|
||||
EXPECT_TRUE(!o17r);
|
||||
|
||||
const m5::stl::optional<int> o18 = m5::stl::nullopt;
|
||||
auto o18r = o18.and_then([](int) { return m5::stl::make_optional(42); });
|
||||
EXPECT_TRUE(!o18r);
|
||||
|
||||
const m5::stl::optional<int> o19 = m5::stl::nullopt;
|
||||
auto o19r = std::move(o19).and_then([](int) { return m5::stl::make_optional(42); });
|
||||
EXPECT_TRUE(!o19r);
|
||||
|
||||
int i = 3;
|
||||
m5::stl::optional<int &> o20{i};
|
||||
std::move(o20).and_then([](int &r) { return m5::stl::optional<int &>{++r}; });
|
||||
EXPECT_TRUE(o20);
|
||||
EXPECT_TRUE(i == 4);
|
||||
}
|
||||
{
|
||||
SCOPED_TRACE("constexpr and_then");
|
||||
#if !defined(_MSC_VER) && defined(TL_OPTIONAL_CXX14)
|
||||
|
||||
constexpr m5::stl::optional<int> o10 = 42;
|
||||
constexpr auto o10r = o10.and_then(get_opt_int);
|
||||
EXPECT_TRUE(*o10r == 42);
|
||||
|
||||
constexpr m5::stl::optional<int> o11 = 42;
|
||||
constexpr auto o11r = std::move(o11).and_then(get_opt_int);
|
||||
EXPECT_TRUE(*o11r == 42);
|
||||
|
||||
constexpr m5::stl::optional<int> o18 = m5::stl::nullopt;
|
||||
constexpr auto o18r = o18.and_then(get_opt_int);
|
||||
EXPECT_TRUE(!o18r);
|
||||
|
||||
constexpr m5::stl::optional<int> o19 = m5::stl::nullopt;
|
||||
constexpr auto o19r = std::move(o19).and_then(get_opt_int);
|
||||
EXPECT_TRUE(!o19r);
|
||||
#endif
|
||||
}
|
||||
{
|
||||
SCOPED_TRACE("or else");
|
||||
m5::stl::optional<int> o1 = 42;
|
||||
EXPECT_TRUE(*(o1.or_else([] { return m5::stl::make_optional(13); })) == 42);
|
||||
|
||||
m5::stl::optional<int> o2;
|
||||
EXPECT_TRUE(*(o2.or_else([] { return m5::stl::make_optional(13); })) == 13);
|
||||
}
|
||||
{
|
||||
SCOPED_TRACE("disjunction");
|
||||
m5::stl::optional<int> o1 = 42;
|
||||
m5::stl::optional<int> o2 = 12;
|
||||
m5::stl::optional<int> o3;
|
||||
|
||||
EXPECT_TRUE(*o1.disjunction(o2) == 42);
|
||||
EXPECT_TRUE(*o1.disjunction(o3) == 42);
|
||||
EXPECT_TRUE(*o2.disjunction(o1) == 12);
|
||||
EXPECT_TRUE(*o2.disjunction(o3) == 12);
|
||||
EXPECT_TRUE(*o3.disjunction(o1) == 42);
|
||||
EXPECT_TRUE(*o3.disjunction(o2) == 12);
|
||||
}
|
||||
{
|
||||
SCOPED_TRACE("conjunction");
|
||||
m5::stl::optional<int> o1 = 42;
|
||||
EXPECT_TRUE(*o1.conjunction(42.0) == 42.0);
|
||||
EXPECT_TRUE(*o1.conjunction(std::string{"hello"}) == std::string{"hello"});
|
||||
|
||||
m5::stl::optional<int> o2;
|
||||
EXPECT_TRUE(!o2.conjunction(42.0));
|
||||
EXPECT_TRUE(!o2.conjunction(std::string{"hello"}));
|
||||
}
|
||||
{
|
||||
SCOPED_TRACE("map_or");
|
||||
m5::stl::optional<int> o1 = 21;
|
||||
EXPECT_TRUE((o1.map_or([](int x) { return x * 2; }, 13)) == 42);
|
||||
|
||||
m5::stl::optional<int> o2;
|
||||
EXPECT_TRUE((o2.map_or([](int x) { return x * 2; }, 13)) == 13);
|
||||
}
|
||||
{
|
||||
SCOPED_TRACE("map_or_else");
|
||||
m5::stl::optional<int> o1 = 21;
|
||||
EXPECT_TRUE((o1.map_or_else([](int x) { return x * 2; }, [] { return 13; })) == 42);
|
||||
|
||||
m5::stl::optional<int> o2;
|
||||
EXPECT_TRUE((o2.map_or_else([](int x) { return x * 2; }, [] { return 13; })) == 13);
|
||||
}
|
||||
{
|
||||
SCOPED_TRACE("take");
|
||||
m5::stl::optional<int> o1 = 42;
|
||||
EXPECT_TRUE(*o1.take() == 42);
|
||||
EXPECT_TRUE(!o1);
|
||||
|
||||
m5::stl::optional<int> o2;
|
||||
EXPECT_TRUE(!o2.take());
|
||||
EXPECT_TRUE(!o2);
|
||||
}
|
||||
|
||||
struct foo {
|
||||
void non_const()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && !defined(TL_OPTIONAL_GCC54) && \
|
||||
!defined(TL_OPTIONAL_GCC55)
|
||||
{
|
||||
SCOPED_TRACE("Issue #1");
|
||||
m5::stl::optional<foo> f = foo{};
|
||||
auto l = [](auto &&x) { x.non_const(); };
|
||||
f.map(l);
|
||||
}
|
||||
#endif
|
||||
|
||||
struct overloaded {
|
||||
m5::stl::optional<int> operator()(foo &)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
m5::stl::optional<std::string> operator()(const foo &)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
};
|
||||
{
|
||||
SCOPED_TRACE("Issue #2");
|
||||
m5::stl::optional<foo> f = foo{};
|
||||
auto x = f.and_then(overloaded{});
|
||||
}
|
||||
};
|
||||
6
libraries/M5Utility/test/optional/hash.cpp
Normal file
6
libraries/M5Utility/test/optional/hash.cpp
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <m5_utility/stl/optional.hpp>
|
||||
|
||||
TEST(Optional, Hashing)
|
||||
{
|
||||
}
|
||||
45
libraries/M5Utility/test/optional/in_place.cpp
Normal file
45
libraries/M5Utility/test/optional/in_place.cpp
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <m5_utility/stl/optional.hpp>
|
||||
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
namespace in_place {
|
||||
struct takes_init_and_variadic {
|
||||
std::vector<int> v;
|
||||
std::tuple<int, int> t;
|
||||
template <class... Args>
|
||||
takes_init_and_variadic(std::initializer_list<int> l, Args &&...args) : v(l), t(std::forward<Args>(args)...)
|
||||
{
|
||||
}
|
||||
};
|
||||
} // namespace in_place
|
||||
|
||||
TEST(Optional, Inplace)
|
||||
{
|
||||
m5::stl::optional<int> o1{m5::stl::in_place};
|
||||
m5::stl::optional<int> o2(m5::stl::in_place);
|
||||
EXPECT_TRUE(o1);
|
||||
EXPECT_TRUE(o1 == 0);
|
||||
EXPECT_TRUE(o2);
|
||||
EXPECT_TRUE(o2 == 0);
|
||||
|
||||
m5::stl::optional<int> o3(m5::stl::in_place, 42);
|
||||
EXPECT_TRUE(o3 == 42);
|
||||
|
||||
m5::stl::optional<std::tuple<int, int>> o4(m5::stl::in_place, 0, 1);
|
||||
EXPECT_TRUE(o4);
|
||||
EXPECT_TRUE(std::get<0>(*o4) == 0);
|
||||
EXPECT_TRUE(std::get<1>(*o4) == 1);
|
||||
|
||||
m5::stl::optional<std::vector<int>> o5(m5::stl::in_place, {0, 1});
|
||||
EXPECT_TRUE(o5);
|
||||
EXPECT_TRUE((*o5)[0] == 0);
|
||||
EXPECT_TRUE((*o5)[1] == 1);
|
||||
|
||||
m5::stl::optional<in_place::takes_init_and_variadic> o6(m5::stl::in_place, {0, 1}, 2, 3);
|
||||
EXPECT_TRUE(o6->v[0] == 0);
|
||||
EXPECT_TRUE(o6->v[1] == 1);
|
||||
EXPECT_TRUE(std::get<0>(o6->t) == 2);
|
||||
EXPECT_TRUE(std::get<1>(o6->t) == 3);
|
||||
}
|
||||
59
libraries/M5Utility/test/optional/issues.cpp
Normal file
59
libraries/M5Utility/test/optional/issues.cpp
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <m5_utility/stl/optional.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
namespace issues {
|
||||
struct foo {
|
||||
int& v()
|
||||
{
|
||||
return i;
|
||||
}
|
||||
int i = 0;
|
||||
};
|
||||
} // namespace issues
|
||||
int& x(int& i)
|
||||
{
|
||||
i = 42;
|
||||
return i;
|
||||
}
|
||||
|
||||
TEST(Optional, issue14)
|
||||
{
|
||||
m5::stl::optional<issues::foo> f = issues::foo{};
|
||||
auto v = f.map(&issues::foo::v).map(x);
|
||||
static_assert(std::is_same<decltype(v), m5::stl::optional<int&>>::value, "Must return a reference");
|
||||
EXPECT_TRUE(f->i == 42);
|
||||
EXPECT_TRUE(*v == 42);
|
||||
EXPECT_TRUE((&f->i) == (&*v));
|
||||
}
|
||||
|
||||
struct fail_on_copy_self {
|
||||
int value;
|
||||
fail_on_copy_self(int v) : value(v)
|
||||
{
|
||||
}
|
||||
fail_on_copy_self(const fail_on_copy_self& other) : value(other.value)
|
||||
{
|
||||
EXPECT_TRUE(&other != this);
|
||||
}
|
||||
};
|
||||
|
||||
TEST(Optional, issue15)
|
||||
{
|
||||
m5::stl::optional<fail_on_copy_self> o = fail_on_copy_self(42);
|
||||
|
||||
o = o;
|
||||
EXPECT_TRUE(o->value == 42);
|
||||
}
|
||||
|
||||
TEST(Optional, issue33)
|
||||
{
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
m5::stl::optional<int&> a = i;
|
||||
a.emplace(j);
|
||||
*a = 42;
|
||||
EXPECT_TRUE(j == 42);
|
||||
EXPECT_TRUE(*a == 42);
|
||||
EXPECT_TRUE(a.has_value());
|
||||
}
|
||||
49
libraries/M5Utility/test/optional/make_optional.cpp
Normal file
49
libraries/M5Utility/test/optional/make_optional.cpp
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <m5_utility/stl/optional.hpp>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
namespace make_opt {
|
||||
struct takes_init_and_variadic {
|
||||
std::vector<int> v;
|
||||
std::tuple<int, int> t;
|
||||
template <class... Args>
|
||||
takes_init_and_variadic(std::initializer_list<int> l, Args &&...args) : v(l), t(std::forward<Args>(args)...)
|
||||
{
|
||||
}
|
||||
};
|
||||
} // namespace make_opt
|
||||
|
||||
TEST(Optional, MakeOptional)
|
||||
{
|
||||
auto o1 = m5::stl::make_optional(42);
|
||||
auto o2 = m5::stl::optional<int>(42);
|
||||
|
||||
constexpr bool is_same = std::is_same<decltype(o1), m5::stl::optional<int>>::value;
|
||||
EXPECT_TRUE(is_same);
|
||||
EXPECT_TRUE(o1 == o2);
|
||||
|
||||
auto o3 = m5::stl::make_optional<std::tuple<int, int, int, int>>(0, 1, 2, 3);
|
||||
EXPECT_TRUE(std::get<0>(*o3) == 0);
|
||||
EXPECT_TRUE(std::get<1>(*o3) == 1);
|
||||
EXPECT_TRUE(std::get<2>(*o3) == 2);
|
||||
EXPECT_TRUE(std::get<3>(*o3) == 3);
|
||||
|
||||
auto o4 = m5::stl::make_optional<std::vector<int>>({0, 1, 2, 3});
|
||||
EXPECT_TRUE(o4.value()[0] == 0);
|
||||
EXPECT_TRUE(o4.value()[1] == 1);
|
||||
EXPECT_TRUE(o4.value()[2] == 2);
|
||||
EXPECT_TRUE(o4.value()[3] == 3);
|
||||
|
||||
auto o5 = m5::stl::make_optional<make_opt::takes_init_and_variadic>({0, 1}, 2, 3);
|
||||
EXPECT_TRUE(o5->v[0] == 0);
|
||||
EXPECT_TRUE(o5->v[1] == 1);
|
||||
EXPECT_TRUE(std::get<0>(o5->t) == 2);
|
||||
EXPECT_TRUE(std::get<1>(o5->t) == 3);
|
||||
|
||||
auto i = 42;
|
||||
auto o6 = m5::stl::make_optional<int &>(i);
|
||||
EXPECT_TRUE((std::is_same<decltype(o6), m5::stl::optional<int &>>::value));
|
||||
EXPECT_TRUE(o6);
|
||||
EXPECT_TRUE(*o6 == 42);
|
||||
}
|
||||
119
libraries/M5Utility/test/optional/noexcept.cpp
Normal file
119
libraries/M5Utility/test/optional/noexcept.cpp
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <m5_utility/stl/optional.hpp>
|
||||
|
||||
TEST(Optional, Noexcept)
|
||||
{
|
||||
m5::stl::optional<int> o1{4};
|
||||
m5::stl::optional<int> o2{42};
|
||||
{
|
||||
SCOPED_TRACE("comparison with nullopt");
|
||||
EXPECT_TRUE(noexcept(o1 == m5::stl::nullopt));
|
||||
EXPECT_TRUE(noexcept(m5::stl::nullopt == o1));
|
||||
EXPECT_TRUE(noexcept(o1 != m5::stl::nullopt));
|
||||
EXPECT_TRUE(noexcept(m5::stl::nullopt != o1));
|
||||
EXPECT_TRUE(noexcept(o1 < m5::stl::nullopt));
|
||||
EXPECT_TRUE(noexcept(m5::stl::nullopt < o1));
|
||||
EXPECT_TRUE(noexcept(o1 <= m5::stl::nullopt));
|
||||
EXPECT_TRUE(noexcept(m5::stl::nullopt <= o1));
|
||||
EXPECT_TRUE(noexcept(o1 > m5::stl::nullopt));
|
||||
EXPECT_TRUE(noexcept(m5::stl::nullopt > o1));
|
||||
EXPECT_TRUE(noexcept(o1 >= m5::stl::nullopt));
|
||||
EXPECT_TRUE(noexcept(m5::stl::nullopt >= o1));
|
||||
}
|
||||
{
|
||||
SCOPED_TRACE("swap");
|
||||
// TODO see why this fails
|
||||
#if !defined(_MSC_VER) || _MSC_VER > 1900
|
||||
EXPECT_TRUE(noexcept(swap(o1, o2)) == noexcept(o1.swap(o2)));
|
||||
|
||||
struct nothrow_swappable {
|
||||
nothrow_swappable &swap(const nothrow_swappable &) noexcept
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
struct throw_swappable {
|
||||
throw_swappable() = default;
|
||||
throw_swappable(const throw_swappable &)
|
||||
{
|
||||
}
|
||||
throw_swappable(throw_swappable &&)
|
||||
{
|
||||
}
|
||||
throw_swappable &swap(const throw_swappable &)
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
m5::stl::optional<nothrow_swappable> ont;
|
||||
m5::stl::optional<throw_swappable> ot;
|
||||
|
||||
EXPECT_TRUE(noexcept(ont.swap(ont)));
|
||||
EXPECT_TRUE(!noexcept(ot.swap(ot)));
|
||||
#endif
|
||||
}
|
||||
{
|
||||
SCOPED_TRACE("constructors");
|
||||
// TODO see why this fails
|
||||
#if !defined(_MSC_VER) || _MSC_VER > 1900
|
||||
EXPECT_TRUE(noexcept(m5::stl::optional<int>{}));
|
||||
EXPECT_TRUE(noexcept(m5::stl::optional<int>{m5::stl::nullopt}));
|
||||
|
||||
struct nothrow_move {
|
||||
nothrow_move(nothrow_move &&) noexcept = default;
|
||||
};
|
||||
|
||||
struct throw_move {
|
||||
throw_move(throw_move &&)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
using nothrow_opt = m5::stl::optional<nothrow_move>;
|
||||
using throw_opt = m5::stl::optional<throw_move>;
|
||||
|
||||
EXPECT_TRUE(std::is_nothrow_move_constructible<nothrow_opt>::value);
|
||||
EXPECT_TRUE(!std::is_nothrow_move_constructible<throw_opt>::value);
|
||||
#endif
|
||||
}
|
||||
{
|
||||
SCOPED_TRACE("assignment");
|
||||
EXPECT_TRUE(noexcept(o1 = m5::stl::nullopt));
|
||||
|
||||
struct nothrow_move_assign {
|
||||
nothrow_move_assign() = default;
|
||||
|
||||
nothrow_move_assign(nothrow_move_assign &&) noexcept = default;
|
||||
|
||||
nothrow_move_assign &operator=(const nothrow_move_assign &) = default;
|
||||
};
|
||||
|
||||
struct throw_move_assign {
|
||||
throw_move_assign() = default;
|
||||
throw_move_assign(throw_move_assign &&)
|
||||
{
|
||||
}
|
||||
throw_move_assign &operator=(const throw_move_assign &)
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
using nothrow_opt = m5::stl::optional<nothrow_move_assign>;
|
||||
using throw_opt = m5::stl::optional<throw_move_assign>;
|
||||
|
||||
EXPECT_TRUE(noexcept(std::declval<nothrow_opt>() = std::declval<nothrow_opt>()));
|
||||
EXPECT_TRUE(!noexcept(std::declval<throw_opt>() = std::declval<throw_opt>()));
|
||||
}
|
||||
{
|
||||
SCOPED_TRACE("observers");
|
||||
EXPECT_TRUE(noexcept(static_cast<bool>(o1)));
|
||||
EXPECT_TRUE(noexcept(o1.has_value()));
|
||||
}
|
||||
{
|
||||
SCOPED_TRACE("modifiers");
|
||||
EXPECT_TRUE(noexcept(o1.reset()));
|
||||
}
|
||||
}
|
||||
17
libraries/M5Utility/test/optional/nullopt.cpp
Normal file
17
libraries/M5Utility/test/optional/nullopt.cpp
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <m5_utility/stl/optional.hpp>
|
||||
|
||||
TEST(Optional, Nullopt)
|
||||
{
|
||||
m5::stl::optional<int> o1 = m5::stl::nullopt;
|
||||
m5::stl::optional<int> o2{m5::stl::nullopt};
|
||||
m5::stl::optional<int> o3(m5::stl::nullopt);
|
||||
m5::stl::optional<int> o4 = {m5::stl::nullopt};
|
||||
|
||||
EXPECT_TRUE(!o1);
|
||||
EXPECT_TRUE(!o2);
|
||||
EXPECT_TRUE(!o3);
|
||||
EXPECT_TRUE(!o4);
|
||||
|
||||
EXPECT_TRUE(!std::is_default_constructible<m5::stl::nullopt_t>::value);
|
||||
}
|
||||
39
libraries/M5Utility/test/optional/observers.cpp
Normal file
39
libraries/M5Utility/test/optional/observers.cpp
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <m5_utility/stl/optional.hpp>
|
||||
|
||||
struct move_detector {
|
||||
move_detector() = default;
|
||||
move_detector(move_detector &&rhs)
|
||||
{
|
||||
rhs.been_moved = true;
|
||||
}
|
||||
bool been_moved = false;
|
||||
};
|
||||
|
||||
TEST(Optional, Observers)
|
||||
{
|
||||
m5::stl::optional<int> o1 = 42;
|
||||
m5::stl::optional<int> o2;
|
||||
const m5::stl::optional<int> o3 = 42;
|
||||
|
||||
EXPECT_TRUE(*o1 == 42);
|
||||
EXPECT_TRUE(*o1 == o1.value());
|
||||
EXPECT_TRUE(o2.value_or(42) == 42);
|
||||
EXPECT_TRUE(o3.value() == 42);
|
||||
auto success = std::is_same<decltype(o1.value()), int &>::value;
|
||||
EXPECT_TRUE(success);
|
||||
success = std::is_same<decltype(o3.value()), const int &>::value;
|
||||
EXPECT_TRUE(success);
|
||||
success = std::is_same<decltype(std::move(o1).value()), int &&>::value;
|
||||
EXPECT_TRUE(success);
|
||||
|
||||
#ifndef TL_OPTIONAL_NO_CONSTRR
|
||||
success = std::is_same<decltype(std::move(o3).value()), const int &&>::value;
|
||||
EXPECT_TRUE(success);
|
||||
#endif
|
||||
|
||||
m5::stl::optional<move_detector> o4{m5::stl::in_place};
|
||||
move_detector o5 = std::move(o4).value();
|
||||
EXPECT_TRUE(o4->been_moved);
|
||||
EXPECT_TRUE(!o5.been_moved);
|
||||
}
|
||||
154
libraries/M5Utility/test/optional/relops.cpp
Normal file
154
libraries/M5Utility/test/optional/relops.cpp
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <m5_utility/stl/optional.hpp>
|
||||
|
||||
TEST(Optional, RelationalOps)
|
||||
{
|
||||
m5::stl::optional<int> o1{4};
|
||||
m5::stl::optional<int> o2{42};
|
||||
m5::stl::optional<int> o3{};
|
||||
{
|
||||
SCOPED_TRACE("self simple");
|
||||
EXPECT_TRUE(!(o1 == o2));
|
||||
EXPECT_TRUE(o1 == o1);
|
||||
EXPECT_TRUE(o1 != o2);
|
||||
EXPECT_TRUE(!(o1 != o1));
|
||||
EXPECT_TRUE(o1 < o2);
|
||||
EXPECT_TRUE(!(o1 < o1));
|
||||
EXPECT_TRUE(!(o1 > o2));
|
||||
EXPECT_TRUE(!(o1 > o1));
|
||||
EXPECT_TRUE(o1 <= o2);
|
||||
EXPECT_TRUE(o1 <= o1);
|
||||
EXPECT_TRUE(!(o1 >= o2));
|
||||
EXPECT_TRUE(o1 >= o1);
|
||||
}
|
||||
{
|
||||
SCOPED_TRACE("nullopt simple");
|
||||
EXPECT_TRUE(!(o1 == m5::stl::nullopt));
|
||||
EXPECT_TRUE(!(m5::stl::nullopt == o1));
|
||||
EXPECT_TRUE(o1 != m5::stl::nullopt);
|
||||
EXPECT_TRUE(m5::stl::nullopt != o1);
|
||||
EXPECT_TRUE(!(o1 < m5::stl::nullopt));
|
||||
EXPECT_TRUE(m5::stl::nullopt < o1);
|
||||
EXPECT_TRUE(o1 > m5::stl::nullopt);
|
||||
EXPECT_TRUE(!(m5::stl::nullopt > o1));
|
||||
EXPECT_TRUE(!(o1 <= m5::stl::nullopt));
|
||||
EXPECT_TRUE(m5::stl::nullopt <= o1);
|
||||
EXPECT_TRUE(o1 >= m5::stl::nullopt);
|
||||
EXPECT_TRUE(!(m5::stl::nullopt >= o1));
|
||||
|
||||
EXPECT_TRUE(o3 == m5::stl::nullopt);
|
||||
EXPECT_TRUE(m5::stl::nullopt == o3);
|
||||
EXPECT_TRUE(!(o3 != m5::stl::nullopt));
|
||||
EXPECT_TRUE(!(m5::stl::nullopt != o3));
|
||||
EXPECT_TRUE(!(o3 < m5::stl::nullopt));
|
||||
EXPECT_TRUE(!(m5::stl::nullopt < o3));
|
||||
EXPECT_TRUE(!(o3 > m5::stl::nullopt));
|
||||
EXPECT_TRUE(!(m5::stl::nullopt > o3));
|
||||
EXPECT_TRUE(o3 <= m5::stl::nullopt);
|
||||
EXPECT_TRUE(m5::stl::nullopt <= o3);
|
||||
EXPECT_TRUE(o3 >= m5::stl::nullopt);
|
||||
EXPECT_TRUE(m5::stl::nullopt >= o3);
|
||||
}
|
||||
{
|
||||
SCOPED_TRACE("with T simple");
|
||||
EXPECT_TRUE(!(o1 == 1));
|
||||
EXPECT_TRUE(!(1 == o1));
|
||||
EXPECT_TRUE(o1 != 1);
|
||||
EXPECT_TRUE(1 != o1);
|
||||
EXPECT_TRUE(!(o1 < 1));
|
||||
EXPECT_TRUE(1 < o1);
|
||||
EXPECT_TRUE(o1 > 1);
|
||||
EXPECT_TRUE(!(1 > o1));
|
||||
EXPECT_TRUE(!(o1 <= 1));
|
||||
EXPECT_TRUE(1 <= o1);
|
||||
EXPECT_TRUE(o1 >= 1);
|
||||
EXPECT_TRUE(!(1 >= o1));
|
||||
|
||||
EXPECT_TRUE(o1 == 4);
|
||||
EXPECT_TRUE(4 == o1);
|
||||
EXPECT_TRUE(!(o1 != 4));
|
||||
EXPECT_TRUE(!(4 != o1));
|
||||
EXPECT_TRUE(!(o1 < 4));
|
||||
EXPECT_TRUE(!(4 < o1));
|
||||
EXPECT_TRUE(!(o1 > 4));
|
||||
EXPECT_TRUE(!(4 > o1));
|
||||
EXPECT_TRUE(o1 <= 4);
|
||||
EXPECT_TRUE(4 <= o1);
|
||||
EXPECT_TRUE(o1 >= 4);
|
||||
EXPECT_TRUE(4 >= o1);
|
||||
}
|
||||
|
||||
m5::stl::optional<std::string> o4{"hello"};
|
||||
m5::stl::optional<std::string> o5{"xyz"};
|
||||
{
|
||||
SCOPED_TRACE("self complex");
|
||||
EXPECT_TRUE(!(o4 == o5));
|
||||
EXPECT_TRUE(o4 == o4);
|
||||
EXPECT_TRUE(o4 != o5);
|
||||
EXPECT_TRUE(!(o4 != o4));
|
||||
EXPECT_TRUE(o4 < o5);
|
||||
EXPECT_TRUE(!(o4 < o4));
|
||||
EXPECT_TRUE(!(o4 > o5));
|
||||
EXPECT_TRUE(!(o4 > o4));
|
||||
EXPECT_TRUE(o4 <= o5);
|
||||
EXPECT_TRUE(o4 <= o4);
|
||||
EXPECT_TRUE(!(o4 >= o5));
|
||||
EXPECT_TRUE(o4 >= o4);
|
||||
}
|
||||
{
|
||||
SCOPED_TRACE("nullopt complex");
|
||||
EXPECT_TRUE(!(o4 == m5::stl::nullopt));
|
||||
EXPECT_TRUE(!(m5::stl::nullopt == o4));
|
||||
EXPECT_TRUE(o4 != m5::stl::nullopt);
|
||||
EXPECT_TRUE(m5::stl::nullopt != o4);
|
||||
EXPECT_TRUE(!(o4 < m5::stl::nullopt));
|
||||
EXPECT_TRUE(m5::stl::nullopt < o4);
|
||||
EXPECT_TRUE(o4 > m5::stl::nullopt);
|
||||
EXPECT_TRUE(!(m5::stl::nullopt > o4));
|
||||
EXPECT_TRUE(!(o4 <= m5::stl::nullopt));
|
||||
EXPECT_TRUE(m5::stl::nullopt <= o4);
|
||||
EXPECT_TRUE(o4 >= m5::stl::nullopt);
|
||||
EXPECT_TRUE(!(m5::stl::nullopt >= o4));
|
||||
|
||||
EXPECT_TRUE(o3 == m5::stl::nullopt);
|
||||
EXPECT_TRUE(m5::stl::nullopt == o3);
|
||||
EXPECT_TRUE(!(o3 != m5::stl::nullopt));
|
||||
EXPECT_TRUE(!(m5::stl::nullopt != o3));
|
||||
EXPECT_TRUE(!(o3 < m5::stl::nullopt));
|
||||
EXPECT_TRUE(!(m5::stl::nullopt < o3));
|
||||
EXPECT_TRUE(!(o3 > m5::stl::nullopt));
|
||||
EXPECT_TRUE(!(m5::stl::nullopt > o3));
|
||||
EXPECT_TRUE(o3 <= m5::stl::nullopt);
|
||||
EXPECT_TRUE(m5::stl::nullopt <= o3);
|
||||
EXPECT_TRUE(o3 >= m5::stl::nullopt);
|
||||
EXPECT_TRUE(m5::stl::nullopt >= o3);
|
||||
}
|
||||
{
|
||||
SCOPED_TRACE("with T complex");
|
||||
EXPECT_TRUE(!(o4 == "a"));
|
||||
EXPECT_TRUE(!("a" == o4));
|
||||
EXPECT_TRUE(o4 != "a");
|
||||
EXPECT_TRUE("a" != o4);
|
||||
EXPECT_TRUE(!(o4 < "a"));
|
||||
EXPECT_TRUE("a" < o4);
|
||||
EXPECT_TRUE(o4 > "a");
|
||||
EXPECT_TRUE(!("a" > o4));
|
||||
EXPECT_TRUE(!(o4 <= "a"));
|
||||
EXPECT_TRUE("a" <= o4);
|
||||
EXPECT_TRUE(o4 >= "a");
|
||||
EXPECT_TRUE(!("a" >= o4));
|
||||
|
||||
EXPECT_TRUE(o4 == "hello");
|
||||
EXPECT_TRUE("hello" == o4);
|
||||
EXPECT_TRUE(!(o4 != "hello"));
|
||||
EXPECT_TRUE(!("hello" != o4));
|
||||
EXPECT_TRUE(!(o4 < "hello"));
|
||||
EXPECT_TRUE(!("hello" < o4));
|
||||
EXPECT_TRUE(!(o4 > "hello"));
|
||||
EXPECT_TRUE(!("hello" > o4));
|
||||
EXPECT_TRUE(o4 <= "hello");
|
||||
EXPECT_TRUE("hello" <= o4);
|
||||
EXPECT_TRUE(o4 >= "hello");
|
||||
EXPECT_TRUE("hello" >= o4);
|
||||
}
|
||||
}
|
||||
29
libraries/M5Utility/test/optional/swap.cpp
Normal file
29
libraries/M5Utility/test/optional/swap.cpp
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <m5_utility/stl/optional.hpp>
|
||||
|
||||
TEST(Optional, SwapValue)
|
||||
{
|
||||
m5::stl::optional<int> o1 = 42;
|
||||
m5::stl::optional<int> o2 = 12;
|
||||
o1.swap(o2);
|
||||
EXPECT_TRUE(o1.value() == 12);
|
||||
EXPECT_TRUE(o2.value() == 42);
|
||||
}
|
||||
|
||||
TEST(Optional, SwapValueWithNullIntialized)
|
||||
{
|
||||
m5::stl::optional<int> o1 = 42;
|
||||
m5::stl::optional<int> o2 = m5::stl::nullopt;
|
||||
o1.swap(o2);
|
||||
EXPECT_TRUE(!o1.has_value());
|
||||
EXPECT_TRUE(o2.value() == 42);
|
||||
}
|
||||
|
||||
TEST(Optional, SwapNullIntializedWithValue)
|
||||
{
|
||||
m5::stl::optional<int> o1 = m5::stl::nullopt;
|
||||
m5::stl::optional<int> o2 = 42;
|
||||
o1.swap(o2);
|
||||
EXPECT_TRUE(o1.value() == 42);
|
||||
EXPECT_TRUE(!o2.has_value());
|
||||
}
|
||||
27
libraries/M5Utility/test/optional_test.cpp
Normal file
27
libraries/M5Utility/test/optional_test.cpp
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
/*
|
||||
UnitTest for M5Utility
|
||||
|
||||
Each split by test_filter creates a separate binary. So they are combined by
|
||||
including cpp. Note that the /optional files are not compiled directly if not
|
||||
set to test_filter
|
||||
*/
|
||||
#include "optional/assignment.cpp"
|
||||
#include "optional/bases.cpp"
|
||||
#include "optional/constexpr.cpp"
|
||||
#include "optional/constructors.cpp"
|
||||
#include "optional/emplace.cpp"
|
||||
#include "optional/extensions.cpp"
|
||||
#include "optional/hash.cpp"
|
||||
#include "optional/in_place.cpp"
|
||||
#include "optional/issues.cpp"
|
||||
#include "optional/make_optional.cpp"
|
||||
#include "optional/noexcept.cpp"
|
||||
#include "optional/nullopt.cpp"
|
||||
#include "optional/observers.cpp"
|
||||
#include "optional/relops.cpp"
|
||||
#include "optional/swap.cpp"
|
||||
73
libraries/M5Utility/test/string_test.cpp
Normal file
73
libraries/M5Utility/test/string_test.cpp
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
/*
|
||||
UnitTest for M5Utility
|
||||
*/
|
||||
#include <gtest/gtest.h>
|
||||
#include <M5Utility.hpp>
|
||||
|
||||
TEST(Utility, String)
|
||||
{
|
||||
std::string org = "\t\r\n\v STRING \v\n\r\t";
|
||||
std::string s = org;
|
||||
s = m5::utility::trim(s); // Call trimRight/Left in it
|
||||
EXPECT_STREQ(s.c_str(), "STRING");
|
||||
}
|
||||
|
||||
TEST(Utility, HexString)
|
||||
{
|
||||
{
|
||||
std::pair<uint8_t, char> table_upper[] = {
|
||||
{0, '0'}, {1, '1'}, {2, '2'}, {3, '3'}, {4, '4'}, {5, '5'}, {6, '6'}, {7, '7'}, {8, '8'},
|
||||
{9, '9'}, {10, 'A'}, {11, 'B'}, {12, 'C'}, {13, 'D'}, {14, 'E'}, {15, 'F'}, {100, '4'},
|
||||
};
|
||||
std::pair<uint8_t, char> table_lower[] = {
|
||||
{0, '0'}, {1, '1'}, {2, '2'}, {3, '3'}, {4, '4'}, {5, '5'}, {6, '6'}, {7, '7'}, {8, '8'},
|
||||
{9, '9'}, {10, 'a'}, {11, 'b'}, {12, 'c'}, {13, 'd'}, {14, 'e'}, {15, 'f'}, {100, '4'},
|
||||
};
|
||||
|
||||
for (auto&& e : table_upper) {
|
||||
EXPECT_EQ(m5::utility::uintToHexChar<true>(e.first), e.second);
|
||||
}
|
||||
for (auto&& e : table_lower) {
|
||||
EXPECT_EQ(m5::utility::uintToHexChar<false>(e.first), e.second);
|
||||
}
|
||||
}
|
||||
|
||||
std::string s;
|
||||
{
|
||||
uint8_t zero = 0;
|
||||
uint8_t v = 0xA2;
|
||||
s = m5::utility::unsignedToHexString(zero);
|
||||
EXPECT_STREQ(s.c_str(), "00");
|
||||
s = m5::utility::unsignedToHexString(v);
|
||||
EXPECT_STREQ(s.c_str(), "A2");
|
||||
}
|
||||
{
|
||||
uint16_t zero = 0;
|
||||
uint16_t v = 0x0D51;
|
||||
s = m5::utility::unsignedToHexString(zero);
|
||||
EXPECT_STREQ(s.c_str(), "0000");
|
||||
s = m5::utility::unsignedToHexString(v);
|
||||
EXPECT_STREQ(s.c_str(), "0D51");
|
||||
}
|
||||
{
|
||||
uint32_t zero = 0;
|
||||
uint32_t v = 0xBEAF1234;
|
||||
s = m5::utility::unsignedToHexString(zero);
|
||||
EXPECT_STREQ(s.c_str(), "00000000");
|
||||
s = m5::utility::unsignedToHexString(v);
|
||||
EXPECT_STREQ(s.c_str(), "BEAF1234");
|
||||
}
|
||||
{
|
||||
uint64_t zero = 0;
|
||||
uint64_t v = 0x5252DEADBEAF0303;
|
||||
s = m5::utility::unsignedToHexString(zero);
|
||||
EXPECT_STREQ(s.c_str(), "0000000000000000");
|
||||
s = m5::utility::unsignedToHexString(v);
|
||||
EXPECT_STREQ(s.c_str(), "5252DEADBEAF0303");
|
||||
}
|
||||
}
|
||||
181
libraries/M5Utility/test/types_test.cpp
Normal file
181
libraries/M5Utility/test/types_test.cpp
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
/*
|
||||
UnitTest for M5Utility
|
||||
*/
|
||||
#include <gtest/gtest.h>
|
||||
#include <M5Utility.hpp>
|
||||
|
||||
using namespace m5::types;
|
||||
|
||||
TEST(Utility, Types_U16)
|
||||
{
|
||||
// Constructor
|
||||
constexpr big_uint16_t bg0;
|
||||
constexpr little_uint16_t lt0;
|
||||
EXPECT_EQ(bg0.u16, 0U);
|
||||
EXPECT_EQ(lt0.u16, 0U);
|
||||
|
||||
big_uint16_t bg1{0x1234};
|
||||
little_uint16_t lt1{0x1234};
|
||||
EXPECT_EQ(bg1.u8[0], 0x12);
|
||||
EXPECT_EQ(bg1.u8[1], 0x34);
|
||||
EXPECT_EQ(lt1.u8[0], 0x34);
|
||||
EXPECT_EQ(lt1.u8[1], 0x12);
|
||||
|
||||
constexpr big_uint16_t bg2{0x12, 0x34};
|
||||
constexpr little_uint16_t lt2{0x12, 0x34};
|
||||
EXPECT_EQ(bg2.u8[0], 0x12);
|
||||
EXPECT_EQ(bg2.u8[1], 0x34);
|
||||
EXPECT_EQ(lt2.u8[0], 0x12);
|
||||
EXPECT_EQ(lt2.u8[1], 0x34);
|
||||
|
||||
big_uint16_t bg3 = bg1;
|
||||
little_uint16_t lt3 = lt1;
|
||||
EXPECT_EQ(bg3.u8[0], 0x12);
|
||||
EXPECT_EQ(bg3.u8[1], 0x34);
|
||||
EXPECT_EQ(lt3.u8[0], 0x34);
|
||||
EXPECT_EQ(lt3.u8[1], 0x12);
|
||||
|
||||
big_uint16_t bg4 = std::move(bg3);
|
||||
little_uint16_t lt4 = std::move(lt3);
|
||||
EXPECT_EQ(bg4.u8[0], 0x12);
|
||||
EXPECT_EQ(bg4.u8[1], 0x34);
|
||||
EXPECT_EQ(lt4.u8[0], 0x34);
|
||||
EXPECT_EQ(lt4.u8[1], 0x12);
|
||||
|
||||
// Assignment
|
||||
big_uint16_t bg5;
|
||||
little_uint16_t lt5;
|
||||
bg5 = bg4;
|
||||
lt5 = lt4;
|
||||
EXPECT_EQ(bg5.u8[0], 0x12);
|
||||
EXPECT_EQ(bg5.u8[1], 0x34);
|
||||
EXPECT_EQ(lt5.u8[0], 0x34);
|
||||
EXPECT_EQ(lt5.u8[1], 0x12);
|
||||
|
||||
big_uint16_t bg60;
|
||||
big_uint16_t bg61;
|
||||
little_uint16_t lt60;
|
||||
little_uint16_t lt61;
|
||||
if (m5::endian::little) {
|
||||
bg60.operator=<false>(0x3412); // big to big
|
||||
bg61.operator=<true>(0x1234); // little to big
|
||||
lt60.operator=<false>(0x3412); // big to little
|
||||
lt61.operator=<true>(0x1234); // little to little
|
||||
} else {
|
||||
bg60.operator=<false>(0x1234); // big to big
|
||||
bg61.operator=<true>(0x3412); // little to big
|
||||
lt60.operator=<false>(0x1234); // big to little
|
||||
lt61.operator=<true>(0x3412); // little to little
|
||||
}
|
||||
EXPECT_EQ(bg60.u8[0], 0x12);
|
||||
EXPECT_EQ(bg60.u8[1], 0x34);
|
||||
EXPECT_EQ(bg61.u8[0], 0x12);
|
||||
EXPECT_EQ(bg61.u8[1], 0x34);
|
||||
EXPECT_EQ(lt60.u8[0], 0x34);
|
||||
EXPECT_EQ(lt60.u8[1], 0x12);
|
||||
EXPECT_EQ(lt61.u8[0], 0x34);
|
||||
EXPECT_EQ(lt61.u8[1], 0x12);
|
||||
|
||||
big_uint16_t bg7;
|
||||
little_uint16_t lt7;
|
||||
bg7 = std::make_pair<int, int>(0x12, 0x34);
|
||||
lt7 = std::make_pair<int, int>(0x12, 0x34);
|
||||
EXPECT_EQ(bg7.u8[0], 0x12);
|
||||
EXPECT_EQ(bg7.u8[1], 0x34);
|
||||
EXPECT_EQ(lt7.u8[0], 0x12);
|
||||
EXPECT_EQ(lt7.u8[1], 0x34);
|
||||
|
||||
// Compile error (static_assert)
|
||||
// bg7 = std::make_pair<float, double>( 1.2f, 3.4 );
|
||||
|
||||
// Cast
|
||||
EXPECT_FALSE((bool)bg0);
|
||||
EXPECT_FALSE((bool)lt0);
|
||||
EXPECT_TRUE((bool)bg1);
|
||||
EXPECT_TRUE((bool)lt1);
|
||||
|
||||
EXPECT_EQ((uint16_t)bg0, 00U);
|
||||
EXPECT_EQ((uint16_t)lt0, 00U);
|
||||
EXPECT_EQ((uint16_t)bg1, 0x1234);
|
||||
EXPECT_EQ((uint16_t)lt1, 0x1234);
|
||||
|
||||
EXPECT_EQ(*(const uint8_t*)bg0, 0U);
|
||||
EXPECT_EQ(*(const uint8_t*)lt0, 0U);
|
||||
EXPECT_EQ(*(const uint8_t*)bg1, 0x12U);
|
||||
EXPECT_EQ(*(const uint8_t*)lt1, 0x34U);
|
||||
|
||||
// set() is using in operator=
|
||||
// get() is using in cast to uint16
|
||||
// data() is using in cast to const uint8_t*
|
||||
}
|
||||
|
||||
TEST(Utility, Types_U16_Compare)
|
||||
{
|
||||
big_uint16_t bg0{0x1234};
|
||||
little_uint16_t lt0{0x1234};
|
||||
|
||||
EXPECT_EQ(bg0, lt0);
|
||||
EXPECT_GE(bg0, lt0);
|
||||
EXPECT_LE(bg0, lt0);
|
||||
EXPECT_FALSE(bg0 < lt0);
|
||||
EXPECT_FALSE(bg0 > lt0);
|
||||
|
||||
{
|
||||
big_uint16_t bg1{0x1235};
|
||||
little_uint16_t lt1{0x1235};
|
||||
|
||||
EXPECT_NE(bg0, bg1);
|
||||
EXPECT_NE(bg0, lt1);
|
||||
EXPECT_LT(bg0, bg1);
|
||||
EXPECT_LT(bg0, lt1);
|
||||
EXPECT_LE(bg0, bg1);
|
||||
EXPECT_LE(bg0, lt1);
|
||||
EXPECT_GE(bg1, bg0);
|
||||
EXPECT_GE(lt1, bg0);
|
||||
EXPECT_GT(bg1, bg0);
|
||||
EXPECT_GT(lt1, bg0);
|
||||
|
||||
EXPECT_NE(lt0, bg1);
|
||||
EXPECT_NE(lt0, lt1);
|
||||
EXPECT_LT(lt0, bg1);
|
||||
EXPECT_LT(lt0, lt1);
|
||||
EXPECT_LE(lt0, bg1);
|
||||
EXPECT_LE(lt0, lt1);
|
||||
EXPECT_GE(bg1, lt0);
|
||||
EXPECT_GE(lt1, lt0);
|
||||
EXPECT_GT(bg1, lt0);
|
||||
EXPECT_GT(lt1, lt0);
|
||||
}
|
||||
|
||||
{
|
||||
big_uint16_t bg1{0x1334};
|
||||
little_uint16_t lt1{0x1334};
|
||||
|
||||
EXPECT_NE(bg0, bg1);
|
||||
EXPECT_NE(bg0, lt1);
|
||||
EXPECT_LT(bg0, bg1);
|
||||
EXPECT_LT(bg0, lt1);
|
||||
EXPECT_LE(bg0, bg1);
|
||||
EXPECT_LE(bg0, lt1);
|
||||
EXPECT_GE(bg1, bg0);
|
||||
EXPECT_GE(lt1, bg0);
|
||||
EXPECT_GT(bg1, bg0);
|
||||
EXPECT_GT(lt1, bg0);
|
||||
|
||||
EXPECT_NE(lt0, bg1);
|
||||
EXPECT_NE(lt0, lt1);
|
||||
EXPECT_LT(lt0, bg1);
|
||||
EXPECT_LT(lt0, lt1);
|
||||
EXPECT_LE(lt0, bg1);
|
||||
EXPECT_LE(lt0, lt1);
|
||||
EXPECT_GE(bg1, lt0);
|
||||
EXPECT_GE(lt1, lt0);
|
||||
EXPECT_GT(bg1, lt0);
|
||||
EXPECT_GT(lt1, lt0);
|
||||
}
|
||||
}
|
||||
333
libraries/M5Utility/test/utility_test.cpp
Normal file
333
libraries/M5Utility/test/utility_test.cpp
Normal file
|
|
@ -0,0 +1,333 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
/*
|
||||
UnitTest for M5Utility
|
||||
*/
|
||||
#include <gtest/gtest.h>
|
||||
#include <M5Utility.hpp>
|
||||
#include <random>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
using namespace m5::utility::log;
|
||||
|
||||
namespace {
|
||||
using pf_t = std::pair<const char* /* full path */, const char* /* filename */>;
|
||||
|
||||
pf_t table[] = {
|
||||
{"", ""}, {nullptr, ""},
|
||||
{"aaa", "aaa"}, {"ソソソソ", "ソソソソ"},
|
||||
{"a/b.c", "b.c"}, {"c:/aaa/bbb/ccc/ddd.eee", "ddd.eee"},
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(Utility, pathToFilename)
|
||||
{
|
||||
{
|
||||
constexpr auto fn0 = pathToFilename("");
|
||||
EXPECT_STREQ(fn0, "");
|
||||
constexpr auto fn1 = pathToFilename("ABC");
|
||||
EXPECT_STREQ(fn1, "ABC");
|
||||
constexpr auto fn2 = pathToFilename("a:/bb/ccc/dddd/eee.f");
|
||||
EXPECT_STREQ(fn2, "eee.f");
|
||||
}
|
||||
|
||||
for (auto&& e : table) {
|
||||
EXPECT_STREQ(pathToFilename(e.first), e.second) << e.first;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
TEST(Utility, log) {
|
||||
M5_LIB_LOGE("Error");
|
||||
M5_LIB_LOGW("Warn");
|
||||
M5_LIB_LOGI("Info");
|
||||
M5_LIB_LOGD("Debug");
|
||||
M5_LIB_LOGV("Verbose");
|
||||
|
||||
constexpr uint8_t test[] = {
|
||||
0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23,
|
||||
0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67,
|
||||
0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB,
|
||||
0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
|
||||
};
|
||||
M5_DUMPE(test + 0, sizeof(test) - 0);
|
||||
M5_DUMPE(test + 1, sizeof(test) - 1);
|
||||
M5_DUMPE(test + 7, sizeof(test) - 07;
|
||||
M5_DUMPE(test + 11, sizeof(test) - 11);
|
||||
M5_DUMPE(test + 19, sizeof(test) - 19);
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
auto rng = std::default_random_engine{};
|
||||
}
|
||||
|
||||
TEST(Utility, BitSegment)
|
||||
{
|
||||
// static_assert
|
||||
#if 0
|
||||
{
|
||||
m5::utility::BitSegment<11, int8_t> compile_error1; // 11 > 8
|
||||
m5::utility::BitSegment<0, int8_t> copile_error2; // 0
|
||||
}
|
||||
#endif
|
||||
|
||||
// Constructor/Assignemt
|
||||
{
|
||||
using bs_t = m5::utility::BitSegment<6, uint8_t>;
|
||||
bs_t v0{0x84}; // base_type constructor
|
||||
bs_t v1 = v0; // same type constructor
|
||||
|
||||
EXPECT_EQ(v0.raw(), 0x84);
|
||||
EXPECT_EQ(v0.upper(), v1.upper());
|
||||
EXPECT_EQ(v0.lower(), v1.lower());
|
||||
EXPECT_EQ(v0.raw(), v1.raw());
|
||||
|
||||
bs_t v2, v3;
|
||||
EXPECT_EQ(v2.raw(), 0);
|
||||
EXPECT_EQ(v2.raw(), v3.raw());
|
||||
|
||||
v2 = -1; // base_type assignment
|
||||
EXPECT_NE(v2.raw(), v3.raw());
|
||||
|
||||
v3 = v2; // same type assignment
|
||||
EXPECT_EQ(v2.raw(), v3.raw());
|
||||
|
||||
bs_t v4 = 0xC0; // base_type constructor
|
||||
EXPECT_EQ(v4.raw(), 0xC0);
|
||||
}
|
||||
|
||||
// Getter/Setter using signed
|
||||
{
|
||||
using bs1_t = m5::utility::BitSegment<12, int16_t>;
|
||||
|
||||
auto t = std::is_same<int16_t, bs1_t::base_type>::value;
|
||||
EXPECT_TRUE(t);
|
||||
t = std::is_same<uint16_t, bs1_t::unsigned_type>::value;
|
||||
EXPECT_TRUE(t);
|
||||
|
||||
EXPECT_TRUE(bs1_t::SIGNED);
|
||||
EXPECT_EQ(+bs1_t::UPPER_BITS, 3);
|
||||
EXPECT_EQ(+bs1_t::LOWER_BITS, 12);
|
||||
EXPECT_EQ(+bs1_t::UPPER_SHIFT, 12);
|
||||
EXPECT_EQ(+bs1_t::UPPER_MASK, 0x07);
|
||||
EXPECT_EQ(+bs1_t::LOWER_MASK, 0xFFF);
|
||||
|
||||
bs1_t value0;
|
||||
EXPECT_EQ(value0.upper(), 0U);
|
||||
EXPECT_EQ(value0.lower(), 0U);
|
||||
EXPECT_EQ(value0.raw(), 0);
|
||||
|
||||
value0.lower(123);
|
||||
EXPECT_EQ(value0.upper(), 0U);
|
||||
EXPECT_EQ(value0.lower(), 123U);
|
||||
EXPECT_EQ(value0.raw(), 123);
|
||||
|
||||
value0.lower(0x7FFF);
|
||||
EXPECT_EQ(value0.upper(), 0U);
|
||||
EXPECT_EQ(value0.lower(), 0x0FFFU);
|
||||
EXPECT_EQ(value0.raw(), 0x0FFF);
|
||||
|
||||
value0.upper(5);
|
||||
EXPECT_EQ(value0.upper(), 5U);
|
||||
EXPECT_EQ(value0.lower(), 0xFFFU);
|
||||
EXPECT_EQ(value0.raw(), 0x5FFF);
|
||||
|
||||
value0.upper(0xFF);
|
||||
EXPECT_EQ(value0.upper(), 0x0007U);
|
||||
EXPECT_EQ(value0.lower(), 0x0FFFU);
|
||||
EXPECT_EQ(value0.raw(), 0x7FFF);
|
||||
|
||||
value0.raw(-1);
|
||||
EXPECT_EQ(value0.upper(), 0x0007U);
|
||||
EXPECT_EQ(value0.lower(), 0x0FFFU);
|
||||
EXPECT_EQ(value0.raw(), -1);
|
||||
|
||||
// Keep signed bit
|
||||
value0.lower(234);
|
||||
EXPECT_EQ(value0.upper(), 0x0007U);
|
||||
EXPECT_EQ(value0.lower(), 234U);
|
||||
EXPECT_EQ(value0.raw(), -3862); // 0xF0EA
|
||||
}
|
||||
|
||||
// Getter/Setter using unsigned
|
||||
{
|
||||
using bs2_t = m5::utility::BitSegment<12, const uint32_t&>;
|
||||
auto t = std::is_same<uint32_t, bs2_t::base_type>::value;
|
||||
EXPECT_TRUE(t);
|
||||
t = std::is_same<uint32_t, bs2_t::unsigned_type>::value;
|
||||
EXPECT_TRUE(t);
|
||||
|
||||
EXPECT_FALSE(bs2_t::SIGNED);
|
||||
EXPECT_EQ(+bs2_t::UPPER_BITS, 20U);
|
||||
EXPECT_EQ(+bs2_t::LOWER_BITS, 12U);
|
||||
EXPECT_EQ(+bs2_t::UPPER_SHIFT, 12U);
|
||||
EXPECT_EQ(+bs2_t::UPPER_MASK, 0xFFFFFU);
|
||||
EXPECT_EQ(+bs2_t::LOWER_MASK, 0xFFFU);
|
||||
|
||||
bs2_t value0;
|
||||
EXPECT_EQ(value0.upper(), 0U);
|
||||
EXPECT_EQ(value0.lower(), 0U);
|
||||
EXPECT_EQ(value0.raw(), 0U);
|
||||
|
||||
value0.lower(123);
|
||||
EXPECT_EQ(value0.upper(), 0U);
|
||||
EXPECT_EQ(value0.lower(), 123U);
|
||||
EXPECT_EQ(value0.raw(), 123U);
|
||||
|
||||
value0.lower(0x00003FFF);
|
||||
EXPECT_EQ(value0.upper(), 0U);
|
||||
EXPECT_EQ(value0.lower(), 0x00000FFFU);
|
||||
EXPECT_EQ(value0.raw(), 0x00000FFFU);
|
||||
|
||||
value0.upper(5);
|
||||
EXPECT_EQ(value0.upper(), 5U);
|
||||
EXPECT_EQ(value0.lower(), 0x00000FFFU);
|
||||
EXPECT_EQ(value0.raw(), 0x00005FFFU);
|
||||
|
||||
value0.upper(0x84218421);
|
||||
EXPECT_EQ(value0.upper(), 0x00018421U);
|
||||
EXPECT_EQ(value0.lower(), 0x00000FFFU);
|
||||
EXPECT_EQ(value0.raw(), 0x18421FFFU);
|
||||
|
||||
value0.raw(-1);
|
||||
EXPECT_EQ(value0.upper(), 0x000FFFFFU);
|
||||
EXPECT_EQ(value0.lower(), 0x00000FFFU);
|
||||
EXPECT_EQ(value0.raw(), 0xFFFFFFFFU);
|
||||
|
||||
// Not include signed bit
|
||||
value0.lower(234);
|
||||
EXPECT_EQ(value0.upper(), 0x000FFFFFU);
|
||||
EXPECT_EQ(value0.lower(), 234U);
|
||||
EXPECT_EQ(value0.raw(), 4294963434U); // 0xFFFFF0EA
|
||||
}
|
||||
|
||||
// Compare
|
||||
{
|
||||
using bs_t = m5::utility::BitSegment<14, int64_t>;
|
||||
|
||||
bs_t v0, v1;
|
||||
EXPECT_TRUE(v0 == v1);
|
||||
EXPECT_FALSE(v0 != v1);
|
||||
EXPECT_FALSE(v0 < v1);
|
||||
EXPECT_FALSE(v0 > v1);
|
||||
EXPECT_TRUE(v0 <= v1);
|
||||
EXPECT_TRUE(v0 >= v1);
|
||||
|
||||
EXPECT_TRUE(v0 == 0);
|
||||
EXPECT_FALSE(v0 != 0);
|
||||
EXPECT_FALSE(v0 < 0);
|
||||
EXPECT_FALSE(v0 > 0);
|
||||
EXPECT_TRUE(v0 <= 0);
|
||||
EXPECT_TRUE(v0 >= 0);
|
||||
|
||||
EXPECT_TRUE(0 == v0);
|
||||
EXPECT_FALSE(0 != v0);
|
||||
EXPECT_FALSE(0 < v0);
|
||||
EXPECT_FALSE(0 > v0);
|
||||
EXPECT_TRUE(0 <= v0);
|
||||
|
||||
v1.lower(123);
|
||||
EXPECT_FALSE(v0 == v1);
|
||||
EXPECT_TRUE(v0 != v1);
|
||||
EXPECT_TRUE(v0 < v1);
|
||||
EXPECT_FALSE(v0 > v1);
|
||||
EXPECT_TRUE(v0 <= v1);
|
||||
EXPECT_FALSE(v0 >= v1);
|
||||
|
||||
v0.lower(987);
|
||||
EXPECT_FALSE(v0 == v1);
|
||||
EXPECT_TRUE(v0 != v1);
|
||||
EXPECT_FALSE(v0 < v1);
|
||||
EXPECT_TRUE(v0 > v1);
|
||||
EXPECT_FALSE(v0 <= v1);
|
||||
EXPECT_TRUE(v0 >= v1);
|
||||
|
||||
v0 = v1;
|
||||
v1.upper(654321);
|
||||
EXPECT_FALSE(v0 == v1);
|
||||
EXPECT_TRUE(v0 != v1);
|
||||
EXPECT_TRUE(v0 < v1);
|
||||
EXPECT_FALSE(v0 > v1);
|
||||
EXPECT_TRUE(v0 <= v1);
|
||||
EXPECT_FALSE(v0 >= v1);
|
||||
|
||||
v0.upper(99999999);
|
||||
EXPECT_FALSE(v0 == v1);
|
||||
EXPECT_TRUE(v0 != v1);
|
||||
EXPECT_FALSE(v0 < v1);
|
||||
EXPECT_TRUE(v0 > v1);
|
||||
EXPECT_FALSE(v0 <= v1);
|
||||
EXPECT_TRUE(v0 >= v1);
|
||||
|
||||
v0 = v1 = 0;
|
||||
|
||||
v0 = -123;
|
||||
v1 = -12;
|
||||
EXPECT_FALSE(v0 == v1);
|
||||
EXPECT_TRUE(v0 != v1);
|
||||
EXPECT_TRUE(v0 < v1);
|
||||
EXPECT_FALSE(v0 > v1);
|
||||
EXPECT_TRUE(v0 <= v1);
|
||||
EXPECT_FALSE(v0 >= v1);
|
||||
|
||||
v1 = -876543;
|
||||
EXPECT_FALSE(v0 == v1);
|
||||
EXPECT_TRUE(v0 != v1);
|
||||
EXPECT_FALSE(v0 < v1);
|
||||
EXPECT_TRUE(v0 > v1);
|
||||
EXPECT_FALSE(v0 <= v1);
|
||||
EXPECT_TRUE(v0 >= v1);
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
using clock = std::chrono::high_resolution_clock;
|
||||
}
|
||||
|
||||
TEST(Utility, comatibility)
|
||||
{
|
||||
// millis
|
||||
{
|
||||
auto ms = m5::utility::millis();
|
||||
auto ams = clock::now() + std::chrono::milliseconds(1);
|
||||
std::this_thread::sleep_until(ams);
|
||||
EXPECT_GT(m5::utility::millis(), ms);
|
||||
}
|
||||
// micros
|
||||
{
|
||||
auto us = m5::utility::micros();
|
||||
auto aus = clock::now() + std::chrono::microseconds(1);
|
||||
std::this_thread::sleep_until(aus);
|
||||
EXPECT_GT(m5::utility::micros(), us);
|
||||
}
|
||||
|
||||
// delay
|
||||
{
|
||||
constexpr unsigned long wait{20};
|
||||
auto start = clock::now();
|
||||
m5::utility::delay(wait);
|
||||
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(clock::now() - start).count();
|
||||
auto elapsed2 = std::chrono::duration_cast<std::chrono::microseconds>(clock::now() - start).count();
|
||||
// printf("-----> %lld %lld\n", elapsed, elapsed2);
|
||||
#if defined(ARDUINO)
|
||||
EXPECT_GE(elapsed,
|
||||
wait - 1); // Arduino delay may return before the specified time.
|
||||
#else
|
||||
EXPECT_GE(elapsed, wait);
|
||||
#endif
|
||||
}
|
||||
|
||||
// delayMicroseconds
|
||||
{
|
||||
auto start = clock::now();
|
||||
m5::utility::delayMicroseconds(1);
|
||||
auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(clock::now() - start).count();
|
||||
EXPECT_GE(elapsed, 1);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue