360 lines
13 KiB
C++
360 lines
13 KiB
C++
#include "rexy/string.hpp"
|
|
#include "rexy/allocator.hpp"
|
|
|
|
#include <cstdlib>
|
|
#include <cstdio>
|
|
#include <cstring>
|
|
#include <utility>
|
|
#include <new>
|
|
|
|
[[noreturn]] void error(const char* str){
|
|
fprintf(stderr, "%s", str);
|
|
exit(1);
|
|
}
|
|
|
|
using namespace rexy::str_literals;
|
|
|
|
using test_str = rexy::basic_string<char,rexy::allocator<char>>;
|
|
|
|
void check_empty_construction(){
|
|
test_str str1;
|
|
if(str1.length() != 0)
|
|
error("length() should return 0 on default init\n");
|
|
if(test_str::uses_sso()){
|
|
if(str1.data()[0] != 0)
|
|
error("data() should return an empty, zero length string\n");
|
|
}else{
|
|
if(str1.data() != nullptr)
|
|
error("data() should return a null string\n");
|
|
}
|
|
if(str1.valid())
|
|
error("valid() should return false on empty string\n");
|
|
if(str1.data() != str1.c_str())
|
|
error("c_str() should be a synonymn of data()\n");
|
|
|
|
test_str str2(str1);
|
|
if(str2.length() != str1.length())
|
|
error("copy construction on empty string should give equivalent length()\n");
|
|
if(str2.capacity() != str1.capacity())
|
|
error("copy construction on empty string should give equivalent capacity()\n");
|
|
if(test_str::uses_sso()){
|
|
if(str2.data()[0] != str1.data()[0])
|
|
error("copy construction on empty string should give equivalent data()\n");
|
|
}else{
|
|
if(str2.data() != str1.data())
|
|
error("copy construction on empty string should give equivalent data()\n");
|
|
}
|
|
|
|
test_str str3(std::move(str2));
|
|
if(str3.length() != str1.length())
|
|
error("move construction on empty string should give equivalent length()\n");
|
|
if(str3.capacity() != str1.capacity())
|
|
error("move construction on empty string should give equivalent capacity()\n");
|
|
if(test_str::uses_sso()){
|
|
if(str3.data()[0] != str1.data()[0])
|
|
error("move construction on empty string should give equivalent data()\n");
|
|
}else{
|
|
if(str3.data() != str1.data())
|
|
error("move construction on empty string should give equivalent data()\n");
|
|
}
|
|
}
|
|
|
|
void check_short_construction(){
|
|
if(!test_str::uses_sso())
|
|
return;
|
|
|
|
test_str::size_type cap = test_str::short_string_size();
|
|
test_str str1("a");
|
|
if(str1.length() != 1)
|
|
error("short constructed string 'a' should be length() == 1\n");
|
|
if(str1.capacity() != cap)
|
|
error("short constructed string 'a' should be capacity() == short_string_size()\n");
|
|
if(strcmp(str1.data(), "a"))
|
|
error("short constructed string 'a' should be !strcmp(data(), \"a\")\n");
|
|
|
|
test_str str2(str1);
|
|
if(str2.length() != str1.length())
|
|
error("short copy constructed string should have equal length()\n");
|
|
if(str2.capacity() != str1.capacity())
|
|
error("short copy constructed string should have equal capacity()\n");
|
|
if(strcmp(str2.data(), str1.data()))
|
|
error("short copy constructed string should have equivalent data()\n");
|
|
|
|
test_str str3(std::move(str2));
|
|
if(str3.length() != str1.length())
|
|
error("short move constructed string should have equal length()\n");
|
|
if(str3.capacity() != str1.capacity())
|
|
error("short move constructed string should have equal capacity()\n");
|
|
if(strcmp(str3.data(), str1.data()))
|
|
error("short move constructed string should have equivalent data()\n");
|
|
}
|
|
void check_long_construction(){
|
|
const char* data = "this is a really long string that should ensure that it makes a dynamic allocation even if it has a big buffer.";
|
|
std::size_t len = strlen(data);
|
|
test_str str1(data);
|
|
if(str1.length() != len)
|
|
error("long constructed string should be length() == strlen(data)\n");
|
|
if(str1.capacity() < len)
|
|
error("long constructed string should be capacity() >= strlen(data)\n");
|
|
if(strcmp(str1.data(), data))
|
|
error("long constructed string should be !strcmp(data(), data)\n");
|
|
|
|
test_str str2(str1);
|
|
if(str2.length() != str1.length())
|
|
error("long copy constructed string should have equal length()\n");
|
|
if(str2.capacity() != str1.capacity())
|
|
error("long copy constructed string should have equal capacity()\n");
|
|
if(strcmp(str2.data(), str1.data()))
|
|
error("long copy constructed string should have equivalent data()\n");
|
|
|
|
test_str str3(std::move(str2));
|
|
if(str3.length() != str1.length())
|
|
error("long move constructed string should have equal length()\n");
|
|
if(str3.capacity() != str1.capacity())
|
|
error("long move constructed string should have equal capacity()\n");
|
|
if(strcmp(str3.data(), str1.data()))
|
|
error("long move constructed string should have equivalent data()\n");
|
|
}
|
|
void check_short_assignment(){
|
|
if(!test_str::uses_sso())
|
|
return;
|
|
|
|
const char* longstartdata = "this is another really long string that should ensure that it makes some sort of dyn alloc for big buf";
|
|
|
|
test_str::size_type cap = test_str::short_string_size();
|
|
test_str str1("zy");
|
|
str1 = "a";
|
|
if(str1.length() != 1)
|
|
error("short assigned string 'a' should be length() == 1\n");
|
|
if(str1.capacity() != cap)
|
|
error("short assigned string 'a' should be capacity() == short_string_size()\n");
|
|
if(strcmp(str1.data(), "a"))
|
|
error("short assigned string 'a' should be !strcmp(data(), \"a\")\n");
|
|
|
|
test_str str2("ba");
|
|
str2 = str1;
|
|
if(str2.length() != str1.length())
|
|
error("short copy assigned string should have equal length()\n");
|
|
if(str2.capacity() != str1.capacity())
|
|
error("short copy assigned string should have equal capacity()\n");
|
|
if(strcmp(str2.data(), str1.data()))
|
|
error("short copy assigned string should have equivalent data()\n");
|
|
|
|
test_str str3("cb");
|
|
str3 = std::move(str2);
|
|
if(str3.length() != str1.length())
|
|
error("short move assigned string should have equal length()\n");
|
|
if(str3.capacity() != str1.capacity())
|
|
error("short move assigned string should have equal capacity()\n");
|
|
if(strcmp(str3.data(), str1.data()))
|
|
error("short move assigned string should have equivalent data()\n");
|
|
|
|
test_str str4(longstartdata);
|
|
str4 = str1;
|
|
if(str4.length() != str1.length())
|
|
error("long->short copy assigned string should have equal length()\n");
|
|
if(str4.capacity() < str1.capacity())
|
|
error("long->short copy assigned string should have equal or greater capacity()\n");
|
|
if(strcmp(str4.data(), str1.data()))
|
|
error("long->short copy assigned string should have equivalent data()\n");
|
|
|
|
test_str str5(longstartdata);
|
|
str5 = std::move(str4);
|
|
if(str5.length() != str1.length())
|
|
error("long->short move assigned string should have equal length()\n");
|
|
if(str5.capacity() < str1.capacity())
|
|
error("long->short move assigned string should have equal or greater capacity()\n");
|
|
if(strcmp(str5.data(), str1.data()))
|
|
error("long->short move assigned string should have equivalent data()\n");
|
|
}
|
|
void check_long_assignment(){
|
|
const char* startdata1 = "this is another really long string that should ensure that it makes some sort of dyn alloc for big buf";
|
|
const char* startdata2 = "zy";
|
|
const char* data = "this is a really long string that should ensure that it makes a dynamic allocation even if it has a big buffer.";
|
|
std::size_t len = strlen(data);
|
|
test_str str1(startdata1);
|
|
str1 = data;
|
|
if(str1.length() != len)
|
|
error("long assigned string should be length() == strlen(data)\n");
|
|
if(str1.capacity() < len)
|
|
error("long assigned string should be capacity() >= strlen(data)\n");
|
|
if(strcmp(str1.data(), data))
|
|
error("long assigned string should be !strcmp(data(), data)\n");
|
|
|
|
test_str str2(startdata1);
|
|
str2 = str1;
|
|
if(str2.length() != str1.length())
|
|
error("long copy assigned string should have equal length()\n");
|
|
if(str2.capacity() != str1.capacity())
|
|
error("long copy assigned string should have equal capacity()\n");
|
|
if(strcmp(str2.data(), str1.data()))
|
|
error("long copy assigned string should have equivalent data()\n");
|
|
|
|
test_str str3(startdata1);
|
|
str3 = std::move(str2);
|
|
if(str3.length() != str1.length())
|
|
error("long move assigned string should have equal length()\n");
|
|
if(str3.capacity() != str1.capacity())
|
|
error("long move assigned string should have equal capacity()\n");
|
|
if(strcmp(str3.data(), str1.data()))
|
|
error("long move assigned string should have equivalent data()\n");
|
|
|
|
test_str str4(startdata2);
|
|
str4 = str1;
|
|
if(str4.length() != str1.length())
|
|
error("short->long copy assigned string should have equal length()\n");
|
|
if(str4.capacity() != str1.capacity())
|
|
error("short->long copy assigned string should have equal capacity()\n");
|
|
if(strcmp(str4.data(), str1.data()))
|
|
error("short->long copy assigned string should have equivalent data()\n");
|
|
|
|
test_str str5(startdata2);
|
|
str5 = std::move(str4);
|
|
if(str5.length() != str1.length())
|
|
error("short->long move assigned string should have equal length()\n");
|
|
if(str5.capacity() != str1.capacity())
|
|
error("short->long move assigned string should have equal capacity()\n");
|
|
if(strcmp(str5.data(), str1.data()))
|
|
error("short->long move assigned string should have equivalent data()\n");
|
|
}
|
|
void check_short_append(){
|
|
test_str str1;
|
|
test_str str2("bc");
|
|
test_str str3("really long string that should trigger a short to long conversion in the string");
|
|
str1.append("a");
|
|
str1.append("b");
|
|
str1.append(str2);
|
|
if(strcmp(str1.data(), "abbc"))
|
|
error("short append should have resulted in abbc\n");
|
|
str1.append(str3);
|
|
if(strcmp(str1.c_str(), "abbcreally long string that should trigger a short to long conversion in the string"))
|
|
error("short->long append should have resulted in abbcreally long string that should trigger a short to long conversion in the string\n");
|
|
}
|
|
void check_long_append(){
|
|
const char* startdata1 = "this is another really long string that should ensure that it makes some sort of dyn alloc for big buf";
|
|
const char* appendeddata = "this is another really long string that should ensure that it makes some sort of dyn alloc for big bufstuff";
|
|
test_str str1(startdata1);
|
|
str1.append("stuff");
|
|
if(strcmp(str1.c_str(), appendeddata))
|
|
error("long append should have resulted in this is another really long string that should ensure that it makes some sort of dyn alloc for big bufstuff\n");
|
|
}
|
|
void check_substring(){
|
|
rexy::string test = "this is a test string";
|
|
rexy::string test2 = test.substring(5, 7);
|
|
if(strcmp(test2.c_str(), "is") || test2.length() != 2)
|
|
error("substring operation should have resulted in 'is'\n");
|
|
}
|
|
void check_string_search(){
|
|
rexy::string test1 = "this is a test string";
|
|
rexy::string_view test2 = "string";
|
|
auto res = test1.search(test2);
|
|
if(test1.begin() + 15 != res){
|
|
error("string search operation 1 did not result in a correct result\n");
|
|
}
|
|
|
|
test1 = "this string has multiple strings of the word string in it";
|
|
res = test1.search(test2);
|
|
if(test1.begin() + 5 != res){
|
|
error("string search operation 2 did not result in a correct result\n");
|
|
}
|
|
|
|
res = test1.rsearch(test2);
|
|
if(test1.begin() + 45 != res){
|
|
error("string search operation 3 did not result in a correct result\n");
|
|
}
|
|
|
|
}
|
|
|
|
void check_string_insert(){
|
|
rexy::string test = "this is a string";
|
|
auto it = test.search("string");
|
|
if(it == test.end()){
|
|
error("string search failed\n");
|
|
}
|
|
test.insert(it - test.begin(), "test ", 5);
|
|
if(test != "this is a test string" || test.length() != 21){
|
|
error("string insert operation failed\n");
|
|
}
|
|
test.insert(0, "wow ");
|
|
if(test != "wow this is a test string" || test.length() != 25){
|
|
error("string insert operation 2 failed\n");
|
|
}
|
|
test.insert(test.length(), " oof");
|
|
if(test != "wow this is a test string oof" || test.length() != 29){
|
|
error("string insert operation 3 failed\n");
|
|
}
|
|
}
|
|
|
|
void check_string_erase(){
|
|
rexy::string test = "this is a test string";
|
|
test.erase(0, 5);
|
|
if(test != "is a test string" || test.length() != 16){
|
|
error("string erase operation 1 did not result in a correct result\n");
|
|
}
|
|
test.erase(5, 5);
|
|
if(test != "is a string" || test.length() != 11){
|
|
error("string erase operation 2 did not result in a correct result\n");
|
|
}
|
|
test.erase(9, 2);
|
|
if(test != "is a stri" || test.length() != 9){
|
|
error("string erase operation 3 did not result in a correct result\n");
|
|
}
|
|
test.erase(8, 2);
|
|
if(test != "is a str" || test.length() != 8){
|
|
error("string erase operation 4 did not result in a correct result\n");
|
|
}
|
|
test.pop_back();
|
|
if(test != "is a st" || test.length() != 7){
|
|
error("string erase operation 5 did not result in a correct result\n");
|
|
}
|
|
}
|
|
|
|
void check_string_replace(){
|
|
rexy::string test = "test string";
|
|
test.replace(0, 4, "yolo");
|
|
if(test != "yolo string"){
|
|
error("string replace operation 1 did not result in a correct result\n");
|
|
}
|
|
|
|
test = "this is a long string version"_sv;
|
|
auto it = test.search("long"_sv);
|
|
if(it == test.end()){
|
|
error("string search failed in replace test\n");
|
|
}
|
|
test.replace(it, it+4, "thic");
|
|
if(test != "this is a thic string version"){
|
|
error("string replace operation 2 did not result in a correct result\n");
|
|
}
|
|
|
|
test.replace(test.end() - 7, test.end(), "vrisiod");
|
|
if(test != "this is a thic string vrisiod"){
|
|
error("string replace operation 3 did not result in a correct result\n");
|
|
}
|
|
|
|
test.replace(test.begin(), test.end(), "change");
|
|
if(test != "changes a thic string vrisiod"){
|
|
error("string replace operation 4 did not result in a correct result\n");
|
|
}
|
|
test = "short"_sv;
|
|
|
|
test.replace(test.begin(), test.end(), "a longer string");
|
|
if(test != "a lon"){
|
|
error("string replace operation 5 did not result in a correct result\n");
|
|
}
|
|
}
|
|
|
|
int main(){
|
|
check_empty_construction();
|
|
check_short_construction();
|
|
check_long_construction();
|
|
check_short_assignment();
|
|
check_long_assignment();
|
|
check_short_append();
|
|
check_long_append();
|
|
check_substring();
|
|
check_string_search();
|
|
check_string_insert();
|
|
check_string_erase();
|
|
check_string_replace();
|
|
}
|