Browse Source

add .clang-format / reformat

If you dont like reformatting
of complete codebases, the solution is to USE this.
master
heck 3 years ago
parent
commit
eaa77767a7
  1. 45
      .clang-format
  2. 23
      src/bloblist.cc
  3. 114
      src/bloblist.hh
  4. 36
      src/crlf.cc
  5. 3
      src/crlf.hh
  6. 48
      src/identity.cc
  7. 42
      src/stringlist.cc
  8. 87
      src/types.cc
  9. 14
      src/types.hh
  10. 404
      src/wrapper.hh
  11. 32
      test/unittest_identity.cc
  12. 239
      test/unittest_message.cc
  13. 134
      test/unittest_nfc.cc
  14. 106
      test/unittest_nfc16.cc
  15. 101
      test/unittest_nfcstring.cc
  16. 64
      test/unittest_stringlist.cc
  17. 60
      test/unittest_stringpair.cc

45
.clang-format

@ -0,0 +1,45 @@
BasedOnStyle: LLVM
Language: Cpp
Standard: c++17
DerivePointerAlignment: true
SortIncludes: Never
ReflowComments: false
PointerAlignment: Left
AlignAfterOpenBracket: AlwaysBreak
AlignOperands: AlignAfterOperator
BreakConstructorInitializers: AfterColon
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortEnumsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: false
BinPackParameters: false
ExperimentalAutoDetectBinPacking: true
BreakBeforeBraces: Custom
BraceWrapping:
AfterFunction: true
ColumnLimit: 100
AllowAllConstructorInitializersOnNextLine: false
#BreakConstructorInitializersBeforeComma: true
ConstructorInitializerAllOnOneLineOrOnePerLine: true
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
PenaltyBreakBeforeFirstCallParameter: 0
PenaltyReturnTypeOnItsOwnLine: 1000000
PenaltyBreakAssignment: 1000000
PenaltyExcessCharacter: 10
IndentCaseLabels: true
IndentWidth: 4
MaxEmptyLinesToKeep: 2
NamespaceIndentation: All
SpaceAfterTemplateKeyword: false
AccessModifierOffset: -4
AllowShortBlocksOnASingleLine: Always
IndentPPDirectives: BeforeHash
IndentExternBlock: Indent
Cpp11BracedListStyle: false
BreakStringLiterals: false

23
src/bloblist.cc

@ -2,44 +2,43 @@
#include <pEp/bloblist.h>
namespace pEp
{
namespace pEp {
template<>
void Wrapper<::bloblist_t*>::_free(::bloblist_t* bl)
{
::free_bloblist(bl);
}
// template<>
// template<>
int BlobList::size() const
{
return bloblist_length(value);
}
// faster than .size()==0 because it's not necessary to iterate throgh the whole list
// template<>
// template<>
bool BlobList::empty() const
{
return !(value && value->value);
}
// template<>
// template<>
void BlobList::clear()
{
free_bloblist(value);
value = nullptr;
}
// template<>
// template<>
void BlobList::push_back(Blob&& s)
{
// TODO
}
////////////////
////////////////
// no explicit instantiation noecessary, because of fully specialized class template. Okay. :-D
// template class ListWrapper<::bloblist_t*, void>;
// no explicit instantiation noecessary, because of fully specialized class template. Okay. :-D
// template class ListWrapper<::bloblist_t*, void>;
} // end of namespace pEp

114
src/bloblist.hh

@ -7,55 +7,79 @@
#include "wrapper.hh"
#include <pEp/bloblist.h>
namespace pEp
{
namespace pEp {
template<>
class ListWrapper<::bloblist_t*, void> : public Wrapper<::bloblist_t*>
{
public:
typedef ::bloblist_t Blob;
typedef Wrapper<Blob*> Base;
typedef ListWrapper<Blob*, void> LW;
// does not own the *value
class iterator
{
template<>
class ListWrapper<::bloblist_t*, void> : public Wrapper<::bloblist_t*> {
public:
iterator() = default;
iterator operator++() { return (value ? value = value->next : value); }
Blob& operator*() { return *value; }
Blob* operator->() { return value; }
const Blob& operator*() const { return *value; }
const Blob* operator->() const { return value; }
bool operator==(const iterator& other) const { return value == other.value; }
bool operator!=(const iterator& other) const { return value != other.value; }
private:
iterator(::bloblist_t* _t) : value{_t} {}
::bloblist_t* value = nullptr;
friend class ListWrapper<::bloblist_t*, void>;
typedef ::bloblist_t Blob;
typedef Wrapper<Blob*> Base;
typedef ListWrapper<Blob*, void> LW;
// does not own the *value
class iterator {
public:
iterator() = default;
iterator operator++()
{
return (value ? value = value->next : value);
}
Blob& operator*()
{
return *value;
}
Blob* operator->()
{
return value;
}
const Blob& operator*() const
{
return *value;
}
const Blob* operator->() const
{
return value;
}
bool operator==(const iterator& other) const
{
return value == other.value;
}
bool operator!=(const iterator& other) const
{
return value != other.value;
}
private:
iterator(::bloblist_t* _t) : value{ _t } {}
::bloblist_t* value = nullptr;
friend class ListWrapper<::bloblist_t*, void>;
};
using Base::value;
ListWrapper() : Base() {}
iterator begin()
{
return iterator{ value };
}
iterator end() const
{
return iterator{};
}
int size() const;
bool empty() const;
void clear();
void push_back(Blob&&);
void emplace_back(char* data, size_t size, const char* mime_type, const char* filename);
};
using Base::value;
ListWrapper() : Base() {}
iterator begin() { return iterator{value}; }
iterator end() const { return iterator{}; }
int size() const;
bool empty() const;
void clear();
void push_back(Blob&&);
void emplace_back(char* data, size_t size, const char* mime_type, const char* filename);
};
using BlobList = ListWrapper<::bloblist_t*, void>;
using BlobList = ListWrapper<::bloblist_t*, void>;
} // end of namespace pEp

36
src/crlf.cc

@ -1,26 +1,24 @@
#include "crlf.hh"
namespace pEp
{
namespace pEp {
std::string operator""_CRLF(const char* str, size_t length)
{
static const std::string CRLF{"\r\n"};
std::string ret;
ret.reserve(length + ((length+29)/30) + 2 ); // rough guess for average line length of 30.
const char* end = str + length;
// N.B.: Loop could be more optimized, but not necessary because it is only used for string literals.
for(; str != end; ++str)
std::string operator""_CRLF(const char* str, size_t length)
{
if(*str == '\n')
ret += CRLF;
else
ret += *str;
static const std::string CRLF{ "\r\n" };
std::string ret;
ret.reserve(length + ((length + 29) / 30) + 2); // rough guess for average line length of 30.
const char* end = str + length;
// N.B.: Loop could be more optimized, but not necessary because it is only used for string literals.
for (; str != end; ++str) {
if (*str == '\n')
ret += CRLF;
else
ret += *str;
}
return ret;
}
return ret;
}
} // end of namespace pEp

3
src/crlf.hh

@ -6,8 +6,7 @@
#include <string>
namespace pEp
{
namespace pEp {
// creates a string where \n ("linefeed" a.k.a. LF) are replaced
// by \r\n ("carriage return + linefeed" a.k.a. CRLF).
// Useful to define strings in NET-ASCII or Net-Unicode (RFC5198) format

48
src/identity.cc

@ -4,15 +4,14 @@
#include <string>
namespace pEp
{
namespace pEp {
template<>
template<>
::pEp_identity* Wrapper<::pEp_identity*>::_new<const char*, const char*, const char*, const char*>
(
const char *address, const char *fpr, const char *user_id,
const char *username
)
::pEp_identity* Wrapper<::pEp_identity*>::_new<const char*, const char*, const char*, const char*>(
const char* address,
const char* fpr,
const char* user_id,
const char* username)
{
return ::new_identity(address, fpr, user_id, username);
}
@ -22,14 +21,14 @@ namespace pEp
{
::free_identity(id);
}
template<>
::pEp_identity* Wrapper<::pEp_identity*>::copy_out() const
{
return identity_dup(value);
}
//////////////
//////////////
template<>
void Wrapper<::identity_list*>::_free(::identity_list* sl)
@ -44,8 +43,8 @@ namespace pEp
}
template<>
::pEp_identity* identity_list::* const ListWrapper<::identity_list*, ::pEp_identity*>::Value
= &identity_list::ident;
::pEp_identity* identity_list::*const
ListWrapper<::identity_list*, ::pEp_identity*>::Value = &identity_list::ident;
template<>
int IdentityList::size() const
@ -59,41 +58,40 @@ namespace pEp
{
return !(value && value->ident);
}
template<>
void IdentityList::clear()
{
free_identity_list(value);
value = nullptr;
}
template<>
void IdentityList::push_back(pEp_identity*&& id)
{
auto last = identity_list_add(value, id);
if(value==nullptr)
if (value == nullptr)
value = last;
}
template<>
ListWrapper<::identity_list*, pEp_identity*>::ListWrapper(const std::initializer_list<Wrapper<pEp_identity*>>& il)
: Base{}
ListWrapper<::identity_list*, pEp_identity*>::ListWrapper(
const std::initializer_list<Wrapper<pEp_identity*>>& il) :
Base{}
{
::identity_list* last = nullptr;
for(const Wrapper<pEp_identity*>& id : il)
{
::identity_list* last = nullptr;
for (const Wrapper<pEp_identity*>& id : il) {
last = identity_list_add(last, identity_dup(id.get()));
if(last==nullptr)
{
if (last == nullptr) {
throw std::runtime_error("Cannot create StringPairList from {}: Out Of Memory.");
}
if(value==nullptr)
if (value == nullptr)
value = last; // save the head of linked list.
}
}
////////////////
////////////////
template class ListWrapper<::identity_list*, ::pEp_identity*>;

42
src/stringlist.cc

@ -5,17 +5,16 @@
#include <string>
namespace pEp
{
namespace pEp {
template<>
void Wrapper<::stringlist_t*>::_free(::stringlist_t* sl)
{
::free_stringlist(sl);
}
template<>
const char* stringlist_t::* const ListWrapper<stringlist_t*, const char*>::Value
= const_cast<const char* stringlist_t::*>(&stringlist_t::value);
const char* stringlist_t::*const ListWrapper<stringlist_t*, const char*>::Value =
const_cast<const char * stringlist_t::*>(&stringlist_t::value);
template<>
int StringList::size() const
@ -29,50 +28,47 @@ namespace pEp
{
return !(value && value->value);
}
template<>
void StringList::erase( const StringList::iterator& it)
void StringList::erase(const StringList::iterator& it)
{
if(it.value && it.value->value)
{
if (it.value && it.value->value) {
value = stringlist_delete(value, it.value->value);
}
}
template<>
void StringList::clear()
{
free_stringlist(value);
value = nullptr;
}
template<>
void StringList::push_back(const char*&& s)
{
auto last = stringlist_add(value, s);
if(value==nullptr)
if (value == nullptr)
value = last;
}
template<>
ListWrapper<::stringlist_t*, const char*>::ListWrapper(const std::initializer_list<const char*>& il)
: StringList{}
ListWrapper<::stringlist_t*, const char*>::ListWrapper(const std::initializer_list<const char*>& il) :
StringList{}
{
::stringlist_t* last = nullptr;
for(const char* s : il)
{
::stringlist_t* last = nullptr;
for (const char* s : il) {
last = stringlist_add(last, s);
if(last==nullptr)
{
if (last == nullptr) {
throw std::runtime_error("Cannot create StringPairList from {}: Out Of Memory.");
}
if(value==nullptr)
if (value == nullptr)
value = last; // save the head of linked list.
}
}
////////////////
////////////////
template class ListWrapper<::stringlist_t*, const char*>;

87
src/types.cc

@ -13,31 +13,31 @@
#include <string>
#include <cstring>
namespace pEp
{
EngineError::EngineError(PEP_STATUS status, const char* message)
: std::runtime_error(
std::string{"EngineError: "}
+ (message ? '"' + std::string{message} + "\" " : std::string{} )
+ status_to_string(status)
)
{}
namespace pEp {
EngineError::EngineError(PEP_STATUS status, const char* message) :
std::runtime_error(
std::string{ "EngineError: " } +
(message ? '"' + std::string{ message } + "\" " : std::string{}) +
status_to_string(status))
{
}
////////////////
////////////////
template<>
template<>
message* Wrapper<::message*>::_new<PEP_msg_direction, const char*>(PEP_msg_direction dir, const char* src)
message* Wrapper<::message*>::_new<PEP_msg_direction, const char*>(
PEP_msg_direction dir,
const char* src)
{
message* m = nullptr;
bool pep_msg = false;
PEP_STATUS status = mime_decode_message(src, strlen(src), &m, &pep_msg);
if(status != PEP_STATUS_OK)
{
if (status != PEP_STATUS_OK) {
throw EngineError(status, "mime_decode_message()");
}
m->dir = dir;
return m;
}
@ -54,30 +54,28 @@ namespace pEp
return ::message_dup(value);
}
////////////////
////////////////
template<>
template<>
::stringpair_t* Wrapper<::stringpair_t*>::_new(const char* key, const char* value)
{
stringpair_t* sp = new_stringpair(key, value);
if(!sp)
{
if (!sp) {
throw EngineError(PEP_OUT_OF_MEMORY, "new_stringpair()");
}
return sp;
}
template<>
template<>
::stringpair_t* Wrapper<::stringpair_t*>::_new(char* key, char* value)
{
return _new<const char*, const char*>(
const_cast<const char*>(key),
const_cast<const char*>(value)
);
const_cast<const char*>(key),
const_cast<const char*>(value));
}
template<>
template<>
::stringpair_t* Wrapper<::stringpair_t*>::_new(const std::string& key, const std::string& value)
@ -102,9 +100,10 @@ namespace pEp
{
free_stringpair_list(spl);
}
template<>
stringpair_t* stringpair_list_t::* const ListWrapper<stringpair_list_t*, stringpair_t*>::Value = &stringpair_list_t::value;
stringpair_t* stringpair_list_t::*const
ListWrapper<stringpair_list_t*, stringpair_t*>::Value = &stringpair_list_t::value;
template<>
int StringPairList::size() const
@ -118,59 +117,57 @@ namespace pEp
{
return !(value && value->value);
}
template<>
void StringPairList::erase( const StringPairList::iterator& it)
void StringPairList::erase(const StringPairList::iterator& it)
{
if(it.value && it.value->value && it.value->value->key)
{
if (it.value && it.value->value && it.value->value->key) {
value = stringpair_list_delete_by_key(value, it.value->value->key);
}
}
template<>
void StringPairList::clear()
{
free_stringpair_list(value);
value = nullptr;
}
template<>
void StringPairList::push_back(::stringpair_t*&& sp)
{
auto last = stringpair_list_add(value, sp);
if(value==nullptr)
if (value == nullptr)
value = last;
sp = nullptr;
}
template<>
void StringPairList::push_back(StringPair&& sp)
{
auto last = stringpair_list_add(value, sp.move_out());
if(value==nullptr)
if (value == nullptr)
value = last;
}
template<>
ListWrapper<::stringpair_list_t*, stringpair_t*>::ListWrapper(const std::initializer_list<StringPair>& il)
: StringPairList{}
ListWrapper<::stringpair_list_t*, stringpair_t*>::ListWrapper(
const std::initializer_list<StringPair>& il) :
StringPairList{}
{
::stringpair_list_t* last = nullptr;
for(const StringPair& sp : il)
{
::stringpair_list_t* last = nullptr;
for (const StringPair& sp : il) {
last = stringpair_list_add(last, stringpair_dup(sp.get()));
if(last==nullptr)
{
if (last == nullptr) {
throw std::runtime_error("Cannot create StringPairList from {}: Out Of Memory.");
}
if(value==nullptr)
if (value == nullptr)
value = last; // save the head of linked list.
}
}
////////////////
////////////////
template class Wrapper<::pEp_identity*>;
template class Wrapper<::stringpair_t*>;

14
src/types.hh

@ -12,23 +12,21 @@
#include <pEp/stringpair.h>
#include <pEp/message.h>
namespace pEp
{
class EngineError : std::runtime_error
{
namespace pEp {
class EngineError : std::runtime_error {
public:
EngineError(PEP_STATUS status, const char* message = nullptr);
};
using Identity = Wrapper<::pEp_identity*>;
using IdentityList = ListWrapper<::identity_list*, ::pEp_identity*>;
using StringPair = Wrapper<::stringpair_t*>;
using StringPairList = ListWrapper<::stringpair_list_t*, ::stringpair_t*>;
using StringList = ListWrapper<::stringlist_t*, const char*>;
using BlobList = ListWrapper<::bloblist_t*, void>;
using BlobList = ListWrapper<::bloblist_t*, void>;
using Message = Wrapper<::message*>;
} // end of namespace pEp

404
src/wrapper.hh

@ -7,193 +7,231 @@
#include <initializer_list>
#include <iterator>
namespace pEp
{
/// A generalized wrapper around pEpEngine's datatypes.
template<class T>
class Wrapper
{
public:
typedef T c_type;
template<class... Args>
Wrapper(Args... args) : value{ this->_new(args...) } {}
// no implicit copying... (yet?)
Wrapper(const Wrapper<T>&) = delete;
void operator=(const Wrapper<T>&) = delete;
// must be implemented separately for each T
Wrapper(Wrapper<T>&& victim);
Wrapper<T>& operator=(Wrapper<T>&& victim);
~Wrapper();
Wrapper<T> copy() const;
bool operator==(const Wrapper<T>& b) const
{
return value==b.value;
}
bool operator!=(const Wrapper<T>& b) const
{
return value!=b.value;
}
private:
// must be defined for each wrapped type:
template<class... Args>
T _new(Args...);
T value;
};
// many wrapped datatypes are pointers, we can generalize a lot for them:
template<class T>
class Wrapper<T*>
{
public:
typedef T* c_type;
Wrapper() : value{nullptr} {}
template<class... Args>
Wrapper(Args... args) : value{ this->_new(args...) } {}
// move is easy, efficient and generic:
Wrapper(Wrapper<T*>&& victim) noexcept
: value{ victim.value}
{
victim.value = nullptr;
}
Wrapper<T*>& operator=(Wrapper<T*>&& victim) noexcept
{
_free(value);
value = victim.value;
victim.value = nullptr;
return *this;
}
Wrapper(const Wrapper<T*>& orig)
: value{ orig.copy_out() }
{}
Wrapper<T*>& operator=(const Wrapper<T*>& orig)
{
if(&orig == this) return *this;
_free(value);
value = orig.copy_out();
return *this;
}
~Wrapper()
{
_free(value);
}
bool operator==(const Wrapper<T*>& b) const
{
return value==b.value;
}
bool operator!=(const Wrapper<T*>& b) const
{
return value!=b.value;
}
// Get read-only access to the value itself
// Beware: 'const' is not transitive in C, so the 2nd indirect data
// allows r/w access!
const T* operator->() const { return value; }
const T* get() const { return value; }
// Dangerous: Get R/W access to the value!
T* operator->() { return value; }
T* get() { return value;}
// Releases ownership of the value. Wrapper becomes valueless.
T* move_out() { T* r = value; value=nullptr; return r;}
// only implemented for the datatypes where necessay.
// other implementations can follow if necessary.
T* copy_out() const;
protected:
Wrapper(T* _value) : value{_value} {}
// must be defined for each wrapped type:
template<class... Args>
T* _new(Args...);
void _free(T*);
T* value;
};
// Wraps single-linked lists and provides an interface compatible
// to std::forward_list
template<class T, class Element>
class ListWrapper;
template<class T, class Element>
class ListWrapper<T*, Element> : public Wrapper<T*>
{
public:
typedef Wrapper<T*> Base;
typedef ListWrapper<T*, Element> LW;
static Element T::* const Value; // to access the current value
// does not own the *value
class iterator : public std::iterator< std::forward_iterator_tag, Element, ptrdiff_t>
{
namespace pEp {
/// A generalized wrapper around pEpEngine's datatypes.
template<class T>
class Wrapper {
public:
iterator() = default;
iterator operator++() { return (value ? value = value->next : value); }
Element operator*() { return value->*LW::Value; }
Element operator->() { return value->*LW::Value; }
bool operator==(const iterator& other) const { return value == other.value; }
bool operator!=(const iterator& other) const { return value != other.value; }
typedef T c_type;
template<class... Args>
Wrapper(Args... args) : value{ this->_new(args...) }
{
}
// no implicit copying... (yet?)
Wrapper(const Wrapper<T>&) = delete;
void operator=(const Wrapper<T>&) = delete;
// must be implemented separately for each T
Wrapper(Wrapper<T>&& victim);
Wrapper<T>& operator=(Wrapper<T>&& victim);
~Wrapper();
Wrapper<T> copy() const;
bool operator==(const Wrapper<T>& b) const
{
return value == b.value;
}
bool operator!=(const Wrapper<T>& b) const
{
return value != b.value;
}
private:
iterator(T* _t) : value{_t} {}
T* value = nullptr;
friend class ListWrapper<T*, Element>;
// must be defined for each wrapped type:
template<class... Args>
T _new(Args...);
T value;
};
// many wrapped datatypes are pointers, we can generalize a lot for them:
template<class T>
class Wrapper<T*> {
public:
typedef T* c_type;
Wrapper() : value{ nullptr } {}
template<class... Args>
Wrapper(Args... args) : value{ this->_new(args...) }
{
}
// move is easy, efficient and generic:
Wrapper(Wrapper<T*>&& victim) noexcept : value{ victim.value }
{
victim.value = nullptr;
}
Wrapper<T*>& operator=(Wrapper<T*>&& victim) noexcept
{
_free(value);
value = victim.value;
victim.value = nullptr;
return *this;
}
Wrapper(const Wrapper<T*>& orig) : value{ orig.copy_out() } {}
Wrapper<T*>& operator=(const Wrapper<T*>& orig)
{
if (&orig == this)
return *this;
_free(value);
value = orig.copy_out();
return *this;
}
~Wrapper()
{
_free(value);
}
bool operator==(const Wrapper<T*>& b) const
{
return value == b.value;
}
bool operator!=(const Wrapper<T*>& b) const
{
return value != b.value;
}
// Get read-only access to the value itself
// Beware: 'const' is not transitive in C, so the 2nd indirect data
// allows r/w access!
const T* operator->() const
{
return value;
}
const T* get() const
{
return value;
}
// Dangerous: Get R/W access to the value!
T* operator->()
{
return value;
}
T* get()
{
return value;
}
// Releases ownership of the value. Wrapper becomes valueless.
T* move_out()
{
T* r = value;
value = nullptr;
return r;
}
// only implemented for the datatypes where necessay.
// other implementations can follow if necessary.
T* copy_out() const;
protected:
Wrapper(T* _value) : value{ _value } {}
// must be defined for each wrapped type:
template<class... Args>
T* _new(Args...);
void _free(T*);
T* value;
};
// Wraps single-linked lists and provides an interface compatible
// to std::forward_list
template<class T, class Element>
class ListWrapper;
template<class T, class Element>
class ListWrapper<T*, Element> : public Wrapper<T*> {
public:
typedef Wrapper<T*> Base;
typedef ListWrapper<T*, Element> LW;
static Element T::*const Value; // to access the current value
// does not own the *value
class iterator : public std::iterator<std::forward_iterator_tag, Element, ptrdiff_t> {
public:
iterator() = default;
iterator operator++()
{
return (value ? value = value->next : value);
}
Element operator*()
{
return value->*LW::Value;
}
Element operator->()
{
return value->*LW::Value;
}
bool operator==(const iterator& other) const
{
return value == other.value;
}
bool operator!=(const iterator& other) const
{
return value != other.value;
}
private:
iterator(T* _t) : value{ _t } {}
T* value = nullptr;
friend class ListWrapper<T*, Element>;
};
typedef const iterator const_iterator;
using Base::value;
ListWrapper() : Base() {}
ListWrapper(const std::initializer_list<pEp::Wrapper<Element>>& i);
ListWrapper(const std::initializer_list<Element>& i);
iterator begin()
{
return iterator{ value };
}
iterator end() const
{
return iterator{};
}
const_iterator cbegin() const
{
return const_iterator{ value };
}
const_iterator cend() const
{
return const_iterator{};
}
int size() const;
bool empty() const;
void erase(const iterator& it);
void clear();
void push_back(Element&&);
void push_back(Wrapper<Element>&&);
};
typedef const iterator const_iterator;
using Base::value;
ListWrapper() : Base() {}
ListWrapper(const std::initializer_list<pEp::Wrapper<Element>>& i);
ListWrapper(const std::initializer_list<Element>& i);
iterator begin() { return iterator{value}; }
iterator end() const { return iterator{}; }
const_iterator cbegin() const { return const_iterator{value}; }
const_iterator cend() const { return const_iterator{}; }
int size() const;
bool empty() const;
void erase(const iterator& it);
void clear();
void push_back(Element&&);
void push_back(Wrapper<Element>&&);
};
} // end of namespace pEp

32
test/unittest_identity.cc

@ -3,32 +3,38 @@
#include "../src/types.hh"
TEST( PepIdentity, Simple )
TEST(PepIdentity, Simple)
{
pEp::Identity id{"test1@pEpdatatypes.lol", "FF00112233445566778899AABBCCDDEEFF001122", "Test User ID", "Test User Name"};
pEp::Identity id{ "test1@pEpdatatypes.lol",
"FF00112233445566778899AABBCCDDEEFF001122",
"Test User ID",
"Test User Name" };
}
TEST( IdentityList, Simple )
TEST(IdentityList, Simple)
{
pEp::IdentityList il;
EXPECT_TRUE(il.empty());
EXPECT_EQ(il.size(), 0);
}
TEST( IdentityList, InitList )
TEST(IdentityList, InitList)
{
pEp::IdentityList il(
{
pEp::Identity{"test-init1@pEpdatatypes.lol", "0100112233445566778899AABBCCDDEEFF001122", "Test User ID1", "Test User 1 Name"},
pEp::Identity{"test-init2@pEpdatatypes.lol", "0200112233445566778899AABBCCDDEEFF001122", "Test User ID2", "Test User 2 Name"}
} );
EXPECT_EQ( il.size(), 2);
pEp::IdentityList il({ pEp::Identity{ "test-init1@pEpdatatypes.lol",
"0100112233445566778899AABBCCDDEEFF001122",
"Test User ID1",
"Test User 1 Name" },
pEp::Identity{ "test-init2@pEpdatatypes.lol",
"0200112233445566778899AABBCCDDEEFF001122",
"Test User ID2",
"Test User 2 Name" } });
EXPECT_EQ(il.size(), 2);
il.clear();
EXPECT_EQ(il.size(), 0);
EXPECT_TRUE( il.empty() );
EXPECT_TRUE(il.empty());
}

239
test/unittest_message.cc

@ -2,113 +2,112 @@
#include "../src/types.hh"
namespace
{
static const char* mail1_eml =
"Return-Path: <alice@pep-project.org>\r\n"
"X-Original-To: alice@pep-project.org\r\n"
"Delivered-To: alice@pep-project.org\r\n"
"Received: from localhost (localhost [127.0.0.1])\r\n"
"\tby dragon.pibit.ch (Postfix) with ESMTP id B84AF171C06F\r\n"
"\tfor <alice@pep-project.org>; Wed, 16 Jan 2019 16:29:39 +0100 (CET)\r\n"
"Received: from dragon.pibit.ch ([127.0.0.1])\r\n"
"\tby localhost (dragon.pibit.ch [127.0.0.1]) (amavisd-new, port 10024)\r\n"
"\twith ESMTP id q0wZqHMoT1gS for <alice@pep-project.org>;\r\n"
"\tWed, 16 Jan 2019 16:29:37 +0100 (CET)\r\n"
"Received: from Alice-PC.local (unknown [192.168.128.20])\r\n"
"\tby dragon.pibit.ch (Postfix) with ESMTPSA id 563DD171C06A\r\n"
"\tfor <alice@pep-project.org>; Wed, 16 Jan 2019 16:29:37 +0100 (CET)\r\n"
"To: Bob <bob@pep-project.org>\r\n"
"From: Alice <alice@pep-project.org>\r\n"
"Cc: Carol Couscous <carol.couscous+private@pep.lol>, Dave Doe (III) \r\n"
" Dexter <dave-dexter@pep.ooo>, dodo@pep.lol, \"Eve @ Evil\" <eve@evil.lol>, \r\n"
" Mallory =?UTF-8?B?TcO2bGxlcg==?= (private) <\"mallory @ moeller\"@sinister.aq>\r\n"
"Subject: =?UTF-8?B?UsO4ZGdyw7hkIG1lZCBmbMO4ZGU=?=\r\n"
"Openpgp: preference=signencrypt\r\n"
"Organization: =?UTF-8?B?8J+Ukg==?=\r\n"
"Message-ID: <65a2df2c-ddc8-0875-a142-21acf62ed467@pep-project.org>\r\n"
"References: <msg-alfa@pep.id> <msg-bravo@pep.aq> <lol-123456789@intern.sc.ful-lol.example>\r\n"
" <msg-charlie@pep.aq>\r\n"
"In-Reply-To: <msg-reply-0815@pep.aq>\r\n"
"Date: Wed, 16 Jan 2019 16:29:30 +0100\r\n"
"User-Agent: B\r\n"
"MIME-Version: 1.0\r\n"
"Content-Type: multipart/mixed;\r\n"
" boundary=\"==pEp_01==\"\r\n"
"\r\n"
"This is a Multipart MIME message.\r\n"
"--==pEp_01==\r\n"
"Content-Type: multipart/alternative; boundary=\"==pEp_02==\";\r\n"
" protected-headers=\"v1\"\r\n"
"\r\n"
"--==pEp_02==\r\n"
"Content-Type: text/plain; charset=\"utf-8\"\r\n"
"Content-Language: en-US\r\n"
"Content-Transfer-Encoding: quoted-printable\r\n"
"\r\n"
"R=C3=B8dgr=C3=B8d med fl=C3=B8de?\r\n"
"\r\n"
"--==pEp_02==\r\n"
"Content-Type: multipart/related; boundary=\"==pEp_LoL==\";\r\n"
"\r\n"
"--==pEp_LoL==\r\n"
"Content-Type: text/html; charset=\"ISO-8859-1\";\r\n"
"Content-Transfer-Encoding: quoted-printable\r\n"
"\r\n"
"<html lang=3D=22de=22><body>=DCbergr=F6=DFen=E4nderung: 1=\r\n"
"0=80.</body></html>\r\n"
"\r\n"
"--==pEp_LoL==\r\n"
"Content-Type: image/png; name=\"rebeccapurple-circle.png\"\r\n"
"Content-Language: en-US\r\n"
"Content-ID: <rebeccapurple-circle-fb25fbb3-fd0b-46af-b567-7d1aa5725c49@pep.lol>\r\n"
"Content-Transfer-Encoding: base64\r\n"
"Content-Disposition: inline;\r\n"
" filename*0*=utf-8'en-US'rebeccapurple;\r\n"
" filename*1*=%2Dcircle.png;\r\n"
"\r\n"
"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEVmM5n///9dvR/iAAAA\r\n"
"H0lEQVQIHWP4Ic/wgJ3hADNDAyMIYQKIOFABUNkPeQC4LQeH3BOsvgAAAABJRU5ErkJggg==\r\n"
"\r\n"
"--==pEp_LoL==--\r\n" // end of multipart/related
"\r\n"
"--==pEp_02==--\r\n" // end of multipart/alternative
"\r\n"
"--==pEp_01==\r\n" // first "real" attachment, 2nd in bloblist
"Content-Type: application/octet-stream; name=\"This is a long\r\n"
" file name so it is split to multiple\r\n"
" physical lines.bin\"\r\n"
"Content-Language: en-US\r\n"
"Content-Transfer-Encoding: base64\r\n"
"Content-Disposition: attachment;\r\n"
" filename*0=\"This is a long file name so it is split to\";\r\n"
" filename*1=\" multiple physical lines.bin\";\r\n"
"\r\n"
"w5xiZXJncsO2w59lbsOkbmRlcnVuZyEK\r\n"
"\r\n"
"--==pEp_01==\r\n" // another text/plain part, 3rd in bloblist
"Content-Type: text/plain; charset=\"ISO-8859-15\";\r\n"
"Content-Transfer-Encoding: quoted-printable\r\n"
"\r\n"
"=DCbergr=F6=DFen=E4nderung: 10=A4.\r\n"
"--==pEp_01==\r\n" // an attached PNG image with bizarre filename as 4th and last element in bloblist
"Content-Type: image/png; name=\"=?UTF-8?B?8J+SqSDwn5iAIPCf?="
" =?UTF-8?B?kqkg8J+YgCDwn5KpIPCfmIAg8J+SqSDwn5iAIPCfkqkg8J+YgCDwn5KpIPCfm?="
" =?UTF-8?B?IAg8J+SqSDwn5iAIPCfkqkg8J+YgC5wbmc=?=\"\r\n"
"Content-Language: en-US\r\n"
"Content-Transfer-Encoding: base64\r\n"
"Content-Disposition: attachment;\r\n"
" filename*0*=utf-8''%F0%9F%92%A9%20%F0%9F%98%80%20%F0%9F%92%A9%20%F0;\r\n"
" filename*1*=%9F%98%80%20%F0%9F%92%A9%20%F0%9F%98%80%20%F0%9F%92%A9;\r\n"
" filename*2*=%20%F0%9F%98%80%20%F0%9F%92%A9%20%F0%9F%98%80%20%F0%9F;\r\n"
" filename*3*=%92%A9%20%F0%9F%98%80%20%F0%9F%92%A9%20%F0%9F%98%80%20;\r\n"
" filename*4*=%F0%9F%92%A9%20%F0%9F%98%80.png\r\n"
"\r\n"
"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEVmM5n///9dvR/iAAAA\r\n"
" H0lEQVQIHWP4Ic/wgJ3hADN\r\n"
"DAyMIYQKIOFABUNkPeQC4LQeH3BOsvgAAAABJRU5ErkJggg==\r\n"
"--==pEp_01==--\r\n"
"\r\n";
namespace {
static const char*
mail1_eml = "Return-Path: <alice@pep-project.org>\r\n"
"X-Original-To: alice@pep-project.org\r\n"
"Delivered-To: alice@pep-project.org\r\n"
"Received: from localhost (localhost [127.0.0.1])\r\n"
"\tby dragon.pibit.ch (Postfix) with ESMTP id B84AF171C06F\r\n"
"\tfor <alice@pep-project.org>; Wed, 16 Jan 2019 16:29:39 +0100 (CET)\r\n"
"Received: from dragon.pibit.ch ([127.0.0.1])\r\n"
"\tby localhost (dragon.pibit.ch [127.0.0.1]) (amavisd-new, port 10024)\r\n"
"\twith ESMTP id q0wZqHMoT1gS for <alice@pep-project.org>;\r\n"
"\tWed, 16 Jan 2019 16:29:37 +0100 (CET)\r\n"
"Received: from Alice-PC.local (unknown [192.168.128.20])\r\n"
"\tby dragon.pibit.ch (Postfix) with ESMTPSA id 563DD171C06A\r\n"
"\tfor <alice@pep-project.org>; Wed, 16 Jan 2019 16:29:37 +0100 (CET)\r\n"
"To: Bob <bob@pep-project.org>\r\n"
"From: Alice <alice@pep-project.org>\r\n"
"Cc: Carol Couscous <carol.couscous+private@pep.lol>, Dave Doe (III) \r\n"
" Dexter <dave-dexter@pep.ooo>, dodo@pep.lol, \"Eve @ Evil\" <eve@evil.lol>, \r\n"
" Mallory =?UTF-8?B?TcO2bGxlcg==?= (private) <\"mallory @ moeller\"@sinister.aq>\r\n"
"Subject: =?UTF-8?B?UsO4ZGdyw7hkIG1lZCBmbMO4ZGU=?=\r\n"
"Openpgp: preference=signencrypt\r\n"
"Organization: =?UTF-8?B?8J+Ukg==?=\r\n"
"Message-ID: <65a2df2c-ddc8-0875-a142-21acf62ed467@pep-project.org>\r\n"
"References: <msg-alfa@pep.id> <msg-bravo@pep.aq> <lol-123456789@intern.sc.ful-lol.example>\r\n"
" <msg-charlie@pep.aq>\r\n"
"In-Reply-To: <msg-reply-0815@pep.aq>\r\n"
"Date: Wed, 16 Jan 2019 16:29:30 +0100\r\n"
"User-Agent: B\r\n"
"MIME-Version: 1.0\r\n"
"Content-Type: multipart/mixed;\r\n"
" boundary=\"==pEp_01==\"\r\n"
"\r\n"
"This is a Multipart MIME message.\r\n"
"--==pEp_01==\r\n"
"Content-Type: multipart/alternative; boundary=\"==pEp_02==\";\r\n"
" protected-headers=\"v1\"\r\n"
"\r\n"
"--==pEp_02==\r\n"
"Content-Type: text/plain; charset=\"utf-8\"\r\n"
"Content-Language: en-US\r\n"
"Content-Transfer-Encoding: quoted-printable\r\n"
"\r\n"
"R=C3=B8dgr=C3=B8d med fl=C3=B8de?\r\n"
"\r\n"
"--==pEp_02==\r\n"
"Content-Type: multipart/related; boundary=\"==pEp_LoL==\";\r\n"
"\r\n"
"--==pEp_LoL==\r\n"
"Content-Type: text/html; charset=\"ISO-8859-1\";\r\n"
"Content-Transfer-Encoding: quoted-printable\r\n"
"\r\n"
"<html lang=3D=22de=22><body>=DCbergr=F6=DFen=E4nderung: 1=\r\n"
"0=80.</body></html>\r\n"
"\r\n"
"--==pEp_LoL==\r\n"
"Content-Type: image/png; name=\"rebeccapurple-circle.png\"\r\n"
"Content-Language: en-US\r\n"
"Content-ID: <rebeccapurple-circle-fb25fbb3-fd0b-46af-b567-7d1aa5725c49@pep.lol>\r\n"
"Content-Transfer-Encoding: base64\r\n"
"Content-Disposition: inline;\r\n"
" filename*0*=utf-8'en-US'rebeccapurple;\r\n"
" filename*1*=%2Dcircle.png;\r\n"
"\r\n"
"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEVmM5n///9dvR/iAAAA\r\n"
"H0lEQVQIHWP4Ic/wgJ3hADNDAyMIYQKIOFABUNkPeQC4LQeH3BOsvgAAAABJRU5ErkJggg==\r\n"
"\r\n"
"--==pEp_LoL==--\r\n" // end of multipart/related
"\r\n"
"--==pEp_02==--\r\n" // end of multipart/alternative
"\r\n"
"--==pEp_01==\r\n" // first "real" attachment, 2nd in bloblist
"Content-Type: application/octet-stream; name=\"This is a long\r\n"
" file name so it is split to multiple\r\n"
" physical lines.bin\"\r\n"
"Content-Language: en-US\r\n"
"Content-Transfer-Encoding: base64\r\n"
"Content-Disposition: attachment;\r\n"
" filename*0=\"This is a long file name so it is split to\";\r\n"
" filename*1=\" multiple physical lines.bin\";\r\n"
"\r\n"
"w5xiZXJncsO2w59lbsOkbmRlcnVuZyEK\r\n"
"\r\n"
"--==pEp_01==\r\n" // another text/plain part, 3rd in bloblist
"Content-Type: text/plain; charset=\"ISO-8859-15\";\r\n"
"Content-Transfer-Encoding: quoted-printable\r\n"
"\r\n"
"=DCbergr=F6=DFen=E4nderung: 10=A4.\r\n"
"--==pEp_01==\r\n" // an attached PNG image with bizarre filename as 4th and last element in bloblist
"Content-Type: image/png; name=\"=?UTF-8?B?8J+SqSDwn5iAIPCf?="
" =?UTF-8?B?kqkg8J+YgCDwn5KpIPCfmIAg8J+SqSDwn5iAIPCfkqkg8J+YgCDwn5KpIPCfm?="
" =?UTF-8?B?IAg8J+SqSDwn5iAIPCfkqkg8J+YgC5wbmc=?=\"\r\n"
"Content-Language: en-US\r\n"
"Content-Transfer-Encoding: base64\r\n"
"Content-Disposition: attachment;\r\n"
" filename*0*=utf-8''%F0%9F%92%A9%20%F0%9F%98%80%20%F0%9F%92%A9%20%F0;\r\n"
" filename*1*=%9F%98%80%20%F0%9F%92%A9%20%F0%9F%98%80%20%F0%9F%92%A9;\r\n"
" filename*2*=%20%F0%9F%98%80%20%F0%9F%92%A9%20%F0%9F%98%80%20%F0%9F;\r\n"
" filename*3*=%92%A9%20%F0%9F%98%80%20%F0%9F%92%A9%20%F0%9F%98%80%20;\r\n"
" filename*4*=%F0%9F%92%A9%20%F0%9F%98%80.png\r\n"
"\r\n"
"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEVmM5n///9dvR/iAAAA\r\n"
" H0lEQVQIHWP4Ic/wgJ3hADN\r\n"
"DAyMIYQKIOFABUNkPeQC4LQeH3BOsvgAAAABJRU5ErkJggg==\r\n"
"--==pEp_01==--\r\n"
"\r\n";
PEP_STATUS dummy_message(::message* msg)
@ -120,21 +119,21 @@ namespace
} // end of anonymous namespace
TEST( MessageTest, Simple )
TEST(MessageTest, Simple)
{
pEp::Message msg{PEP_dir_outgoing, mail1_eml};
pEp::Message msg{ PEP_dir_outgoing, mail1_eml };
EXPECT_EQ(msg->dir, PEP_dir_outgoing);
EXPECT_STREQ( msg->shortmsg, "Rødgrød med fløde" );
EXPECT_STREQ( msg->longmsg , "Rødgrød med fløde?\r\n" );
EXPECT_EQ( identity_list_length(msg->to), 1 );
EXPECT_EQ( identity_list_length(msg->cc), 5 );
EXPECT_EQ( identity_list_length(msg->bcc), 0 );
EXPECT_EQ( bloblist_length(msg->attachments), 4 );
EXPECT_STREQ(msg->shortmsg, "Rødgrød med fløde");
EXPECT_STREQ(msg->longmsg, "Rødgrød med fløde?\r\n");
EXPECT_EQ(identity_list_length(msg->to), 1);
EXPECT_EQ(identity_list_length(msg->cc), 5);
EXPECT_EQ(identity_list_length(msg->bcc), 0);
EXPECT_EQ(bloblist_length(msg->attachments), 4);
ASSERT_NE(msg->from, nullptr);
EXPECT_STREQ( msg->from->username, "Alice");
EXPECT_EQ( dummy_message(msg.get()), PEP_STATUS_OK);
EXPECT_STREQ( msg->shortmsg, "Hello World");
EXPECT_STREQ(msg->from->username, "Alice");
EXPECT_EQ(dummy_message(msg.get()), PEP_STATUS_OK);
EXPECT_STREQ(msg->shortmsg, "Hello World");
}

134
test/unittest_nfc.cc

@ -1,6 +1,6 @@
#include <gtest/gtest.h>
#include "../src/nfc.hh" // for illegal_utf8 exception
#include "../src/nfc.hh" // for illegal_utf8 exception
#include <vector>
using namespace pEp;
@ -8,70 +8,82 @@ using std::string_view;
namespace {
struct TestEntry
{
string_view input;
bool is_nfc;
IsNFC quick;
string_view nfc;
struct TestEntry {
string_view input;
bool is_nfc;
IsNFC quick;
string_view nfc;
};
typedef TestEntry TE;
std::ostream& operator<<(std::ostream& o, const TestEntry& tt)
{
return o << "input=«" << tt.input << "», isNfc=" << tt.is_nfc << ", quick=" << tt.quick
<< ". ";
}
const char nullo[4] = { 0, 0, 0, 0 };
const std::vector<TestEntry> testValues = {
{ "", true, IsNFC::Yes, "" }, // always start with the simple case ;-)
{ "123", true, IsNFC::Yes, "123" }, // some ASCII digits. Still easy.
{ "\n\\\b", true, IsNFC::Yes, "\n\\\b" }, // backslash escapes for ASCII and control chars
{ "ä", true, IsNFC::Yes, "ä" }, // <U+00E4> small a with diaeresis
{ "\xc4\x85", true, IsNFC::Yes, "\xc4\x85" }, // <U+0105> small a with ogonek
{ "a\xcc\x88", false, IsNFC::Maybe, "ä" }, // a + <U+0308> combining diaresis
{ "a\xcc\xa8", false, IsNFC::Maybe, "\xc4\x85" }, // a + <U+0328> combining ogonek
{ "a\xcc\xa8\xcc\x88",
false,
IsNFC::Maybe,
"\xc4\x85\xcc\x88" }, // a + <U+0328> + <U+0308> (ogonek + diaeresis)
{ "a\xcc\x88\xcc\xa8",
false,
IsNFC::Maybe,
"\xc4\x85\xcc\x88" }, // a + <U+0308> + <U+0328> (diaeresis + ogonek)
{ "\xc4\x85\xcc\x88",
true,
IsNFC::Maybe,
"\xc4\x85\xcc\x88" }, // <U+0105> small a with ogonek + combining diaeresis
{ "ä\xcc\xa8", false, IsNFC::Maybe, "\xc4\x85\xcc\x88" }, // a diaeresis + <U+0328> combining ogonek
// Already implemented, because <U+305> and <U+33C> have neither "No" nor "Maybe" NFC class:
{ "a\xcc\x85\xcc\xbc",
false,
IsNFC::No,
"a\xcc\xbc\xcc\x85" }, // a + <U+0305> + <U+033C> (overline + seagull_below)
{ "a\xcc\xbc\xcc\x85",
true,
IsNFC::Yes,
"a\xcc\xbc\xcc\x85" }, // a + <U+033C> + <U+0305> (seagull_below + overline)
{ string_view(nullo, 1), true, IsNFC::Yes, string_view(nullo, 1) }, // Yeah, 1 NUL byte
{ string_view(nullo, 4), true, IsNFC::Yes, string_view(nullo, 4) }, // Yeah, 4 NUL bytes
{ "EOF", true, IsNFC::Yes, "EOF" }
};
} // namespace
class NfcTest : public ::testing::TestWithParam<TestEntry> {
// intentionally left blank for now.
};
typedef TestEntry TE;
std::ostream& operator<<(std::ostream& o, const TestEntry& tt)
{
return o << "input=«" << tt.input << "», isNfc=" << tt.is_nfc << ", quick=" << tt.quick << ". ";
}
const char nullo[4] = {0,0,0,0};
const std::vector<TestEntry> testValues =
{
{ "" , true, IsNFC::Yes, "" }, // always start with the simple case ;-)
{ "123" , true, IsNFC::Yes, "123" }, // some ASCII digits. Still easy.
{ "\n\\\b" , true, IsNFC::Yes, "\n\\\b" }, // backslash escapes for ASCII and control chars
{ "ä" , true, IsNFC::Yes, "ä" }, // <U+00E4> small a with diaeresis
{ "\xc4\x85" , true, IsNFC::Yes, "\xc4\x85" }, // <U+0105> small a with ogonek
INSTANTIATE_TEST_SUITE_P(NfcTestInstance, NfcTest, testing::ValuesIn(testValues));
{ "a\xcc\x88", false, IsNFC::Maybe, "ä" }, // a + <U+0308> combining diaresis
{ "a\xcc\xa8", false, IsNFC::Maybe, "\xc4\x85" }, // a + <U+0328> combining ogonek
{ "a\xcc\xa8\xcc\x88", false, IsNFC::Maybe, "\xc4\x85\xcc\x88" }, // a + <U+0328> + <U+0308> (ogonek + diaeresis)
{ "a\xcc\x88\xcc\xa8", false, IsNFC::Maybe, "\xc4\x85\xcc\x88" }, // a + <U+0308> + <U+0328> (diaeresis + ogonek)
{ "\xc4\x85\xcc\x88" , true, IsNFC::Maybe, "\xc4\x85\xcc\x88" }, // <U+0105> small a with ogonek + combining diaeresis
{ "ä\xcc\xa8" , false, IsNFC::Maybe, "\xc4\x85\xcc\x88" }, // a diaeresis + <U+0328> combining ogonek
// Already implemented, because <U+305> and <U+33C> have neither "No" nor "Maybe" NFC class:
{ "a\xcc\x85\xcc\xbc", false, IsNFC::No , "a\xcc\xbc\xcc\x85"}, // a + <U+0305> + <U+033C> (overline + seagull_below)
{ "a\xcc\xbc\xcc\x85", true, IsNFC::Yes , "a\xcc\xbc\xcc\x85"}, // a + <U+033C> + <U+0305> (seagull_below + overline)
{ string_view(nullo, 1), true, IsNFC::Yes, string_view(nullo, 1) }, // Yeah, 1 NUL byte
{ string_view(nullo, 4), true, IsNFC::Yes, string_view(nullo, 4) }, // Yeah, 4 NUL bytes
{ "EOF", true, IsNFC::Yes, "EOF" }
};
}
class NfcTest : public ::testing::TestWithParam<TestEntry>
TEST_P(NfcTest, Meh)
{
// intentionally left blank for now.
};
const auto& v = GetParam();
EXPECT_EQ(v.quick, UTF8::isNFC_quick_check(v.input));
INSTANTIATE_TEST_SUITE_P(NfcTestInstance, NfcTest, testing::ValuesIn(testValues) );
EXPECT_EQ(v.is_nfc, UTF8::isNFC(v.input));
EXPECT_EQ(v.nfc, UTF8::toNFC(v.input));
TEST_P( NfcTest, Meh )
{
const auto& v = GetParam();
EXPECT_EQ( v.quick, UTF8::isNFC_quick_check(v.input) );
EXPECT_EQ( v.is_nfc, UTF8::isNFC(v.input) );
EXPECT_EQ( v.nfc , UTF8::toNFC(v.input) );
if(v.is_nfc)
{
EXPECT_EQ( v.input, UTF8::toNFC(v.input) );
}
if (v.is_nfc) {
EXPECT_EQ(v.input, UTF8::toNFC(v.input));
}
}

106
test/unittest_nfc16.cc

@ -1,85 +1,81 @@
#include <gtest/gtest.h>
#include "../src/nfc.hh" // for illegal_utf8 exception
#include "../src/nfc.hh" // for illegal_utf8 exception
#include <vector>
using namespace pEp;
using std::u16string_view;
namespace pEp
{
std::string escape_utf16(u16string_view s);
namespace pEp {
std::string escape_utf16(u16string_view s);
}
namespace {
struct TestEntry
{
u16string_view input;
bool is_nfc;
IsNFC quick;
u16string_view nfc;
};
struct TestEntry {
u16string_view input;
bool is_nfc;
IsNFC quick;
u16string_view nfc;
};
typedef TestEntry TE;
typedef TestEntry TE;
std::ostream& operator<<(std::ostream& o, const TestEntry& tt)
{
return o << "input=«" << pEp::escape_utf16(tt.input) << "», isNfc=" << tt.is_nfc << ", quick=" << tt.quick << ". ";
}
std::ostream& operator<<(std::ostream& o, const TestEntry& tt)
{
return o << "input=«" << pEp::escape_utf16(tt.input) << "», isNfc=" << tt.is_nfc
<< ", quick=" << tt.quick << ". ";
}
const char16_t nullo[4] = {0,0,0,0};
const char16_t nullo[4] = { 0, 0, 0, 0 };
const std::vector<TestEntry> testValues =
{
{ u"" , true, IsNFC::Yes, u"" }, // always start with the simple case ;-)
{ u"123" , true, IsNFC::Yes, u"123" }, // some ASCII digits. Still easy.
{ u"\n\\\b" , true, IsNFC::Yes, u"\n\\\b" }, // backslash escapes for ASCII and control chars
{ u"ä" , true, IsNFC::Yes, u"ä" }, // <U+00E4> small a with diaeresis
{ u"\u0105" , true, IsNFC::Yes, u"\u0105" }, // <U+0105> small a with ogonek
const std::vector<TestEntry> testValues = {
{ u"", true, IsNFC::Yes, u"" }, // always start with the simple case ;-)
{ u"123", true, IsNFC::Yes, u"123" }, // some ASCII digits. Still easy.
{ u"\n\\\b", true, IsNFC::Yes, u"\n\\\b" }, // backslash escapes for ASCII and control chars
{ u"ä", true, IsNFC::Yes, u"ä" }, // <U+00E4> small a with diaeresis
{ u"\u0105", true, IsNFC::Yes, u"\u0105" }, // <U+0105> small a with ogonek
{ u"a\u0308" , false, IsNFC::Maybe, u"ä" }, // a + <U+0308> combining diaresis
{ u"a\u0328" , false, IsNFC::Maybe, u"\u0105" }, // a + <U+0328> combining ogonek
{ u"a\u0328\u0308", false, IsNFC::Maybe, u"\u0105\u0308" }, // a + <U+0328> + <U+0308> (ogonek + diaeresis)
{ u"a\u0308\u0328", false, IsNFC::Maybe, u"\u0105\u0308" }, // a + <U+0308> + <U+0328> (diaeresis + ogonek)
{ u"a\u0308", false, IsNFC::Maybe, u"ä" }, // a + <U+0308> combining diaresis
{ u"a\u0328", false, IsNFC::Maybe, u"\u0105" }, // a + <U+0328> combining ogonek
{ u"a\u0328\u0308", false, IsNFC::Maybe, u"\u0105\u0308" }, // a + <U+0328> + <U+0308> (ogonek + diaeresis)
{ u"a\u0308\u0328", false, IsNFC::Maybe, u"\u0105\u0308" }, // a + <U+0308> + <U+0328> (diaeresis + ogonek)
{ u"\u0105\u0308" , true, IsNFC::Maybe, u"\u0105\u0308" }, // <U+0105> small a with ogonek + combining diaeresis
{ u"ä\u0328" , false, IsNFC::Maybe, u"\u0105\u0308" }, // a diaeresis + <U+0328> combining ogonek
{ u"\u0105\u0308", true, IsNFC::Maybe, u"\u0105\u0308" }, // <U+0105> small a with ogonek + combining diaeresis
{ u"ä\u0328", false, IsNFC::Maybe, u"\u0105\u0308" }, // a diaeresis + <U+0328> combining ogonek
// Already implemented, because <U+305> and <U+33C> have neither "No" nor "Maybe" NFC class:
{ u"a\u0305\u033c", false, IsNFC::No , u"a\u033c\u0305"}, // a + <U+0305> + <U+033C> (overline + seagull_below)
{ u"a\u033c\u0305", true, IsNFC::Yes , u"a\u033c\u0305"}, // a + <U+033C> + <U+0305> (seagull_below + overline)
// Already implemented, because <U+305> and <U+33C> have neither "No" nor "Maybe" NFC class:
{ u"a\u0305\u033c", false, IsNFC::No, u"a\u033c\u0305" }, // a + <U+0305> + <U+033C> (overline + seagull_below)
{ u"a\u033c\u0305", true, IsNFC::Yes, u"a\u033c\u0305" }, // a + <U+033C> + <U+0305> (seagull_below + overline)
// MUSICAL SYMBOL SIXTEENTH NOTE -> will be decomposed and not re-composed according to Unicode data, for whatever reason. :-/
{ u"\U0001D161", false, IsNFC::No, u"\U0001d15f\U0001d16f" },
{ u16string_view(nullo, 1), true, IsNFC::Yes, u16string_view(nullo, 1) }, // Yeah, 1 NUL byte
{ u16string_view(nullo, 4), true, IsNFC::Yes, u16string_view(nullo, 4) }, // Yeah, 4 NUL bytes
{ u"EOF", true, IsNFC::Yes, u"EOF" }
};
// MUSICAL SYMBOL SIXTEENTH NOTE -> will be decomposed and not re-composed according to Unicode data, for whatever reason. :-/
{ u"\U0001D161", false, IsNFC::No, u"\U0001d15f\U0001d16f" },
{ u16string_view(nullo, 1), true, IsNFC::Yes, u16string_view(nullo, 1) }, // Yeah, 1 NUL byte
{ u16string_view(nullo, 4), true, IsNFC::Yes, u16string_view(nullo, 4) }, // Yeah, 4 NUL bytes
{ u"EOF", true, IsNFC::Yes, u"EOF" }
};
} // end of anonymous namespace
class Nfc16Test : public ::testing::TestWithParam<TestEntry>
{
// intentionally left blank for now.
class Nfc16Test : public ::testing::TestWithParam<TestEntry> {
// intentionally left blank for now.
};
INSTANTIATE_TEST_SUITE_P(Nfc16TestInstance, Nfc16Test, testing::ValuesIn(testValues) );
INSTANTIATE_TEST_SUITE_P(Nfc16TestInstance, Nfc16Test, testing::ValuesIn(testValues));
TEST_P( Nfc16Test, Meh )
TEST_P(Nfc16Test, Meh)
{
const auto& v = GetParam();
EXPECT_EQ( v.quick, UTF16::isNFC_quick_check(v.input) );
EXPECT_EQ( v.is_nfc, UTF16::isNFC(v.input) );
EXPECT_EQ( v.nfc , UTF16::toNFC(v.input) );
if(v.is_nfc)
{
EXPECT_EQ( v.input, UTF16::toNFC(v.input) );
}
const auto& v = GetParam();
EXPECT_EQ(v.quick, UTF16::isNFC_quick_check(v.input));
EXPECT_EQ(v.is_nfc, UTF16::isNFC(v.input));
EXPECT_EQ(v.nfc, UTF16::toNFC(v.input));
if (v.is_nfc) {
EXPECT_EQ(v.input, UTF16::toNFC(v.input));
}
}

101
test/unittest_nfcstring.cc

@ -1,6 +1,6 @@
#include <gtest/gtest.h>
#include "../src/nfc.hh" // for illegal_utf8 exception
#include "../src/nfc.hh" // for illegal_utf8 exception
#include <vector>
using namespace pEp;
@ -8,67 +8,64 @@ using std::string_view;
namespace {
struct TestEntry
{
string_view input;
string_view nfc;
};
struct TestEntry {
string_view input;
string_view nfc;
};
typedef TestEntry TE;
typedef TestEntry TE;
std::ostream& operator<<(std::ostream& o, const TestEntry& tt)
{
return o << "input=«" << tt.input << "», nfc=«" << tt.nfc << "» ";
}
std::ostream& operator<<(std::ostream& o, const TestEntry& tt)
{
return o << "input=«" << tt.input << "», nfc=«" << tt.nfc << "» ";
}
} // end of anonymous namespace
TEST( NfcTestString, Simple )
TEST(NfcTestString, Simple)
{
pEp::nfc_string s;
EXPECT_TRUE( s.empty() );
EXPECT_EQ( s.size(), 0 );
s.reserve(1000);
EXPECT_GE(s.capacity(), 1000);
s = "Ha\u0308user"; // non-NFC input will be normalized.
EXPECT_NE( s.get(), std::string("Ha\u0308user") );
EXPECT_EQ( s.get(), std::string("Häuser") );
s.insert(0, "U\u0308ber");
EXPECT_EQ( s.get(), std::string("ÜberHäuser") );
s += "\u0328\u030c"; // COMBINING OGONEK (below), COMBINING CARON (above)
// r absorbs the caron into U+0159, the combining ogonek remains separate
EXPECT_EQ( s.get(), std::string("ÜberHäuse\u0159\u0328") );
EXPECT_EQ( s.size(), 15);
EXPECT_THROW( s.substr(1), pEp::illegal_utf );
EXPECT_THROW( s.substr(2, 10), pEp::illegal_utf );
// removal of the r-with-caron let the remaining ogonek combine with the e to U+0119 (E WITH OGONEK)
EXPECT_EQ( s.erase(11, 2).get(), "ÜberHäus\u0119" );
EXPECT_TRUE ( s.starts_with("Üb") );
EXPECT_FALSE( s.starts_with("Üx") );
EXPECT_TRUE ( s.ends_with("s\u0119") );
EXPECT_FALSE( s.ends_with("ss\u0119") );
EXPECT_EQ( s.find("Über"), 0u );
EXPECT_EQ( s.find("ber") , 2u );
EXPECT_EQ( s.find("über"), UTF8::nfc_string::npos );
EXPECT_EQ( s.find("Übel"), UTF8::nfc_string::npos );
pEp::nfc_string s;
EXPECT_TRUE(s.empty());
EXPECT_EQ(s.size(), 0);
s.reserve(1000);
EXPECT_GE(s.capacity(), 1000);
s = "Ha\u0308user"; // non-NFC input will be normalized.
EXPECT_NE(s.get(), std::string("Ha\u0308user"));
EXPECT_EQ(s.get(), std::string("Häuser"));
s.insert(0, "U\u0308ber");
EXPECT_EQ(s.get(), std::string("ÜberHäuser"));
s += "\u0328\u030c"; // COMBINING OGONEK (below), COMBINING CARON (above)
// r absorbs the caron into U+0159, the combining ogonek remains separate
EXPECT_EQ(s.get(), std::string("ÜberHäuse\u0159\u0328"));
EXPECT_EQ(s.size(), 15);
EXPECT_THROW(s.substr(1), pEp::illegal_utf);
EXPECT_THROW(s.substr(2, 10), pEp::illegal_utf);
// removal of the r-with-caron let the remaining ogonek combine with the e to U+0119 (E WITH OGONEK)
EXPECT_EQ(s.erase(11, 2).get(), "ÜberHäus\u0119");
EXPECT_TRUE(s.starts_with("Üb"));
EXPECT_FALSE(s.starts_with("Üx"));
EXPECT_TRUE(s.ends_with("s\u0119"));
EXPECT_FALSE(s.ends_with("ss\u0119"));
EXPECT_EQ(s.find("Über"), 0u);
EXPECT_EQ(s.find("ber"), 2u);
EXPECT_EQ(s.find("über"), UTF8::nfc_string::npos);
EXPECT_EQ(s.find("Übel"), UTF8::nfc_string::npos);
}
TEST( NfcTestString, Exceptions )
TEST(NfcTestString, Exceptions)
{
pEp::nfc_string s;
EXPECT_THROW( s = "Meep\xc0\x80.", pEp::illegal_utf );
EXPECT_THROW( s += '\377', pEp::illegal_utf );
pEp::nfc_string s;
EXPECT_THROW(s = "Meep\xc0\x80.", pEp::illegal_utf);
EXPECT_THROW(s += '\377', pEp::illegal_utf);
}

64
test/unittest_stringlist.cc

@ -3,70 +3,68 @@
#include "../src/types.hh"
TEST( StringList, Simple )
TEST(StringList, Simple)
{
pEp::StringList sl;
EXPECT_TRUE(sl.empty());
EXPECT_EQ(sl.size(), 0);
}
TEST( StringList, InitList )
TEST(StringList, InitList)
{
pEp::StringList sl( {"Hello", "world"} );
EXPECT_EQ( sl.size(), 2);
pEp::StringList sl({ "Hello", "world" });
EXPECT_EQ(sl.size(), 2);
sl.clear();
EXPECT_EQ(sl.size(), 0);
EXPECT_TRUE( sl.empty() );
EXPECT_TRUE(sl.empty());
}
TEST( StringList, Algorithm )
TEST(StringList, Algorithm)
{
pEp::StringList sl( {"Alice", "Bob", "Carol", "Dave", "Eve", "Frank", "George", "Harry"} );
pEp::StringList sl({ "Alice", "Bob", "Carol", "Dave", "Eve", "Frank", "George", "Harry" });
auto qe = std::find(sl.begin(), sl.end(), std::string("Santa Claus")); // not there!
EXPECT_EQ( qe, sl.end() );
EXPECT_EQ(qe, sl.end());
// BEWARE: DOES NOT WORK, because find() uses operator== on char* pointers. :-(
// auto q = std::find(sl.begin(), sl.end(), "Eve");
// BEWARE: DOES NOT WORK, because find() uses operator== on char* pointers. :-(
// auto q = std::find(sl.begin(), sl.end(), "Eve");
auto q = std::find(sl.begin(), sl.end(), std::string("Eve"));
EXPECT_NE( q, sl.end() );
EXPECT_STREQ( *q, "Eve" );
EXPECT_NE(q, sl.end());
EXPECT_STREQ(*q, "Eve");
}
TEST( StringList, Dynamic )
TEST(StringList, Dynamic)
{
static const unsigned NumberOfElements = 17;
pEp::StringList sl;
EXPECT_EQ(sl.size(), 0);
EXPECT_TRUE( sl.empty() );
EXPECT_TRUE(sl.empty());
char buffer[16];
for(unsigned u=0; u<NumberOfElements; ++u)
{
for (unsigned u = 0; u < NumberOfElements; ++u) {
EXPECT_EQ(sl.size(), u);
snprintf(buffer, 15, "k%u", u);
sl.push_back( buffer );
sl.push_back(buffer);
}
auto find_value = [&buffer](const char* v){ return strcmp(v, buffer)==0; };
auto find_value = [&buffer](const char* v) { return strcmp(v, buffer) == 0; };
// delete random elements.
for(unsigned u=0; u<NumberOfElements; ++u)
{
EXPECT_EQ(sl.size(), NumberOfElements-u);
snprintf(buffer, 15, "k%u", (u*7) % NumberOfElements); // permutate keys order
auto q = std::find_if( sl.begin(), sl.end(), find_value );
ASSERT_NE( q, sl.end() ); // element with key is found
EXPECT_STREQ( *q, buffer);
for (unsigned u = 0; u < NumberOfElements; ++u) {
EXPECT_EQ(sl.size(), NumberOfElements - u);
snprintf(buffer, 15, "k%u", (u * 7) % NumberOfElements); // permutate keys order
auto q = std::find_if(sl.begin(), sl.end(), find_value);
ASSERT_NE(q, sl.end()); // element with key is found
EXPECT_STREQ(*q, buffer);
sl.erase(q);
q = std::find_if( sl.begin(), sl.end(), find_value );
EXPECT_EQ( q, sl.end() ); // element with that key is no longer found
q = std::find_if(sl.begin(), sl.end(), find_value);
EXPECT_EQ(q, sl.end()); // element with that key is no longer found
}
}

60
test/unittest_stringpair.cc

@ -5,62 +5,60 @@
typedef pEp::StringPair SP;
TEST( StringPair, Simple )
TEST(StringPair, Simple)
{
pEp::StringPair s1{"key", "value"};
pEp::StringPair s1{ "key", "value" };
pEp::StringPairList spl;
EXPECT_TRUE(spl.empty());
EXPECT_EQ(spl.size(), 0);
// pEp::StringPair s2{ std::string{"key2"}, std::string{"value"} };
// pEp::StringPair s2{ std::string{"key2"}, std::string{"value"} };
}
TEST( StringPair, InitList )
TEST(StringPair, InitList)
{
const std::initializer_list<pEp::StringPair> il{ SP{"key0", "value0"}, SP{"key1", "value1"} };
pEp::StringPairList spl( il );
EXPECT_EQ( spl.size(), 2);
const std::initializer_list<pEp::StringPair> il{ SP{ "key0", "value0" }, SP{ "key1", "value1" } };
pEp::StringPairList spl(il);
EXPECT_EQ(spl.size(), 2);
spl.clear();
EXPECT_EQ(spl.size(), 0);
EXPECT_TRUE( spl.empty() );
EXPECT_TRUE(spl.empty());
}
TEST( StringPair, Dynamic )
TEST(StringPair, Dynamic)
{
static const unsigned NumberOfElements = 17;
char key[16];
char value[16];
pEp::StringPairList spl;
EXPECT_EQ(spl.size(), 0);
EXPECT_TRUE( spl.empty() );
for(unsigned u=0; u<NumberOfElements; ++u)
{
EXPECT_TRUE(spl.empty());
for (unsigned u = 0; u < NumberOfElements; ++u) {
EXPECT_EQ(spl.size(), u);
snprintf(key, 15, "k%u", u);
snprintf(value, 15, "v%u", u*91);
spl.push_back( pEp::StringPair{key, value} );
snprintf(value, 15, "v%u", u * 91);
spl.push_back(pEp::StringPair{ key, value });
}
auto find_by_key = [&key](const ::stringpair_t* sp){ return strcmp(sp->key, key)==0; };
auto find_by_key = [&key](const ::stringpair_t* sp) { return strcmp(sp->key, key) == 0; };
// delete random elements.
for(unsigned u=0; u<NumberOfElements; ++u)
{
EXPECT_EQ(spl.size(), NumberOfElements-u);
snprintf(key, 15, "k%u", (u*7) % NumberOfElements); // permutate keys order
auto q = std::find_if( spl.begin(), spl.end(), find_by_key );
ASSERT_NE( q, spl.end() ); // element with key is found
EXPECT_STREQ( q->key, key);
for (unsigned u = 0; u < NumberOfElements; ++u) {
EXPECT_EQ(spl.size(), NumberOfElements - u);
snprintf(key, 15, "k%u", (u * 7) % NumberOfElements); // permutate keys order
auto q = std::find_if(spl.begin(), spl.end(), find_by_key);
ASSERT_NE(q, spl.end()); // element with key is found
EXPECT_STREQ(q->key, key);
spl.erase(q);
q = std::find_if( spl.begin(), spl.end(), find_by_key );
EXPECT_EQ( q, spl.end() ); // element with that key is no longer found
q = std::find_if(spl.begin(), spl.end(), find_by_key);
EXPECT_EQ(q, spl.end()); // element with that key is no longer found
}
}

Loading…
Cancel
Save