print('Checking bags package\n');

readlib 'bags'
b := bags.bag(1, 1, 1, 4);
x1, x2 := bags.attrib(b);
if x1 <> 2 then print('error in bags.attrib, 1') fi;
if x2 <> 4 then print('error in bags.attrib, 2') fi;

b := bags.bag();
for i to 10 do
   bags.include(b, i)
od;

if b <> bags.bag(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) then
   print('error in bags.include')
fi;

for i to 10 do
   bags.remove(b, i)
od;

if b <> bags.bag() then
   print('error in bags.remove')
fi;

bags.minclude(b, nseq(1, 10));

if b <> bags.bag(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) then
   print('error in bags.minclude')
fi;

if bags.bagtoset(b) <> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} then
   print('error in bags.bagtoset')
fi;

to 16 do
   a := bags.bag(2, 3)
   b := bags.bag(1, 2)
   if a minus b <> bags.bag(3) then
      print('error in bags/minus, 1')
   fi;
   if b minus a <> bags.bag(1) then
      print('error in bags/minus, 2')
   fi;
   if a union b <> bags.bag(1, 2, 2, 3) then
      print('error in bags/union, 1')
   fi;
   if b union a <> bags.bag(1, 2, 2, 3) then
      print('error in bags/union, 2')
   fi;
   if a intersect b <> bags.bag(2, 2) then
      print('error in bags/intersect, 1')
   fi;
   if b intersect a <> bags.bag(2, 2) then
      print('error in bags/intersect, 2')
   fi
od;


print('Checking skycrane package\n');

readlib 'skycrane'

to 512 do
   if skycrane.tocomma('1.2') <> '1,2' then
      print('error in skycrane.tocomma, 1')
   fi;
   if skycrane.tocomma(1.2) <> '1,2' then
      print('error in skycrane.tocomma, 2')
   fi;
   if skycrane.trimpath('\\/') <> '/' then
      print('error in skycrane.trimpath, 1')
   fi;
   if skycrane.removedquotes('\"1234\"') <> '1234' then
      print('error in skycrane.removedquotes, 1')
   fi
od;

path, fn, fno := '_temp_', 'read.me', 'read.bak';

if skycrane.fcopy(fn, fno) <> true then
   print('error in skycrane.fcopy, 1');
else
   os.remove(fno);
fi;

os.mkdir(path);
if skycrane.fcopy(fn, path) <> true then
   print('error in skycrame.fcopy, 2');
else
   os.remove(path & '/' & fn);
   os.rmdir(path)
fi;


print('Checking llist package\n');

readlib 'llist';

for i to 100 do
   L := llist.list(1, 2, 3, 4, 5, 6);
   for i to 4 do
      if L[i] <> i then
         print('error in llist, 1')
      fi;
   od;
   # 1, 2, 3, 4, 5, 6
   for i to 4 do
      L[i] := L[i] + 1;
      if L[i] <> i + 1 then
         print('error in llist, 2')
      fi;
   od;
   # 2, 3, 4, 5, 5, 6
   llist.append(L, 8);
   # 2, 3, 4, 5, 5, 6, 8
   if L[7] <> 8 then
      print('error in llist, 3')
   fi;
   llist.prepend(L, 1);
   # 1, 2, 3, 4, 5, 5, 6, 8
   if L[1] <> 1 then
      print('error in llist, 4')
   fi;
   llist.purge(L, 1);
   # 2, 3, 4, 5, 5, 6, 8
   if L[1] <> 2 then
      print('error in llist, 5')
   fi;
   llist.purge(L, 7);
   # 2, 3, 4, 5, 5, 6
   if L[6] <> 6 then
      print('error in llist, 6')
   fi;
   llist.purge(L, 3);
   # 2, 3, 5, 5, 6
   if L[3] <> 5 then
      print('error in llist, 7')
   fi;
   llist.put(L, 1, 1);
   # 1, 2, 3, 5, 5, 6
   if L[1] <> 1 then
      print('error in llist, 8')
   fi;
   llist.put(L, 4, 4);
   # 1, 2, 3, 4, 5, 5, 6
   if L[4] <> 4 and L[5] <> 5 then
      print('error in llist, 9')
   fi;
   llist.put(L, 7, -1);
   # 1, 2, 3, 4, 5, 5, -1, 6
   if L[7] <> -1 and L[8] <> 7 then
      print('error in llist, 10')
   fi;
   L1 := [1, 2, 3, 4, 5, 5, -1, 6];
   f := llist.iterate(L)
   for i to 8 do
      if f() <> L1[i] then print('error in llist, 11') fi
   od
   if f() <> null then
      print('error in llist, 12')
   fi;
   clear L;
   L := llist.list();
   for i to 6 do L[i] := i od;
   for i from 6 downto 1 do llist.purge(L, i) od;
   f := llist.iterate(L);
   if f() <> null then
     print('error in llist, 12')
   fi;
   clear L;
   L := llist.list();
   for i to 6 do L[i] := i od;
   L1 := llist.replicate(L);
   for i from 6 downto 1 do llist.purge(L, i) od;
   f := llist.iterate(L1);
   for i to 6 do
      if f() <> i then print('error in llist, 12', i) fi
   od;
   L := llist.list();
   f := llist.iterate(L);
   if f() <> null then
      print('error in llist, 13')
   fi;
   L := llist.list();
   for i to 6 do L[i] := i od;
   f := llist.iterate(L);
   if f(10k) <> null then
      print('error in llist, 14')
   fi;
   L := llist.list();
   f := llist.iterate(L);
   for i to 6 do L[i] := i od;
   for i from 6 downto 1 do llist.purge(L, i) od;
   if f() <> null then
      print('error in llist, 13')
   fi;
   L := llist.list();
   for i to 6 do L[i] := i od;
   f := llist.iterate(L);
   for i from 6 downto 1 do llist.purge(L, i) od;
   if f() <> null then
      print('error in llist, 13')
   fi;
   L := llist.list();
   f := llist.iterate(L);
   if f() <> null then
      print('error in llist, 14')
   fi;
   a := llist.list()
   for i to 9 do llist.prepend(a, i) od  # 9, 8, 7, 6, 5, 4, 3, 2, 1
   llist.append(a, 10);  # 9, 8, 7, 6, 5, 4, 3, 2, 1, 10
   llist.put(a, 2, -1);  # 9, -1, 8, 7, 6, 5, 4, 3, 2, 1, 10
   llist.put(a, 9, -2);  # 9, -1, 8, 7, 6, 5, 4, 3, -2, 2, 1, 10
   a[1] := 100           # 100, -1, 8, 7, 6, 5, 4, 3, -2, 2, 1, 10
   llist.prepend(a, -3)  # -3, 100, -1, 8, 7, 6, 5, 4, 3, -2, 2, 1, 10
   llist.append(a, 11)   # -3, 100, -1, 8, 7, 6, 5, 4, 3, -2, 2, 1, 10, 11
   llist.purge(a, 1);    # 100, -1, 8, 7, 6, 5, 4, 3, -2, 2, 1, 10, 11
   if a <> llist.list(100, -1, 8, 7, 6, 5, 4, 3, -2, 2, 1, 10, 11) then
      print('Error, llist, 15')
   fi;
   llist.purge(a, 13);   # 100, -1, 8, 7, 6, 5, 4, 3, -2, 2, 1, 10, 11
   if a <> llist.list(100, -1, 8, 7, 6, 5, 4, 3, -2, 2, 1, 10) then
      print('Error, llist, 16')
   fi;
   while size a <> 0 do
      llist.purge(a, 1);
   od;
   if a <> llist.list() then
      print('Error, llist, 17')
   fi;
   clear a;
   a := llist.list()
   if filled a then
      print('Error, llist, 18')
   fi;
   for i to 9 do llist.prepend(a, i) od  # 9, 8, 7, 6, 5, 4, 3, 2, 1
   if empty a then
      print('Error, llist, 19')
   fi;
   b := llist.dump(a)
   if b <> seq(9, 8, 7, 6, 5, 4, 3, 2, 1) then
      print('Error, llist, 20')
   fi;
   clear a;
   environ.gc()
od;


print('Checking ulist package\n');

for i to 100 do
   L := ulist.list(5);
   for i to 6 do
      ulist.append(L, i)
   od;
   for i to 4 do
      if L[i] <> i then
         print('error in ulist, 1')
      fi;
   od;
   # 1, 2, 3, 4, 5, 6
   for i to 4 do
      L[i] := L[i] + 1;
      if L[i] <> i + 1 then
         print('error in ulist, 2')
      fi;
   od;
   # 2, 3, 4, 5, 5, 6
   ulist.append(L, 8);
   # 2, 3, 4, 5, 5, 6, 8
   if L[7] <> 8 then
      print('error in ulist, 3')
   fi;
   ulist.prepend(L, 1);
   # 1, 2, 3, 4, 5, 5, 6, 8
   if L[1] <> 1 then
      print('error in ulist, 4')
   fi;
   ulist.purge(L, 1);
   # 2, 3, 4, 5, 5, 6, 8
   if L[1] <> 2 then
      print('error in ulist, 5')
   fi;
   ulist.purge(L, 7);
   # 2, 3, 4, 5, 5, 6
   if L[6] <> 6 then
      print('error in ulist, 6')
   fi;
   ulist.purge(L, 3);
   # 2, 3, 5, 5, 6
   if L[3] <> 5 then
      print('error in ulist, 7')
   fi;
   ulist.put(L, 1, 1);
   # 1, 2, 3, 5, 5, 6
   if L[1] <> 1 then
      print('error in ulist, 8')
   fi;
   ulist.put(L, 4, 4);
   # 1, 2, 3, 4, 5, 5, 6
   if L[4] <> 4 and L[5] <> 5 then
      print('error in ulist, 9')
   fi;
   ulist.put(L, 7, -1);
   # 1, 2, 3, 4, 5, 5, -1, 6
   if L[7] <> -1 and L[8] <> 7 then
      print('error in ulist, 10')
   fi;
   L1 := [1, 2, 3, 4, 5, 5, -1, 6];
   f := ulist.iterate(L)
   for i to 8 do
      if f() <> L1[i] then print('error in ulist, 11') fi
   od
   if f() <> null then
      print('error in ulist, 12')
   fi;
   clear L;
   L := ulist.list(5);
   for i to 6 do L[i] := i od;
   for i from 6 downto 1 do ulist.purge(L, i) od;
   f := ulist.iterate(L);
   if f() <> null then
     print('error in ulist, 12')
   fi;
   clear L;
   L := ulist.list(5);
   f := ulist.iterate(L);
   if f() <> null then
      print('error in ulist, 13')
   fi;
   L := ulist.list(5);
   for i to 6 do L[i] := i od;
   /* f := ulist.iterate(L);
   if f(10k) <> null then
      print('error in ulist, 14')
   fi; */
   L := ulist.list(5);
   f := ulist.iterate(L);
   for i to 6 do L[i] := i od;
   for i from 6 downto 1 do ulist.purge(L, i) od;
   if f() <> null then
      print('error in ulist, 13')
   fi;
   L := ulist.list(5);
   for i to 6 do L[i] := i od;
   f := ulist.iterate(L);
   for i from 6 downto 1 do ulist.purge(L, i) od;
   if f() <> null then
      print('error in ulist, 13')
   fi;
   L := ulist.list(5);
   f := ulist.iterate(L);
   if f() <> null then
      print('error in ulist, 14')
   fi;
   a := ulist.list(5)
   for i to 9 do ulist.prepend(a, i) od  # 9, 8, 7, 6, 5, 4, 3, 2, 1
   ulist.append(a, 10);  # 9, 8, 7, 6, 5, 4, 3, 2, 1, 10
   ulist.put(a, 2, -1);  # 9, -1, 8, 7, 6, 5, 4, 3, 2, 1, 10
   ulist.put(a, 9, -2);  # 9, -1, 8, 7, 6, 5, 4, 3, -2, 2, 1, 10
   a[1] := 100           # 100, -1, 8, 7, 6, 5, 4, 3, -2, 2, 1, 10
   ulist.prepend(a, -3)  # -3, 100, -1, 8, 7, 6, 5, 4, 3, -2, 2, 1, 10
   ulist.append(a, 11)   # -3, 100, -1, 8, 7, 6, 5, 4, 3, -2, 2, 1, 10, 11
   ulist.purge(a, 1);    # 100, -1, 8, 7, 6, 5, 4, 3, -2, 2, 1, 10, 11
   p := seq(100, -1, 8, 7, 6, 5, 4, 3, -2, 2, 1, 10, 11)
   a1 := ulist.list(5);
   for i in p do ulist.append(a1, i) od;
   if a <> a1 then
      print('Error, ulist, 15')
   fi;
   ulist.purge(a, 13);   # 100, -1, 8, 7, 6, 5, 4, 3, -2, 2, 1, 10, 11
   p := seq(100, -1, 8, 7, 6, 5, 4, 3, -2, 2, 1, 10)
   a1 := ulist.list(5);
   for i in p do ulist.append(a1, i) od;
   if a <> a1 then
      print('Error, ulist, 16')
   fi;
   while size a <> 0 do
      ulist.purge(a, 1);
   od;
   if a <> ulist.list() then
      print('Error, ulist, 17')
   fi;
   clear a;
   p := seq(100, -1, 8, 7, 6, 5, 4, 3, -2, 2, 1, 10, 11)
   a1 := ulist.list(5);
   for i in p do ulist.append(a1, i) od;
   q := seq(100, -1, 8, 7, 6, 5, 4, 3, -2, 2, 1, 10, 11)
   a2 := ulist.list(15);
   for i in q do ulist.append(a2, i) od;
   if not(a1 = a2) then
      print('Error, ulist, 17')
   fi;
   p := seq(100, -1, 8, 7, 6, 5, 4, 3, -2, 2, 1, 10, 11)
   a1 := ulist.list(5);
   for i in p do ulist.append(a1, i) od;
   q := seq(100, -1, 8, 7, 6, 5, 4, 3, -2, 2, 1, 10, 11)
   a2 := ulist.list(20);
   for i in q do ulist.append(a2, i) od;
   if not(a1 = a2) then
      print('Error, ulist, 18')
   fi;
   a1[1] := 0;
   if a1 = a2 then
      print('Error, ulist, 19')
   fi;
   a1 := ulist.list(5);
   a2 := ulist.list(6);
   if not(a1 = a2) then
      print('Error, ulist, 20')
   fi;
   p := seq(100, -1, 8, 7, 6, 5, 4, 3, -2, 2, 1, 10, 11)
   a1 := ulist.list(5);
   for i in p do ulist.append(a1, i) od;
   q := seq(100, -1, 8, 7, 6, 5, 4, 3, -2, 2, 1, 10)
   a2 := ulist.list(20);
   for i in q do ulist.append(a2, i) od;
   if a1 = a2 then
      print('Error, ulist, 21')
   fi;
   p := [100, -1, 8, 7, 6, 5, 4, 3, -2, 2, 1, 10, 11]
   a1 := ulist.list(5);
   if filled a1 then
      print('Error, ulist, 22')
   fi;
   for i in p do ulist.append(a1, i) od;
   if empty a1 then
      print('Error, ulist, 23')
   fi;
   if ulist.totable(a1) <> p then
      print('Error, ulist, 24')
   fi;
   a1 := ulist.dump(a1);
   if a1 <> seq(100, -1, 8, 7, 6, 5, 4, 3, -2, 2, 1, 10, 11) then
      print('Error, ulist, 25')
   fi
   a1 := ulist.list(5);
   for i in p do ulist.append(a1, i) od;
   if ulist.totable(a1) <> p then
      print('Error, ulist, 26')
   fi;
   p := ulist.dump(a1);
   if p <> seq(100, -1, 8, 7, 6, 5, 4, 3, -2, 2, 1, 10, 11) then
      print('Error, ulist, 27')
   fi;
   clear a1;
   environ.gc()
od;

clear p, q, a1, a2;


print('Checking io package\n');

to 50 do
   fd := io.open('misc.agn', 'r');
   io.skiplines(fd, 2);
   if io.lines(fd)() <> 'readlib \'bags\'' then
      print('error in io.skiplines, 1')
   fi;
   io.skiplines(fd, 100k);
   if io.lines(fd)() <> null then
      print('error in io.skiplines, 2')
   fi;
   io.close(fd);
   if 'io package' notin io.readfile('misc.agn') then
      print('error in io.readfile, 1')
   fi;
   fd := io.open('sample.csv');
   if io.filesize(fd) <> 39 then
      print('error in io.filesize, 1')
   fi;
   if io.move(fd, 2) <> true then
      print('error in io.move, 1')
   fi;
   if io.seek(fd) <> 2 then
      print('error in io.move, 2')
   fi;
   io.close(fd);
   fd := io.open('sample2.csv', 'w');
   io.write(fd, '123456789A123456789B');
   io.move(fd, -10);
   io.truncate(fd);
   if io.seek(fd) <> 10 then
      print('error in io.truncate, 1')
   fi;
   io.close(fd);
   os.remove('sample2.csv');
   if io.writefile('sample2.csv', '123456789A123456789B', '123456789A123456789B', '123456789A123456789B', delim='\n') <> 62 then
      print('error in io.writefile, 1')
   fi;
   fd := io.open('sample2.csv', 'r');
   if io.filesize(fd) <> 62 then
      print('error in io.writefile, 2')
   fi;
   if io.seek(fd) <> 0 then
      print('error in io.writefile, 3')
   fi;
   if io.isfdesc(fd) <> true then
      print('error in io.isfdesc, 3')
   fi;
   if io.fileno(fd) :- number then
      print('error in io.fileno, 3')
   fi;
   io.close(fd);
   os.remove('sample2.csv');
   if os.system()[1] in {'Windows', 'MS-DOS', 'IBMPcDos', 'OS/2'} then
      os.curdrive();
   fi;
   if os.system()[1] = 'Windows' then
      os.ismounted('c');
      os.isvaliddrive('c');
   fi;
   if not os.isfile('misc.agn') then
      print('error in os.isfile')
   fi;
   if not os.isdir('..') or not os.isdir('../testall') then
      print('error in os.isfile')
   fi;
od;

if os.isUNIX() then
   try
      #print('Valgrind reported memory leaks with a Linux flavour of os.userinfo.');
      #os.userinfo();
      os.groupinfo(os.userinfo()['username'])
   yrt
fi;


print('Checking utils package\n');

if not(filled(utils.findfiles('*', 'alex'))) then
   print('error in utils.findfiles, 1')
fi

if not(filled(utils.findfiles('strings.agn', 'alex'))) then
   print('error in utils.findfiles, 2')
fi

#if io.infile('../testall/bigfile.txt', '4096') <> true then
#   print('error in io.file, 1')
#fi

#if io.infile('../testall/bigfile.txt', '200000') <> false then
#   print('error in io.file, 2')
#fi

if utils.readini('example.ini') <> ['Agena' ~ '', 'Pizza' ~ ['Capres' ~ 0, 'Cheese' ~ 'Non', 'Ham' ~ 'yes', 'Mushrooms' ~ true],
   'Taxi' ~ 'Pizza Cab', 'Wine' ~ ['Country' ~ 'Spain', 'Grape' ~ 'Cabernet Sauvignon', 'Preis' ~ '3,99', 'Price' ~ 3.99,
   'Year' ~ 1989]] then
   print('error in utils.readini, 1')
fi


print('Checking xbase package\n');

import xbase;

xbase.new('test.dbf', Number=number, Float='float', Double='double', String='string', Date='date', Boolean='boolean',
  Integer = 'I', TimeStamp='T');

f := xbase.open('test.dbf', 'write')

for i from 0 to 9 do
   xbase.writenumber(f,  i + 1, 1, Pi + i);
   xbase.writefloat(f,   i + 1, 2, Pi + i);
   xbase.writedouble(f,  i + 1, 3, Pi + i);
   xbase.writestring(f,  i + 1, 4, 'Alex');
   xbase.writedate(f,    i + 1, 5, '20000101');
   xbase.writeboolean(f, i + 1, 6, true);
   xbase.writelong(f,    i + 1, 7, 1000);
   xbase.writetime(f,    i + 1, 8, 2016, 8, 1, 11, 0, 0);
od;

if xbase.close(f) <> true then
   print('error in xbase, 1')
fi;

f := xbase.open('test.dbf', 'write')

contents := xbase.attrib(f);

contents.lastmodified := null;

if contents <>
   ['codepage' ~ 'LDID/0', 'fieldinfo' ~ [
      ['nativetype' ~ 'N', 'scale' ~ 15, 'title' ~ 'Number',  'type' ~ 'number',  'width' ~ 19],
      ['nativetype' ~ 'F', 'scale' ~ 18, 'title' ~ 'Float',   'type' ~ 'number',  'width' ~ 20],
      ['nativetype' ~ 'B', 'scale' ~ 0,  'title' ~ 'Double',  'type' ~ 'number',  'width' ~ 8],
      ['nativetype' ~ 'C', 'scale' ~ 0,  'title' ~ 'String',  'type' ~ 'string',  'width' ~ 64],
      ['nativetype' ~ 'D', 'scale' ~ 0,  'title' ~ 'Date',    'type' ~ 'string',  'width' ~ 8],
      ['nativetype' ~ 'L', 'scale' ~ 0,  'title' ~ 'Boolean', 'type' ~ 'boolean', 'width' ~ 1],
      ['nativetype' ~ 'I', 'scale' ~ 0,  'title' ~ 'Integer', 'type' ~ 'number',  'width' ~ 4],
      ['nativetype' ~ 'T', 'scale' ~ 0,  'title' ~ 'TimeStamp', 'type' ~ 'number', 'width' ~ 8],
   ],
   'fields' ~ 8, 'filename' ~ 'test.dbf', 'headerlength' ~ 289, 'languagedriver' ~ 0,
   'recordlength' ~ 133, 'records' ~ 10, 'version' ~ 48] then
      print('error in xbase, 2')
fi;

if xbase.mark(f, 5, true) = false then
   print('error in xbase.mark, 1')
fi;

if xbase.ismarked(f, 5) <> true then
   print('error in xbase.ismarked, 1')
fi;

for i to xbase.fields(f) do
   if xbase.readvalue(f, 5, i) <> null then
      print('error in xbase.readvalue, 1')
   fi
od;

if xbase.mark(f, 6, false) = false then
   print('error in xbase.mark, 2')
fi;

if xbase.ismarked(f, 6) <> false then
   print('error in xbase.ismarked, 2')
fi;

for i to xbase.fields(f) do
   if xbase.readvalue(f, 6, i) = null then
      print('error in xbase.readvalue, 2')
   fi
od;

myrecord := xbase.record(f, 2);
if not approx(myrecord[1], 4.1415926535898) then
   print('error in xbase, 3')
fi;
if not approx(myrecord[2], 4.1415926535898) then
   print('error in xbase, 4')
fi;
if not approx(myrecord[3], 4.1415926535898) then
   print('error in xbase, 5')
fi;
if myrecord[4] <> 'Alex' then
   print('error in xbase, 6')
fi;
if myrecord[5] <> '20000101' then
   print('error in xbase, 7')
fi;
if myrecord[6] <> true then
   print('error in xbase, 8')
fi;
if myrecord[7] <> 1k then
   print('error in xbase, 9')
fi;
if myrecord[8] <> 2457602:39600000 then
   print('error in xbase, 10', myrecord[8])
fi;

myfield := xbase.readdbf(f, fields=3);
if size myfield <> 9 then  # record #5 has been marked `deleted`
   print('error in xbase.field, 1')
fi;
if not(myfield ~= seq(3.1415926535898, 4.1415926535898, 5.1415926535898, 6.1415926535898,
                  8.1415926535898, 9.1415926535898, 10.14159265359, 11.14159265359,
                  12.14159265359)) then
   print('error in xbase.field, 2')
fi;

xbase.close(f);

os.remove('test.dbf');


print('Checking hashes package\n');

import hashes;

heyne := proc(f :: string) is
   return utils.readcsv(f, delim = '|', field = 1, ignore = << x -> '#' in x = 1 >>)
end;

h := heyne('gothic.csv')

hashes.collisions(h, hashes.asu, 10);
hashes.collisions(h, hashes.bkdr, 10);
#hashes.collisions(h, hashes.bsd, 10);   # see check below
hashes.collisions(h, hashes.cksum, 10);
hashes.collisions(h, hashes.crc16, 10);
hashes.collisions(h, hashes.crc32, 10);
#hashes.collisions(h, hashes.damm, 10);  # see check below
hashes.collisions(h, hashes.dek, 10);
hashes.collisions(h, hashes.djb, 10);
hashes.collisions(h, hashes.djb2, 10);
hashes.collisions(h, hashes.djb2rot, 10);
hashes.collisions(h, hashes.elf, 10);
#hashes.collisions(h, hashes.fletcher, 10);  # see check below
hashes.collisions(h, hashes.fnv, 10);
hashes.collisions(h, hashes.jen, 10);
hashes.collisions(h, hashes.lua, 10);
hashes.collisions(h, hashes.md5, 10);
hashes.collisions(h, hashes.oaat, 10);
hashes.collisions(h, hashes.pl, 10);
hashes.collisions(h, hashes.raw, 10);
hashes.collisions(h, hashes.sax, 10);
hashes.collisions(h, hashes.sdbm, 10);
hashes.collisions(h, hashes.sth, 10);
hashes.collisions(h, hashes.strval, 10);
hashes.collisions(h, hashes.murmur2, 10);
hashes.collisions(h, hashes.murmur3, 10);
hashes.collisions(h, hashes.murmur3128, 10);

clear h, heyne;

str := 'sun microsystems sun pro';
f := reg(hashes.djb, hashes.djb2, hashes.fnv, hashes.jen, hashes.md5,
         hashes.oaat, hashes.pl, hashes.raw, hashes.sax, hashes.sdbm,
         hashes.sth);
f0 := reg('hashes.djb', 'hashes.djb2', 'hashes.fnv', 'hashes.jen', 'hashes.md5',
         'hashes.oaat', 'hashes.pl', 'hashes.raw', 'hashes.sax', 'hashes.sdbm',
         'hashes.sth');
r := reg(180, 684, 978, 55, '226E8EDF4A99547BD8DA5A3E1827B7B8',
         118, 587, 292, 653, 949,
         548);
for i to size f do
   if f[i] <> hashes.md5 then
      if f[i](str, 1000) <> r[i] then
         print('Error in ' & f0[i], i, r[i])
      fi
   else
      if f[i](str) <> r[i] then
         print('Error in ' & f0[i], i, r[i])
      fi
   fi;
od;

if hashes.cksum(io.readfile('cksum.txt')) <> 1272272399 then
   print('Error in hashes.cksum')
fi;

if hashes.crc16('123456789') <> 47933 or hashes.crc16('123456789') <> 0xbb3d then
   print('Error in hashes.crc16')
fi;

hashes.murmur2('1234567890');
hashes.murmur3('1234567890');
if not os.system()[1] in {'OS/2'} then
   hashes.murmur3128('1234567890')
fi;
hashes.murmur2('');
hashes.murmur3('');
if not os.system()[1] in {'OS/2'} then
   hashes.murmur3128('')
fi;
if hashes.sha512('Artikel 1 (1) GG: Die Wuerde des Menschen ist unantastbar.', '1234567890') <>
   # Xubuntu 14.04: mkpasswd -m sha-512 "Artikel 1 (1) GG: Die Wuerde des Menschen ist unantastbar." -s "1234567890"
   # $6$1234567890$fIcexUkD4g4hAaMl0maW5y.PQYE.1Qh3lw1AAE37omBswA4spjNAMba/E.t2GPoMQsm6ug7pxh6bMi.cu/TZN0
   'fIcexUkD4g4hAaMl0maW5y.PQYE.1Qh3lw1AAE37omBswA4spjNAMba/E.t2GPoMQsm6ug7pxh6bMi.cu/TZN0' then
   print('Error in hashes.sha512')
fi;

if hashes.damm(1232) <> 2 then
   print('Error in hashes.damm')
fi;

if hashes.bsd('123454') <> 34918 then
   print('Error in hashes.bsd')
fi;

if hashes.fletcher('123454') <> 69599539 then
   print('Error in hashes.fletcher')
fi;

clear f, r, i;


print('Checking os package\n');

os.chdir('../testall');

for i in ['chdir', 'computername', 'cpuinfo', 'cpuload', 'date', 'drives', 'endian', 'environ',
          'freemem', 'isANSI', 'list', 'login', 'now', 'system', 'uptime', 'time', 'tmpname'] do
   os[i]()
od;

if not os.exists('misc.agn') then
   print('error in os.exists');
fi;

os.getenv('AGENAPATH');

if environ.os notin {'dos', '??unknow'} then
   os.memstate();
fi;

environ.kernel();

if os.system()[1] in {'SunOS', 'Linux', 'Windows'} then
   os.drivestat('/');
fi

os.getlocale();

if os.filename('./misc.agn') <> 'misc.agn' then
   print('error in os.filename');
fi;

if os.dirname('../testall/misc.agn') <> '../testall' then
   print('error in os.dirname');
fi;

path, fn, fno := '_temp_', 'read.me', 'read.bak';

if os.fcopy(fn, fno) <> true then
   print('error in os.fcopy, 1');
else
   os.remove(fno);
fi;

os.mkdir(path);
if os.fcopy(fn, path) <> true then
   print('error in os.fcopy, 2');
else
   os.remove(path & '/' & fn);
   os.rmdir(path)
fi;

# os.chdir('../testall')
subdir := 'fileops';
file1 := subdir & '.tst';
file2 := subdir & '.txt';
try
   os.mkdir(subdir)
catch
   print('error in os.mkdir, A1')
yrt;
if os.mkdir(subdir, true) <> fail then
   print('error in os.mkdir, A1')
fi;
# okay
try
   os.fcopy(file1, subdir)
catch
   print('error in os.fcopy, A1')
yrt;
if os.fcopy(file1, subdir, true) <> fail then
   print('error in os.fcopy, A2')
fi;
# okay
os.chdir(subdir);
# we are now in new subfolder try to rename file1
try
   os.move(file1, file2)
catch
   print('error in os.move, A1')
yrt;
if os.exists(file1) then
   print('error in os.move, A2')
fi;
# we have renamed file1 to file2, so file1 does no longer exist
if os.move(file1, file2, true) <> fail then
   print('error in os.move, A3')
fi;
#file1 has now been renamed to file2, we are still in new subfolder
try
   os.remove(file2)
catch
   print('error in os.remove, A1')
yrt;
if os.remove(file2, true) <> fail then
   print('error in os.remove, A2')
fi;
# there no longer is a file in subdir
try
   os.remove(file1)
yrt;
if os.remove(file1, true) <> fail then
   print('error in os.remove, A3')
fi;
os.chdir('..');
try
   os.rmdir(subdir)
catch
   print('error in os.rmdir, A1')
yrt;
if os.rmdir(subdir, true) <> fail then
   print('error in os.rmdir, A2')
fi;

/*
to 10 do
   os.mkstemp('fileXXXXXX');
   os.wait(1)
od
*/

print('Checking environ package\n');

f := proc(x, ?) is return x end

if environ.attrib(f) <> ['C' ~ false, 'arity' ~ 1, 'bytes' ~ 40, 'nupvals' ~ 0, 'rtableWritemode' ~ fail, 'utype' ~ fail, 'varargs'  ~ true] then
   print('error in environ.attrib, 1')
fi;

a, b := environ.arity(f);

if a <> 1 or b <> true then
   print('error in environ.attrib, 2')
fi;

t1 := ['C' ~ true, 'arity' ~ fail, 'bytes' ~ 40, 'nupvals' ~ 0, 'rtableWritemode' ~ fail, 'utype' ~ fail, 'varargs' ~ fail];
t2 := environ.attrib(math.accu);

t1.bytes, t2.bytes -> null;  # values may differ between platforms

if t1 <> t2 then
   print('error in environ.attrib, 3')
fi;

clear t1, t2;

print('Checking clock package\n');

import clock;

a := clock.tm(1, 30)

b := clock.tm(1, 40)

if a + b <> clock.tm(0, 3, 10) then
   print('error in clock/add')
fi;

if a - b <> clock.tm(-0, -0, -10) then
   print('error in clock/sub')
fi;


print('Checking ads package\n');

import ads
fn := 'test.agb';
ads.createbase(fn);
fh := ads.openbase(fn);
if ads.writebase(fh, 'Duck', 'Donald') <> true then
   print('error in ads.writebase')
fi;
if ads.readbase(fh, 'Duck') <> 'Donald' then
   print('error in ads.readbase')
fi;
ads.attrib(fh);
ads.comment(fh, 'testdb');
if ads.comment(fh) <> 'testdb' then
   print('error in ads.comment')
fi;
if ads.clean(fh) <> false then
   print('error in ads.clean')
fi;
if ads.desc(fh) <> '' then
   print('error in ads.desc, 1')
fi;
ads.desc(fh, 'testdb');
if ads.desc(fh) <> 'testdb' then
   print('error in ads.desc, 2')
fi;
if ads.lookup(fh, '<th>iudinassus') <> [] then
   print('error in ads.lookup/iterate')
fi;
if ads.invalids(fh) <> [] then
   print('error in ads.lookup/invalids')
fi;
if ads.getkeys(fh) <> ['Duck'] then
   print('error in ads.getkeys')
fi;
if ads.getvalues(fh) <> ['Donald'] then
   print('error in ads.getvalues')
fi;
if ads.free(fh) <> 19999 then
   print('error in ads.free')
fi;
if ads.filepos(fh) <> 0 then
   print('error in ads.filepos')
fi;
ads.expand(fh);
if ads.free(fh) <> 20009 then
   print('error in ads.expand')
fi;
if ads.clean(fh) <> false then
   print('error in ads.clean')
fi;
if ads.index(fh, 'Duck') <> 80296 then
   print('error in ads.index, 1')
fi;
if ads.index(fh, 'Ducka') <> null then
   print('error in ads.index, 2')
fi;
if ads.remove(fh, 'Duck') <> true then
   print('error in ads.remove')
fi;
ads.clean(fh);
if ads.indices(fh) <> [] then
   print('error in ads.indices')
fi;
ads.writebase(fh, 'Klaas', 'Klever');
if ads.readbase(fh, 'Klaas') <> 'Klever' then
   print('error in ads.readbase')
fi;
if ads.comment(fh) <> 'testdb' then
   print('error in ads.comment')
fi;
if ads.invalids(fh) <> [] then
   print('error in ads.invalids')
fi;
if ads.remove(fh, 'Klaas') <> true then
   print('error in ads.remove, 1')
fi;
if ads.remove(fh, 'Klaas') <> false then
   print('error in ads.remove, 2')
fi;
if ads.invalids(fh) <> [80296] then
   print('error in ads.remove')
fi;
ads.clean(fh);
if ads.invalids(fh) <> [] then
   print('error in ads.invalids')
fi;
if ads.comment(fh) <> 'testdb' then
   print('error in ads.comment')
fi;
if ads.clean(fh) <> false then
   print('error in ads.clean')
fi;
if ads.getkeys(fh) <> null then
   print('error in ads.getkeys, 1')
fi;
if ads.getvalues(fh) <> null then
   print('error in ads.getvalues, 1')
fi;
ads.writebase(fh, 'Duck', 'Daisy');
ads.writebase(fh, 'Klever', 'Klaas');
if ads.getkeys(fh) <> ['Duck', 'Klever'] then
   print('error in ads.getkeys, 2')
fi;
if ads.getvalues(fh) <> ['Daisy', 'Klaas'] then
   print('error in ads.getvalues, 2')
fi;
if ads.indices(fh) <> [80296, 80315] then
   print('error in ads.indices')
fi;
if [ads.peekin(fh, 80315)] <> [7, 'Klever'] then
   print('error in ads.peek')
fi;
if ads.retrieve(fh, 80315) <> ['Klever', 'Klaas'] then
   print('error in ads.retrieve')
fi;
if ads.rawsearch(fh, 'Klever', 1) <> ['Klever' ~ 'Klever'] then
   print('error in ads.rawsearch, 1')
fi
if ads.rawsearch(fh, 'Kleve', 1) <> ['Klever' ~ 'Klever'] then
   print('error in ads.rawsearch, 2')
fi;
if ads.rawsearch(fh, 'Klere', 1) <> [] then
   print('error in ads.rawsearch, 3')
fi;
ads.closebase(fh);
os.remove(fn);


print('Checking bloom package\n');

import bloom, hashes

to 10 do
   spacecraft := // Akatsuki Chandrayaan Chang'e "Mars Express" Venera Voyager \\;
   b := bloom.new(size spacecraft, 4);
   for i in spacecraft do
      bloom.include(b, hashes.pl(i))
   od;
   for i in spacecraft do
      if not bloom.find(b, hashes.pl(i)) then
         print('Error, could not find', i)
      fi
   od;
   bloom.get(b, 1);
   bloom.attrib(b);
   clear b, i, spacecraft  # force gc
od;


print('Checking for global names in packages (lasterror & calls to packages are ok)\n');

for i, j in _G do
   if j :: procedure and not environ.attrib(j)['C'] then
      c := environ.globals(j);
      if assigned c then
         c := remove(<< x -> left x = 'lasterror' >>, c);
         if filled(c) then
            print(i, c)
         fi
      fi
   fi
od;

allpackages := [
   'ads', 'ansi', 'astro', 'bags', 'binio', 'calc', 'clock', 'divs', 'hashes', 'io',
   'linalg', 'llist', 'math', 'mp', 'numarray', 'os', 'package', 'rtable', 'skycrane',
   'stats', 'strings', 'tables', 'tar', 'utils', 'xbase', 'zx', 'bloom', 'factory'
];

case environ.os
   of 'windows', 'solaris', 'linux', 'macosx' then
      insert 'net', 'xml', 'fractals', 'gdi' into allpackages
   of 'OS/2', 'dos' then
      insert 'xml' into allpackages
   of 'macosx' then
      delete 'mp' from allpackages
esac;


flag := false;
for i in allpackages do
   if unassigned(_G[i]) then
      readlib(i)
   fi;
   if _G[i] :: table then
      for j in _G[i] do
         if j :: procedure and not environ.attrib(j)['C'] then
            c := environ.globals(j);
            if assigned(c) then
               c := remove(<< x -> left x = 'lasterror' >>, c);
               if filled(c) then
                  print(i, c);
                  flag := true
               fi
            fi
         fi
      od
   fi
od;
if flag then print() fi;

if 'xml' in allpackages then
   print('Checking xml package\n');
   str := io.readfile('lang.xml');
   x := utils.decodexml(str);
   if x.language.data[2].name <> 'Lua' then
      print('error in utils.decodexml')
   fi
fi;


print('Checking factory package\n');

import factory;

s := [10, 20, 30, 'a'~40];
f := factory.iterate(s);
t := [];
for i to size s do
   x, y := f()
   insert y into t
od;
if t <> tables.entries(s) then
   print('error in `factory.iterate`, 1')
fi;

s := [10, 20, 30, 'a'~40];
f := factory.cycle(s);
t := [];
for i to size s do
   x, y := f()
   insert y into t
od;
if t <> tables.entries(s) then
   print('error in `factory.cycle`, 1')
fi;

s := seq(10, 20, 30, 40);
f := factory.iterate(s, 1);
t := seq();
for i to size s do
   x, y := f()
   insert y into t
od;
if t <> s then
   print('error in `factory.iterate`, 2')
fi;

s := seq(10, 20, 30, 40);
f := factory.cycle(s);
t := seq();
for i to size s do
   x, y := f()
   insert y into t
od;
if t <> s then
   print('error in `factory.cycle`, 2')
fi;

s := reg(10, 20, 30, 40);
f := factory.iterate(s, 1);
t := reg();
for i to size s do
   x, y := f()
   insert y into t
od;
if t[1 to 4] <> s then
   print('error in `factory.iterate`, 3')
fi;

s := reg(10, 20, 30, 40);
f := factory.cycle(s);
t := reg();
for i to size s do
   x, y := f()
   insert y into t
od;
if t[1 to 4] <> s then
   print('error in `factory.cycle`, 3')
fi;

s := 'alex';
f := factory.iterate(s, 1);
t := seq();
for i to size s do
   x, y := f()
   insert y into t
od;
if join(t) <> s then
   print('error in `factory.iterate`, 4')
fi;

s := 'alex';
f := factory.cycle(s);
t := seq();
for i to size s do
   x, y := f()
   insert y into t
od;
if join(t) <> s then
   print('error in `factory.cycle`, 4')
fi;

import factory
s := [10, 20, 30, 'a'~40];
f := factory.iterate(s);
f();
f();
factory.reset(f, null);
x, y := f();
if x <> 1 or y <> s[1] then
   print('error in `factory.reset`, 1')
fi;

s := seq(10, 20, 30, 40);
f := factory.iterate(s);
f();
f();
factory.reset(f, 1);
x, y := f();
if x <> 1 or y <> s[1] then
   print('error in `factory.reset`, 1')
fi;

s := reg(10, 20, 30, 40);
f := factory.iterate(s);
f();
f();
factory.reset(f, 1);
x, y := f();
if x <> 1 or y <> s[1] then
   print('error in `factory.reset`, 3')
fi;

f := factory.count(0, 1);
f();
f();
factory.reset(f, 0);
if f() <> 0 then
   print('error in `factory.reset`, 4')
fi;
if f() <> 1 then
   print('error in `factory.reset`, 5')
fi;

f := factory.count(0, 0.5);
f();
f();
factory.reset(f, 0);
if f() <> 0 then
   print('error in `factory.reset`, 6')
fi;
if f() <> 0.5 then
   print('error in `factory.reset`, 7')
fi;

f := factory.count(0, 0.5, 1);
f();
f();
f();
if f() <> null then
   print('error in `factory.reset`, 8')
fi;
factory.reset(f, 0);
if f() <> 0 then
   print('error in `factory.reset`, 9')
fi;

f := factory.count(0, 2, 6);
f();
f();
f();
f();
if f() <> null then
   print('error in `factory.reset`, 10')
fi;
factory.reset(f, 0);
if f() <> 0 then
   print('error in `factory.reset`, 11')
fi;


print('Checking sema package\n');

import sema;

i := 8*32 + 16;

to i do sema.open() od;
sema.close(1);
if sema.open() <> 1 then
   print('error in `sema.open`, 1')
fi;
if sema.open() <> i then
   print('error in `sema.open`, 2')
fi;
sema.reset();
if sema.open() <> 0 then
   print('error in `sema.open`, 3')
fi;

to 8 * 32 do sema.open() od;
if sema.shrink() then
   print('error in `sema.shrink`, 1')
fi;
to 8 * 32 do sema.open() od;  # 512 open
if sema.shrink() then
   print('error in `sema.shrink`, 2')
fi;
for i from 512 downto 255 do sema.close(i) od;
if not sema.shrink() then
   print('error in `sema.shrink`, 3')
fi;
if sema.open() <> 255 then
   print('error in `sema.open/shrink`, 1')
fi;

sema.reset();
sema.open(10000);
if sema.open() <> 0 then
   print('error in `sema.open`, 4')
fi;
for i from 1 to 9999 do sema.open() od;
if sema.open() <> 10001 then
   print('error in `sema.open`, 5')
fi;
sema.reset();

i := 8*32 + 16;

s := sema.new();
to i do sema.open(s) od;
sema.close(s, 1);
if sema.open(s) <> 1 then
   print('error in `sema.open`, 6')
fi;
if sema.open(s) <> i then
   print('error in `sema.open`, 7')
fi;
sema.reset(s);
if sema.open(s) <> 0 then
   print('error in `sema.open`, 8')
fi;

to 8 * 32 do sema.open(s) od;
if sema.shrink(s) then
   print('error in `sema.shrink`, 4')
fi;
to 8 * 32 do sema.open(s) od;  # 512 open
if sema.shrink(s) then
   print('error in `sema.shrink`, 5')
fi;
for i from 512 downto 255 do sema.close(s, i) od;
if not sema.shrink(s) then
   print('error in `sema.shrink`, 6')
fi;
if sema.open(s) <> 255 then
   print('error in `sema.open/shrink`, 2')
fi;

sema.reset(s);
sema.open(s, 10000);
if sema.open(s) <> 0 then
   print('error in `sema.open`, 9')
fi;
for i from 1 to 9999 do sema.open(s) od;
if sema.open(s) <> 10001 then
   print('error in `sema.open`, 10')
fi;
sema.reset(s);


print('Checking bytes package\n');

import bytes;

if bytes.unpack('n', bytes.pack('n', Pi)) <> Pi then
   print('error in `bytes.pack/unpack`, 1')
fi;

if bytes.bcd(100) <> 256 then
   print('error in `bytes.bcd`, 1')
fi;

if bytes.bcd(256, true) <> 100 then
   print('error in `bytes.bcd`, 2')
fi;

if bytes.bcd(0) <> 0 then
   print('error in `bytes.bcd`, 3')
fi;

if bytes.bcd(0, true) <> 0 then
   print('error in `bytes.bcd`, 4')
fi;

if bytes.tobytes(257, 4) <> seq(1, 1, 0, 0) then
   print('error in `bytes.tobytes`, 1')
fi;

if bytes.tobytes(Pi) <> seq(24, 45, 68, 84, 251, 33, 9, 64) then
   print('error in `bytes.tobytes`, 2')
fi;

if bytes.tonumber(bytes.tobytes(Pi)) <> Pi then
   print('error in `bytes.tonumber`, 1')
fi;

if bytes.shift32(1, -2) <> 4 then
   print('error in `bytes.shift32`, 1')
fi;

if bytes.shift32(65536, 6) <> 1024 then
   print('error in `bytes.shift32`, 2')
fi;

if bytes.not32(2) <> 4294967293 then
   print('error in `bytes.not32`, 1')
fi;

if bytes.mask32(8) <> 255 then
   print('error in `bytes.mask32`, 1')
fi;

if bytes.xor32(8, 1) <> 9 then
   print('error in `bytes.xor32`, 1')
fi;

if bytes.xnor32(8, 1) <> -10 then
   print('error in `bytes.xnor32`, 1')
fi;

if bytes.and32(1, 0) <> 0 then
   print('error in `bytes.and32`, 1')
fi;

if bytes.or32(2, 1) <> 3 then
   print('error in `bytes.or32`, 1')
fi;

if bytes.nor32(2, 1) <> -4 then
   print('error in `bytes.nor32`, 1')
fi;

to 10 do
   x := bytes.cast(-Pi);
   if bytes.gethigh(x) <> 3221823995 then
      print('error in `bytes.gethigh`, 1')
   fi;
   if bytes.getlow(x) <> 1413754136 then
      print('error in `bytes.getlow`, 1')
   fi;
   clear x  # force gc
od;

if bytes.onebits(2^32-1) <> 32 then
   print('error in `bytes.onebits`, 1')
fi;

# 3221823995d = 11000000000010010010000111111011 > 2^31
if bytes.onebits(3221823995) <> 13 then
   print('error in `bytes.onebits`, 2')
fi;

if bytes.leadzeros(2^32-1) <> 0 then
   print('error in `bytes.leadzeros`, 1')
fi;

if bytes.trailzeros(3221823995) <> 0 then
   print('error in `bytes.trailzeros`, 1')
fi;

if bytes.mostsigbit(2^31-1) <> 31 then
   print('error in `bytes.mostsigbit`, 1')
fi;

if bytes.leastsigbit(2^31-1) <> 1 then
   print('error in `bytes.leastsigbit`, 1')
fi;

if bytes.gethighofdouble(Pi) && (1 <<< 31) <> 0 then  # get signbit
   print('error in `bytes.gethighofdouble <<< 31`, 1')
fi;

if bytes.gethighofdouble(-Pi) && (1 <<< 31) = 0 then
   print('error in `bytes.gethighofdouble <<< 31`, 2')
fi;

clear x;


print('Checking numarray package\n');

import numarray  # for DOS flavours to import lib/numarray.agn
to 100 do
   n :=  numarray.double(128);
   if n[0] <> [] then
      print('error in `numarray.double`, 1')
   fi;
   if n[1] <> 0 then
      print('error in `numarray.double`, 2')
   fi;
   n := numarray.double(5);
   for i to 5 do
      n[i] := i
   od;
   for i to 5 do
      if n[i] <> i then
         print('error in `numarray.getitem`, 1')
      fi
   od;
   if size n <> 5 then
      print('error in numarray `size`, 1')
   fi;
   m := numarray.double(5);
   numarray.include(m, 1, n);
   for i to 5 do
      if n[i] <> m[i] then
         print('error in `numarray.include`, 1')
      fi
   od;
   numarray.include(n, 1, 0);
   if n[1] <> 0 then
      print('error in `numarray.include`, 2')
   fi;
   f := numarray.cycle(n, 1, 1);
   for i from 0 to 5 do
      if f() <> i then
         print('error in `numarray.cycle`, 1')
      fi
   od;
   for i from 0 to 5 do
      if f() <> i then
         print('error in `numarray.cycle`, 2')
      fi
   od;
   f := numarray.iterate(n, 1, 1);
   for i from 0 to 5 do
      if f() <> i then
         print('error in `numarray.iterate`, 1')
      fi
   od;
   if f() <> null then
      print('error in `numarray.iterate`, 2')
   fi;
   numarray.resize(n, 10);
   if size n <> 10 then
      print('error in numarray `size`, 2')
   fi;
   if numarray.toseq(n) <> seq(0, 1, 2, 3, 4, 5, 0, 0, 0, 0) then
      print('error in `numarray.resize`, 1')
   fi;
   if numarray.whereis(n, 0, 2) <> 7 then
      print('error in `numarray.resize`, 2')
   fi;
   fh := binio.open('doubles.bin');
   numarray.write(fh, n);
   binio.rewind(fh);
   if numarray.toseq(numarray.readdoubles(fh)) <> seq(0, 1, 2, 3, 4, 5, 0, 0, 0, 0) then
      print('error in `numarray.read/write`, 1')
   fi;
   binio.close(fh);
   clear n, fh  # force gc
od;

os.remove('doubles.bin');


to 100 do
   n :=  numarray.int32(128);
   if n[0] <> [] then
      print('error in `numarray.int32`, 1')
   fi;
   if n[1] <> 0 then
      print('error in `numarray.int32`, 2')
   fi;
   n := numarray.int32(5);
   for i to 5 do
      n[i] := i
   od;
   for i to 5 do
      if n[i] <> i then
         print('error in `numarray.getitem`, 2')
      fi
   od;
   if size n <> 5 then
      print('error in numarray `size`, 3')
   fi;
   m := numarray.int32(5);
   numarray.include(m, 1, n);
   for i to 5 do
      if n[i] <> m[i] then
         print('error in `numarray.include`, 3')
      fi
   od;
   numarray.include(n, 1, 0);
   if n[1] <> 0 then
      print('error in `numarray.include`, 4')
   fi;
   f := numarray.cycle(n, 1, 1);
   for i from 0 to 5 do
      if f() <> i then
         print('error in `numarray.cycle`, 3')
      fi
   od;
   for i from 0 to 5 do
      if f() <> i then
         print('error in `numarray.cycle`, 4')
      fi
   od;
   f := numarray.iterate(n, 1, 1);
   for i from 0 to 5 do
      if f() <> i then
         print('error in `numarray.iterate`, 3')
      fi
   od;
   if f() <> null then
      print('error in `numarray.iterate`, 4')
   fi;
   numarray.resize(n, 10);
   if size n <> 10 then
      print('error in numarray `size`, 2')
   fi;
   if numarray.toseq(n) <> seq(0, 1, 2, 3, 4, 5, 0, 0, 0, 0) then
      print('error in `numarray.resize`, 3')
   fi;
   if numarray.whereis(n, 0, 2) <> 7 then
      print('error in `numarray.resize`, 4')
   fi;
   fh := binio.open('int32.bin');
   numarray.write(fh, n);
   binio.rewind(fh);
   if numarray.toseq(numarray.readintegers(fh)) <> seq(0, 1, 2, 3, 4, 5, 0, 0, 0, 0) then
      print('error in `numarray.read/write`, 2')
   fi;
   binio.close(fh);
   clear n, fh  # force gc
od;

os.remove('int32.bin');


to 100 do
   n :=  numarray.uchar(128);
   if n[0] <> [] then
      print('error in `numarray.uchar`, 1')
   fi;
   if n[1] <> 0 then
      print('error in `numarray.uchar`, 2')
   fi;
   n := numarray.uchar(5);
   for i to 5 do
      n[i] := i
   od;
   for i to 5 do
      if n[i] <> i then
         print('error in `numarray.getitem`, 3')
      fi
   od;
   if size n <> 5 then
      print('error in numarray `size`, 4')
   fi;
   m := numarray.uchar(5);
   numarray.include(m, 1, n);
   for i to 5 do
      if n[i] <> m[i] then
         print('error in `numarray.include`, 4')
      fi
   od;
   numarray.include(n, 1, 0);
   if n[1] <> 0 then
      print('error in `numarray.include`, 5')
   fi;
   f := numarray.cycle(n, 1, 1);
   for i from 0 to 5 do
      if f() <> i then
         print('error in `numarray.cycle`, 5')
      fi
   od;
   for i from 0 to 5 do
      if f() <> i then
         print('error in `numarray.cycle`, 6')
      fi
   od;
   f := numarray.iterate(n, 1, 1);
   for i from 0 to 5 do
      if f() <> i then
         print('error in `numarray.iterate`, 5')
      fi
   od;
   if f() <> null then
      print('error in `numarray.iterate`, 6')
   fi;
   numarray.resize(n, 10);
   if size n <> 10 then
      print('error in numarray `size`, 3')
   fi;
   if numarray.toseq(n) <> seq(0, 1, 2, 3, 4, 5, 0, 0, 0, 0) then
      print('error in `numarray.resize`, 2')
   fi;
   if numarray.whereis(n, 0, 2) <> 7 then
      print('error in `numarray.resize`, 5')
   fi;
   fh := binio.open('uchar.bin');
   numarray.write(fh, n);
   binio.rewind(fh);
   if numarray.toseq(numarray.readuchars(fh)) <> seq(0, 1, 2, 3, 4, 5, 0, 0, 0, 0) then
      print('error in `numarray.read/write`, 3')
   fi;
   binio.close(fh);
   clear n, fh  # force gc
od;

os.remove('uchar.bin');


print('Checking binio package\n');

for i to 25 do
   local f, fd, line;
   fd := binio.open('misc.agn', true)  # read me only
   f := binio.lines(fd);
   do
      line := f()
   until line = null;
   binio.close(fd)
od;

for i to 25 do
   local fd;
   fd := binio.open('misc.agn', true)  # read me only
   if not binio.isfdesc(fd) then
      print('error in binio.isfdesc');
   fi
   if binio.readbytes(fd, 10) <> seq(112, 114, 105, 110, 116, 40, 39, 67, 104, 101) then
      print('error in binio.readbytes')
   fi;
   binio.close(fd)
od;


fd := binio.open('test.dat');

for i to 10 do
   binio.writenumber(fd, i*Pi)
od;
binio.rewind(fd);
for i to 10 do
   if i*Pi <> binio.readnumber(fd) then
      print('Error in binio.read/writenumber, 1')
   fi
od;
binio.rewind(fd);
for i to 10 do
   local data := binio.readindex(fd, i, 'number');
   if i*Pi <> data then
      print('Error in binio.readindex, 1', data)
   fi
od;

binio.close(fd);

fd := binio.open('test.dat');

for i to 10 do
   binio.writelong(fd, i)
od;
binio.rewind(fd);
for i to 10 do
   if i <> binio.readlong(fd) then
      print('Error in binio.read/writelong, 1')
   fi
od;
binio.rewind(fd);
for i to 10 do
   if i <> binio.readindex(fd, i, 'long') then
      print('Error in binio.readindex, 2')
   fi
od;

binio.close(fd);


fd := binio.open('test.dat');

for i to 10 do
   binio.writestring(fd, tostring(i*Pi))
od;
binio.rewind(fd);
for i to 10 do
   if tostring(i*Pi) <> binio.readstring(fd) then
      print('Error in binio.read/writestring, 1');
   fi
od;
binio.rewind(fd);
for i to 10 do
   if tostring(i*Pi) <> binio.readindex(fd, i, 'string') then
      print('Error in binio.readindex, 3')
   fi
od;

binio.close(fd);


fd := binio.open('test.dat');

for i to 10 do
   binio.writeshortstring(fd, tostring(i*Pi))
od;
binio.rewind(fd);
for i to 10 do
   if tostring(i*Pi) <> binio.readshortstring(fd) then
      print('Error in binio.read/writeshortstring, 1')
   fi
od;
binio.rewind(fd);
for i to 10 do
   if tostring(i*Pi) <> binio.readindex(fd, i, 'shortstring') then
      print('Error in binio.readindex, 4')
   fi
od;
binio.lock(fd);
binio.rewind(fd);
binio.toend(fd);
if not binio.eof(fd) then
   print('Error in binio.eof, 1')
fi;
binio.unlock(fd);

binio.close(fd);


fd := binio.open('test.dat');

for i to 10 do
   binio.writeindex(fd, i, 'number', Pi*i)
od;
binio.rewind(fd);
for i to 10 do
   if binio.readindex(fd, i, 'number') <> Pi*i then
      print("Error in binio.write/readindex, 1")
   fi
od;
binio.rewind(fd);
# write something else
binio.writeindex(fd, 4, 'number', 10);
if binio.readindex(fd, 4, 'number') <> 10 then
   print("Error in binio.write/readindex, 2")
fi;

binio.close(fd);


fd := binio.open('test.dat');

for i to 10 do
   binio.writeindex(fd, i, 'long', i)
od;
binio.rewind(fd);
for i to 10 do
   if binio.readindex(fd, i, 'long') <> i then
      print("Error in binio.write/readindex, 1a")
   fi
od;
binio.rewind(fd);
# write something else
binio.writeindex(fd, 4, 'long', 10);
if binio.readindex(fd, 4, 'long') <> 10 then
   print("Error in binio.write/readindex, 2a")
fi;

binio.close(fd);

os.remove('test.dat');
fd := binio.open('test.dat');

for i to 10 do
   binio.writeindex(fd, i, 'shortstring', tostring(Pi*i))
od;
binio.rewind(fd);
for i to 10 do
   data := binio.readindex(fd, i, 'shortstring');
   if data <> tostring(Pi*i) then
      print("Error in binio.write/readindex, 3", data)
   fi
od;
binio.rewind(fd);

binio.close(fd);

os.remove('test.dat');

fd := binio.open('test.dat');

for i to 10 do
   binio.writeindex(fd, i, 'string', tostring(Pi*i))
od;
binio.rewind(fd);
for i to 10 do
   if binio.readindex(fd, i, 'string') <> tostring(Pi*i) then
      print("Error in binio.write/readindex, 4")
   fi
od;
binio.rewind(fd);

binio.close(fd);

os.remove('test.dat');

tbl := [
  1, 2, 3:4, 'agena', true, Pi,
  ['agena' ~ 'programming', 1, 2, 3:4, 'agena', true, Pi],
  {1, 2, 3:4, 'agena', true, Pi},
  seq(1, 2, 3:4, 'agena', true, Pi),
  reg(1, 2, 3:4, 'agena', true, Pi)
]

save(tbl, 'test.dat');

if read('test.dat') <> tbl then
   print('Error in `read/save`, 1');
fi;

os.remove('test.dat');

tbl := seq(
  1, 2, 3:4, 'agena', true, Pi,
  ['agena' ~ 'programming', 1, 2, 3:4, 'agena', true, Pi],
  {1, 2, 3:4, 'agena', true, Pi},
  seq(1, 2, 3:4, 'agena', true, Pi),
  reg(1, 2, 3:4, 'agena', true, Pi)
)

save(tbl, 'test.dat');

if read('test.dat') <> tbl then
   print('Error in `read/save`, 2');
fi;

os.remove('test.dat');

tbl := reg(
  1, 2, 3:4, 'agena', true, Pi,
  ['agena' ~ 'programming', 1, 2, 3:4, 'agena', true, Pi],
  {1, 2, 3:4, 'agena', true, Pi},
  seq(1, 2, 3:4, 'agena', true, Pi),
  reg(1, 2, 3:4, 'agena', true, Pi)
)

save(tbl, 'test.dat');

if read('test.dat') <> tbl then
   print('Error in `read/save`, 3');
fi;

os.remove('test.dat');

tbl := [
  1, 2, 3:4, 'agena', true, Pi,
  ['agena' ~ 'programming', 1, 2, 3:4, 'agena', true, Pi],
  {1, 2, 3:4, 'agena', true, Pi},
  seq(1, 2, 3:4, 'agena', true, Pi),
  reg(1, 2, 3:4, 'agena', true, Pi)
]

if read('littlend.dat') <> tbl then
   print('Error in `read/save`, 10');
fi

if os.exists('bigend.dat') and read('bigend.dat') <> tbl then
   print('Error in `read/save`, 11');
fi;


# test all `registry` functions

print('Checking registry package');

f := proc(x) is  # 2.16.6, some sort of stop watch, see also: `skycrane.stopwatch`, sized down.
   local id, val;
   id := 'baselib_watch';  # create light userdata as registry key
   unassigned registry.get(id) ? registry.anchor(id, 0);  # 2.16.7
   if x then  # reset the clock but do not turn it on again; call watch with no arguments to start the clock again
      registry.anchor(id, 0);
      return
   fi;
   val := registry.get(id);  # get old time (in seconds)
   if val = 0 then  # start clock
      registry.anchor(id, 0);
   else  # return elapsed time and set clock to current time
      registry.anchor(id, 1)
   fi
end;

for i to 10k do
   f();
   f(0)
od;


clear L, L1, a, allpackages, b, blue, contents, cyan, cyanalex, cyannew, f, fd, flag, fn, i,
      myrecord, path, red, str, tbl, violet, white, x, x1, x2;
