/**
   * The compare test creates a sorted stream, writes it to the buffer and compares random elements.
   * It expects that earlier elements are lower than later ones.
   */
  @Test
  public void testCompare() throws Exception {
    final int numSegments = MEMORY_SIZE / MEMORY_PAGE_SIZE;
    final List<MemorySegment> memory =
        this.memoryManager.allocatePages(new DummyInvokable(), numSegments);

    FixedLengthRecordSorter<IntPair> sorter = newSortBuffer(memory);
    UniformIntPairGenerator generator = new UniformIntPairGenerator(Integer.MAX_VALUE, 1, true);

    // write the records
    IntPair record = new IntPair();
    int num = -1;
    do {
      generator.next(record);
      num++;
    } while (sorter.write(record) && num < 3354624);

    // compare random elements
    Random rnd = new Random(SEED << 1);
    for (int i = 0; i < 2 * num; i++) {
      int pos1 = rnd.nextInt(num);
      int pos2 = rnd.nextInt(num);

      int cmp = sorter.compare(pos1, pos2);

      if (pos1 < pos2) {
        Assert.assertTrue(cmp <= 0);
      } else {
        Assert.assertTrue(cmp >= 0);
      }
    }

    // release the memory occupied by the buffers
    this.memoryManager.release(sorter.dispose());
  }
  @Test
  public void testWriteAndRead() throws Exception {
    final int numSegments = MEMORY_SIZE / MEMORY_PAGE_SIZE;
    final List<MemorySegment> memory =
        this.memoryManager.allocatePages(new DummyInvokable(), numSegments);

    FixedLengthRecordSorter<IntPair> sorter = newSortBuffer(memory);
    RandomIntPairGenerator generator = new RandomIntPairGenerator(SEED);

    //		long startTime = System.currentTimeMillis();
    // write the records
    IntPair record = new IntPair();
    int num = -1;
    do {
      generator.next(record);
      num++;
    } while (sorter.write(record) && num < 3354624);
    //		System.out.println("WRITE TIME " + (System.currentTimeMillis() - startTime));

    // re-read the records
    generator.reset();
    IntPair readTarget = new IntPair();

    //		startTime = System.currentTimeMillis();
    int i = 0;
    while (i < num) {
      generator.next(record);
      readTarget = sorter.getRecord(readTarget, i++);

      int rk = readTarget.getKey();
      int gk = record.getKey();

      int rv = readTarget.getValue();
      int gv = record.getValue();

      if (gk != rk) {
        Assert.fail("The re-read key is wrong " + i);
      }
      if (gv != rv) {
        Assert.fail("The re-read value is wrong");
      }
    }
    //		System.out.println("READ TIME " + (System.currentTimeMillis() - startTime));
    //		System.out.println("RECORDS " + num);

    // release the memory occupied by the buffers
    this.memoryManager.release(sorter.dispose());
  }
  @Test
  public void testSort() throws Exception {
    final int NUM_RECORDS = 559273;
    final int numSegments = MEMORY_SIZE / MEMORY_PAGE_SIZE;
    final List<MemorySegment> memory =
        this.memoryManager.allocatePages(new DummyInvokable(), numSegments);

    FixedLengthRecordSorter<IntPair> sorter = newSortBuffer(memory);
    RandomIntPairGenerator generator = new RandomIntPairGenerator(SEED);

    // write the records
    IntPair record = new IntPair();
    int num = -1;
    do {
      generator.next(record);
      num++;
    } while (sorter.write(record) && num < NUM_RECORDS);

    QuickSort qs = new QuickSort();
    qs.sort(sorter);

    MutableObjectIterator<IntPair> iter = sorter.getIterator();
    IntPair readTarget = new IntPair();

    int current = 0;
    int last = 0;

    iter.next(readTarget);
    // readTarget.getFieldInto(0, last);
    last = readTarget.getKey();

    while ((readTarget = iter.next(readTarget)) != null) {
      current = readTarget.getKey();

      final int cmp = last - current;
      if (cmp > 0) {
        Assert.fail("Next key is not larger or equal to previous key.");
      }

      int tmp = current;
      current = last;
      last = tmp;
    }

    // release the memory occupied by the buffers
    this.memoryManager.release(sorter.dispose());
  }
  /**
   * The swap test fills the sort buffer and swaps all elements such that they are backwards. It
   * then resets the generator, goes backwards through the buffer and compares for equality.
   */
  @Test
  public void testSwap() throws Exception {
    final int numSegments = MEMORY_SIZE / MEMORY_PAGE_SIZE;
    final List<MemorySegment> memory =
        this.memoryManager.allocatePages(new DummyInvokable(), numSegments);

    FixedLengthRecordSorter<IntPair> sorter = newSortBuffer(memory);
    RandomIntPairGenerator generator = new RandomIntPairGenerator(SEED);

    // write the records
    IntPair record = new IntPair();
    int num = -1;
    do {
      generator.next(record);
      num++;
    } while (sorter.write(record) && num < 3354624);

    // swap the records
    int start = 0, end = num - 1;
    while (start < end) {
      sorter.swap(start++, end--);
    }

    // re-read the records
    generator.reset();
    IntPair readTarget = new IntPair();

    int i = num - 1;
    while (i >= 0) {
      generator.next(record);
      readTarget = sorter.getRecord(readTarget, i--);

      int rk = readTarget.getKey();
      int gk = record.getKey();

      int rv = readTarget.getValue();
      int gv = record.getValue();

      Assert.assertEquals("The re-read key is wrong", gk, rk);
      Assert.assertEquals("The re-read value is wrong", gv, rv);
    }

    // release the memory occupied by the buffers
    this.memoryManager.release(sorter.dispose());
  }
  @Test
  public void testWriteAndIterator() throws Exception {
    final int numSegments = MEMORY_SIZE / MEMORY_PAGE_SIZE;
    final List<MemorySegment> memory =
        this.memoryManager.allocatePages(new DummyInvokable(), numSegments);

    FixedLengthRecordSorter<IntPair> sorter = newSortBuffer(memory);
    RandomIntPairGenerator generator = new RandomIntPairGenerator(SEED);

    // write the records
    IntPair record = new IntPair();
    int num = -1;
    do {
      generator.next(record);
      num++;
    } while (sorter.write(record));

    // re-read the records
    generator.reset();

    MutableObjectIterator<IntPair> iter = sorter.getIterator();
    IntPair readTarget = new IntPair();
    int count = 0;

    while ((readTarget = iter.next(readTarget)) != null) {
      count++;

      generator.next(record);

      int rk = readTarget.getKey();
      int gk = record.getKey();

      int rv = readTarget.getValue();
      int gv = record.getValue();

      Assert.assertEquals("The re-read key is wrong", gk, rk);
      Assert.assertEquals("The re-read value is wrong", gv, rv);
    }

    Assert.assertEquals("Incorrect number of records", num, count);

    // release the memory occupied by the buffers
    this.memoryManager.release(sorter.dispose());
  }
  @Test
  public void testReset() throws Exception {
    final int numSegments = MEMORY_SIZE / MEMORY_PAGE_SIZE;
    final List<MemorySegment> memory =
        this.memoryManager.allocatePages(new DummyInvokable(), numSegments);

    FixedLengthRecordSorter<IntPair> sorter = newSortBuffer(memory);
    RandomIntPairGenerator generator = new RandomIntPairGenerator(SEED);

    // write the buffer full with the first set of records
    IntPair record = new IntPair();
    int num = -1;
    do {
      generator.next(record);
      num++;
    } while (sorter.write(record) && num < 3354624);

    sorter.reset();

    // write a second sequence of records. since the values are of fixed length, we must be able to
    // write an equal number
    generator.reset();

    // write the buffer full with the first set of records
    int num2 = -1;
    do {
      generator.next(record);
      num2++;
    } while (sorter.write(record) && num2 < 3354624);

    Assert.assertEquals(
        "The number of records written after the reset was not the same as before.", num, num2);

    // re-read the records
    generator.reset();
    IntPair readTarget = new IntPair();

    int i = 0;
    while (i < num) {
      generator.next(record);
      readTarget = sorter.getRecord(readTarget, i++);

      int rk = readTarget.getKey();
      int gk = record.getKey();

      int rv = readTarget.getValue();
      int gv = record.getValue();

      Assert.assertEquals("The re-read key is wrong", gk, rk);
      Assert.assertEquals("The re-read value is wrong", gv, rv);
    }

    // release the memory occupied by the buffers
    this.memoryManager.release(sorter.dispose());
  }