// Copyright (c) 2001 - 2025 kio@little-bat.de
// BSD-2-Clause license
// https://opensource.org/licenses/BSD-2-Clause


#define loglevel 1
#include "String.h"
#include "doctest/doctest/doctest.h"
#include "kio/kio.h"


#define RMASK(n) (~(0xFFFFFFFF << (n))) // mask to select n bits from the right (BUMMER: max. 31!!)
static uint random(uint n) { return (uint32(n) * uint16(random())) >> 16; } // 16 bit random number in range [0 ... [n


TEST_CASE("String")
{
	SUBCASE("") { logline("●●● %s:", __FILE__); }

	SUBCASE("~String()")
	{
		String a, b(33), c(40, csz4), d(50, ' ');
		String e(c, 13, 33), f(e);
		String viele[500];
		String g(viele[123]);
	}

	SUBCASE("String()")
	{
		String s;
		CHECK_FALSE(s.Len() != 0);
		CHECK_FALSE(s.Csz() != 1);
		CHECK_FALSE(s.NotWritable());
	}

	SUBCASE("String(UCS4Char)")
	{
		String a('a');
		CHECK_FALSE(a.Csz() != 1);
		CHECK_FALSE(a.Len() != 1);
		CHECK_FALSE(a[0] != 'a');
		//CHECK_FALSE( a.NotWritable() );
		for (uint i = 0; i < 256; i++)
		{
			String b(i);
			CHECK_FALSE(b.Csz() != 1);
			CHECK_FALSE(b.Len() != 1);
			CHECK_FALSE(b[0] != i);
			//CHECK_FALSE( b.NotWritable() );
		}

		a = String(300);
		CHECK_FALSE(a.Csz() != 2);
		CHECK_FALSE(a.Len() != 1);
		CHECK_FALSE(a[0] != 300);
		//CHECK_FALSE( a.NotWritable() );
		for (uint i = 256; i < 0x10000; i += 17)
		{
			String b(i);
			CHECK_FALSE(b.Csz() != 2);
			CHECK_FALSE(b.Len() != 1);
			CHECK_FALSE(b[0] != i);
			//CHECK_FALSE( b.NotWritable() );
		}

		a = String(0x10030);
		CHECK_FALSE(a.Csz() != 4);
		CHECK_FALSE(a.Len() != 1);
		CHECK_FALSE(a[0] != 0x10030);
		//CHECK_FALSE( a.NotWritable() );
		for (ucs4char i = 0x10000; i < 0xF0000000; i += i / 2001)
		{
			String b(i);
			CHECK_FALSE(b.Csz() != 4);
			CHECK_FALSE(b.Len() != 1);
			CHECK_FALSE(b[0] != i);
			//CHECK_FALSE( b.NotWritable() );
		}
	}

	SUBCASE("String(cUCS1CharPtr,long)")
	{
		ucs1char c[] = {'a', 'n', 't', 'o', 'n', 'x', 'x'};
		String	 s(c, 5);
		CHECK_FALSE(s.Len() != 5);
		CHECK_FALSE(s.Csz() != 1);
		CHECK_FALSE(s.NotWritable());
		for (int i = 0; i < 5; i++) CHECK_FALSE(s.UCS1Text()[i] != c[i]);

		s = String(c, 0);
		CHECK_FALSE(s.Len() != 0);
		CHECK_FALSE(s.Csz() != 1);
		CHECK_FALSE(s.NotWritable());
	}

	SUBCASE("String(cUCS2CharPtr,long)")
	{
		ucs2char c[] = {'a', 'n', 't', 'o', 'n', 'x', 'x'};
		String	 s(c, 5);
		CHECK_FALSE(s.Len() != 5);
		CHECK_FALSE(s.Csz() != 2);
		CHECK_FALSE(s.NotWritable());
		for (int i = 0; i < 5; i++) CHECK_FALSE(s.UCS2Text()[i] != c[i]);

		s = String(c, 0);
		CHECK_FALSE(s.Len() != 0);
		CHECK_FALSE(s.Csz() != 1);
		CHECK_FALSE(s.NotWritable());
	}

	SUBCASE("String(cUCS4CharPtr,long)")
	{
		ucs4char c[] = {'a', 'n', 't', 'o', 'n', 'x', 'x'};
		String	 s(c, 5);
		CHECK_FALSE(s.Len() != 5);
		CHECK_FALSE(s.Csz() != 4);
		CHECK_FALSE(s.NotWritable());
		for (int i = 0; i < 5; i++) CHECK_FALSE(s.UCS4Text()[i] != c[i]);

		s = String(c, 0);
		CHECK_FALSE(s.Len() != 0);
		CHECK_FALSE(s.Csz() != 1);
		CHECK_FALSE(s.NotWritable());
	}

	SUBCASE("String(cUTF8CharPtr,long)")
	{
		cstr   c = {"antonxx"};
		String s(c, 5);
		CHECK_FALSE(s.Len() != 5);
		CHECK_FALSE(s.Csz() != 1);
		CHECK_FALSE(s.NotWritable());
		for (int i = 0; i < s.Len(); i++) CHECK_FALSE(s[i] != ucs1char("anton"[i]));

		ucs2char c3[] = {'a', 'n', 't', 0xf6, 'n', 'z', 'x'};
		s			  = String("antönxx", 6);
		CHECK_FALSE(s.Len() != 5);
		CHECK_FALSE(s.Csz() != 1);
		CHECK_FALSE(s.NotWritable());
		for (int i = 0; i < s.Len(); i++) CHECK_FALSE(s[i] != c3[i]);

		ucs2char c5[] = {'a', 'n', 't', 0x160, 'n', 'z', 'x'};
		s			  = String("antŠnxx", 6);
		CHECK_FALSE(s.Len() != 5);
		CHECK_FALSE(s.Csz() != 2);
		CHECK_FALSE(s.NotWritable());
		for (int i = 0; i < s.Len(); i++) CHECK_FALSE(s[i] != c5[i]);

		ucs4char c2[] = {'<', 'a', 'h', 'a', 8226, 8364, '>'};
		s			  = String("<aha•€>", 11);
		CHECK_FALSE(s.Len() != 7);
		CHECK_FALSE(s.Csz() != 2);
		CHECK_FALSE(s.NotWritable());
		for (int i = 0; i < s.Len(); i++) { CHECK_FALSE(s[i] != c2[i]); }

		s = String(c, 0);
		CHECK_FALSE(s.Len() != 0);
		CHECK_FALSE(s.Csz() != 1);
		CHECK_FALSE(s.NotWritable());
	}

	SUBCASE("String(long,CharSize)")
	{
		String s(66, csz1);
		CHECK_FALSE(s.Csz() != 1);
		CHECK_FALSE(s.Len() != 66);
		CHECK_FALSE(s.NotWritable());

		s = String(0, csz1);
		CHECK_FALSE(s.Csz() != 1);
		CHECK_FALSE(s.Len() != 0);
		CHECK_FALSE(s.NotWritable());

		s = String(77, csz2);
		CHECK_FALSE(s.Csz() != 2);
		CHECK_FALSE(s.Len() != 77);
		CHECK_FALSE(s.NotWritable());

		s = String(0, csz2);
		CHECK_FALSE(s.Csz() != 1);
		CHECK_FALSE(s.Len() != 0);
		CHECK_FALSE(s.NotWritable());

		s = String(33, csz4);
		CHECK_FALSE(s.Csz() != 4);
		CHECK_FALSE(s.Len() != 33);
		CHECK_FALSE(s.NotWritable());

		s = String(0, csz4);
		CHECK_FALSE(s.Csz() != 1);
		CHECK_FALSE(s.Len() != 0);
		CHECK_FALSE(s.NotWritable());
	}

	SUBCASE("String(long,UCS4Char)")
	{
		CHECK_FALSE(String(7, 'a') != "aaaaaaa");
		CHECK_FALSE(String(int32(0), 's') != emptyString);
		CHECK_FALSE(String(4, 0x160) != "ŠŠŠŠ");
		CHECK_FALSE(String(7, ' ') != "       ");

		String s = String(int32(0), 99999);
		CHECK_FALSE(s.Len() != 0);
		CHECK_FALSE(s.Csz() != 1);
		CHECK_FALSE(s.NotWritable());

		s = String(int32(0), 999);
		CHECK_FALSE(s.Len() != 0);
		CHECK_FALSE(s.Csz() != 1);
		CHECK_FALSE(s.NotWritable());

		s = String(int32(0), 99);
		CHECK_FALSE(s.Len() != 0);
		CHECK_FALSE(s.Csz() != 1);
		CHECK_FALSE(s.NotWritable());

		s = String(9, 'a');
		CHECK_FALSE(s.Len() != 9);
		CHECK_FALSE(s.Csz() != 1);
		CHECK_FALSE(s.NotWritable());
		CHECK_FALSE(s != "aaaaaaaaa");

		s = String(9, 0x160);
		CHECK_FALSE(s.Len() != 9);
		CHECK_FALSE(s.Csz() != 2);
		CHECK_FALSE(s.NotWritable());
		CHECK_FALSE(s != "ŠŠŠŠŠŠŠŠŠ");
	}

	SUBCASE("String(cUTF8Str)")
	{
		String s = String("Trottellumme_0123FF");
		CHECK_FALSE(s.Len() != 19);
		CHECK_FALSE(s.Csz() != 1);
		CHECK_FALSE(s.NotWritable());
		for (int i = 0; i < s.Len(); i++) CHECK_FALSE(s[i] != uint("Trottellumme_0123FF"[i]));

		uchar c[] = {'G', 'r', 0xfc, 0xdf, ' ', 'G', 'o', 't', 't', '!'};
		s		  = String("Grüß Gott!");
		CHECK_FALSE(s.Len() != 10);
		CHECK_FALSE(s.Csz() != 1);
		CHECK_FALSE(s.NotWritable());
		for (int i = 0; i < s.Len(); i++) CHECK_FALSE(s[i] != c[i]);

		s = String("");
		CHECK_FALSE(s.Len() != 0);
		CHECK_FALSE(s.Csz() != 1);
		CHECK_FALSE(s.NotWritable());

		ucs4char c2[] = {'<', 'a', 'h', 'a', 8226, 8364, '>'};
		s			  = String("<aha•€>");
		CHECK_FALSE(s.Len() != 7);
		CHECK_FALSE(s.Csz() != 2);
		CHECK_FALSE(s.NotWritable());
		for (int i = 0; i < s.Len(); i++) { CHECK_FALSE(s[i] != c2[i]); }

		uchar bogus[] = {0x80, 'a', 0x93, 'b', 0xbf, 0xbf, 0xc0, 0xc1, 0xc2, 0x80, 0};
		uchar anton[] = {
			'a', 'b', '?', '?', 0x80,
		};
		s = String(ptr(bogus));
		CHECK_FALSE(s.Len() != 5);
		CHECK_FALSE(s.Csz() != 1);
		CHECK_FALSE(s.NotWritable());
		for (int i = 0; i < s.Len(); i++) { CHECK_FALSE(s[i] != anton[i]); }

		uchar  bummer[] = {0x80, 'a', 0x93, 'b', 0xbf, 0xbf, 0xc0, 0xc1, 0xc2, 0x80, 0xdf, 0xbf, 0};
		ushort anton2[] = {'a', 'b', '?', '?', 0x80, (1 << 11) - 1};
		s				= String(ptr(bummer));
		CHECK_FALSE(s.Len() != 6);
		CHECK_FALSE(s.Csz() != 2);
		CHECK_FALSE(s.NotWritable());
		for (int i = 0; i < s.Len(); i++) { CHECK_FALSE(s[i] != anton2[i]); }
	}

	SUBCASE("String(cString)")
	{
		String s = "test";
		String a(s);
		CHECK_FALSE(s != a);
		CHECK_FALSE(s.IsWritable());
		CHECK_FALSE(a.IsWritable());
		CHECK_FALSE(a.Csz() != 1);
		CHECK_FALSE(a.Len() != 4);
		CHECK_FALSE(a != "test");

		s = String("<aha•€>");
		CHECK_FALSE(a.NotWritable());
		CHECK_FALSE(s.NotWritable());
		String b(s);
		CHECK_FALSE(s != b);
		CHECK_FALSE(s.IsWritable());
		CHECK_FALSE(b.IsWritable());
		CHECK_FALSE(b.Csz() != 2);
		CHECK_FALSE(b.Len() != 7);
		CHECK_FALSE(b != "<aha•€>");
	}

	SUBCASE("String(cString,long,long)")
	{
		CHECK_FALSE(String("Esmeralda", 1, 6) != "smera");
		CHECK_FALSE(String("<aha•€>", 1, 6) != "aha•€");
		CHECK_FALSE(String("Esmeralda", -1, 6) != "Esmera");
		CHECK_FALSE(String("<aha•€>", -111, 6) != "<aha•€");
		CHECK_FALSE(String("Esmeralda", 1, 66) != "smeralda");
		CHECK_FALSE(String("<aha•€>", 1, 66) != "aha•€>");
		CHECK_FALSE(String("Esmeralda", 111, 66) != "");
		CHECK_FALSE(String("Esmeralda", 66, 111) != "");
		CHECK_FALSE(String("Esmeralda", 5, 2) != "");
		CHECK_FALSE(String("Esmeralda", 5, 5) != "");
		CHECK_FALSE(String("Esmeralda", 0, 0) != "");
		CHECK_FALSE(String("Esmeralda", 0, -1) != "");
		CHECK_FALSE(String("Esmeralda", 9, 9) != "");
		CHECK_FALSE(String("Esmeralda", 10, 9) != "");
		CHECK_FALSE(String("Esmeralda", 9, 10) != "");
	}

	SUBCASE("compare(cString)")
	{
		String a[] = {"",	 " ",	"2•",	 "2€", "A",	 "Antimon", "Anton", "Antonov", "a",	   "a ", "aa",
					  "aaa", "aab", "anton", "b",  "b ", "berta",	"cÄsar", "cäsar",	"Äffchen", "•",	 "•2"};
		for (int i = 0; i < int(NELEM(a)); i += 2) a[i] = (SpaceString(i) + a[i]).MidString(i);
		for (int i = 0; i < int(NELEM(a)); i++)
			for (int j = 0; j < int(NELEM(a)); j++) { CHECK_EQ(sign(a[i].compare(a[j])), sign(i - j)); }
	}

	SUBCASE("Truncate(long)")
	{
		String s = "antonov";
		s.Truncate(5);
		CHECK_FALSE(s != "anton");
		s.Truncate(99);
		CHECK_FALSE(s != "anton");
		s.Truncate(0);
		CHECK_FALSE(s != "");
		s = "antonov";
		s.Truncate(-1);
		CHECK_FALSE(s != "");
	}

	SUBCASE("Resize(long,UCS4Char)")
	{
		String s = "antonov";
		s.Resize(5);
		CHECK_FALSE(s != "anton");
		s.Resize(9);
		CHECK_FALSE(s != "anton    ");
		s.Resize(0);
		CHECK_FALSE(s != "");
		s = "antonov";
		s.Resize(-1);
		CHECK_FALSE(s != "");
		s.Resize(10, 'x');
		CHECK_FALSE(s != "xxxxxxxxxx");
		s = "antonov";
		s.Resize(10, 'x');
		CHECK_FALSE(s != "antonovxxx");
		s = "anton";
		s.Resize(6, 8364);
		CHECK_FALSE(s != "anton€");
		s.Resize(10, 'x');
		CHECK_FALSE(s != "anton€xxxx");
	}

	SUBCASE("Len()")
	{
		CHECK_FALSE(SpaceString(0).Len() != 0);
		CHECK_FALSE(SpaceString(1).Len() != 1);
		CHECK_FALSE(SpaceString(55).Len() != 55);
		CHECK_FALSE(SpaceString(999).Len() != 999);
		CHECK_FALSE(String("ö").Len() != 1);
		CHECK_FALSE(String("€").Len() != 1);
		CHECK_FALSE(String("22,--€").Len() != 6);
		CHECK_FALSE(String(0x1010).Len() != 1);
		CHECK_FALSE(String(22, 0x1010).Len() != 22);
		CHECK_FALSE(String(0x10010).Len() != 1);
		CHECK_FALSE(String(22, 0x10010).Len() != 22);
		String s = "xxanton";
		s		 = s.MidString(2);
		CHECK_FALSE(s.Len() != 5);
	}

	SUBCASE("Csz()")
	{
		CHECK_FALSE(String("").Csz() != 1);
		CHECK_FALSE(String("anton").Csz() != 1);
		CHECK_FALSE(String("Äffe").Csz() != 1);
		CHECK_FALSE(String("€").Csz() != 2);
		CHECK_FALSE(String("33,€").Csz() != 2);
		CHECK_FALSE(String(0x1010).Csz() != 2);
		CHECK_FALSE(String(77, 0x1010).Csz() != 2);
		CHECK_FALSE(String(0x10010).Csz() != 4);
		CHECK_FALSE(String(77, 0x10010).Csz() != 4);
	}

	SUBCASE("operator[](long)")
	{
		String s = "antonov";
		CHECK_FALSE(s[0] != 'a');
		CHECK_FALSE(s[1] != 'n');
		CHECK_FALSE(s[s.Len() - 1] != 'v');
		s = "antonov€ic";
		CHECK_FALSE(s[0] != 'a');
		CHECK_FALSE(s[1] != 'n');
		CHECK_FALSE(s[7] != 8364);
		CHECK_FALSE(s[s.Len() - 1] != 'c');
		s += String(0x101010);
		CHECK_FALSE(s[s.Len() - 1] != 0x101010);
		CHECK_FALSE(s[0] != 'a');
		CHECK_FALSE(s[1] != 'n');
		CHECK_FALSE(s[7] != 8364);
		s = s.MidString(2);
		CHECK_FALSE(s[0] != 't');
		CHECK_FALSE(s[1] != 'o');
		CHECK_FALSE(s[5] != 8364);
		s = "anton_0815";
		s = s.MidString(2);
		CHECK_FALSE(s[0] != 't');
		CHECK_FALSE(s[7] != '5');
		s = "ant€n_0815";
		s = s.MidString(2);
		CHECK_FALSE(s[0] != 't');
		CHECK_FALSE(s[7] != '5');
	}

	SUBCASE("UCS1Text()")
	{
		String s = "xxanton";
		CHECK_FALSE(String(s.UCS1Text() + 2, 5) != "anton");
		s = s.MidString(2);
		CHECK_FALSE(String(s.UCS1Text() + 0, 5) != "anton");
	}

	SUBCASE("UCS2Text()")
	{
		String s = "x€anton";
		CHECK_FALSE(String(s.UCS2Text() + 2, 5) != "anton");
		s = s.MidString(2);
		CHECK_FALSE(String(s.UCS2Text() + 0, 5) != "anton");
	}

	SUBCASE("UCS4Text()")
	{
		String s = String(0x101010) + "€anton";
		CHECK_FALSE(String(s.UCS4Text() + 2, 5) != "anton");
		s = s.MidString(2);
		CHECK_FALSE(String(s.UCS4Text() + 0, 5) != "anton");
	}

	SUBCASE("Text()")
	{
		String s = "xxanton";
		CHECK_FALSE(s.Text() != ptr(s.UCS1Text()));
		s = "x€anton";
		CHECK_FALSE(s.Text() != ptr(s.UCS2Text()));
		s = String(0x101010) + "€anton";
		CHECK_FALSE(s.Text() != ptr(s.UCS4Text()));
	}

	SUBCASE("IsWritable()")
	{
		String s = String(55, csz1);
		CHECK_FALSE(!s.IsWritable());
		s = String(55, csz2);
		CHECK_FALSE(!s.IsWritable());
		s = String(55, csz4);
		CHECK_FALSE(!s.IsWritable());
		String z(s);
		CHECK_FALSE(s.IsWritable());
		CHECK_FALSE(z.IsWritable());
		z = "";
		CHECK_FALSE(!s.IsWritable());
		CHECK_FALSE(!z.IsWritable());
		z = s.SubString(3, 5);
		CHECK_FALSE(s.IsWritable());
		CHECK_FALSE(z.IsWritable());
	}


	SUBCASE("NotWritable()")
	{
		String s = String(55, csz1);
		CHECK_FALSE(s.NotWritable());
		s = String(55, csz2);
		CHECK_FALSE(s.NotWritable());
		s = String(55, csz4);
		CHECK_FALSE(s.NotWritable());
		String z(s);
		CHECK_FALSE(!s.NotWritable());
		CHECK_FALSE(!z.NotWritable());
		z = "";
		CHECK_FALSE(s.NotWritable());
		CHECK_FALSE(z.NotWritable());
		z = s.SubString(3, 5);
		CHECK_FALSE(!s.NotWritable());
		CHECK_FALSE(!z.NotWritable());
	}

	SUBCASE("MakeWritable()")
	{
		String s = "anton";
		s.MakeWritable();
		CHECK_FALSE(s.NotWritable());
		CHECK_FALSE(s != "anton");
		String z(s);
		z.MakeWritable();
		CHECK_FALSE(z.NotWritable());
		CHECK_FALSE(z != "anton");
		CHECK_FALSE(s.NotWritable());
		CHECK_FALSE(s != "anton");
		z.UCS1Text()[0] = 'A';
		CHECK_FALSE(s != "anton");
		CHECK_FALSE(z != "Anton");
	}

	SUBCASE("SubString(long,long)")
	{
		String s = "anton";
		CHECK_FALSE(s.SubString(0, s.Len()) != s);
		CHECK_FALSE(s.SubString(0, 3) != "ant");
		CHECK_FALSE(s.SubString(1, 3) != "nt");
		CHECK_FALSE(s.SubString(1, 8) != "nton");
		CHECK_FALSE(s.SubString(1, 5) != "nton");
		CHECK_FALSE(s.SubString(-1, 3) != "ant");
		CHECK_FALSE(s.SubString(3, 1) != "");
		CHECK_FALSE(s.SubString(1, 1) != "");
		CHECK_FALSE(s.SubString(8, 8) != "");
	}

	SUBCASE("MidString(long,long)")
	{
		String s = "anton";
		CHECK_FALSE(s.MidString(0, s.Len()) != s);
		CHECK_FALSE(s.MidString(0, 3) != "ant");
		CHECK_FALSE(s.MidString(1, 2) != "nt");
		CHECK_FALSE(s.MidString(1, 7) != "nton");
		CHECK_FALSE(s.MidString(1, 4) != "nton");
		CHECK_FALSE(s.MidString(-1, 4) != "ant");
		CHECK_FALSE(s.MidString(3, -2) != "");
		CHECK_FALSE(s.MidString(1, 0) != "");
		CHECK_FALSE(s.MidString(8, 0) != "");
		SpaceString(33, 33);
	}

	SUBCASE("MidString(long)")
	{
		String s = "anton";
		CHECK_FALSE(s.MidString(0) != s);
		CHECK_FALSE(s.MidString(-1) != s);
		CHECK_FALSE(s.MidString(1) != "nton");
		CHECK_FALSE(s.MidString(-1) != s);
		CHECK_FALSE(s.MidString(4) != "n");
		CHECK_FALSE(s.MidString(5) != "");
	}

	SUBCASE("LeftString(long)")
	{
		String s = "anton";
		CHECK_FALSE(s.LeftString(s.Len()) != s);
		CHECK_FALSE(s.LeftString(3) != "ant");
		CHECK_FALSE(s.LeftString(0) != "");
		CHECK_FALSE(s.LeftString(8) != "anton");
		CHECK_FALSE(s.LeftString(-1) != "");
	}

	SUBCASE("RightString(long)")
	{
		String s = "anton";
		CHECK_FALSE(s.RightString(s.Len()) != s);
		CHECK_FALSE(s.RightString(3) != "ton");
		CHECK_FALSE(s.RightString(0) != "");
		CHECK_FALSE(s.RightString(8) != "anton");
		CHECK_FALSE(s.RightString(-1) != "");
	}

	SUBCASE("operator=(cString)")
	{
		String s = "anton";
		CHECK_FALSE(s != "anton");
		CHECK_FALSE(s.NotWritable());
		String z = s;
		CHECK_FALSE(s.IsWritable());
		CHECK_FALSE(z.IsWritable());
		CHECK_FALSE(s != "anton");
		CHECK_FALSE(z != "anton");
		s = "";
		CHECK_FALSE(s != "");
		s = "€";
		CHECK_FALSE(s != "€");
	}

	SUBCASE("operator+(cString)")
	{
		String s = "anto";
		CHECK_FALSE(s + "" != s);
		s = "antonov";
		CHECK_FALSE(s + "" != s);
		s = "anton";
		CHECK_FALSE(s + "" != s);
		CHECK_FALSE(String("") + s != s);
		CHECK_FALSE(String("") + s != s);
		CHECK_FALSE(s + s != "antonanton");
		CHECK_FALSE(s + String("xyz") != "antonxyz");
		CHECK_FALSE(s + "xyz" != "antonxyz");
		CHECK_FALSE(String("") + "" != "");
		s = s + "xyz";
		s = s.LeftString(5) + s.RightString(3);
		CHECK_FALSE(s != "antonxyz");
		s = s.RightString(3) + s.LeftString(5);
		CHECK_FALSE(s != "xyzanton");
		s = s.RightString(5) + "x€z";
		s = s.LeftString(5) + s.RightString(3);
		CHECK_FALSE(s != "antonx€z");
		s = s.RightString(3) + s.LeftString(5);
		CHECK_FALSE(s != "x€zanton");
	}

	SUBCASE("operator+=(cString)")
	{
		String s = "";
		CHECK_FALSE((s += "") != "");
		CHECK_FALSE(s != "");
		CHECK_FALSE((s += "anton") != "anton");
		CHECK_FALSE(s != "anton");
		CHECK_FALSE((s += "bert") != "antonbert");
		CHECK_FALSE(s != "antonbert");
		CHECK_FALSE((s += "") != "antonbert");
		CHECK_FALSE(s != "antonbert");
		s = s.MidString(5);
		s += "xyz";
		CHECK_FALSE(s != "bertxyz");
		s += s.RightString(4);
		CHECK_FALSE(s != "bertxyztxyz");
		s = s.RightString(3);
		s += "ant€n";
		CHECK_FALSE(s != "xyzant€n");
		s += s.RightString(5);
		CHECK_FALSE(s != "xyzant€nant€n");
	}

	SUBCASE("operator*(long)")
	{
		String s = "";
		CHECK_FALSE(s * 0 != "");
		CHECK_FALSE(s * 1 != "");
		CHECK_FALSE(s * 5 != "");
		CHECK_FALSE(s * -5 != "");
		s = "X";
		CHECK_FALSE(s * 0 != "");
		CHECK_FALSE(s * 1 != "X");
		CHECK_FALSE(s * 5 != "XXXXX");
		CHECK_FALSE(s * -5 != "");
		s = "anton";
		CHECK_FALSE(s * 0 != "");
		CHECK_FALSE(s * 1 != "anton");
		CHECK_FALSE(s * 5 != "antonantonantonantonanton");
		CHECK_FALSE(s * -5 != "");
		s = s.RightString(3);
		CHECK_FALSE(s * 5 != "tontontontonton");
	}

	SUBCASE("operator*=(long)")
	{
		String s = "anton";
		CHECK_FALSE((s *= 3) != "antonantonanton");
		CHECK_FALSE(s != "antonantonanton");
		s = "";
		CHECK_FALSE((s *= 3) != "");
		CHECK_FALSE(s != "");
		s = "anton";
		CHECK_FALSE((s *= 1) != "anton");
		CHECK_FALSE(s != "anton");
		s = "anton";
		CHECK_FALSE((s *= 0) != "");
		CHECK_FALSE(s != "");
		s = "beton";
		s = s.RightString(3);
		s *= 5;
		CHECK_FALSE(s != "tontontontonton");
	}

	SUBCASE("operator==(cString)") // uses compare(cString) --> only basic tests here
	{
		CHECK_FALSE(String("a") == "b");
		CHECK_FALSE(String("b") == "a");
		assert(String("a") == "a");
	}

	SUBCASE("operator!=(cString)") // uses compare(cString) --> only basic tests here
	{
		assert(String("a") != "b");
		assert(String("b") != "a");
		CHECK_FALSE(String("a") != "a");
	}

	SUBCASE("operator<(cString)") // uses compare(cString) --> only basic tests here
	{
		assert(String("a") < "b");
		CHECK_FALSE(String("b") < "a");
		CHECK_FALSE(String("a") < "a");
	}

	SUBCASE("operator>(cString)") // uses compare(cString) --> only basic tests here
	{
		CHECK_FALSE(String("a") > "b");
		assert(String("b") > "a");
		CHECK_FALSE(String("a") > "a");
	}

	SUBCASE("operator>=(cString)") // uses compare(cString) --> only basic tests here
	{
		CHECK_FALSE(String("a") >= "b");
		assert(String("b") >= "a");
		assert(String("a") >= "a");
	}

	SUBCASE("operator<=(cString)") // uses compare(cString) --> only basic tests here
	{
		assert(String("a") <= "b");
		CHECK_FALSE(String("b") <= "a");
		assert(String("a") <= "a");
	}

	SUBCASE("CString()")
	{
		CHECK_FALSE(strcmp(String("anton").CString(), "anton") != 0);
		CHECK_FALSE(strcmp(String("").CString(), "") != 0);
		CHECK_FALSE(strcmp(String("antons €").CString(), "antons €") != 0);
		CHECK_FALSE(strcmp(String("xyzanton").MidString(3).CString(), "anton") != 0);
	}

	SUBCASE("NumVal()")
	{
		double f;
		CHECK_FALSE(NumVal("123") != 123);
		CHECK_FALSE(NumVal("34567890") != 34567890);
		CHECK_FALSE(NumVal("-1000000") != -1000000);
		CHECK_FALSE(NumVal("+123.00e-00") != 123);
		CHECK_FALSE(NumVal("-123.00e+00") != -123);
		CHECK_FALSE(NumVal("47.5") != 47.5);
		CHECK_FALSE(NumVal("47.12") != 47.12);
		CHECK_FALSE(NumVal("47.12Effe") != 47.12);
		CHECK_FALSE(NumVal("-432e+123") != -432e123);
		CHECK_FALSE(NumVal("-56789056.7890") != -56789056.7890);
		CHECK_FALSE(NumVal("+56789056.7890") != 56789056.7890);
		CHECK_FALSE(NumVal("+432.432e-123") != 432.432e-123);
		f = NumVal("XXX");
		CHECK_FALSE(errno != notanumber);
		errno = 0;
		CHECK_FALSE(f == f);

		CHECK_FALSE(NumVal("'A'") != 'A');
		CHECK_FALSE(NumVal("'A'xxx") != 'A');
		CHECK_FALSE(NumVal("-'A'") != -'A');
		CHECK_FALSE(NumVal("'\\''") != '\'');
		CHECK_FALSE(NumVal("'\\x'") != 'x');
		CHECK_FALSE(NumVal("'\\017'") != 15);
		CHECK_FALSE(NumVal("'\\017\\100'") != 15 * 256 + 8 * 8);
		CHECK_FALSE(NumVal("'ABCD'") != 0x41424344u);
		f = NumVal("''");
		CHECK_FALSE(errno != notanumber);
		errno = 0;
		CHECK_FALSE(f == f);
		f = NumVal("'12");
		CHECK_FALSE(errno != notanumber);
		errno = 0;
		CHECK_FALSE(f == f);
		f = NumVal("'12\\");
		CHECK_FALSE(errno != notanumber);
		errno = 0;
		CHECK_FALSE(f == f);

		CHECK_FALSE(NumVal("$1234") != 0x1234);
		CHECK_FALSE(NumVal("$1234ggg") != 0x1234);
		CHECK_FALSE(NumVal("-$12345678") != -0x12345678);
		CHECK_FALSE(NumVal("-$1234.5678") != -(0x1234 + 1.0 * 0x5678 / 0x10000));
		CHECK_FALSE(NumVal("$1") != 0x1);
		CHECK_FALSE(NumVal("+$1") != 0x1);
		f = NumVal("+$");
		CHECK_FALSE(errno != notanumber);
		errno = 0;
		CHECK_FALSE(f == f);

		CHECK_FALSE(NumVal("%1010101001011010") != 0xAA5A);
		CHECK_FALSE(NumVal("%10101010222") != 0xAA);
		CHECK_FALSE(NumVal("-%00010010001101000101011001111000") != -0x12345678);
		CHECK_FALSE(NumVal("-%0001001000110100.0101011001111000") != -(0x1234 + 1.0 * 0x5678 / 0x10000));
		CHECK_FALSE(NumVal("%1") != 1.0);
		CHECK_FALSE(NumVal("+%1") != 1.0);
		f = NumVal("+%");
		CHECK_FALSE(errno != notanumber);
		errno = 0;
		CHECK_FALSE(f == f);

		String s = "xyz123";
		CHECK_FALSE(NumVal(s.MidString(3)) != 123.0);
		s = "x€z123";
		CHECK_FALSE(NumVal(s.MidString(3)) != 123.0);
		CHECK_FALSE(NumVal("  +123") != 123.0);
		CHECK_FALSE(NumVal("  +123€") != 123.0);
	}

	SUBCASE("Find(UCS4Char,long)")
	{
		CHECK_FALSE(String("12345").Find('6') != -1);
		CHECK_FALSE(String("").Find('6') != -1);
		CHECK_FALSE(String("12345").Find('1') != 0);
		CHECK_FALSE(String("12345").Find('5') != 4);
		CHECK_FALSE(String("12325").Find('2') != 1);
		CHECK_FALSE(String("12345").Find('6', 3) != -1);
		CHECK_FALSE(String("").Find('6', 3) != -1);
		CHECK_FALSE(String("12345").Find('1', 0) != 0);
		CHECK_FALSE(String("12345").Find('1', 1) != -1);
		CHECK_FALSE(String("12345").Find('1', -1) != 0);
		CHECK_FALSE(String("12345").Find('5', 3) != 4);
		CHECK_FALSE(String("12345").Find('5', 4) != 4);
		CHECK_FALSE(String("12345").Find('5', 5) != -1);
		CHECK_FALSE(String("12325").Find('2', 1) != 1);
		CHECK_FALSE(String("12325").Find('2', 2) != 3);
		CHECK_FALSE(String("12325").Find('2', 3) != 3);
		CHECK_FALSE(String("12325").Find('2', 4) != -1);
		String s = "00012325";
		CHECK_FALSE(s.MidString(3).Find('2', 3) != 3);
	}

	SUBCASE("RFind(UCS4Char,long)")
	{
		CHECK_FALSE(String("12345").RFind('6') != -1);
		CHECK_FALSE(String("").RFind('6') != -1);
		CHECK_FALSE(String("12345").RFind('1') != 0);
		CHECK_FALSE(String("12345").RFind('5') != 4);
		CHECK_FALSE(String("12325").RFind('2') != 3);
		CHECK_FALSE(String("12345").RFind('6', 3) != -1);
		CHECK_FALSE(String("").RFind('6', 3) != -1);
		CHECK_FALSE(String("12345").RFind('1', 0) != 0);
		CHECK_FALSE(String("12345").RFind('1', 1) != 0);
		CHECK_FALSE(String("12345").RFind('1', -1) != -1);
		CHECK_FALSE(String("12345").RFind('5', 3) != -1);
		CHECK_FALSE(String("12345").RFind('5', 4) != 4);
		CHECK_FALSE(String("12345").RFind('5', 5) != 4);
		CHECK_FALSE(String("12325").RFind('2', 1) != 1);
		CHECK_FALSE(String("12325").RFind('2', 2) != 1);
		CHECK_FALSE(String("12325").RFind('2', 3) != 3);
		CHECK_FALSE(String("12325").RFind('2', 4) != 3);
		String s = "00012325";
		CHECK_FALSE(s.MidString(3).RFind('2', 4) != 3);
	}

	SUBCASE("Find(cString,long)")
	{
		CHECK_FALSE(String("ABCBCD34CDE").Find(String("")) != 0);
		CHECK_FALSE(String("").Find(String("")) != 0);
		CHECK_FALSE(String("").Find(String(""), 0) != 0);
		CHECK_FALSE(String("").Find(String(""), 1) != -1);
		CHECK_FALSE(String("123").Find(String(""), -1) != 0);
		CHECK_FALSE(String("123").Find(String(""), 2) != 2);
		CHECK_FALSE(String("ABCBCD34CDE").Find(String("XYZ")) != -1);
		CHECK_FALSE(String("").Find(String("6sdf")) != -1);
		CHECK_FALSE(String("ABCBCD34CDE").Find(String("ABC")) != 0);
		CHECK_FALSE(String("ABCBCD34CDE").Find(String("CDE")) != 8);
		CHECK_FALSE(String("ABCBCD3BCDCDE").Find(String("BCD")) != 3);
		CHECK_FALSE(String("ABCBCD34CDE").Find(String("678"), 3) != -1);
		CHECK_FALSE(String("").Find(String("678"), 3) != -1);
		CHECK_FALSE(String("ABCBCD34CDE").Find(String("ABC"), 0) != 0);
		CHECK_FALSE(String("ABCBCD34CDE").Find(String("ABC"), 1) != -1);
		CHECK_FALSE(String("ABCBCD34CDE").Find(String("ABC"), -1) != 0);
		CHECK_FALSE(String("ABCBCD34CDE").Find(String("CDE"), 7) != 8);
		CHECK_FALSE(String("ABCBCD34CDE").Find(String("CDE"), 8) != 8);
		CHECK_FALSE(String("ABCBCD34CDE").Find(String("CDE"), 9) != -1);
		CHECK_FALSE(String("ABCBCD3BCDCDE").Find(String("BCD"), 3) != 3);
		CHECK_FALSE(String("ABCBCD3BCDCDE").Find(String("BCD"), 6) != 7);
		CHECK_FALSE(String("ABCBCD3BCDCDE").Find(String("BCD"), 7) != 7);
		CHECK_FALSE(String("ABCBCD3BCDCDE").Find(String("BCD"), 8) != -1);
		String s = "xxxABCBCD3BCDCDE";
		CHECK_FALSE(s.MidString(3).Find(String("BCD"), 6) != 7);
	}

	SUBCASE("RFind(cString,long)")
	{
		CHECK_FALSE(String("ABCBCD34CDE").RFind(String("")) != 11);
		CHECK_FALSE(String("").RFind(String("")) != 0);
		CHECK_FALSE(String("").RFind(String(""), 0) != 0);
		CHECK_FALSE(String("").RFind(String(""), 1) != 0);
		CHECK_FALSE(String("123").RFind(String(""), -2) != -1);
		CHECK_FALSE(String("123").RFind(String(""), 2) != 2);
		CHECK_FALSE(String("ABCBCD34CDE").RFind(String("XYZ")) != -1);
		CHECK_FALSE(String("").RFind(String("6sdf")) != -1);
		CHECK_FALSE(String("ABCBCD34CDE").RFind(String("ABC")) != 0);
		CHECK_FALSE(String("ABCBCD34CDE").RFind(String("CDE")) != 8);
		CHECK_FALSE(String("ABCBCD3BCDCDE").RFind(String("BCD")) != 7);
		CHECK_FALSE(String("ABCBCD34CDE").RFind(String("678"), 3) != -1);
		CHECK_FALSE(String("").RFind(String("678"), 3) != -1);
		CHECK_FALSE(String("ABCBCD34CDE").RFind(String("ABC"), 0) != 0);
		CHECK_FALSE(String("ABCBCD34CDE").RFind(String("ABC"), 1) != 0);
		CHECK_FALSE(String("ABCBCD34CDE").RFind(String("ABC"), -1) != -1);
		CHECK_FALSE(String("ABCBCD34CDE").RFind(String("CDE"), 7) != -1);
		CHECK_FALSE(String("ABCBCD34CDE").RFind(String("CDE"), 8) != 8);
		CHECK_FALSE(String("ABCBCD34CDE").RFind(String("CDE"), 9) != 8);
		CHECK_FALSE(String("ABCBCD3BCDCDE").RFind(String("BCD"), 3) != 3);
		CHECK_FALSE(String("ABCBCD3BCDCDE").RFind(String("BCD"), 6) != 3);
		CHECK_FALSE(String("ABCBCD3BCDCDE").RFind(String("BCD"), 7) != 7);
		CHECK_FALSE(String("ABCBCD3BCDCDE").RFind(String("BCD"), 8) != 7);
		String s = "xxxABCBCD3BCDCDE";
		CHECK_FALSE(s.MidString(3).RFind(String("BCD"), 8) != 7);
	}

	SUBCASE("Find(cUTF8Str,long)")
	{
		CHECK_FALSE(String("ABCBCD34CDE").Find("") != 0);
		CHECK_FALSE(String("").Find("") != 0);
		CHECK_FALSE(String("").Find("", 0) != 0);
		CHECK_FALSE(String("").Find("", 1) != -1);
		CHECK_FALSE(String("123").Find("", -1) != 0);
		CHECK_FALSE(String("123").Find("", 2) != 2);
		CHECK_FALSE(String("ABCBCD34CDE").Find("XYZ") != -1);
		CHECK_FALSE(String("").Find("6sdf") != -1);
		CHECK_FALSE(String("ABCBCD34CDE").Find("ABC") != 0);
		CHECK_FALSE(String("ABCBCD34CDE").Find("CDE") != 8);
		CHECK_FALSE(String("ABCBCD3BCDCDE").Find("BCD") != 3);
		CHECK_FALSE(String("ABCBCD34CDE").Find("678", 3) != -1);
		CHECK_FALSE(String("").Find("678", 3) != -1);
		CHECK_FALSE(String("ABCBCD34CDE").Find("ABC", 0) != 0);
		CHECK_FALSE(String("ABCBCD34CDE").Find("ABC", 1) != -1);
		CHECK_FALSE(String("ABCBCD34CDE").Find("ABC", -1) != 0);
		CHECK_FALSE(String("ABCBCD34CDE").Find("CDE", 7) != 8);
		CHECK_FALSE(String("ABCBCD34CDE").Find("CDE", 8) != 8);
		CHECK_FALSE(String("ABCBCD34CDE").Find("CDE", 9) != -1);
		CHECK_FALSE(String("ABCBCD3BCDCDE").Find("BCD", 3) != 3);
		CHECK_FALSE(String("ABCBCD3BCDCDE").Find("BCD", 6) != 7);
		CHECK_FALSE(String("ABCBCD3BCDCDE").Find("BCD", 7) != 7);
		CHECK_FALSE(String("ABCBCD3BCDCDE").Find("BCD", 8) != -1);
		String s = "xxxABCBCD3BCDCDE";
		CHECK_FALSE(s.MidString(3).Find("BCD", 6) != 7);
	}

	SUBCASE("RFind(cUTF8Str,long)")
	{
		CHECK_FALSE(String("ABCBCD34CDE").RFind("") != 11);
		CHECK_FALSE(String("").RFind("") != 0);
		CHECK_FALSE(String("").RFind("", 0) != 0);
		CHECK_FALSE(String("").RFind("", 1) != 0);
		CHECK_FALSE(String("123").RFind("", -2) != -1);
		CHECK_FALSE(String("123").RFind("", 2) != 2);
		CHECK_FALSE(String("ABCBCD34CDE").RFind("XYZ") != -1);
		CHECK_FALSE(String("").RFind("6sdf") != -1);
		CHECK_FALSE(String("ABCBCD34CDE").RFind("ABC") != 0);
		CHECK_FALSE(String("ABCBCD34CDE").RFind("CDE") != 8);
		CHECK_FALSE(String("ABCBCD3BCDCDE").RFind("BCD") != 7);
		CHECK_FALSE(String("ABCBCD34CDE").RFind("678", 3) != -1);
		CHECK_FALSE(String("").RFind("678", 3) != -1);
		CHECK_FALSE(String("ABCBCD34CDE").RFind("ABC", 0) != 0);
		CHECK_FALSE(String("ABCBCD34CDE").RFind("ABC", 1) != 0);
		CHECK_FALSE(String("ABCBCD34CDE").RFind("ABC", -1) != -1);
		CHECK_FALSE(String("ABCBCD34CDE").RFind("CDE", 7) != -1);
		CHECK_FALSE(String("ABCBCD34CDE").RFind("CDE", 8) != 8);
		CHECK_FALSE(String("ABCBCD34CDE").RFind("CDE", 9) != 8);
		CHECK_FALSE(String("ABCBCD3BCDCDE").RFind("BCD", 3) != 3);
		CHECK_FALSE(String("ABCBCD3BCDCDE").RFind("BCD", 6) != 3);
		CHECK_FALSE(String("ABCBCD3BCDCDE").RFind("BCD", 7) != 7);
		CHECK_FALSE(String("ABCBCD3BCDCDE").RFind("BCD", 8) != 7);
		String s = "xxxABCBCD3BCDCDE";
		CHECK_FALSE(s.MidString(3).RFind("BCD", 8) != 7);
	}

	SUBCASE("Replace(UCS4Char,UCS4Char)")
	{
		String s;
		s = " Stetes Klopfen hört das Schwein. ";
		s.Replace(' ', 'X');
		CHECK_FALSE(s != "XStetesXKlopfenXhörtXdasXSchwein.X");

		s = " Stetes Klopfen hört das Schwein. ";
		s.Replace(246, 'X');
		CHECK_FALSE(s != " Stetes Klopfen hXrt das Schwein. ");

		s = "•Stetes•Klopfen•hört•das•Schwein.•";
		s.Replace(8226, ' ');
		CHECK_FALSE(s != " Stetes Klopfen hört das Schwein. ");

		s = "xxx xxx Stetes Klopfen hört das Schwein. ";
		s = s.MidString(7);
		s.Replace(' ', 'X');
		CHECK_FALSE(s != "XStetesXKlopfenXhörtXdasXSchwein.X");

		s = "xxx€xxx Stetes Klopfen hört das Schwein. ";
		s = s.MidString(7);
		s.Replace(' ', 'X');
		CHECK_FALSE(s != "XStetesXKlopfenXhörtXdasXSchwein.X");
	}

	SUBCASE("Swap(UCS4Char,UCS4Char)")
	{
		String s;
		s = " Stetes Klopfen hört das Schwein. ";

		s.Swap(' ', 'X');
		CHECK_FALSE(s != "XStetesXKlopfenXhörtXdasXSchwein.X");
		s.Swap(' ', 'X');
		CHECK_FALSE(s != " Stetes Klopfen hört das Schwein. ");

		s.Swap(246, 'X');
		CHECK_FALSE(s != " Stetes Klopfen hXrt das Schwein. ");
		s.Swap(246, 'X');
		CHECK_FALSE(s != " Stetes Klopfen hört das Schwein. ");

		s.Swap(8226, ' ');
		CHECK_FALSE(s != "•Stetes•Klopfen•hört•das•Schwein.•");
		s.Swap(8226, ' ');
		CHECK_FALSE(s != " Stetes Klopfen hört das Schwein. ");

		s = "xxxXxxx Stetes Klopfen hört dasXSchwein.X";
		s = s.MidString(7);
		s.Swap(' ', 'X');
		CHECK_FALSE(s != "XStetesXKlopfenXhörtXdas Schwein. ");

		s = "xxx€xxx Stetes Klopfen hört dasXSchwein.X";
		s = s.MidString(7);
		s.Swap(' ', 'X');
		CHECK_FALSE(s != "XStetesXKlopfenXhörtXdas Schwein. ");
	}

	SUBCASE("ToUpper()")
	{
		String s;
		s = "AnTönchenöäüßÖÄÜß";
		CHECK_FALSE(s.ToUpper() != "ANTÖNCHENÖÄÜßÖÄÜß");
		s = "AnTönchenöäüßÖÄÜßÿ";
		CHECK_FALSE(s.ToUpper() != "ANTÖNCHENÖÄÜßÖÄÜßŸ");
		s = "AnTönchenöäüßÖÄÜß€";
		CHECK_FALSE(s.ToUpper() != "ANTÖNCHENÖÄÜßÖÄÜß€");
		s = "xxxxxxAnTönchenöäüßÖÄÜß";
		CHECK_FALSE(s.MidString(6).ToUpper() != "ANTÖNCHENÖÄÜßÖÄÜß");
		s = "xxx€xxAnTönchenöäüßÖÄÜß";
		CHECK_FALSE(s.MidString(6).ToUpper() != "ANTÖNCHENÖÄÜßÖÄÜß");
	}

	SUBCASE("ToLower()")
	{
		String s;
		s = "AnTönchenöäüßÖÄÜß";
		CHECK_FALSE(s.ToLower() != "antönchenöäüßöäüß");
		s = "AnTönchenöäüßÖÄÜßŸ";
		CHECK_FALSE(s.ToLower() != "antönchenöäüßöäüßÿ");
		s = "AnTönchenöäüßÖÄÜß€";
		CHECK_FALSE(s.ToLower() != "antönchenöäüßöäüß€");
		s = "xxxxxxAnTönchenöäüßÖÄÜß";
		CHECK_FALSE(s.MidString(6).ToLower() != "antönchenöäüßöäüß");
		s = "xxx€xxAnTönchenöäüßÖÄÜß";
		CHECK_FALSE(s.MidString(6).ToLower() != "antönchenöäüßöäüß");
	}

	SUBCASE("ToHtml()")
	{
		CHECK_FALSE(String("").ToHtml() != "");
		CHECK_FALSE(String("Antons Äffchen").ToHtml() != "Antons Äffchen");
		CHECK_FALSE(String("< > & \"").ToHtml() != "&lt; &gt; &amp; &quot;");
		CHECK_FALSE(String("<€>").ToHtml() != "&lt;€&gt;");
		String s = "xxx<€>";
		CHECK_FALSE(s.MidString(3).ToHtml() != "&lt;€&gt;");
	}

	SUBCASE("FromHtml()")
	{
		CHECK_FALSE(String("").FromHtml() != "");
		CHECK_FALSE(String("Antons Äffchen").FromHtml() != "Antons Äffchen");
		CHECK_FALSE(String("&lt; &gt; &amp; &quot;").FromHtml() != "< > & \"");
		CHECK_FALSE(String("Antons &Auml;ffchen").FromHtml() != "Antons Äffchen");
		CHECK_FALSE(String("Pat & Paterson").FromHtml() != "Pat & Paterson");
		CHECK_FALSE(String("&lt;€&gt;").FromHtml() != "<€>");
		CHECK_FALSE(String("&lt;&euro;&gt;").FromHtml() != "<€>");
		CHECK_FALSE(String("&lt;&#8364;&gt;").FromHtml() != "<€>");
		CHECK_FALSE(String("&lt;&#x20AC;&gt;").FromHtml() != "<€>");
		CHECK_FALSE(String("&lt;&Auml;&gt;").FromHtml() != "<Ä>");
		CHECK_FALSE(String("&lt;&#214;&gt;").FromHtml() != "<Ö>");
		CHECK_FALSE(String("&lt;&#xDC;&gt;").FromHtml() != "<Ü>");
		CHECK_FALSE(String("€&lt;&Auml;&gt;").FromHtml() != "€<Ä>");
		CHECK_FALSE(String("€&lt;&#214;&gt;").FromHtml() != "€<Ö>");
		CHECK_FALSE(String("€&lt;&#xDC;&gt;").FromHtml() != "€<Ü>");
		String s = "xxx&lt; &gt; &amp; &quot;";
		CHECK_FALSE(s.MidString(3).FromHtml() != "< > & \"");
		s = "x€x&lt; &gt; &amp; &quot;";
		CHECK_FALSE(s.MidString(3).FromHtml() != "< > & \"");
	}

	SUBCASE("ToEscaped(bool)") // ***TODO*** ToEscaped(UCS4Char)
	{
		CHECK_FALSE(ToEscaped("anton") != "anton");
		CHECK_FALSE(ToEscaped("anton€") != "anton€");
		CHECK_FALSE(ToEscaped("anton\n", 1) != "\"anton\\n\"");
		CHECK_FALSE(ToEscaped("anton€\n", 1) != "\"anton€\\n\"");
		CHECK_FALSE(ToEscaped("\tanton\n") != "\\tanton\\n");
		CHECK_FALSE(ToEscaped("\tanton€\n") != "\\tanton€\\n");
		CHECK_FALSE(ToEscaped("\016anton\n") != "\\016anton\\n");
		CHECK_FALSE(ToEscaped("\016€anton\n") != "\\016€anton\\n");
		CHECK_FALSE(ToEscaped("\177anton\n", 1) != "\"\\177anton\\n\"");
		CHECK_FALSE(ToEscaped("\177€anton\n", 1) != "\"\\177€anton\\n\"");
		String s = "xxx\177Eanton\n";
		CHECK_FALSE(s.MidString(3).ToEscaped(1) != "\"\\177Eanton\\n\"");
		s = "xxx\177€anton\n";
		CHECK_FALSE(s.MidString(3).ToEscaped(1) != "\"\\177€anton\\n\"");
	}

	SUBCASE("FromEscaped(bool)") // ***TODO*** FromEscaped(UCS4Char)
	{
		CHECK_FALSE(FromEscaped("anton") != "anton");
		CHECK_FALSE(FromEscaped("anton€") != "anton€");
		CHECK_FALSE(FromEscaped("\"anton\\n\"", 1) != "anton\n");
		CHECK_FALSE(FromEscaped("\"anton€\\n\"", 1) != "anton€\n");
		CHECK_FALSE(FromEscaped("\\tanton\\n") != "\tanton\n");
		CHECK_FALSE(FromEscaped("\\tanton€\\n") != "\tanton€\n");
		CHECK_FALSE(FromEscaped("\\016anton\\n") != "\016anton\n");
		CHECK_FALSE(FromEscaped("\\016€anton\\n") != "\016€anton\n");
		CHECK_FALSE(FromEscaped("\"\\177anton\\n\"", 1) != "\177anton\n");
		CHECK_FALSE(FromEscaped("\"\\177€anton\\n\"", 1) != "\177€anton\n");
		CHECK_FALSE(FromEscaped("\\x0eanton\\n") != "\016anton\n");
		CHECK_FALSE(FromEscaped("\\xe€anton\\n") != "\016€anton\n");
		CHECK_FALSE(FromEscaped("\"\\x7fanton\\n\"", 1) != "\177anton\n");
		CHECK_FALSE(FromEscaped("\"\\x7f€anton\\n\"", 1) != "\177€anton\n");
		String s = "xxx\"\\x7fEanton\\n\"";
		CHECK_FALSE(s.MidString(3).FromEscaped(1) != "\177Eanton\n");
		s = "xxx\"\\x7f€anton\\n\"";
		CHECK_FALSE(s.MidString(3).FromEscaped(1) != "\177€anton\n");
	}

	SUBCASE("ToUTF8() / FromUTF8()")
	{
		for (int bu = 0; bu <= 32; bu++) // max num of bits
		{
			for (int nu = 0; nu < 300; nu += 1 + nu / 2) // str.len
			{
				ucs4char u4[300];
				for (int j = 0; j < nu; j++)
				{
					u4[j] = (uint32(random()) + uint32(random()) * 0x10000u);
					if (bu < 32) u4[j] &= RMASK(bu);
				}
				String su = String(ptr(u4), nu, csz4);
				su		  = su.ToUTF8();
				assert(su.Csz() == csz1);
				su = su.FromUTF8();
				assert(su.Len() == nu);
				su.ResizeCsz(csz4);
				assert(memcmp(u4, su.Text(), uint(nu) * 4) == 0);
			}
		}
	}

	//	TODO		ToUCS1			( ) const;
	//	TODO		FromUCS1		( ) const;
	//	TODO		ToUCS2			( ) const;
	//	TODO		FromUCS2		( ) const;
	//	TODO		ToUCS4			( ) const;
	//	TODO		FromUCS4		( ) const;

	SUBCASE("CharString(UCS4Char)")
	{
		CHECK_FALSE(CharString('a') != "a");
		CHECK_FALSE(CharString(8364) != "€");
	}

	SUBCASE("SpaceString(long,UCS4Char)")
	{
		CHECK_FALSE(SpaceString(10) != "          ");
		CHECK_FALSE(SpaceString(10, 'X') != "XXXXXXXXXX");
		CHECK_FALSE(SpaceString(10, 8364) != "€€€€€€€€€€");
		CHECK_FALSE(SpaceString(0) != "");
		CHECK_FALSE(SpaceString(0, 'X') != "");
		CHECK_FALSE(SpaceString(-5) != "");
		CHECK_FALSE(SpaceString(-5, 'X') != "");
		CHECK_FALSE(SpaceString(1) != " ");
		CHECK_FALSE(SpaceString(1, 'X') != "X");
	}

	SUBCASE("NumString(double)")
	{
		CHECK_FALSE(NumString(0.0) != "0");
		CHECK_FALSE(NumString(26473246.0) != "26473246");
		CHECK_FALSE(NumString(2147483647.0) != "2147483647");
		CHECK_FALSE(NumString(-26473246.0) != "-26473246");
		CHECK_FALSE(NumString(-2147483648.0) != "-2147483648");
		CHECK_FALSE(NumString(1.2) != "1.2");
		CHECK_FALSE(NumString(1.22e-4) != "0.000122");
		CHECK_FALSE(NumString(-5.5) != "-5.5");
		CHECK_FALSE(NumString(0.1 / 3) != "0.033333333333333");
		CHECK_FALSE(NumString(0.00001 / -3) != "-3.3333333333333e-06");
		CHECK_FALSE(NumString(1e200) != "1e+200");
		CHECK_FALSE(NumString(1e200 / 3) != "3.3333333333333e+199");
		CHECK_FALSE(NumString(1e200 / -3) != "-3.3333333333333e+199");
		CHECK_FALSE(NumString(1e-200 / -3) != "-3.3333333333333e-201");
	}

	SUBCASE("NumString(ulong)")
	{
		CHECK_FALSE(NumString(0u) != "0");
		CHECK_FALSE(NumString(88u) != "88");
		CHECK_FALSE(NumString(26473246u) != "26473246");
		CHECK_FALSE(NumString(2147483647u) != "2147483647");
		CHECK_FALSE(NumString(0x80000000u) != "2147483648");
		CHECK_FALSE(NumString(0xFFFFFFFFu) != "4294967295");
	}

	SUBCASE("NumString(long)")
	{
		CHECK_FALSE(NumString(0) != "0");
		CHECK_FALSE(NumString(-0) != "0");
		CHECK_FALSE(NumString(88) != "88");
		CHECK_FALSE(NumString(-88) != "-88");
		CHECK_FALSE(NumString(-1) != "-1");
		CHECK_FALSE(NumString(-26473246) != "-26473246");
		CHECK_FALSE(NumString(26473246) != "26473246");
		CHECK_FALSE(NumString(0x7FFFFFFF) != "2147483647");
		CHECK_FALSE(NumString(int32(0x80000000)) != "-2147483648");
	}

	SUBCASE("HexString(ulong,int)")
	{
		CHECK_FALSE(HexString(0x444333u, 0) != "00444333");
		CHECK_FALSE(HexString(0x444333u, -3) != "");
		CHECK_FALSE(HexString(0x2342d2u, 2) != "D2");
		CHECK_FALSE(HexString(0x2342d2f1u, 8) != "2342D2F1");
		CHECK_FALSE(HexString(0xE342d2f1u, 8) != "E342D2F1");
		CHECK_FALSE(HexString(0x2342d2f1u, 9) != "02342D2F1");
	}

	SUBCASE("allocation test")
	{
		const uint SZ = 5000;
		String*	   v  = new String[SZ];
		for (uint i = 0; i < SZ; i++) { v[i] = v[0]; }
		for (uint i = 0; i < SZ; i++) { v[i] = SpaceString(33, 33); }
		for (uint i = 0; i < SZ; i++) { v[i] = v[0]; }
		delete[] v;
	}

	SUBCASE("allocation test2")
	{
		srandom(uint(time(nullptr)));
		const uint SZ = 5000;
		String*	   v[SZ];
		for (uint i = 0; i < SZ; i++) v[i] = nullptr;

		int i, j;

		for (uint ii = 0; ii < 50000; ii++)
		{
			i = int(random(NELEM(v)));
			j = int(random(NELEM(v)));

			if (v[i])
			{
				if (v[j])
				{
					*v[i] += *v[j];
					*v[i] = v[i]->MidString(int(random(uint(v[i]->Len()))), int(random(100000)));
					delete v[j];
					v[j] = nullptr;
				}
				else
				{
					*v[i] += *v[i];
					*v[i] = v[i]->MidString(int(random(uint(v[i]->Len()))), int(random(100000)));
				}
			}
			else
			{
				if (v[j]) { v[i] = new String(*v[j]); }
				else
				{
					CharSize csz   = random(5) ? csz1 : random(5) ? csz2 : csz4;
					int32	 count = int32(random(10000));
					v[i]		   = new String(count, csz);
				}
			}
		}

		for (uint ii = 0; ii < NELEM(v); ii++) delete v[ii];
	}
}


/*














































*/
