/*******************************************************
* unit:    lists             release 0.19              *
* purpose: test of functionality of unit lists         *
* Licency: GPL                                         *
* Copyright: (c) 1998-2025 Jaroslav Fojtik             *
********************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>

#define CurrentDir

#ifdef __BORLANDC__
#include <alloc.h>
#else
#define heapcheck() 1
#endif

#include "lists.h"
#include "dbllist.h"

#ifdef Streams
 #ifndef IOSTREAM_H_ONLY
  using namespace std; 
 #endif
#endif



/*
string istr(void)
{
for(int Q=1;Q++;);
string();
return('j');
}


int test1(string s)
{
 return(check(s));
}
*/

void Benchmark(void);

#ifdef ERROR_HANDLER
 void RaiseError(int ErrNo, const void *Instance)
     {
     fprintf(stderr,"Lists::Error %d (%p)\n",ErrNo,Instance);
     }
#endif


#define DblListOp -80

/// Double List tests
int maindbl(void)
{
doublelist dbl0,dbl1,dbl2;
int i;

  if((i=check(dbl0))!=0)
	{
#ifdef Streams
	cout<<"Check dbl0 failed:"<<i<<":"<<dbl0<<"\n";
#endif
	return(DblListOp);
	}

  dbl0.Add("Hallo","Ahoj");
  dbl0.Add("World","Svete");

  if((i=check(dbl0))!=0)
	{
#ifdef Streams
	cout<<"Check dbl0 failed:"<<i<<":"<<dbl0<<"\n";
#endif
	return(DblListOp-1);
	}

  dbl1=dbl0;

  if((i=check(dbl1))!=0)
	{
#ifdef Streams
	cout<<"Check dbl1 failed:"<<i<<":"<<dbl1<<"\n";
#endif
	return(DblListOp-2);
	}

  if(!(dbl1==dbl0))
    {
#ifdef Streams
    cout<<"Double list was copied wrongly! "<<dbl0<<" copy:"<<dbl1<<"\n";
#endif
    return(DblListOp-3);
    }

  dbl0.Flip(1);
  dbl1.Flip(1);

  if(!(dbl1==dbl0))
    {
#ifdef Streams
    cout<<"Double list was copied wrongly! "<<dbl0<<" copy:"<<dbl1<<"\n";
#endif
    return(DblListOp-4);
    }

  dbl2=dbl1;

  if(!(dbl1==dbl2))
    {
#ifdef Streams
    cout<<"Double list was copied wrongly! "<<dbl1<<" copy:"<<dbl2<<"\n";
#endif
    return(DblListOp-5);
    }


return(0);
}


int main(int argc, char *argv[])
{
list l0,l1,l2,l3,l4;
sortedlist sl0;
int i;
char abc[2]="A";
char *EMPTY=NULL;
const char *strbase[]={"Ahoj","Svete","Kdy","Uz","to","Vsechno","Skonci"};
const char *strbase2[]={"Dalí","řetězce"};
int Ops;


 puts("");
 printf("<<<lists>>> (c)1998-2025 Jaroslav Fojtik %ubits\n", (unsigned)sizeof(void*)*8);
 printf("                 This program tests the list unit, release %d.%d\n",
	LISTS_VERSION>>8, LISTS_VERSION&0xFF);

 if(argc>1)
 {
   Ops=0;
   for(i=1; i<argc; i++)
   {
     if(!strcmp(argv[i],"-bench")) Ops|=3;
     if(!strcmp(argv[i],"-demo")) Ops|=4;
     if(!strcmp(argv[i],"-test")) Ops|=1;
     if(!strcmp(argv[i],"-help") || !strcmp(argv[i],"/help"))
     {
       printf("Command line parameters:\n-bench -demo -test -help\n");
       return 1;
     }
   }
 }
 else Ops=3;


 if(Ops & 1)
 {
 if(length(l0)!=0 || l0.length()!=length(l0))
	 {
WrongLen:
#ifdef Streams
         cout<<"Wrong length reported:"<<l0<<" "<<length(l0)<<"\n";
#endif
	 i=-1;
	 goto Abnormal_End;
	 }
 if(!l0.isEmpty())
 {
ReportEmptyErr:
   i=-2;
   printf("Error: List should be reported as empty\n");
   goto Abnormal_End;
 }

 l0 += "X";
 if(length(l0)!=1 || l0.length()!=length(l0)) goto WrongLen;
 if(l0.isEmpty())
 {
   i=-3;
   printf("Error: List should be reported as non empty\n");
   goto Abnormal_End;
 }


 l0.erase();
 if(!l0.isEmpty()) goto ReportEmptyErr;


//////////////////////////////////
#define CopyOp -10
puts(" copy operator, operator =");

if((i=check(l0))!=0)
	 {
CopyErr:
#ifdef Streams
         cout<<"Check l0 failed:"<<l0<<"\n";
#endif
	 i = CopyOp;
	 goto Abnormal_End;
	 }
l0+="Ahoj";
if((i=check(l0))!=0) goto CopyErr;
l0+="Svete";
if((i=check(l0))!=0) goto CopyErr;
l0+="Hoj";
if((i=check(l0))!=0) goto CopyErr;
l0+="Hoj";
if((i=check(l0))!=0) goto CopyErr;
l0+="Ty";
if((i=check(l0))!=0) goto CopyErr;
l0+="Stedry";
if((i=check(l0))!=0) goto CopyErr;
l0+="Vecere";
if((i=check(l0))!=0) goto CopyErr;
l0+="Ty";
if((i=check(l0))!=0) goto CopyErr;


l1=l0;
if(l1!=l0)
	{
#ifdef Streams
	cout<<"l0:"<<l0<<" should be same as l1:"<<l1<<"\n";
#endif
	i=CopyOp-1;
	goto Abnormal_End;
	}
if((i=check(l1))!=0) goto Abnormal_End;


if(l2!=l3)
	{
#ifdef Streams
	cout<<"l2:"<<l2<<" should be same as l3:"<<l3<<"\n";
#endif
	i=CopyOp-2;
	goto Abnormal_End;
	}
if(l1==l3)
	{
#ifdef Streams
	cout<<"l1:"<<l1<<" should be same as l3:"<<l3<<"\n";
#endif
	i=CopyOp-3;
	goto Abnormal_End;
	}

l2+="Ahoj";
if(l2==l3)
	{
#ifdef Streams
	cout<<"l2:"<<l2<<" should not be same as l3:"<<l3<<"\n";
#endif
	i=CopyOp-4;
	goto Abnormal_End;
	}
if((i=check(l2))!=0) goto Abnormal_End;

l3+="Ahoj";
if(l2!=l3)
	{
#ifdef Streams
	cout<<"l2:"<<l2<<" should be same as l3:"<<l3<<"\n";
#endif
	i=CopyOp-5;
	goto Abnormal_End;
	}
if((i=check(l3))!=0) goto Abnormal_End;

  {
  list Lnew1(l1);
  list Lnew2(l2);
  list Lnew3(l3);
  list Lnew3_("Ahoj");

  if(Lnew1!=l1)
	{
	i=CopyOp-6;
	goto Abnormal_End;
	}
  if(Lnew2!=l2)
	{
	i=CopyOp-7;
	goto Abnormal_End;
	}
  if(Lnew3!=l3)
	{
	i=CopyOp-8;
	goto Abnormal_End;
	}
  if(Lnew3_!=l3)
	{
	i=CopyOp-9;
	goto Abnormal_End;
	}

  if((i=check(Lnew1))!=0) goto Abnormal_End;
  if((i=check(Lnew2))!=0) goto Abnormal_End;
  if((i=check(Lnew3))!=0) goto Abnormal_End;
  if((i=check(Lnew3_))!=0) goto Abnormal_End;
  }

//////////////////////////////////
puts(" operator IN");
#define OperatorIN -20


if(!("Ahoj" IN l0))
	 {
OpINErr:
#ifdef Streams
	 cout<<"Required string is not is l0:"<<l0<<"\n";
#endif
	 i=OperatorIN-1;
	 goto Abnormal_End;
	 }
if(!("Svete" IN l0)) goto OpINErr;
if(!("Hoj" IN l0)) goto OpINErr;
if(!("Ty" IN l0)) goto OpINErr;
if(!("Stedry" IN l0)) goto OpINErr;
if(!("Vecere" IN l0)) goto OpINErr;


if("Ahoj_" IN l0)
	 {
OpINErr2:i=OperatorIN-2;
	 goto Abnormal_End;
	 }
if("Svvete" IN l0) goto OpINErr2;
if("HojH" IN l0) goto OpINErr2;
if("T" IN l0) goto OpINErr2;
if("St" IN l0) goto OpINErr2;
if("VeceŠe" IN l0) goto OpINErr2;

l1=l0;
if(!(l1 IN l0))
	{
#ifdef Streams
	cout<<l1<<" is not in "<<l0<<"\n";
#endif
	i=OperatorIN-3;
	goto Abnormal_End;
	}
if(!(l0 IN l1))
	{
#ifdef Streams
	cout<<l0<<" is not in "<<l1<<"\n";
#endif
	i = OperatorIN-4;
	goto Abnormal_End;
	}



//////////////////////////////////
puts(" concatenation operator + +=");
#define AddOp -30

l0="ahoj";
l1=l0;
l1+=l0;
l2=l0+l0;
if(l1!=l2)
	{
#ifdef Streams
	cout<<l1<<" : "<<l2<<"\n";
#endif
	i=AddOp-1;
	goto Abnormal_End;
	}

l0+=l0;
if(l0!=l2)
	{
#ifdef Streams
	cout<<l0<<" : "<<l2<<"\n";
#endif
	i=AddOp-2;
	goto Abnormal_End;
	}

erase(l0);
erase(l1);
erase(l2);
erase(l3);
for(i=0;i<20;i++)
	{
	l0+=abc;
	l1=l1+abc;
	if(l1!=l0)
	  {
#ifdef Streams
	  cout<<l0<<" : "<<l1<<"\n";
#endif
	  i=AddOp-3;
	  goto Abnormal_End;
	  }
	l4=abc;
	l2=l2+l4;
	if(l2!=l0)
	  {
#ifdef Streams
	  cout<<l0<<" : "<<l2<<"\n";
#endif
	  i=AddOp-4;
	  goto Abnormal_End;
	  }
	l3+=l4;
	if(l3!=l0)
	  {
#ifdef Streams
	  cout<<l0<<" : "<<l3<<"\n";
#endif
	  i=AddOp-5;
	  goto Abnormal_End;
	  }
	abc[0]++;
	}

//////////////////////////////////
puts(" operators or | |=");
#define OrOp -40

l0="ahoj";
l1.erase();
l1|="ahoj";
if(l1!=l0)
	{
#ifdef Streams
	cout<<l0<<" != "<<l1<<"\n";
#endif
	i = OrOp-1;
	goto Abnormal_End;
	}
l1 = l0;
l1|=l0;
l2=l0|l0;
if(l1!=l2)
	{
#ifdef Streams
	cout<<l1<<" : "<<l2<<"\n";
#endif
	i = OrOp-2;
	goto Abnormal_End;
	}
if(l0!=l1)
	{
#ifdef Streams
	cout<<l1<<" : "<<l2<<"\n";
#endif
	i = OrOp-3;
	goto Abnormal_End;
	}

l0|=l0;
if(l0!=l2)
	{
#ifdef Streams
	cout<<l0<<" : "<<l2<<"\n";
#endif
	i = OrOp-4;
	goto Abnormal_End;
	}

l4="svete";
l0=l1|l4;
l1|=l4;
if(l1!=l0)
	{
#ifdef Streams
	cout<<l1<<" : "<<l2<<"\n";
#endif
	i = OrOp-5;
	goto Abnormal_End;
	}
l2+=l4;
if(l1!=l2)
	{
#ifdef Streams
	cout<<"Discrepancy found:"<<l1<<" : "<<l2<<"\n";
#endif
	i = OrOp-6;
	goto Abnormal_End;
	}

l2|=EMPTY;
l1=l1|EMPTY;
if(l1!=l2)
	{
#ifdef Streams
	cout<<"List "<<l2<<" |= NULL do not work!\n";
#endif
	i = OrOp-7;
	goto Abnormal_End;
	}


//////////////////////////////////
puts(" const_list");
#define ClistOp -50
 {
 const_list l(strbase,7);
 if(l.length() <= 0)
 {
   puts("Bad allocation of const_list");
   i = ClistOp;
   goto Abnormal_End;
 }

 const_list l2(l); 
 if(l.length() != l2.length())
 {
   puts("Bad copy ctor of const_list");
   i = ClistOp - 1;
   goto Abnormal_End;
 }

 const_list l3(strbase2,2);
 if(l3.length() != 2)
 {
   puts("Bad allocation of const_list, expected size 2");
   i = ClistOp - 2;
   goto Abnormal_End;
 }

 l3 = l;
 if(l.length() != l3.length())
 {
   puts("Bad operator = of const_list");
   i = ClistOp - 3;
   goto Abnormal_End;
 }

  //l+="Nesmi jit nic pridat";
  //l.erase();
 }



//////////////////////////////////
puts(" misc functions MoveSTR(), MoveSTRPos()");
#define MiscF -60

l0="ahoj";
l1.erase();
MoveSTR(l1,strdup("ahoj"));
if(l0!=l1)
	{
NotSame:
#ifdef Streams
        cout<<"Discrepancy found:"<<l0<<" : "<<l1<<"\n";
#endif
	i=MiscF;
	goto Abnormal_End;
	}

l0+="svete";
l2=l1;
MoveSTR(l1,strdup("svete"));
if(l0!=l1) goto NotSame;

MoveSTRPos(l2,strdup("svete"),1);
if(l2!=l1)
	{
#ifdef Streams
	cout<<"Discrepancy found:"<<l1<<" : "<<l2<<"\n";
#endif
	i=MiscF-1;
	goto Abnormal_End;
	}

MoveSTR(l0,NULL);
l0+=NULL;
l0+="Tak a je to";
if(l0[0]==NULL || l0[1]==NULL || l0[2]!=NULL || l0[3]!=NULL || l0[4]==NULL)
	{
#ifdef Streams
	cout<<"Wrong list after MoveSTR:"<<l0<<"\n";
#endif
	i=MiscF-2;
	goto Abnormal_End;
	}
MoveSTRPos(l2,strdup("Tak a je to"),4);
if(l2[0]==NULL || l2[1]==NULL || l2[2]!=NULL || l2[3]!=NULL || l2[4]==NULL)
	{
#ifdef Streams
	cout<<"Wrong list after MoveSTRPos:"<<l2<<"\n";
#endif
	i=MiscF-3;
	goto Abnormal_End;
	}
if(l2!=l0)
	{
#ifdef Streams
	cout<<"Discrepancy found:"<<l2<<" : "<<l0<<"\n";
#endif
	i=MiscF-4;
	goto Abnormal_End;
	}


///////////////////////////////////
puts(" sorted lists");
#define SListOp -70

sl0.AddSorter(strcmp);
sl0+="Ahoj";
sl0+="Svete";
sl0+="Hoj";
sl0+="Hoj";
sl0+="Ty";
sl0+="Stedry";
sl0+="Vecere";
sl0+="Ty";

sl0+="aaa";

if(!("Ahoj" IN sl0)) goto Abnormal_End;
if(!("Svete" IN sl0)) goto Abnormal_End;
if(!("Hoj" IN sl0)) goto Abnormal_End;
if(!("Ty" IN sl0)) goto Abnormal_End;
if(!("Stedry" IN sl0)) goto Abnormal_End;
if(!("Vecere" IN sl0)) goto Abnormal_End;

if("Ahoj_" IN sl0) goto Abnormal_End;
if("Svvete" IN sl0) goto Abnormal_End;
if("HojH" IN sl0) goto Abnormal_End;
if("T" IN sl0) goto Abnormal_End;
if("St" IN sl0) goto Abnormal_End;
if("VeceŠe" IN sl0) goto Abnormal_End;

if((i=RemoveDups(sl0))!=2)
   {
#ifdef Streams
   cout<<"Unwanted duplicities "<<i<<" found:"<<sl0<<"\n";
#endif
   i = SListOp - 1;
   goto Abnormal_End;
   }

sl0|="Ahoj";
if((i=RemoveDups(sl0))!=0)
   {
#ifdef Streams
   cout<<"Unwanted duplicities "<<i<<" found:"<<sl0<<"\n";
#endif
   i = SListOp - 2;
   goto Abnormal_End;
   }

sl0 += "Ahoj";
if((i=RemoveDups(sl0))!=1)
   {
#ifdef Streams
   cout<<"Unwanted duplicities "<<i<<" found:"<<sl0<<"\n";
#endif
   i = SListOp - 3;
   goto Abnormal_End;
   }
//print(sl0);



///////////////////////////////////
 puts(" double lists");
 i = maindbl();
 if(i<0) goto Abnormal_End;
 }

//////////////////////////
 if(Ops & 2)
    Benchmark();
//////////////////////////


i=0;
Abnormal_End:
if(heapcheck()<=0)
	 {
	 printf("Bad allocation %d",heapcheck());
	 return(-1);
	 }
if(i!=0) {
	 printf("Unit Error %d",i);
	 return(-1);
	 }
puts(" .............. Test passed OK ..............");
return(0);
}


#include "../test/bench.h"


void Addition(long i)
{
list l,l2,l3;
while(i-->0)
   {
   l2="XXX";
   l="Ahoj";
   l+="Svete";
   l2+=l;
   l2=l2+"jak";
   l2+="se";
   l2+="ti";
   l2="Hlaska:"+l2;
   l3=l2+l;
   l=l3+l2;
   }
}


void Copy(long i)
{
const char *strbase[]={"Ahoj","Svete","Kdy","Uz","to","Vsechno","Skonci"};
while(i-->0)
   {
   list l(strbase,7);
   list l2,l3(l),l4("Tak tak a mel jsem dlouhy retezec");

   l2=l;
   l2=l3;
   l=l4;
   }
}


void Or(long i)
{
list l,l2,l3;
while(i-->0)
   {
   l2="XXX";
   l="Ahoj";
   l|="Svete";
   l2|=l;
   l2=l2|"jak";
   l2|="se";
   l2|="ti";
   l3=l2|l;
   l=l3|l2;
   }
}


void DblMember(long i)
{
doublelist dbl;
char *c;

while(i-->0)
   {
   dbl.erase();
   dbl.Add("Ahoj","Svete");
   dbl.Add("Hallo","Word");

   c=dbl.Member(0,0);
   c=dbl.Member(0,1);
   c=dbl.Member(1,0);
   c=dbl.Member(1,1);
   }
c=c;
}



void Benchmark(void)
{
float f;

puts(" .............. Benchmarks ..............");


f=AutoMeasure(Addition);
printf(" Addition loop time: %fus\n",f);


f=AutoMeasure(Copy);
printf(" Copy loop time: %fus\n",f);


f=AutoMeasure(Or);
printf(" Or loop time: %fus\n",f);


f=AutoMeasure(DblMember);
printf(" Double list add/member loop time: %fus\n",f);


/*
f=Measure(UpLoSpaces,200000);
printf(" Toupper & Tolower loop time: %fus\n",f);*/

}
