write('Testing strings ...\n\n');
t := time();

i := 'alex;alex;agena';
ta := ['a', 'b', 'c', 'd', 'e', 'a', 'b', 'c', 'd', 'e'];
for c to 128 do
   inc c;
   nhits := strings.hits(i, 'alex');
   if nhits <> 2 then
      print(tostring(c) & '[strings.hits]>' & tostring(nhits))
   fi;
   nsplit := i split ';'
   if nsplit <> seq('alex', 'alex', 'agena') then
      print(tostring(c) & '[split]>' & tostring(nsplit))
   fi;
   if size nsplit <> 3 then
      print(tostring(c) & '[size]>' & size nsplit)
   fi;
   if not('alex' in i) then
      print(tostring(c) & '[in]>' & i)
   fi;
   if 'aleX' in i then
      print(tostring(c) & '[in, aleX]>' & i)
   fi;
   if 'alex' notin i then
      print(tostring(c) & '[notin]>' & i)
   fi;
   if not('aleX' notin i) then
      print(tostring(c) & '[notin, aleX]>' & i)
   fi;
   if instr(i, '[Aa]gena') <> 11 then
      print(tostring(c) & '[instr <> 11]>' & i)
   fi;
   if not(instr(i, '[Aa]gena', 11)) then
      print(tostring(c) & '[instr, 11]>' & i)
   fi;
   if instr(i, 'alex', 'borders') <> 1:4 then
      print(tostring(c) & '[instr, 12]>' & i)
   fi;
   if instr(i, 'alex', 'borders', 2) <> 6:9 then
      print(tostring(c) & '[instr, 13]>' & i)
   fi;
   if instr(i, 'alex', 'borders', 20) <> null then
      print(tostring(c) & '[instr, 14]>' & i)
   fi;
   if not('agena' atendof i) then
      print(tostring(c) & '[atendof]>' & i)
   fi;
   if 'alex;alex;agena' atendof 'alex;alex;agena' <> null then
      print(tostring(c) & '[atendof whole string]>' & i)
   fi;
   if lower(i) <> i then
      print(tostring(c) & '[lower]>' & i)
   fi;
   if upper(i) <> 'ALEX;ALEX;AGENA' then
      print(tostring(c) & '[upper]>' & i)
   fi;
   if lower('') <> '' then
      print(tostring(c) & '[lower empty]>' & i)
   fi;
   if upper('') <> '' then
      print(tostring(c) & '[upper empty]>' & i)
   fi;
   if trim('   ' & i & '  ') <> i then
      print(tostring(c) & '[trim with white spaces]>' & i)
   fi;
   if trim(i) <> i then
      print(tostring(c) & '[trim without white spaces]>' & i)
   fi;
   if strings.gmatches(i, '[Aa]lex') <> seq('alex', 'alex') then
      print(tostring(c) & '[strings.gmatches]>' & i)
   fi;
   if strings.isabbrev(i, 'alex') <> true then
      print(tostring(c) & '[strings.isabbrev]>' & i)
   fi;
   if strings.isalpha(i) = true then
      print(tostring(c) & '[strings.isalpha]>' & i)
   fi;
   if strings.isalphanumeric(i) = true then
      print(tostring(c) & '[strings.isalphanumeric]>' & i)
   fi;
   if strings.isalphaspace(i) = true then
      print(tostring(c) & '[strings.isalphaspace]>' & i)
   fi;
   if strings.isending(i, '[Aa]gena') <> true then
      print(tostring(c) & '[strings.isending]>' & i)
   fi;
   if strings.isfloat(i) then
      print(tostring(c) & '[strings.isfloat]>' & i)
   fi;
   if strings.isnumeric(i) then
      print(tostring(c) & '[strings.isnumeric]>' & i)
   fi;
   if strings.iscenumeric(i) then
      print(tostring(c) & '[strings.iscenumeric]>' & i)
   fi;
   if strings.islatin(i) then
      print(tostring(c) & '[strings.islatin]>' & i)
   fi;
   if strings.isloweralpha(i) then
      print(tostring(c) & '[strings.isloweralpha]>' & i)
   fi;
   if strings.islowerlatin(i) then
      print(tostring(c) & '[strings.islowerlatin]>' & i)
   fi
   if strings.ismagic(i) <> false then
      print(tostring(c) & '[strings.ismagic]>' & i)
   fi;
   if strings.ismagic(char(255)) <> false then
      print('strings.ismagic, 2')
   fi;
   if strings.isprintable(char(255)) <> true then
      print('strings.isprintable')
   fi;
   if strings.isspec(char(255)) then
      print('strings.isspec')
   fi;
   if strings.isalpha(char(255)) then
      print('strings.isalpha')
   fi;
   if strings.isnumber(i) then
      print(tostring(c) & '[strings.isnumber]>' & i)
   fi
   if strings.isnumberspace(i) then
      print(tostring(c) & '[strings.isnumberspace]>' & i)
   fi;
   if strings.isupperalpha(i) then
      print(tostring(c) & '[strings.isupperalpha]>' & i)
   fi;
   if strings.isupperlatin(i) then
      print(tostring(c) & '[strings.isupperlatin]>' & i)
   fi;
   if strings.ltrim('   ' & i) <> i then
      print(tostring(c) & '[strings.ltrim]>' & i)
   fi;
   if strings.rtrim(i & '   ') <> i then
      print(tostring(c) & '[strings.rtrim]>' & i)
   fi;
   if strings.remove(i, 1, 4) <> ';alex;agena' then
      print(tostring(c) & '[strings.remove.1]>' & i)
   fi;
   if strings.remove('agena', 'a') <> 'gen' then
      print(tostring(c) & '[strings.remove.2]>' & i)
   fi;
   if strings.remove('agena', 'a', 1) <> 'gena' then
      print(tostring(c) & '[strings.remove.3]>' & i)
   fi;
   if strings.remove('agena', '', 1) <> 'agena' then
      print(tostring(c) & '[strings.remove.4]>' & i)
   fi;
   if strings.remove('agena', '') <> 'agena' then
      print(tostring(c) & '[strings.remove.5]>' & i)
   fi;
   if strings.remove('', '') <> '' then
      print(tostring(c) & '[strings.remove.6]>' & i)
   fi;
   if strings.remove('agena', 'pp') <> 'agena' then
      print(tostring(c) & '[strings.remove.7]>' & i)
   fi;
   if replace(i, 'alex', '') <> ';;agena' then
      print(tostring(c) & '[replace]>' & i)
   fi;
   if replace(i, 'Alex', '') <> i then
      print(tostring(c) & '[replace]>' & i)
   fi;
   if replace('agena proglang', ['a':'A', ' ':'_']) <> 'AgenA_proglAng' then
      print(tostring(c) & '[replace.a1]')
   fi;
   if replace('agena proglang', seq('a':'A', ' ':'_')) <> 'AgenA_proglAng' then
      print(tostring(c) & '[replace.a2]')
   fi;
   if replace('agena proglang', reg('a':'A', ' ':'_')) <> 'AgenA_proglAng' then
      print(tostring(c) & '[replace.a3]')
   fi;
   if replace('agena proglang', 6, '') <> 'agenaproglang' then
      print(tostring(c) & '[replace.a4]')
   fi;
   if replace('agena proglang', 6, '_') <> 'agena_proglang' then
      print(tostring(c) & '[replace.a5]')
   fi;
   if replace('agena proglang', 6, '__') <> 'agena__proglang' then
      print(tostring(c) & '[replace.a6]')
   fi;
   if replace('agena proglang', 14, 'G__') <> 'agena proglanG__' then
      print(tostring(c) & '[replace.a7]')
   fi;
   if replace('agena proglang', 1, 'G__') <> 'G__gena proglang' then
      print(tostring(c) & '[replace.a8]')
   fi;
   if replace('agena proglang', -1, 'G__') <> 'agena proglanG__' then
      print(tostring(c) & '[replace.a9]')
   fi;
   if join(['1', '23', '456'], '|') <> '1|23|456' then
      print(tostring(c) & '[join.1]')
   fi;
   if join(seq('1', '23', '456'), '|') <> '1|23|456' then
      print(tostring(c) & '[join.2]')
   fi;
   if join(reg('1', '23', '456'), '|') <> '1|23|456' then
      print(tostring(c) & '[join.3]')
   fi;
   if join(['1', '23', '456']) <> '123456' then
      print(tostring(c) & '[join.4]')
   fi;
   if join(seq('1', '23', '456')) <> '123456' then
      print(tostring(c) & '[join.5]')
   fi;
   if join(reg('1', '23', '456')) <> '123456' then
      print(tostring(c) & '[join.6]')
   fi;
   if instr(i, 'agena') <> 11 then
      print(tostring(c) & '[instr]>' & i)
   fi;
   if instr(i, 'agena', 1, true) <> 11 then
      print(tostring(c) & '[instr]>' & i)
   fi;
   if strings.words(replace(i, ';', ' ')) <> 3 then
      print(tostring(c) & '[strings.words]>' & i)
   fi;
   numbers := map(<< x -> abs(x) >>, totable(i));
   if i <> strings.tochars(unpack(numbers)) then
      print(tostring(c) & '[strings.tochars]>' & i)
   fi;
   if strings.fields(i, 3, ';') <> seq('agena') then
      print(tostring(c) & '[strings.fields]>' & i)
   fi;
   if strings.dleven(i, i) <> 0 then
      print(tostring(c) & '[strings.dleven.1]>' & i)
   fi;
   if strings.dleven(i, 'alex;aelx;agena') <> 1 then
      print(tostring(c) & '[strings.dleven.2]>' & i)
   fi;
   if strings.dleven(i, 'alex;alx;agena') <> 1 then
      print(tostring(c) & '[strings.dleven.3]>' & i)
   fi;
   if strings.dleven(i, 'alex;alqx;agena') <> 1 then
      print(tostring(c) & '[strings.dleven.3]>' & i)
   fi;
   if strings.include(i, 1, 'A') <> 'A' & i then
      print(tostring(c) & '[strings.include.1]>' & i)
   fi;
   if strings.include('alex', 5, 'alex') <> 'alexalex' then
      print(tostring(c) & '[strings.include.2]>' & i)
   fi;
   base64 := 'abcde01234abcde01234abcde01234';
   if utils.decodeb64(utils.encodeb64(base64)) <> base64 then
      print('error in encodeb64/decodeb64')
   fi;
   if utils.unhexlify(utils.hexlify(base64)) <> base64 then
      print('error in hexlify/unhexlify')
   fi;
   L := utils.readcsv('sample.csv', delim='|', convert=false, header=true);
   K := seq(seq('Maple', '7'), seq('Lua', '5.1'), seq('Algol', '68'));
   if L <> K then
      print('error in utils.readcsv, 1')
   fi;
   L := utils.readcsv('sample.csv', delim='|', header=true);
   K := seq(seq('Maple', 7), seq('Lua', 5.1), seq('Algol', 68));
   if L <> K then
      print('error in utils.readcsv, 2')
   fi;
   base64 := 'abcde01234äöüßABCDEÄÖÜ';
   alphas := 'abcdeABCDE';
   if strings.isisoalpha(alphas) <> true then
      print('error in strings.isisoalpha')
   fi;
   if strings.isisolower(alphas[1 to 5]) <> true then
      print('error in strings.isisolower')
   fi;
   if strings.isisoupper(alphas[6 to 10]) <> true then
      print('error in strings.isisoupper')
   fi;
   if strings.isisospace(' \t\n') <> true then
      print('error in strings.isisospace')
   fi;
   if strings.isoupper(alphas[1 to 5]) <> alphas[6 to 10] then
      print('error in strings.isoupper')
   fi;
   if strings.isolower(alphas[6 to 10]) <> alphas[1 to 5] then
      print('error in strings.isolower')
   fi;
   if strings.transform(<< x -> x + 1>>, alphas[1 to 5]) <> 'bcdef' then
      print('error in strings.transform')
   fi
   utf8 := strings.toutf8(base64);
   if strings.isutf8(utf8) <> true then
      print('error in strings.tolatin/strings.isutf8')
   fi;
   if size base64 <> strings.utf8size(utf8) then
      print('error in strings.tolatin/strings.utf8size')
   fi;
   if strings.tolatin(utf8) <> base64 then
      print('error in strings.tolatin/strings.toutf8')
   fi;
   if strings.capitalise('alex') <> 'Alex' then
      print('error in strings.capitalise, 1')
   fi;
   if strings.mfind('alexalex', 'alex') <> seq(1:4, 5:8) then
      print('error in strings.mfind, 1')
   fi;
   for i in seq('   <alex >  </alex >   ':'<alex >  </alex >',
     '':'', '  alex':'alex', 'alex   ':'alex', 'alex':'alex',
   ' ':'', 'alex ':'alex', ' alex':'alex') do
      if strings.lrtrim(left(i)) <> right(i) then
         print('error in strings.lrtrim, 1')
      fi
   od;
   local i, xyz;
   for i to 64 do
      if strings.format('%q', Pi) <> '\"3.1415926535898\"' then
         print('error in strings.format, 1/' & i)
      fi;
      if strings.format('%a', Pi) <> '3.1415926535898' then
         print('error in strings.format, 21/' & i)
      fi;
      if strings.format('%6.2F', Pi) <> '  3.14' then
         print('error in strings.format, 21/' & i)
      fi;
      xyz := strings.format('%6.2F', fail);
      xyz := strings.format('%6.2D', fail)
   od;
   if reduce(<< x, a -> a & x & '|' >>, '1234', '') <> '1|2|3|4|' then
      print('error in reduce/' & i)
   fi;
   if strings.charset('agena programming language') <> {' ' , 'a', 'e', 'g', 'i', 'l', 'm', 'n', 'o', 'p', 'r', 'u'} then
      print('error in strings.charset/' & i)
   fi;
   if not([0.55583362792012, 1.846439344671, 18.46439344671] ~= [strings.shannon('1223334444')]) then
      print('error in strings.shannon/' & i)
   fi;
od;


str := 'string'

f := proc(str, a, b) is
   local r := str[a to b]
   return(r)
end;

to 10 do
   for i to 50 do
      d := str[2 to 3];
      e := f(str, 2, 3)
   od;

   if d <> e then print('error in new substring op, 1') fi;

   for i to 50 do
      if str[1 to 2][2] <> 't' then print('error in new substring op, 2') fi;
      if str[1 to 2][2 to 2] <> 't' then print('error in new substring op, 3') fi;
   od;

   # instr 1.3.3 patches

   if instr('alex', '[ab]', 1) <> 1 then
      print('error in instr, a1')
   fi;
   if instr('alex', 'a', 1) <> 1 then
      print('error in instr, a2')
   fi;
   if instr('alex', 'b') <> null then
      print('error in instr, a3')
   fi;
   if instr('alex', 'b', 1, true) <> null then
      print('error in instr, a4')
   fi;
   if strings.fields('1;2;3;4;5', seq(2), ';') <> seq('2') then
      print('error in strings.fields, -1')
   fi;
   if strings.fields('1;2;3;4;5', seq(1)) <> seq('1;2;3;4;5') then
      print('error in strings.fields, -2')
   fi;
   if strings.dleven('alexander', 'alxeander') <> 1 then
      print('error in strings.dleven/1')
   fi;
   if strings.dleven('alexander', 'aleander') <> 1 then
      print('error in strings.dleven/2')
   fi;
   if strings.dleven('aleander', 'alexander') <> 1 then
      print('error in strings.dleven/3')
   fi;
   if strings.dleven('aleyander', 'alexander') <> 1 then
      print('error in strings.dleven/4')
   fi;
   if strings.dleven('', 'alexander') <> undefined then
      print('error in strings.dleven/5')
   fi;
   if strings.dleven('alexander', '') <> undefined then
      print('error in strings.dleven/6')
   fi;
   if strings.dleven('alexandre', 'alxeander') <> 2 then
      print('error in strings.dleven/7')
   fi;
   if strings.dleven('alexander', 'aleaner') <> 2 then
      print('error in strings.dleven/8')
   fi;
   if strings.dleven('aleander', 'alexandery') <> 2 then
      print('error in strings.dleven/9')
   fi;
   if strings.dleven('akeyander', 'alexander') <> 2 then
      print('error in strings.dleven/10')
   fi;
   if strings.between('abcdefghi', 'abc', 'ghi') <> 'def' then
      print('error in strings.between/1')
   fi;
   if strings.between('abcdefghi', 'abc', 'ghj') <> null then
      print('error in strings.between/2')
   fi;
   if strings.chop('abc') <> 'ab' then
      print('error in strings.chop/1')
   fi;
   if strings.chop('a') <> '' then
      print('error in strings.chop/2')
   fi;
   if strings.chop('') <> '' then
      print('error in strings.chop/3')
   fi;
   if strings.chop('path///', << x -> x <> '?' >>) <> '' then
      print('error in strings.chop/4')
   fi;
   if strings.chomp('abcdef', 'def') <> 'abc' then
      print('error in strings.chomp/1')
   fi;
   if strings.chomp('abcdef', 'deg') <> 'abcdef' then
      print('error in strings.chomp/2')
   fi;
   if strings.chomp('abc', 'abc') <> '' then
      print('error in strings.chomp/3')
   fi;
   if strings.chomp('bc', 'abc') <> 'bc' then
      print('error in strings.chomp/4')
   fi;
   if strings.chomp('', 'abc') <> '' then
      print('error in strings.chomp/5')
   fi;
   if strings.chomp('', '') <> '' then
      print('error in strings.chomp/6')
   fi;
   if strings.contains('abcdefg', 'abc') <> false then
      print('error in strings.contains/1')
   fi;
   if strings.contains('abc', 'abc') <> true then
      print('error in strings.contains/2')
   fi;
   if strings.appendmissing('append', 'ing') <> 'appending' then
      print('error in strings.appendmissing/1')
   fi;
   if strings.appendmissing('append', '') <> 'append' then
      print('error in strings.appendmissing/2')
   fi;
   if strings.appendmissing('appending', 'ing') <> 'appending' then
      print('error in strings.appendmissing/3')
   fi;
   if strings.iswrapped('PappendingP', 'P') <> true then
      print('error in strings.iswrapped/1')
   fi;
   if strings.iswrapped('PappendingPa', 'Pa') <> true then
      print('error in strings.iswrapped/2')
   fi;
   if strings.iswrapped('PappendingPa', 'Pb') <> false then
      print('error in strings.iswrapped/3')
   fi;
   if strings.iswrapped('==P==', '==') <> true then
      print('error in strings.iswrapped/4')
   fi;
   if strings.iswrapped('P', '==') <> false then
      print('error in strings.iswrapped/5')
   fi;
   if strings.wrap('appendingP', 'P') <> 'PappendingPP' then
      print('error in strings.wrap/1')
   fi;
   if strings.wrap('appendingP', '') <> 'appendingP' then
      print('error in strings.wrap/2')
   fi;
   if strings.wrap('', 'P') <> 'PP' then
      print('error in strings.wrap/3')
   fi;
   if strings.wrap('', '') <> '' then
      print('error in strings.wrap/4')
   fi;
   if strings.wrapmissing('P', '==') <> '==P==' then
      print('error in strings.wrapmissing/1')
   fi;
   if strings.wrapmissing('P', '=') <> '=P=' then
      print('error in strings.wrapmissing/2')
   fi;
   if strings.wrapmissing('=P=', '=') <> '=P=' then
      print('error in strings.wrapmissing/3')
   fi;
   if strings.wrapmissing('==P==', '=') <> '==P==' then
      print('error in strings.wrapmissing/4')
   fi;
   if strings.wrapmissing('==P==', '===') <> '=====P=====' then
      print('error in strings.wrapmissing/5')
   fi;
   if strings.format('%3.10p', Pi) <> '314.1592653590%' then
      print('error in strings.format/p')
   fi;
   if strings.format('%m', Pi) <> '3.14' then
      print('error in strings.format/m1')
   fi;
   if strings.format('%m', 1m) <> '1,000,000.00' then
      print('error in strings.format/m2')
   fi;
   if strings.format('%m', 100k) <> '100,000.00' then
      print('error in strings.format/m3')
   fi;
   if strings.format('%m', -100k) <> '-100,000.00' then
      print('error in strings.format/m4')
   fi;
   if strings.format('%20.4m', -100k) <> '       -100,000.0000' then
      print('error in strings.format/m5')
   fi;
   if not(os.isdos() or os.iswindows()) or os.winver() > 5 then  # does not work in Windows 2000, unknown whether it works in XP
      if strings.format('%3.15h', Pi) <> '0x1.921fb54442d1800p+1' then
         print('error in strings.format/h')
      fi;
      if strings.format('%3.15H', Pi) <> '0X1.921FB54442D1800P+1' then
         print('error in strings.format/H')
      fi
   fi;
   # avoid locale trouble
   if size strings.format('%20.4n', -100k) <> size '        -100000.0000' then
      print('error in strings.format/n1')
   fi;

   g := strings.gseparate('123;456;789;0', ';');
   if g() <> '123' then
      print('Error in strings.gseparate, 1', x)
   fi;
   if g() <> '456' then
      print('Error in strings.gseparate, 2', x)
   fi;
   if g() <> '789' then
      print('Error in strings.gseparate, 3', x)
   fi;
   if g() <> '0' then
      print('Error in strings.gseparate, 4', x)
   fi;
   if g() <> null then
      print('Error in strings.gseparate, 5', x)
   fi;

   r := [];
   a := '123;456;789;0';
   do
      b, a := strings.cut(a, ';')
      insert b into r
   as a <> null;
   if r <> ['123', '456', '789', '0'] then
      print('Error in strings.cut')
   fi;
   a := '123;456;789;0';
   if strings.advance(a, '789') <> '789;0' then
      print('Error in strings.advance, 1')
   fi;
   if strings.advance(a, '0') <> '0' then
      print('Error in strings.advance, 2')
   fi;
   if strings.advance(a, '') <> null then
      print('Error in strings.advance, 3')
   fi;
   if strings.a64(100k) <> 'UOM' then
      print('Error in strings.a64, 1')
   fi;
   if strings.a64('UOM') <> 100k then
      print('Error in strings.a64, 2')
   fi
od;

# binary data serialisation
f := proc() is
  return [1, 2!3, ++Pi, 0, -0],
         seq(4, reg(infinity:(-infinity))),
         'lua':'agena',
         {0, undefined, true, false, fail} end;
s := strings.dump(f);
r := [loadstring(s)()];

if r[1] <> [1, 2!3, ++Pi, 0 -0] or
   r[2] <> seq(4, reg(infinity:(-infinity))) or
   r[3] <> 'lua':'agena' or
   r[4] <> {0, undefined, true, false, fail} then
      print('Error in strings.dump/loadstring')
fi;

# misc
to 10 do
   strings.random(8);
   strings.random(24);
   strings.random(128)
od;

str := 'Agena Programming Language from the Rhineland'

for i from 0 to 7 do
   if strings.rotateleft(strings.rotateright(str, i), i) <> str then
      print('Error in strings.rotateleft/strings.rotateright, 1')
   fi
od;

for i from 0 to 7 do
   for j from 1 to 2 do
      if i = j and strings.rotateleft(strings.rotateright(str, i, j), i, j) <> str then
         print('Error in strings.rotateleft/strings.rotateright, 2', i, j)
      fi
   od
od;

# Embedded zeros
s := 'alex' & char(0) & 'walz' & char(127) & 'san antonio';  # embedded zero (\0) and DEL key
if size s <> 21 then
   print('Error in string with embedded zeros')
fi;

/* for i from 0 to 8 do  # checks agnhlps.c/tools_optstrlen, too
   str := strings.repeat('0', i);
   p, q := strings.stralloc(str);
   if p <> q then
      print('Error in strings.stralloc', i)
   fi
   if strings.strpbrk("Alexander", "pqtx") <> true then
     print('Error in strings.strpbrk, 1')
   fi
   if strings.strpbrk("Alexander", "pqty") <> false then
     print('Error in strings.strpbrk, 2')
   fi;
   if strings.strpbrk("Agena", "") <> false then
      print('Error in strings.strpbrk, 3')
   fi;
   if strings.strpbrk("", "") <> false then
      print('Error in strings.strpbrk, 4')
   fi
od; */

writeline('\nDone in ' & time() - t & ' seconds');


# delete all global variables
clear c, d, e, f, g, i, r, str, fd, nhits, nsplit, numbers, r, s, t, L, K, base64, utf8, alphas, ta;

