with Integer_Hashed_Multisets;  use Integer_Hashed_Multisets;
--with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Ada.Text_IO;  use Ada.Text_IO;
with Ada.Numerics.Discrete_Random;

procedure Test_Hashed_Multisets is

   subtype Integer_Subtype is Integer range 1 .. 1000;

   package Random_Numbers is
      new Ada.Numerics.Discrete_Random (Integer_Subtype);

   use Random_Numbers;

   function In_Range (I : Iterator_Type;
                      S : Container_Type) return Boolean is

      J : Iterator_Type := Find (S, Element (I));
   begin
      if J = Back (S) then
         return False;
      end if;

      while J /= Null_Iterator
        and then Is_Equal_Key (J, I)
      loop
         if I = J then
            return True;
         end if;

         Increment (S, J);
      end loop;

      return False;
   end In_Range;

   G : Generator;

   S, S2 : Container_Type;

   E : Integer;
   I, J : Iterator_Type;

   N : Natural;

begin

   Reset (G);

   pragma Assert (Length (S) = 0);
   pragma Assert (S = S2);

   S2 := S;
   pragma Assert (S = S2);

   Assign (Target => S2, Source => S);
   pragma Assert (S = S2);

   pragma Assert (Find (S, Item => 42) = Back (S));

   Insert (S, 42, I);
   pragma Assert (Length (S) = 1);
   pragma Assert (Element (I) = 42);
   pragma Assert (I = First (S));
   pragma Assert (Succ (S, I) = Back (S));
   pragma Assert (In_Range (I, S));

   S2 := S;
   pragma Assert (S = S2);

   Assign (Target => S2, Source => S);
   pragma Assert (S = S2);

   J := Find (S, 42);
   pragma Assert (J /= Back (S));
   pragma Assert (Element (J) = 42);

   S2 := S;
   pragma Assert (S = S2);

   Assign (Target => S2, Source => S);
   pragma Assert (S = S2);

   Put_Line ("inserting");

   loop

      N := Length (S);

      exit when N > 900;

      E := Random (G);

      Insert (S, E, I);
      pragma Assert (Element (I) = E);
      pragma Assert (In_Range (I, S));

      J := Find (S, E);
      pragma Assert (J /= Back (S));
      pragma Assert (Element (J) = E);
      pragma Assert (Length (S) = N + 1);

      S2 := S;
      pragma Assert (S = S2);

      Assign (Target => S2, Source => S);
      pragma Assert (S = S2);

   end loop;

   Put_Line ("deleting");

   while not Is_Empty (S) loop

      I := First (S);

      for J in 1 .. Random (G) mod Length (S) loop
         Increment (S, I);
      end loop;

      pragma Assert (I /= Back (S));

      E := Element (I);

      Delete (S, I);

      S2 := S;
      pragma Assert (S = S2);

      Assign (Target => S2, Source => S);
      pragma Assert (S = S2);

   end loop;

end Test_Hashed_Multisets;


