//+------------------------------------------------------------------+
//|                                               TestLinkedList.mq5 |
//|                             Copyright 2000-2026, MetaQuotes Ltd. |
//|                                                     www.mql5.com |
//+------------------------------------------------------------------+
#include <Generic\LinkedList.mqh>
#include <Generic\ArrayList.mqh>
//+------------------------------------------------------------------+
//| TestAddAfter_Node.                                               |
//+------------------------------------------------------------------+
bool TestAddAfter_Node(const int count)
  {
   CLinkedList<int>list_test();
//--- create test arrays
   int check_array[];
   int temp_items[];
   int head_items[];
   int head_reverse_items[];
   int tail_items[];
   ArrayResize(temp_items,count);
   ArrayResize(head_items,count);
   ArrayResize(head_reverse_items,count);
   ArrayResize(tail_items,count);
   for(int i=0; i<count; i++)
     {
      int index=count-1-i;
      int head = MathRand();
      int tail = MathRand();
      head_items[i]=head;
      head_reverse_items[index]=head;
      tail_items[i]=tail;
     }
//--- test verify value is -1     
//--- add values
   CLinkedListNode<int>*node=list_test.AddFirst(head_items[0]);
   list_test.AddAfter(node,-1);
//--- check
   list_test.CopyTo(check_array);
   if(check_array[0]!=head_items[0] && check_array[1]!=-1)
      return(false);
//--- clear
   list_test.Clear();

//--- test node in the head   
//--- add values
   list_test.AddFirst(head_items[0]);
   ArrayCopy(temp_items,head_items);
   ArrayReverse(temp_items,1,count-1);
   for(int i=1; i<count; i++)
      list_test.AddAfter(list_test.First(),head_items[i]);
//--- check
   list_test.CopyTo(check_array);
   if(ArrayCompare(check_array,temp_items)!=0)
      return(false);
//--- clear
   list_test.Clear();

//--- test node in the tail
//--- add values
   list_test.AddFirst(head_items[0]);
   for(int i=1; i<count;++i)
      list_test.AddAfter(list_test.Last(),head_items[i]);
//--- check
   list_test.CopyTo(check_array);
   if(ArrayCompare(check_array,head_items)!=0)
      return(false);
//--- clear
   list_test.Clear();

//--- test node is after the head
//--- add values
   list_test.AddFirst(head_items[0]);
   list_test.AddLast(head_items[1]);
   ArrayCopy(temp_items,head_items);
   ArrayReverse(temp_items,2,count-2);
   for(int i=2; i<count;++i)
      list_test.AddAfter(list_test.First().Next(),head_items[i]);
//--- check
   list_test.CopyTo(check_array);
   if(ArrayCompare(check_array,temp_items)!=0)
      return(false);
//--- clear
   list_test.Clear();

//--- test node is before the tail
//--- add values
   list_test.AddFirst(head_items[0]);
   list_test.AddLast(head_items[1]);
   ArrayCopy(temp_items,head_items,1,2,count-2);
   temp_items[0]=head_items[0];
   temp_items[count-1]=head_items[1];
   for(int i=2; i<count;++i)
      list_test.AddAfter(list_test.Last().Previous(),head_items[i]);
//--- check
   list_test.CopyTo(check_array);
   if(ArrayCompare(check_array,temp_items)!=0)
      return(false);
//--- clear
   list_test.Clear();

//--- test node is somewhere in the middle
//--- add values
   list_test.AddFirst(head_items[0]);
   list_test.AddLast(head_items[1]);
   list_test.AddLast(head_items[2]);
   ArrayCopy(temp_items,head_items,1,3,count-3);
   temp_items[0]=head_items[0];
   temp_items[count - 2] = head_items[1];
   temp_items[count - 1] = head_items[2];
   for(int i=3; i<count;++i)
      list_test.AddAfter(list_test.Last().Previous().Previous(),head_items[i]);
//--- check
   list_test.CopyTo(check_array);
   if(ArrayCompare(check_array,temp_items)!=0)
      return(false);
//--- clear
   list_test.Clear();

//--- test call AddAfter several times remove some of the items
//--- add values
   list_test.AddFirst(head_items[0]);
   for(int i=1; i<count;++i)
      list_test.AddAfter(list_test.Last(),head_items[i]);
//--- remove values
   list_test.Remove(head_items[2]);
   list_test.Remove(head_items[count-3]);
   list_test.Remove(head_items[1]);
   list_test.Remove(head_items[count-2]);
   list_test.RemoveFirst();
   list_test.RemoveLast();
//--- with the above remove we should have removed the first and last 3 items 
   ArrayFree(temp_items);
   ArrayCopy(temp_items,head_items,0,3,count-6);
//--- check
   ArrayFree(check_array);
   list_test.CopyTo(check_array);
   if(ArrayCompare(check_array,temp_items)!=0)
      return(false);
//--- add values
   for(int i=0; i<count;++i)
      list_test.AddAfter(list_test.Last(),tail_items[i]);
   int temp_items2[];
   ArrayCopy(temp_items2,temp_items);
   ArrayCopy(temp_items2,tail_items,ArraySize(temp_items));
//--- check
   list_test.CopyTo(check_array);
   if(ArrayCompare(check_array,temp_items2)!=0)
      return(false);
//--- clear
   list_test.Clear();

//--- test call AddAfter several times remove all of the items
//--- add values
   list_test.AddFirst(head_items[0]);
   for(int i=1; i<count;++i)
      list_test.AddAfter(list_test.Last(),head_items[i]);
//--- remove values
   for(int i=0; i<count;++i)
      list_test.RemoveFirst();
//--- add values
   list_test.AddFirst(tail_items[0]);
   for(int i=1; i<count;++i)
      list_test.AddAfter(list_test.Last(),tail_items[i]);
//--- check
   ArrayFree(check_array);
   list_test.CopyTo(check_array);
   if(ArrayCompare(check_array,tail_items)!=0)
      return(false);
//--- clear
   list_test.Clear();

//--- test call AddAfter several times then call Clear
//--- add values
   list_test.AddFirst(head_items[0]);
   for(int i=1; i<count;++i)
      list_test.AddAfter(list_test.Last(),head_items[i]);
//--- clear
   list_test.Clear();
//--- add values
   list_test.AddFirst(tail_items[0]);
   for(int i=1; i<count;++i)
      list_test.AddAfter(list_test.Last(),tail_items[i]);
//--- check
   list_test.CopyTo(check_array);
   if(ArrayCompare(check_array,tail_items)!=0)
      return(false);
//--- clear
   list_test.Clear();

//--- test mix AddBefore and AddAfter calls
//--- add values
   list_test.AddLast(head_items[0]);
   list_test.AddLast(tail_items[0]);
   for(int i=1; i<count;++i)
     {
      list_test.AddBefore(list_test.First(), head_items[i]);
      list_test.AddAfter(list_test.Last(), tail_items[i]);
     }
   ArrayFree(temp_items);
   ArrayCopy(temp_items,head_reverse_items);
   ArrayCopy(temp_items,tail_items,count);
//--- check
   list_test.CopyTo(check_array);
   if(ArrayCompare(check_array,temp_items)!=0)
      return(false);

//--- successful
   return(true);
  }
//+------------------------------------------------------------------+
//| TestAddAfter_Node_Negative.                                      |
//+------------------------------------------------------------------+
bool TestAddAfter_Node_Negative(const int count)
  {
//--- create lists
   CLinkedList<int>list_test();
   CLinkedList<int>list_temp();

//--- test verify null node
//--- check
   if(list_test.AddAfter(NULL,0)!=NULL)
      return(false);
   if(list_test.Count()!=0)
      return(false);

//--- test verify Node that is a new Node
//--- add values
   list_test.AddLast(0);
   CLinkedListNode<int>node(1);
//--- check
   if(list_test.AddAfter(GetPointer(node),-1)!=NULL)
      return(false);
   if(list_test.Count()!=1)
      return(false);
//--- clear
   list_test.Clear();

//--- test verify Node that already exists in another collection
//--- add values   
   list_test.AddLast(MathRand());
   list_test.AddLast(MathRand());
   list_temp.AddLast(MathRand());
   list_temp.AddLast(MathRand());
//--- check   
   if(list_test.AddAfter(list_temp.Last(),MathRand())!=NULL)
      return(false);
   if(list_test.Count()!=2)
      return(false);

//--- successful
   return(true);
  }
//+------------------------------------------------------------------+
//| TestAddAfter.                                                    |
//+------------------------------------------------------------------+
bool TestAddAfter(const string test_name)
  {
   PrintFormat("%s started",test_name);
//--- test 1
   PrintFormat("%s: Test 1: Complex validation of AddAfter method for head node, tail node, some node in the middle, "+
               "also testing after remove several element, remove all element and cleaning of list.",test_name);
   if(!TestAddAfter_Node(16))
      return(false);
//--- test 2
   PrintFormat("%s: Test 2: Validation of AddAfter method for incorrect node.",test_name);
   if(!TestAddAfter_Node_Negative(16))
      return(false);
//--- successful
   PrintFormat("%s passed",test_name);
   return(true);
  }
//+------------------------------------------------------------------+
//| TestAddBefore_Node.                                              |
//+------------------------------------------------------------------+
bool TestAddBefore_Node(const int count)
  {
   CLinkedList<int>list_test();
//--- create test arrays
   int check_array[];
   int temp_items[];
   int head_items[];
   int head_reverse_items[];
   int tail_items[];
   int tail_reverse_items[];
   ArrayResize(temp_items,count);
   ArrayResize(head_items,count);
   ArrayResize(head_reverse_items,count);
   ArrayResize(tail_items,count);
   ArrayResize(tail_reverse_items,count);
   for(int i=0; i<count; i++)
     {
      int index=count-1-i;
      int head = MathRand();
      int tail = MathRand();
      head_items[i]=head;
      head_reverse_items[index]=head;
      tail_items[i]=tail;
      tail_reverse_items[index]=tail;
     }
//--- test verify value is -1
//--- add values
   list_test.AddFirst(head_items[0]);
   list_test.AddBefore(list_test.First(), -1);
//--- check
   list_test.CopyTo(check_array);
   if(check_array[0]!=-1 && check_array[1]!=head_items[0])
      return(false);
//--- clear
   list_test.Clear();

//--- test node is the head
   list_test.AddFirst(head_items[0]);
   for(int i=1; i<count;++i)
      list_test.AddBefore(list_test.First(),head_items[i]);
//--- check
   list_test.CopyTo(check_array);
   if(ArrayCompare(check_array,head_reverse_items)!=0)
      return(false);
//--- clear
   list_test.Clear();

//--- test node is the tail
   list_test.AddFirst(head_items[0]);
   ArrayCopy(temp_items,head_items,0,1,count);
   temp_items[count-1]=head_items[0];
   for(int i=1; i<count;++i)
      list_test.AddBefore(list_test.Last(),head_items[i]);
//--- check
   list_test.CopyTo(check_array);
   if(ArrayCompare(check_array,temp_items)!=0)
      return(false);
//--- clear
   list_test.Clear();

//--- test node is after the head
//--- add values
   list_test.AddFirst(head_items[0]);
   list_test.AddLast(head_items[1]);
   ArrayFree(temp_items);
   ArrayCopy(temp_items,head_items);
   ArrayReverse(temp_items,1,count-1);
   for(int i=2; i<count;++i)
      list_test.AddBefore(list_test.First().Next(),head_items[i]);
//--- check
   list_test.CopyTo(check_array);
   if(ArrayCompare(check_array,temp_items)!=0)
      return(false);
//--- clear
   list_test.Clear();

//--- test node is before the tail
//--- add values
   list_test.AddFirst(head_items[0]);
   list_test.AddLast(head_items[1]);
   ArrayResize(temp_items,count);
   ArrayCopy(temp_items,head_items,0,2,count-2);
   temp_items[count-2] = head_items[0];
   temp_items[count-1] = head_items[1];
   for(int i=2; i<count;++i)
      list_test.AddBefore(list_test.Last().Previous(),head_items[i]);
//--- check
   list_test.CopyTo(check_array);
   if(ArrayCompare(check_array,temp_items)!=0)
      return(false);
//--- clear
   list_test.Clear();

//--- test node is somewhere in the middle
//--- add values
   list_test.AddFirst(head_items[0]);
   list_test.AddLast(head_items[1]);
   list_test.AddLast(head_items[2]);
   ArrayResize(temp_items,count);
   ArrayCopy(temp_items,head_items,0,3,count-3);
   temp_items[count-3] = head_items[0];
   temp_items[count-2] = head_items[1];
   temp_items[count-1] = head_items[2];
   for(int i=3; i<count;++i)
      list_test.AddBefore(list_test.Last().Previous().Previous(),head_items[i]);
//--- check
   list_test.CopyTo(check_array);
   if(ArrayCompare(check_array,temp_items)!=0)
      return(false);
//--- clear
   list_test.Clear();

//--- test call AddBefore several times remove some of the items
//--- add values
   list_test.AddFirst(head_items[0]);
   for(int i=1; i<count;++i)
      list_test.AddBefore(list_test.First(),head_items[i]);
//--- remove values
   list_test.Remove(head_items[2]);
   list_test.Remove(head_items[count - 3]);
   list_test.Remove(head_items[1]);
   list_test.Remove(head_items[count - 2]);
   list_test.RemoveFirst();
   list_test.RemoveLast();
//--- with the above remove we should have removed the first and last 3 items 
   ArrayResize(temp_items,count-6);
   ArrayCopy(temp_items,head_reverse_items,0,3,count-6);
//--- check
   ArrayFree(check_array);
   list_test.CopyTo(check_array);
   if(ArrayCompare(check_array,temp_items)!=0)
      return(false);
//--- add values
   for(int i=0; i<count;++i)
      list_test.AddBefore(list_test.First(),tail_items[i]);
   int temp_items2[];
   ArrayCopy(temp_items2,tail_reverse_items);
   ArrayCopy(temp_items2,temp_items,count);
//--- check
   list_test.CopyTo(check_array);
   if(ArrayCompare(check_array,temp_items2)!=0)
      return(false);
//--- clear
   list_test.Clear();

//--- test call AddBefore several times remove all of the items
//--- add values
   list_test.AddFirst(head_items[0]);
   for(int i=1; i<count;++i)
      list_test.AddBefore(list_test.First(),head_items[i]);
//--- remove values
   for(int i=0; i<count;++i)
      list_test.RemoveFirst();
//--- add values
   list_test.AddFirst(tail_items[0]);
   for(int i=1; i<count;++i)
      list_test.AddBefore(list_test.First(),tail_items[i]);
//--- check
   ArrayFree(check_array);
   list_test.CopyTo(check_array);
   if(ArrayCompare(check_array,tail_reverse_items)!=0)
      return(false);
//--- clear
   list_test.Clear();

//--- test call AddBefore several times then call Clear
//--- add values
   list_test.AddFirst(head_items[0]);
   for(int i=1; i<count;++i)
      list_test.AddBefore(list_test.First(),head_items[i]);
//--- clear
   list_test.Clear();
//--- add values
   list_test.AddFirst(tail_items[0]);
   for(int i=1; i<count;++i)
      list_test.AddBefore(list_test.First(),tail_items[i]);
//--- check
   list_test.CopyTo(check_array);
   if(ArrayCompare(check_array,tail_reverse_items)!=0)
      return(false);
//--- clear
   list_test.Clear();

//--- test mix AddBefore and AddAfter calls
   list_test.AddLast(head_items[0]);
   list_test.AddLast(tail_items[0]);
   for(int i=1; i<count;++i)
     {
      list_test.AddBefore(list_test.First(), head_items[i]);
      list_test.AddAfter(list_test.Last(), tail_items[i]);
     }
   ArrayResize(temp_items,count*2);
   ArrayCopy(temp_items,head_reverse_items);
   ArrayCopy(temp_items,tail_items,count);
//--- check
   list_test.CopyTo(check_array);
   if(ArrayCompare(check_array,temp_items)!=0)
      return(false);
//--- clear
   list_test.Clear();

//--- successful
   return(true);
  }
//+------------------------------------------------------------------+
//| TestAddBefore_Node_Negative.                                     |
//+------------------------------------------------------------------+
bool TestAddBefore_Node_Negative(const int count)
  {
//--- create lists
   CLinkedList<int>list_test();
   CLinkedList<int>list_temp();

//--- test verify null node
//--- check
   if(list_test.AddBefore(NULL,0)!=NULL)
      return(false);
   if(list_test.Count()!=0)
      return(false);

//--- test verify Node that is a new Node
//--- add values
   list_test.AddLast(0);
   CLinkedListNode<int>node(1);
//--- check
   if(list_test.AddBefore(GetPointer(node),-1)!=NULL)
      return(false);
   if(list_test.Count()!=1)
      return(false);
//--- clear
   list_test.Clear();

//--- test verify Node that already exists in another collection
//--- add values   
   list_test.AddLast(MathRand());
   list_test.AddLast(MathRand());
   list_temp.AddLast(MathRand());
   list_temp.AddLast(MathRand());
//--- check   
   if(list_test.AddBefore(list_temp.Last(),MathRand())!=NULL)
      return(false);
   if(list_test.Count()!=2)
      return(false);

//--- successful
   return(true);
  }
//+------------------------------------------------------------------+
//| TestAddBefore.                                                   |
//+------------------------------------------------------------------+
bool TestAddBefore(const string test_name)
  {
   PrintFormat("%s started",test_name);
//--- test 1
   PrintFormat("%s: Test 1: Complex validation of AddBefore method for head node, tail node, some node in the middle, "+
               "also testing after remove several element, remove all element and cleaning of list.",test_name);
   if(!TestAddBefore_Node(16))
      return(false);
//--- test 2
   PrintFormat("%s: Test 2: Validation of AddBefore method for incorrect node.",test_name);
   if(!TestAddBefore_Node_Negative(16))
      return(false);
//--- successful
   PrintFormat("%s passed",test_name);
   return(true);
  }
//+------------------------------------------------------------------+
//| TestAddFirst_Node.                                               |
//+------------------------------------------------------------------+
bool TestAddFirst_Node(const int count)
  {
   CLinkedList<int>list_test();
//--- create test arrays
   int check_array[];
   int temp_items[];
   int head_items[];
   int head_reverse_items[];
   int tail_items[];
   int tail_reverse_items[];
   ArrayResize(temp_items,count);
   ArrayResize(head_items,count);
   ArrayResize(head_reverse_items,count);
   ArrayResize(tail_items,count);
   ArrayResize(tail_reverse_items,count);
   for(int i=0; i<count; i++)
     {
      int index=count-1-i;
      int head = MathRand();
      int tail = MathRand();
      head_items[i]=head;
      head_reverse_items[index]=head;
      tail_items[i]=tail;
      tail_reverse_items[index]=tail;
     }
//--- test verify value is -1
//--- add values
   list_test.AddFirst(-1);
//--- check
   list_test.CopyTo(check_array);
   if(check_array[0]!=-1)
      return(false);
//--- clear 
   list_test.Clear();

//--- test call AddHead several times
//--- add values
   for(int i=0; i<count;++i)
      list_test.AddFirst(head_items[i]);
//--- check
   list_test.CopyTo(check_array);
   if(ArrayCompare(check_array,head_reverse_items)!=0)
      return(false);
//--- clear 
   list_test.Clear();

//--- test call AddHead several times remove some of the items
//--- add values
   for(int i=0; i<count;++i)
      list_test.AddFirst(head_items[i]);
//--- remove values
   list_test.Remove(head_items[2]);
   list_test.Remove(head_items[count-3]);
   list_test.Remove(head_items[1]);
   list_test.Remove(head_items[count-2]);
   list_test.RemoveFirst();
   list_test.RemoveLast();
//--- with the above remove we should have removed the first and last 3 items 
//--- expected items are head_items in reverse order, or a subset of them.
   ArrayResize(temp_items,count-6);
   ArrayCopy(temp_items,head_reverse_items,0,3,count-6);
//--- check
   ArrayFree(check_array);
   list_test.CopyTo(check_array);
   if(ArrayCompare(check_array,temp_items)!=0)
      return(false);
//--- add values
   for(int i=0; i<count;++i)
      list_test.AddFirst(tail_items[i]);
   int temp_items2[];
   ArrayCopy(temp_items2,tail_reverse_items);
   ArrayCopy(temp_items2,temp_items,count);
//--- check
   list_test.CopyTo(check_array);
   if(ArrayCompare(check_array,temp_items2)!=0)
      return(false);
//--- clear 
   list_test.Clear();

//--- test call AddHead several times remove all of the items
//--- add values   
   for(int i=0; i<count;++i)
      list_test.AddFirst(head_items[i]);
//--- remove values
   for(int i=0; i<count;++i)
      list_test.RemoveFirst();
//--- add values
   for(int i=0; i<count;++i)
      list_test.AddFirst(tail_items[i]);
//--- check
   ArrayFree(check_array);
   list_test.CopyTo(check_array);
   if(ArrayCompare(check_array,tail_reverse_items)!=0)
      return(false);
//--- clear 
   list_test.Clear();

//--- test call AddHead several times then call Clear
//--- add vlues
   for(int i=0; i<count;++i)
      list_test.AddFirst(head_items[i]);
//--- clear
   list_test.Clear();
//--- add values
   for(int i=0; i<count;++i)
      list_test.AddFirst(tail_items[i]);
//--- check
   list_test.CopyTo(check_array);
   if(ArrayCompare(check_array,tail_reverse_items)!=0)
      return(false);
//--- clear 
   list_test.Clear();

//--- test mix AddHead and AddTail calls
//--- add values
   for(int i=0; i<count;++i)
     {
      list_test.AddFirst(head_items[i]);
      list_test.AddLast(tail_items[i]);
     }
   ArrayResize(temp_items,count*2);
   ArrayCopy(temp_items,head_reverse_items);
   ArrayCopy(temp_items,tail_items,count);
//--- check
   list_test.CopyTo(check_array);
   if(ArrayCompare(check_array,temp_items)!=0)
      return(false);

//--- successful
   return(true);
  }
//+------------------------------------------------------------------+
//| TestAddFirst_Node_Negative.                                      |
//+------------------------------------------------------------------+
bool TestAddFirst_Node_Negative(const int count)
  {
//--- create lists
   CLinkedList<int>list_test();
   CLinkedList<int>list_temp();

//--- test verify null node
//--- check
   if(list_test.AddFirst((CLinkedListNode<int>*)NULL)==true)
      return(false);
   if(list_test.Count()!=0)
      return(false);

//--- test verify Node that is a new Node
//--- add values
   list_test.AddLast(0);
   CLinkedListNode<int>node(1);
//--- check
   if(list_test.AddFirst(list_test.First())==true)
      return(false);
   if(list_test.Count()!=1)
      return(false);
//--- clear
   list_test.Clear();

//--- test verify Node that already exists in another collection
//--- add values
   list_test.AddLast(MathRand());
   list_test.AddLast(MathRand());
//--- check   
   if(list_test.AddFirst(list_test.Last())==true)
      return(false);
   if(list_test.Count()!=2)
      return(false);
//--- clear
   list_test.Clear();

//--- test verify Node that already exists in another collection
//--- add values   
   list_test.AddLast(MathRand());
   list_test.AddLast(MathRand());
   list_temp.AddLast(MathRand());
   list_temp.AddLast(MathRand());
//--- check   
   if(list_test.AddFirst(list_temp.Last())==true)
      return(false);
   if(list_test.Count()!=2)
      return(false);

//--- successful
   return(true);
  }
//+------------------------------------------------------------------+
//| TestAddFirst.                                                    |
//+------------------------------------------------------------------+
bool TestAddFirst(const string test_name)
  {
   PrintFormat("%s started",test_name);
//--- test 1
   PrintFormat("%s: Test 1: Complex validation of AddFirst method after remove several element, remove all, several calling method of clearing.",test_name);
   if(!TestAddFirst_Node(16))
      return(false);
//--- test 2
   PrintFormat("%s: Test 2: Validation of AddFirst method for incorrect node.",test_name);
   if(!TestAddFirst_Node_Negative(16))
      return(false);
//--- successful
   PrintFormat("%s passed",test_name);
   return(true);
  }
//+------------------------------------------------------------------+
//| TestAddLast_Node.                                                |
//+------------------------------------------------------------------+
bool TestAddLast_Node(const int count)
  {
   CLinkedList<int>list_test();
//--- create test arrays
   int check_array[];
   int temp_items[];
   int head_items[];
   int head_reverse_items[];
   int tail_items[];
   int tail_reverse_items[];
   ArrayResize(temp_items,count);
   ArrayResize(head_items,count);
   ArrayResize(head_reverse_items,count);
   ArrayResize(tail_items,count);
   ArrayResize(tail_reverse_items,count);
   for(int i=0; i<count; i++)
     {
      int index=count-1-i;
      int head = MathRand();
      int tail = MathRand();
      head_items[i]=head;
      head_reverse_items[index]=head;
      tail_items[i]=tail;
      tail_reverse_items[index]=tail;
     }
//--- test verify value is -1
//--- add values
   list_test.AddLast(-1);
//--- check
   list_test.CopyTo(check_array);
   if(check_array[0]!=-1)
      return(false);
//--- clear 
   list_test.Clear();

//--- test call AddTail several times
//--- add values
   for(int i=0; i<count;++i)
      list_test.AddLast(tail_items[i]);
//--- check
   list_test.CopyTo(check_array);
   if(ArrayCompare(check_array,tail_items)!=0)
      return(false);
//--- clear 
   list_test.Clear();

//--- test call AddTail several times remove some of the items
//--- add values
   for(int i=0; i<count;++i)
      list_test.AddLast(tail_items[i]);
//--- remove values
   list_test.Remove(tail_items[2]);
   list_test.Remove(tail_items[count - 3]);
   list_test.Remove(tail_items[1]);
   list_test.Remove(tail_items[count - 2]);
   list_test.RemoveFirst();
   list_test.RemoveLast();
//--- with the above remove we should have removed the first and last 3 items 
   ArrayResize(temp_items,count-6);
   ArrayCopy(temp_items,tail_items,0,3,count-6);
//--- check
   ArrayFree(check_array);
   list_test.CopyTo(check_array);
   if(ArrayCompare(check_array,temp_items)!=0)
      return(false);
//--- adding some more items to the tail of the linked list
   for(int i=0; i<count;++i)
      list_test.AddLast(head_items[i]);
   int temp_items2[];
   ArrayCopy(temp_items2,temp_items);
   ArrayCopy(temp_items2,head_items,ArraySize(temp_items));
//--- check
   list_test.CopyTo(check_array);
   if(ArrayCompare(check_array,temp_items2)!=0)
      return(false);
//--- clear 
   list_test.Clear();

//--- test call AddTail several times then call Clear
//--- add values
   for(int i=0; i<count;++i)
      list_test.AddLast(tail_items[i]);
//--- clear   
   list_test.Clear();
//--- add values
   for(int i=0; i<count;++i)
      list_test.AddLast(head_items[i]);
//--- check
   ArrayFree(check_array);
   list_test.CopyTo(check_array);
   if(ArrayCompare(check_array,head_items)!=0)
      return(false);
//--- clear 
   list_test.Clear();

//--- test mix AddTail and AddTail calls
   for(int i=0; i<count;++i)
     {
      list_test.AddFirst(head_items[i]);
      list_test.AddLast(tail_items[i]);
     }
   ArrayResize(temp_items,count);
//--- adding the head_items in reverse order.
   for(int i=0; i<count; i++)
     {
      int index=count-1-i;
      temp_items[i]=head_items[index];
     }
   ArrayCopy(temp_items2,temp_items);
   ArrayCopy(temp_items2,tail_items,count);
//--- check
   list_test.CopyTo(check_array);
   if(ArrayCompare(check_array,temp_items2)!=0)
      return(false);

//--- successful
   return(true);
  }
//+------------------------------------------------------------------+
//| TestAddLast_Node_Negative.                                       |
//+------------------------------------------------------------------+
bool TestAddLast_Node_Negative(const int count)
  {
//--- create lists
   CLinkedList<int>list_test();
   CLinkedList<int>list_temp();

//--- test verify null node
//--- check
   if(list_test.AddLast((CLinkedListNode<int>*)NULL)==true)
      return(false);
   if(list_test.Count()!=0)
      return(false);

//--- test verify Node that is a new Node
//--- add values
   list_test.AddLast(0);
   CLinkedListNode<int>node(1);
//--- check
   if(list_test.AddLast(list_test.First())==true)
      return(false);
   if(list_test.Count()!=1)
      return(false);
//--- clear
   list_test.Clear();

//--- test verify Node that already exists in another collection
//--- add values
   list_test.AddLast(MathRand());
   list_test.AddLast(MathRand());
//--- check   
   if(list_test.AddLast(list_test.Last())==true)
      return(false);
   if(list_test.Count()!=2)
      return(false);
//--- clear
   list_test.Clear();

//--- test verify Node that already exists in another collection
//--- add values   
   list_test.AddLast(MathRand());
   list_test.AddLast(MathRand());
   list_temp.AddLast(MathRand());
   list_temp.AddLast(MathRand());
//--- check   
   if(list_test.AddLast(list_temp.Last())==true)
      return(false);
   if(list_test.Count()!=2)
      return(false);

//--- successful
   return(true);
  }
//+------------------------------------------------------------------+
//| TestAddLast.                                                     |
//+------------------------------------------------------------------+
bool TestAddLast(const string test_name)
  {
   PrintFormat("%s started",test_name);
//--- test 1
   PrintFormat("%s: Test 1: Complex validation of AddLast method after remove several element, remove all, several calling method of clearing.",test_name);
   if(!TestAddLast_Node(16))
      return(false);
//--- test 2
   PrintFormat("%s: Test 2: Validation of AddLast method for incorrect node.",test_name);
   if(!TestAddLast_Node_Negative(16))
      return(false);
//--- successful
   PrintFormat("%s passed",test_name);
   return(true);
  }
//+------------------------------------------------------------------+
//| TestConstructor_Complex.                                         |
//+------------------------------------------------------------------+
bool TestConstructor_Complex(const int count)
  {
//--- create source array and list
   int array[];
   ArrayResize(array,count);
   for(int i=0; i<count; i++)
      array[i]=MathRand();
   CArrayList<int>list(array);
//--- crete linked list
   CLinkedList<int>llist1(array);
   CLinkedList<int>llist2(GetPointer(list));
   CLinkedList<int>llist3(GetPointer(llist1));
   CLinkedList<int>llist4(NULL);
//--- check
   int check_array1[];
   llist1.CopyTo(check_array1);
   if(ArrayCompare(check_array1,array)!=0)
      return(false);
   int check_array2[];
   llist1.CopyTo(check_array2);
   if(ArrayCompare(check_array2,array)!=0)
      return(false);
   int check_array3[];
   llist1.CopyTo(check_array3);
   if(ArrayCompare(check_array3,array)!=0)
      return(false);
   if(llist4.Count()!=0)
      return(false);

//--- successful
   return(true);
  }
//+------------------------------------------------------------------+
//| TestConstructor.                                                 |
//+------------------------------------------------------------------+
bool TestConstructor(const string test_name)
  {
   PrintFormat("%s started",test_name);
//--- test 1
   PrintFormat("%s: Test 1: Complex validation constructor of linked list dased on array, several ICollection objects and NULL object.",test_name);
   if(!TestConstructor_Complex(16))
      return(false);
//--- successful
   PrintFormat("%s passed",test_name);
   return(true);
  }
//+------------------------------------------------------------------+
//| TestMisc_Find.                                                   |
//+------------------------------------------------------------------+
bool TestMisc_Find(const int count)
  {
   CLinkedList<int>list_test();
//--- create test arrays
   int check_array[];
   int head_items[];
   int tail_items[];
   int head_prepend_items[];
   int tail_prepend_items[];
   ArrayResize(head_items,count);
   ArrayResize(tail_items,count);
   ArrayResize(head_prepend_items,count+1);
   ArrayResize(tail_prepend_items,count+1);
   head_prepend_items[0]=-1;
   tail_prepend_items[0]=-1;
   for(int i=0; i<count; i++)
     {
      int head = (i+1);
      int tail = (i+1)*100;
      head_items[i]=head;
      tail_items[i]=tail;
      head_prepend_items[i+1]=head;
      tail_prepend_items[i+1]=tail;
     }
//--- test call Find an empty collection
//--- check
   if(list_test.Find(head_items[0])!=NULL)
      return(false);
   if(list_test.Find(-1)!=NULL)
      return(false);

//--- test call Find on a collection with one item in it
//--- add values
   list_test.AddLast(head_items[0]);
//--- check
   if(list_test.Find(head_items[1])!=NULL)
      return(false);
   if(list_test.Find(-1)!=NULL)
      return(false);
   if(list_test.Find(head_items[0]).Value()!=head_items[0])
      return(false);
//--- clear
   list_test.Clear();

//--- test call Find on a collection with two items in it
//--- add values
   list_test.AddFirst(head_items[0]);
   list_test.AddLast(head_items[1]);
//--- check 
   if(list_test.Find(head_items[2])!=NULL)
      return(false);
   if(list_test.Find(-1)!=NULL)
      return(false);
   if(list_test.Find(head_items[0]).Value()!=head_items[0])
      return(false);
   if(list_test.Find(head_items[1]).Value()!=head_items[1])
      return(false);
//--- clear
   list_test.Clear();

//--- test call Find on a collection with three items in it
//--- add values
   list_test.AddFirst(head_items[0]);
   list_test.AddLast(head_items[1]);
   list_test.AddLast(head_items[2]);
//--- check 
   if(list_test.Find(head_items[3])!=NULL)
      return(false);
   if(list_test.Find(-1)!=NULL)
      return(false);
   if(list_test.Find(head_items[0]).Value()!=head_items[0])
      return(false);
   if(list_test.Find(head_items[1]).Value()!=head_items[1])
      return(false);
   if(list_test.Find(head_items[2]).Value()!=head_items[2])
      return(false);
//--- clear
   list_test.Clear();

//--- test call Find on a collection with multiple items in it
//--- add values
   for(int i=0; i<count;++i)
      list_test.AddLast(head_items[i]);
//--- check
   if(list_test.Find(tail_items[0])!=NULL)
      return(false);
   if(list_test.Find(-1)!=NULL)
      return(false);
   for(int i=0; i<list_test.Count(); i++)
      if(list_test.Find(head_items[i]).Value()!=head_items[i])
         return(false);
//--- clear
   list_test.Clear();

//--- test call Find on a collection with duplicate items in it
//--- add values  
   for(int i=0; i<count;++i)
      list_test.AddLast(head_items[i]);
   for(int i=0; i<count;++i)
      list_test.AddLast(head_items[i]);
   int temp_items[];
   ArrayCopy(temp_items,head_items);
   ArrayCopy(temp_items,head_items,count);
//--- check
   if(list_test.Find(tail_items[0])!=NULL)
      return(false);
   if(list_test.Find(-1)!=NULL)
      return(false);
   for(int i=0; i<list_test.Count(); i++)
      if(list_test.Find(temp_items[i]).Value()!=temp_items[i])
         return(false);
//--- clear
   list_test.Clear();

//--- test call Find with -1 at the beginning
//--- add values
   for(int i=0; i<count;++i)
      list_test.AddLast(head_items[i]);
   list_test.AddFirst(-1);
//--- check
   if(list_test.Find(tail_items[0])!=NULL)
      return(false);
   for(int i=0; i<list_test.Count(); i++)
      if(list_test.Find(head_prepend_items[i]).Value()!=head_prepend_items[i])
         return(false);
//--- clear
   list_test.Clear();

//--- test call Find with -1 in the middle
//--- add values
   for(int i=0; i<count;++i)
      list_test.AddLast(head_items[i]);
   list_test.AddLast(-1);
   for(int i=0; i<count;++i)
      list_test.AddLast(tail_items[i]);
   ArrayFree(temp_items);
   ArrayCopy(temp_items,head_items);
   ArrayCopy(temp_items,tail_prepend_items,count);
//--- check
   for(int i=0; i<list_test.Count(); i++)
      if(list_test.Find(temp_items[i]).Value()!=temp_items[i])
         return(false);
//--- clear
   list_test.Clear();

//--- test call Find on a collection with duplicate items in it
//--- add values
   for(int i=0; i<count;++i)
      list_test.AddLast(head_items[i]);
   list_test.AddLast(-1);
   ArrayResize(temp_items,count+1);
   temp_items[count]=-1;
   ArrayCopy(temp_items,head_items);
//--- check
   if(list_test.Find(tail_items[0])!=NULL)
      return(false);
   for(int i=0; i<list_test.Count(); i++)
      if(list_test.Find(temp_items[i]).Value()!=temp_items[i])
         return(false);

//--- successful
   return(true);
  }
//+------------------------------------------------------------------+
//| TestMisc_FindLast.                                               |
//+------------------------------------------------------------------+
bool TestMisc_FindLast(const int count)
  {
   CLinkedList<int>list_test();
//--- create test arrays
   int check_array[];
   int head_items[];
   int tail_items[];
   int head_prepend_items[];
   int tail_prepend_items[];
   ArrayResize(head_items,count);
   ArrayResize(tail_items,count);
   ArrayResize(head_prepend_items,count+1);
   ArrayResize(tail_prepend_items,count+1);
   head_prepend_items[0]=-1;
   tail_prepend_items[0]=-1;
   for(int i=0; i<count; i++)
     {
      int head = (i+1);
      int tail = (i+1)*100;
      head_items[i]=head;
      tail_items[i]=tail;
      head_prepend_items[i+1]=head;
      tail_prepend_items[i+1]=tail;
     }
//--- test call FindLast an empty collection
//--- check
   if(list_test.FindLast(head_items[0])!=NULL)
      return(false);
   if(list_test.FindLast(-1)!=NULL)
      return(false);

//--- test call FindLast on a collection with one item in it
//--- add values
   list_test.AddLast(head_items[0]);
//--- check
   if(list_test.FindLast(head_items[1])!=NULL)
      return(false);
   if(list_test.FindLast(-1)!=NULL)
      return(false);
   if(list_test.FindLast(head_items[0]).Value()!=head_items[0])
      return(false);
//--- clear
   list_test.Clear();

//--- test call FindLast on a collection with two items in it
//--- add values
   list_test.AddFirst(head_items[0]);
   list_test.AddLast(head_items[1]);
//--- check 
   if(list_test.FindLast(head_items[2])!=NULL)
      return(false);
   if(list_test.FindLast(-1)!=NULL)
      return(false);
   if(list_test.FindLast(head_items[0]).Value()!=head_items[0])
      return(false);
   if(list_test.FindLast(head_items[1]).Value()!=head_items[1])
      return(false);
//--- clear
   list_test.Clear();

//--- test call FindLast on a collection with three items in it
//--- add values
   list_test.AddFirst(head_items[0]);
   list_test.AddLast(head_items[1]);
   list_test.AddLast(head_items[2]);
//--- check 
   if(list_test.FindLast(head_items[3])!=NULL)
      return(false);
   if(list_test.FindLast(-1)!=NULL)
      return(false);
   if(list_test.FindLast(head_items[0]).Value()!=head_items[0])
      return(false);
   if(list_test.FindLast(head_items[1]).Value()!=head_items[1])
      return(false);
   if(list_test.FindLast(head_items[2]).Value()!=head_items[2])
      return(false);
//--- clear
   list_test.Clear();

//--- test call FindLast on a collection with multiple items in it
//--- add values
   for(int i=0; i<count;++i)
      list_test.AddLast(head_items[i]);
//--- check
   if(list_test.FindLast(tail_items[0])!=NULL)
      return(false);
   if(list_test.FindLast(-1)!=NULL)
      return(false);
   for(int i=0; i<list_test.Count(); i++)
      if(list_test.FindLast(head_items[i]).Value()!=head_items[i])
         return(false);
//--- clear
   list_test.Clear();

//--- test call FindLast on a collection with duplicate items in it
//--- add values  
   for(int i=0; i<count;++i)
      list_test.AddLast(head_items[i]);
   for(int i=0; i<count;++i)
      list_test.AddLast(head_items[i]);
   int temp_items[];
   ArrayCopy(temp_items,head_items);
   ArrayCopy(temp_items,head_items,count);
//--- check
   if(list_test.FindLast(tail_items[0])!=NULL)
      return(false);
   if(list_test.FindLast(-1)!=NULL)
      return(false);
   for(int i=0; i<list_test.Count(); i++)
      if(list_test.FindLast(temp_items[i]).Value()!=temp_items[i])
         return(false);
//--- clear
   list_test.Clear();

//--- test call FindLast with -1 at the beginning
//--- add values
   for(int i=0; i<count;++i)
      list_test.AddLast(head_items[i]);
   list_test.AddFirst(-1);
//--- check
   if(list_test.FindLast(tail_items[0])!=NULL)
      return(false);
   for(int i=0; i<list_test.Count(); i++)
      if(list_test.FindLast(head_prepend_items[i]).Value()!=head_prepend_items[i])
         return(false);
//--- clear
   list_test.Clear();

//--- test call FindLast with -1 in the middle
//--- add values
   for(int i=0; i<count;++i)
      list_test.AddLast(head_items[i]);
   list_test.AddLast(-1);
   for(int i=0; i<count;++i)
      list_test.AddLast(tail_items[i]);
   ArrayFree(temp_items);
   ArrayCopy(temp_items,head_items);
   ArrayCopy(temp_items,tail_prepend_items,count);
//--- check
   for(int i=0; i<list_test.Count(); i++)
      if(list_test.FindLast(temp_items[i]).Value()!=temp_items[i])
         return(false);
//--- clear
   list_test.Clear();

//--- test call FindLast on a collection with duplicate items in it
//--- add values
   for(int i=0; i<count;++i)
      list_test.AddLast(head_items[i]);
   list_test.AddLast(-1);
   ArrayResize(temp_items,count+1);
   temp_items[count]=-1;
   ArrayCopy(temp_items,head_items);
//--- check
   if(list_test.FindLast(tail_items[0])!=NULL)
      return(false);
   for(int i=0; i<list_test.Count(); i++)
      if(list_test.FindLast(temp_items[i]).Value()!=temp_items[i])
         return(false);

//--- successful
   return(true);
  }
//+------------------------------------------------------------------+
//| TestMisc_RemoveNode.                                             |
//+------------------------------------------------------------------+
bool TestMisc_RemoveNode(const int count)
  {
   CLinkedList<int>list_test();
   int temp_value1;
   int temp_value2;
   int temp_value3;
//--- create test arrays
   int check_array[];
   int head_items[];
   int tail_items[];
   int temp_items[];
   ArrayResize(head_items,count);
   ArrayResize(tail_items,count);
   for(int i=0; i<count; i++)
     {
      int head = (i+1);
      int tail = (i+1)*100;
      head_items[i]=head;
      tail_items[i]=tail;
     }
//--- test call Remove with an item that exists in the collection size=1
//--- add values
   list_test.AddLast(head_items[0]);
   temp_value1=list_test.First().Value();
//--- remove
   list_test.Remove(list_test.First());
//--- check
   if(list_test.Count()!=0)
      return(false);
   if(temp_value1!=head_items[0])
      return(false);
//--- clear
   list_test.Clear();

//--- test call Remove with the Head collection size=2
//--- add values
   list_test.AddFirst(head_items[0]);
   list_test.AddLast(head_items[1]);
   temp_value1=list_test.First().Value();
//--- remove 
   list_test.Remove(list_test.First());
//--- check
   if(list_test.Count()!=1)
      return(false);
   if(list_test.First().Value()!=head_items[1])
      return(false);
   if(temp_value1!=head_items[0])
      return(false);
//--- clear
   list_test.Clear();

//--- test call Remove with the Tail collection size=2
//--- add values   
   list_test.AddFirst(head_items[0]);
   list_test.AddLast(head_items[1]);
   temp_value1=list_test.Last().Value();
//--- remove
   list_test.Remove(list_test.Last());
//--- check
   if(list_test.Count()!=1)
      return(false);
   if(list_test.First().Value()!=head_items[0])
      return(false);
   if(temp_value1!=head_items[1])
      return(false);
//--- clear
   list_test.Clear();

//--- test call Remove all the items collection size=2
//--- add values
   list_test.AddFirst(head_items[0]);
   list_test.AddLast(head_items[1]);
   temp_value1 = list_test.First().Value();
   temp_value2 = list_test.Last().Value();
//--- remove
   list_test.Remove(list_test.First());
   list_test.Remove(list_test.Last());
//--- check
   if(list_test.Count()!=0)
      return(false);
   if(temp_value2!=head_items[1])
      return(false);
   if(temp_value1!=head_items[0])
      return(false);
//--- clear
   list_test.Clear();

//--- test call Remove with the Head collection size=3
//--- add values   
   list_test.AddFirst(head_items[0]);
   list_test.AddLast(head_items[1]);
   list_test.AddLast(head_items[2]);
   temp_value1=list_test.First().Value();
//--- remove
   list_test.Remove(list_test.First());
//--- check
   if(list_test.Count()!=2)
      return(false);
   if(list_test.First().Value()!=head_items[1])
      return(false);
   if(list_test.First().Next().Value()!=head_items[2])
      return(false);
   if(temp_value1!=head_items[0])
      return(false);
//--- clear
   list_test.Clear();

//--- test call Remove with the middle item collection size=3
//--- add values
   list_test.AddFirst(head_items[0]);
   list_test.AddLast(head_items[1]);
   list_test.AddLast(head_items[2]);
   temp_value1=list_test.First().Next().Value();
//--- remove
   list_test.Remove(list_test.First().Next());
//--- check
   if(list_test.Count()!=2)
      return(false);
   if(list_test.First().Value()!=head_items[0])
      return(false);
   if(list_test.First().Next().Value()!=head_items[2])
      return(false);
   if(temp_value1!=head_items[1])
      return(false);
//--- clear
   list_test.Clear();

//--- test call Remove with the Tail collection size=3
//--- add values   
   list_test.AddFirst(head_items[0]);
   list_test.AddLast(head_items[1]);
   list_test.AddLast(head_items[2]);
   temp_value1=list_test.Last().Value();
//--- remove   
   list_test.Remove(list_test.Last());
//--- check
   if(list_test.Count()!=2)
      return(false);
   if(list_test.First().Value()!=head_items[0])
      return(false);
   if(list_test.First().Next().Value()!=head_items[1])
      return(false);
   if(temp_value1!=head_items[2])
      return(false);
//--- clear
   list_test.Clear();

//--- test call Remove all the items collection size=3
//--- add values   
   list_test.AddFirst(head_items[0]);
   list_test.AddLast(head_items[1]);
   list_test.AddLast(head_items[2]);
   temp_value1 = list_test.First().Value();
   temp_value2 = list_test.First().Next().Value();
   temp_value3 = list_test.Last().Value();
//--- remove
   list_test.Remove(list_test.First().Next().Next());
   list_test.Remove(list_test.First().Next());
   list_test.Remove(list_test.First());
//--- check 
   if(list_test.Count()!=0)
      return(false);
   if(temp_value3!=head_items[2])
      return(false);
   if(temp_value2!=head_items[1])
      return(false);
   if(temp_value1!=head_items[0])
      return(false);
//--- clear
   list_test.Clear();

//--- test call Remove all the items starting with the first collection size=16
//--- add values
   for(int i=0; i<count;++i)
      list_test.AddLast(head_items[i]);
//--- remove and check
   for(int i=0; i<count;++i)
     {
      list_test.Remove(list_test.First());
      int index=i+1;
      int length=count-i-1;
      int expected[];
      int actual[];
      ArrayCopy(expected,head_items,0,index,length);
      list_test.CopyTo(actual);
      if(ArrayCompare(actual,expected)!=0)
         return(false);
     }
//--- clear
   list_test.Clear();

//--- test call Remove all the items starting with the last collection size=16
//--- add values   
   for(int i=0; i<count;++i)
      list_test.AddLast(head_items[i]);
//--- remove and check
   for(int i=count-1; 0<=i; --i)
     {
      list_test.Remove(list_test.Last());
      int expected[];
      int actual[];
      ArrayCopy(expected,head_items,0,0,i);
      list_test.CopyTo(actual);
      if(ArrayCompare(actual,expected)!=0)
         return(false);
     }
//--- clear
   list_test.Clear();

//--- test remove some items in the middle
//--- add values   
   for(int i=0; i<count;++i)
      list_test.AddFirst(head_items[i]);
//--- remove
   list_test.Remove(list_test.First().Next().Next());
   list_test.Remove(list_test.Last().Previous().Previous());
   list_test.Remove(list_test.First().Next());
   list_test.Remove(list_test.Last().Previous());
   list_test.Remove(list_test.First());
   list_test.Remove(list_test.Last());
//--- with the above remove we should have removed the first and last 3 items 
   int head_reverse_items[];
   ArrayCopy(head_reverse_items,head_items);
   ArrayReverse(head_reverse_items,0,count);
   ArrayCopy(temp_items,head_reverse_items,0,3,count-6);
//--- check
   list_test.CopyTo(check_array);
   if(ArrayCompare(check_array,temp_items)!=0)
      return(false);
//--- clear
   list_test.Clear();

//--- test remove an item with a value of -1
//--- add values
   for(int i=0; i<count;++i)
      list_test.AddLast(head_items[i]);
   list_test.AddLast(-1);
//--- remove
   list_test.Remove(list_test.Last());
//--- check
   ArrayFree(check_array);
   list_test.CopyTo(check_array);
   if(ArrayCompare(check_array,head_items)!=0)
      return(false);
//--- clear
   list_test.Clear();

//--- test remove node with duplicates
   int items[];
   ArrayResize(items,count);
   for(int i=0; i<count; i++)
      items[i]=MathRand();
//--- add values      
   for(int i=0; i<count; i++)
      list_test.AddLast(items[i]);
   for(int i=0; i<count; i++)
      list_test.AddLast(items[i]);
//--- store nodes
   CLinkedListNode<int>*nodes[];
   CLinkedListNode<int>*current_node=list_test.First();
   int index=0;
   ArrayResize(nodes,count*2);
   while(index<count*2)
     {
      nodes[index] = current_node;
      current_node = current_node.Next();
      index++;
     }
//--- remove
   list_test.Remove(list_test.First().Next().Next());
   list_test.Remove(list_test.Last().Previous().Previous());
   list_test.Remove(list_test.First().Next());
   list_test.Remove(list_test.Last().Previous());
   list_test.Remove(list_test.First());
   list_test.Remove(list_test.Last());
//--- check
   current_node=list_test.First();
   for(int i=3; i<(count*2)-3;i++)
     {
      if(current_node==NULL)
         return(false);
      if(current_node!=nodes[i])
         return(false);
      if(items[i%count]!=current_node.Value())
         return(false);
      current_node=current_node.Next();
     }
//--- clear
   list_test.Clear();

//--- test verify NULL node
//--- check
   if(list_test.Remove((CLinkedListNode<int>*)NULL) && list_test.Remove(0))
      return(false);

//--- test verify Node that is a new Node
//--- add values
   list_test.AddLast(0);
   CLinkedListNode<int>node(1);
//--- check
   if(list_test.Remove(GetPointer(node)))
      return(false);
//--- clear
   list_test.Clear();

//--- test verify Node that already exists in another collection
   list_test.AddLast(MathRand());
   list_test.AddLast(MathRand());
   CLinkedList<int>other();
   other.AddLast(MathRand());
   other.AddLast(MathRand());
   if(list_test.Remove(other.Last()))
      return(false);

//--- successful
   return(true);
  }
//+------------------------------------------------------------------+
//| TestMisc_RemoveFirst.                                            |
//+------------------------------------------------------------------+
bool TestMisc_RemoveFirst(const int count)
  {
   CLinkedList<int>list_test();
   int temp_value1;
   int temp_value2;
   int temp_value3;
//--- create test arrays
   int check_array[];
   int head_items[];
   int tail_items[];
   int temp_items[];
   ArrayResize(head_items,count);
   ArrayResize(tail_items,count);
   ArrayResize(temp_items,count);
   for(int i=0; i<count; i++)
     {
      int head = (i+1);
      int tail = (i+1)*100;
      head_items[i]=head;
      tail_items[i]=tail;
     }
//--- test call RemoveHead on a collection with one item in it
//--- add values
   list_test.AddLast(head_items[0]);
   temp_value1=list_test.First().Value();
   list_test.RemoveFirst();
//--- check
   if(list_test.Count()!=0)
      return(false);
   if(temp_value1!=head_items[0])
      return(false);

//--- test call RemoveHead on a collection with two items in it
//--- add values
   list_test.AddFirst(head_items[0]);
   list_test.AddLast(head_items[1]);
   temp_value1 = list_test.First().Value();
   temp_value2 = list_test.Last().Value();
//--- remove 
   list_test.RemoveFirst();
   list_test.RemoveFirst();
//--- check
   if(list_test.Count()!=0)
      return(false);
   if(temp_value1!=head_items[0])
      return(false);
   if(temp_value2!=head_items[1])
      return(false);

//--- test call RemoveHead on a collection with three items in it
//--- add  values   
   list_test.AddFirst(head_items[0]);
   list_test.AddLast(head_items[1]);
   list_test.AddLast(head_items[2]);
   temp_value1 = list_test.First().Value();
   temp_value2 = list_test.First().Next().Value();
   temp_value3 = list_test.Last().Value();
//--- remove
   list_test.RemoveFirst();
   list_test.RemoveFirst();
   list_test.RemoveFirst();
//--- check
   if(list_test.Count()!=0)
      return(false);
   if(temp_value1!=head_items[0])
      return(false);
   if(temp_value2!=head_items[1])
      return(false);
   if(temp_value3!=head_items[2])
      return(false);

//--- test call RemoveHead on a collection with 16 items in it
//--- add values
   for(int i=0; i<count;++i)
      list_test.AddLast(head_items[i]);
//--- remove and check
   for(int i=0; i<count;++i)
     {
      list_test.RemoveFirst();
      int index=i+1;
      int length=count-i-1;
      int expected[];
      int actual[];
      ArrayCopy(expected,head_items,0,index,length);
      list_test.CopyTo(actual);
      if(ArrayCompare(actual,expected)!=0)
         return(false);
     }
//--- clear
   list_test.Clear();

//--- test mix RemoveHead and RemoveTail call
//--- add values
   for(int i=0; i<count;++i)
      list_test.AddLast(head_items[i]);
//--- remove and check
   for(int i=0; i<count;++i)
     {
      if((i  &1)==0)
         list_test.RemoveFirst();
      else
         list_test.RemoveLast();
      int index=(i/2)+1;
      int length=count-i-1;
      int expected[];
      int actual[];
      ArrayCopy(expected,head_items,0,index,length);
      list_test.CopyTo(actual);
      if(ArrayCompare(actual,expected)!=0)
         return(false);
     }
//--- clear
   list_test.Clear();

//--- test call RemoveHead an empty collection
   if(list_test.RemoveFirst())
      return(false);

//--- successful
   return(true);
  }
//+------------------------------------------------------------------+
//| TestMisc_RemoveLast.                                             |
//+------------------------------------------------------------------+
bool TestMisc_RemoveLast(const int count)
  {
   CLinkedList<int>list_test();
   int temp_value1;
   int temp_value2;
   int temp_value3;
//--- create test arrays
   int check_array[];
   int head_items[];
   int tail_items[];
   int temp_items[];
   ArrayResize(head_items,count);
   ArrayResize(tail_items,count);
   ArrayResize(temp_items,count);
   for(int i=0; i<count; i++)
     {
      int head = (i+1);
      int tail = (i+1)*100;
      head_items[i]=head;
      tail_items[i]=tail;
     }
//--- test call RemoveHead on a collection with one item in it
//--- add values
   list_test.AddLast(head_items[0]);
   temp_value1=list_test.First().Value();
   list_test.RemoveLast();
//--- check
   if(list_test.Count()!=0)
      return(false);
   if(temp_value1!=head_items[0])
      return(false);

//--- test call RemoveHead on a collection with two items in it
//--- add values
   list_test.AddFirst(head_items[0]);
   list_test.AddLast(head_items[1]);
   temp_value1 = list_test.First().Value();
   temp_value2 = list_test.Last().Value();
//--- remove and check
   list_test.RemoveLast();
   if(list_test.Last().Value()!=head_items[0])
      return(false);
   list_test.RemoveLast();
//--- check
   if(list_test.Count()!=0)
      return(false);
   if(temp_value1!=head_items[0])
      return(false);
   if(temp_value2!=head_items[1])
      return(false);

//--- test call RemoveHead on a collection with three items in it
//--- add  values   
   list_test.AddFirst(head_items[0]);
   list_test.AddLast(head_items[1]);
   list_test.AddLast(head_items[2]);
   temp_value1 = list_test.First().Value();
   temp_value2 = list_test.First().Next().Value();
   temp_value3 = list_test.Last().Value();
//--- remove and check
   list_test.RemoveLast();
   if(list_test.Last().Value()!=head_items[1])
      return(false);
   list_test.RemoveLast();
   if(list_test.Last().Value()!=head_items[0])
      return(false);
   list_test.RemoveLast();
//--- check
   if(list_test.Count()!=0)
      return(false);
   if(temp_value1!=head_items[0])
      return(false);
   if(temp_value2!=head_items[1])
      return(false);
   if(temp_value3!=head_items[2])
      return(false);

//--- test call RemoveHead on a collection with 16 items in it
//--- add values
   for(int i=0; i<count;++i)
      list_test.AddLast(head_items[i]);
//--- remove and check
   for(int i=0; i<count;++i)
     {
      list_test.RemoveLast();
      int length=count-i-1;
      int expected[];
      int actual[];
      ArrayCopy(expected,head_items,0,0,length);
      list_test.CopyTo(actual);
      if(ArrayCompare(actual,expected)!=0)
         return(false);
     }
//--- clear
   list_test.Clear();

//--- test mix RemoveHead and RemoveTail call
//--- add values
   for(int i=0; i<count;++i)
      list_test.AddLast(head_items[i]);
//--- remove and check
   for(int i=0; i<count;++i)
     {
      if((i  &1)==0)
         list_test.RemoveFirst();
      else
         list_test.RemoveLast();
      int index=(i/2)+1;
      int length=count-i-1;
      int expected[];
      int actual[];
      ArrayCopy(expected,head_items,0,index,length);
      list_test.CopyTo(actual);
      if(ArrayCompare(actual,expected)!=0)
         return(false);
     }
//--- clear
   list_test.Clear();

//--- test call RemoveHead an empty collection
   if(list_test.RemoveLast())
      return(false);

//--- successful
   return(true);
  }
//+------------------------------------------------------------------+
//| TestMisc.                                                        |
//+------------------------------------------------------------------+
bool TestMisc(const string test_name)
  {
   PrintFormat("%s started",test_name);
//--- test 1
   PrintFormat("%s: Test 1: Complex validation of Find method of some element in different positions on the linked list with and without duplicates.",test_name);
   if(!TestMisc_Find(16))
      return(false);
//--- test 2
   PrintFormat("%s: Test 2: Complex validation of FindLast method of some element in different positions on the linked list with and without duplicates.",test_name);
   if(!TestMisc_FindLast(16))
      return(false);
//--- test 3
   PrintFormat("%s: Test 3: Complex validation of Remove method of some node in different positions on the linked list with different count of elements.",test_name);
   if(!TestMisc_RemoveNode(16))
      return(false);
//--- test 4
   PrintFormat("%s: Test 3: Complex validation of RemoveFirst method on the linked list with different count of elements.",test_name);
   if(!TestMisc_RemoveFirst(16))
      return(false);
//--- test 5
   PrintFormat("%s: Test 3: Complex validation of RemoveLast method on the linked list with different count of elements.",test_name);
   if(!TestMisc_RemoveLast(16))
      return(false);
//--- successful
   PrintFormat("%s passed",test_name);
   return(true);
  }
//+------------------------------------------------------------------+
//| TestLinkedList.                                                  |
//+------------------------------------------------------------------+
void TestLinkedList(int &tests_performed,int &tests_passed)
  {
   string test_name="";
//--- AddAfter functions
   tests_performed++;
   test_name="AddAfter functions test";
   if(TestAddAfter(test_name))
      tests_passed++;
   else
      PrintFormat("%s failed",test_name);
//--- AddBefore functions
   tests_performed++;
   test_name="AddBefore functions test";
   if(TestAddBefore(test_name))
      tests_passed++;
   else
      PrintFormat("%s failed",test_name);
//--- AddFirst functions
   tests_performed++;
   test_name="AddFirst functions test";
   if(TestAddFirst(test_name))
      tests_passed++;
   else
      PrintFormat("%s failed",test_name);
//--- AddLast functions
   tests_performed++;
   test_name="AddLast functions test";
   if(TestAddLast(test_name))
      tests_passed++;
   else
      PrintFormat("%s failed",test_name);
//--- Constructor functions
   tests_performed++;
   test_name="Constructor functions test";
   if(TestConstructor(test_name))
      tests_passed++;
   else
      PrintFormat("%s failed",test_name);
//--- Misc functions
   tests_performed++;
   test_name="Misc functions test";
   if(TestMisc(test_name))
      tests_passed++;
   else
      PrintFormat("%s failed",test_name);
  }
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
   MathSrand(0);
   string package_name="Generic";
   PrintFormat("Unit tests for Package %s\n",package_name);
//--- initial values
   int tests_performed=0;
   int tests_passed=0;
//--- test distributions
   TestLinkedList(tests_performed,tests_passed);
//--- print statistics
   PrintFormat("\n%d of %d passed",tests_passed,tests_performed);
  }
//+------------------------------------------------------------------+
