Back to index

lightning-sunbird  0.9+nobinonly
Classes | Defines | Functions | Variables
TestTXMgr.cpp File Reference
#include <stdlib.h>
#include <stdio.h>
#include "nsXPCOM.h"
#include "nsITransactionManager.h"
#include "nsIComponentManager.h"

Go to the source code of this file.

Classes

class  TestTransaction
class  SimpleTransaction
class  AggregateTransaction
class  TestTransactionFactory
class  SimpleTransactionFactory
class  AggregateTransactionFactory

Defines

#define TEST_TXMGR_IF_RELEASE(tx)   if (tx) tx->Release();
#define NONE_FLAG   0
#define THROWS_DO_ERROR_FLAG   1
#define THROWS_UNDO_ERROR_FLAG   2
#define THROWS_REDO_ERROR_FLAG   4
#define MERGE_FLAG   8
#define TRANSIENT_FLAG   16
#define BATCH_FLAG   32
#define ALL_ERROR_FLAGS   (THROWS_DO_ERROR_FLAG|THROWS_UNDO_ERROR_FLAG|THROWS_REDO_ERROR_FLAG)

Functions

void reset_globals ()
nsresult quick_test (TestTransactionFactory *factory)
nsresult simple_test ()
nsresult aggregation_test ()
nsresult quick_batch_test (TestTransactionFactory *factory)
nsresult simple_batch_test ()
nsresult aggregation_batch_test ()
nsresult stress_test (TestTransactionFactory *factory, PRInt32 iterations)
nsresult simple_stress_test ()
nsresult aggregation_stress_test ()
nsresult aggregation_batch_stress_test ()
int main (int argc, char *argv[])

Variables

static PRInt32 sConstructorCount = 0
static PRInt32 sDestructorCount = 0
static PRInt32sDestructorOrderArr = 0
static PRInt32 sDoCount = 0
static PRInt32sDoOrderArr = 0
static PRInt32 sUndoCount = 0
static PRInt32sUndoOrderArr = 0
static PRInt32 sRedoCount = 0
static PRInt32sRedoOrderArr = 0
PRInt32 sSimpleTestDestructorOrderArr []
PRInt32 sSimpleTestDoOrderArr []
PRInt32 sSimpleTestUndoOrderArr []
static PRInt32 sSimpleTestRedoOrderArr []
PRInt32 sAggregateTestDestructorOrderArr []
PRInt32 sAggregateTestDoOrderArr []
PRInt32 sAggregateTestUndoOrderArr []
PRInt32 sAggregateTestRedoOrderArr []
PRInt32 sSimpleBatchTestDestructorOrderArr []
PRInt32 sSimpleBatchTestDoOrderArr []
PRInt32 sSimpleBatchTestUndoOrderArr []
PRInt32 sSimpleBatchTestRedoOrderArr []
PRInt32 sAggregateBatchTestDestructorOrderArr []
PRInt32 sAggregateBatchTestDoOrderArr []
PRInt32 sAggregateBatchTestUndoOrderArr []
PRInt32 sAggregateBatchTestRedoOrderArr []

Define Documentation

Definition at line 461 of file TestTXMgr.cpp.

#define BATCH_FLAG   32

Definition at line 460 of file TestTXMgr.cpp.

#define MERGE_FLAG   8

Definition at line 458 of file TestTXMgr.cpp.

#define NONE_FLAG   0

Definition at line 454 of file TestTXMgr.cpp.

#define TEST_TXMGR_IF_RELEASE (   tx)    if (tx) tx->Release();

Definition at line 436 of file TestTXMgr.cpp.

Definition at line 455 of file TestTXMgr.cpp.

Definition at line 457 of file TestTXMgr.cpp.

Definition at line 456 of file TestTXMgr.cpp.

Definition at line 459 of file TestTXMgr.cpp.


Function Documentation

Definition at line 4635 of file TestTXMgr.cpp.

{
  /*******************************************************************
   *
   * Initialize globals for test.
   *
   *******************************************************************/

  reset_globals();

  /*******************************************************************
   *
   * Do the stress test:
   *
   *******************************************************************/

  AggregateTransactionFactory factory(3,4,BATCH_FLAG);

  printf("\n-----------------------------------------------------\n");
  printf("- Aggregate Batch Transaction Stress Test:\n");
  printf("-----------------------------------------------------\n");

  //
  // 500 iterations sends 2,630,250 transactions through the system!!
  //
  return stress_test(&factory, 500);
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 4432 of file TestTXMgr.cpp.

{
  /*******************************************************************
   *
   * Initialize globals for test.
   *
   *******************************************************************/

  reset_globals();
  sDestructorOrderArr = sAggregateBatchTestDestructorOrderArr;
  sDoOrderArr         = sAggregateBatchTestDoOrderArr;
  sUndoOrderArr       = sAggregateBatchTestUndoOrderArr;
  sRedoOrderArr       = sAggregateBatchTestRedoOrderArr;

  /*******************************************************************
   *
   * Run the quick batch test.
   *
   *******************************************************************/

  AggregateTransactionFactory factory(3,2,BATCH_FLAG);

  printf("\n-----------------------------------------------------\n");
  printf("- Begin Batch Aggregate Transaction Test:\n");
  printf("-----------------------------------------------------\n");

  return quick_batch_test(&factory);
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 4606 of file TestTXMgr.cpp.

{
  /*******************************************************************
   *
   * Initialize globals for test.
   *
   *******************************************************************/

  reset_globals();

  /*******************************************************************
   *
   * Do the stress test:
   *
   *******************************************************************/

  AggregateTransactionFactory factory(3,4);

  printf("\n-----------------------------------------------------\n");
  printf("- Aggregate Transaction Stress Test:\n");
  printf("-----------------------------------------------------\n");

  //
  // 500 iterations sends 2,630,250 transactions through the system!!
  //
  return stress_test(&factory, 500);
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 2729 of file TestTXMgr.cpp.

{
  /*******************************************************************
   *
   * Initialize globals for test.
   *
   *******************************************************************/

  reset_globals();
  sDestructorOrderArr = sAggregateTestDestructorOrderArr;
  sDoOrderArr         = sAggregateTestDoOrderArr;
  sUndoOrderArr       = sAggregateTestUndoOrderArr;
  sRedoOrderArr       = sAggregateTestRedoOrderArr;

  /*******************************************************************
   *
   * Run the quick test.
   *
   *******************************************************************/

  AggregateTransactionFactory factory(3,2);

  printf("\n-----------------------------------------------------\n");
  printf("- Begin Aggregate Transaction Test:\n");
  printf("-----------------------------------------------------\n");

  return quick_test(&factory);
}

Here is the call graph for this function:

Here is the caller graph for this function:

int main ( int  argc,
char *  argv[] 
)

Definition at line 4664 of file TestTXMgr.cpp.

{
  nsresult result = NS_InitXPCOM2(nsnull, nsnull, nsnull);
  if (NS_FAILED(result))
    return result;

  result = simple_test();

  if (NS_FAILED(result))
    return result;

  result = simple_batch_test();

  if (NS_FAILED(result))
    return result;

  result = aggregation_test();

  if (NS_FAILED(result))
    return result;

  result = aggregation_batch_test();

  if (NS_FAILED(result))
    return result;

  result = simple_stress_test();

  if (NS_FAILED(result))
    return result;

  result = aggregation_stress_test();

  if (NS_FAILED(result))
    return result;

  result = aggregation_batch_stress_test();

  if (NS_FAILED(result))
    return result;

  return NS_OK;
}

Here is the call graph for this function:

Definition at line 2759 of file TestTXMgr.cpp.

{
  /*******************************************************************
   *
   * Create a transaction manager implementation:
   *
   *******************************************************************/

  printf("Create transaction manager instance ... ");

  PRInt32 i, numitems = 0;
  nsCOMPtr<nsITransactionManager> mgr;
  nsITransaction *tx          = 0;
  TestTransaction *tximpl   = 0;
  nsITransaction *u1 = 0, *u2 = 0;
  nsITransaction *r1 = 0, *r2 = 0;
  nsresult result;

  mgr = do_CreateInstance(NS_TRANSACTIONMANAGER_CONTRACTID, &result);
  if (NS_FAILED(result) || !mgr) {
    printf("ERROR: Failed to create Transaction Manager instance.\n");
    return NS_ERROR_OUT_OF_MEMORY;
  }

  printf("passed\n");

  /*******************************************************************
   *
   * Make sure an unbalanced call to EndBatch() with empty undo stack
   * throws an error!
   *
   *******************************************************************/

  printf("Test unbalanced EndBatch() with empty undo stack ... ");

  result = mgr->GetNumberOfUndoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfUndoItems() on empty undo stack failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 0) {
    printf("ERROR: GetNumberOfUndoItems() expected 0 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->EndBatch();

  if (result != NS_ERROR_FAILURE) {
    printf("ERROR: EndBatch() returned unexpected status. (%d)\n", result);
    return result;
  }

  result = mgr->GetNumberOfUndoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfUndoItems() on empty undo stack failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 0) {
    printf("ERROR: GetNumberOfUndoItems() expected 0 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  printf("passed\n");


  /*******************************************************************
   *
   * Make sure that an empty batch is not added to the undo stack
   * when it is closed.
   *
   *******************************************************************/

  printf("Test empty batch ... ");

  result = mgr->GetNumberOfUndoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfUndoItems() on empty undo stack failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 0) {
    printf("ERROR: GetNumberOfUndoItems() expected 0 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->BeginBatch();

  if (NS_FAILED(result)) {
    printf("ERROR: BeginBatch() failed. (%d)\n", result);
    return result;
  }

  result = mgr->GetNumberOfUndoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfUndoItems() on empty undo stack failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 0) {
    printf("ERROR: GetNumberOfUndoItems() expected 0 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->EndBatch();

  if (NS_FAILED(result)) {
    printf("ERROR: EndBatch() failed. (%d)\n", result);
    return result;
  }

  result = mgr->GetNumberOfUndoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfUndoItems() on empty undo stack failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 0) {
    printf("ERROR: GetNumberOfUndoItems() expected 0 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  printf("passed\n");

  /*******************************************************************
   *
   * Execute 20 transactions. Afterwards, we should have 1
   * transaction on the undo stack:
   *
   *******************************************************************/

  printf("Execute 20 batched transactions ... ");

  result = mgr->BeginBatch();

  if (NS_FAILED(result)) {
    printf("ERROR: BeginBatch() failed. (%d)\n", result);
    return result;
  }

  for (i = 1; i <= 20; i++) {
    tximpl = factory->create(mgr, NONE_FLAG);

    if (!tximpl) {
      printf("ERROR: Failed to allocate transaction %d.\n", i);
      return NS_ERROR_OUT_OF_MEMORY;
    }

    tx = 0;
    result = tximpl->QueryInterface(NS_GET_IID(nsITransaction), (void **)&tx);
    if (NS_FAILED(result)) {
      printf("ERROR: QueryInterface() failed for transaction %d. (%d)\n",
             i, result);
      return result;
    }

    result = mgr->DoTransaction(tx);
    if (NS_FAILED(result)) {
      printf("ERROR: Failed to execute transaction %d. (%d)\n", i, result);
      return result;
    }

    tx->Release();
  }

  result = mgr->GetNumberOfUndoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfUndoItems() on empty undo stack failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 0) {
    printf("ERROR: GetNumberOfUndoItems() expected 0 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->EndBatch();

  if (NS_FAILED(result)) {
    printf("ERROR: EndBatch() failed. (%d)\n", result);
    return result;
  }

  result = mgr->GetNumberOfUndoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfUndoItems() on undo stack with 1 item failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 1) {
    printf("ERROR: GetNumberOfUndoItems() expected 1 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  printf("passed\n");

  /*******************************************************************
   *
   * Execute 20 transient transactions. Afterwards, we should still
   * have the same transaction on the undo stack:
   *
   *******************************************************************/

  printf("Execute 20 batched transient transactions ... ");

  u1 = u2 = r1 = r2 = 0;

  result = mgr->PeekUndoStack(&u1);

  TEST_TXMGR_IF_RELEASE(u1); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Initial PeekUndoStack() failed. (%d)\n", result);
    return result;
  }

  result = mgr->PeekRedoStack(&r1);

  TEST_TXMGR_IF_RELEASE(r1); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Initial PeekRedoStack() failed. (%d)\n", result);
    return result;
  }

  result = mgr->BeginBatch();

  if (NS_FAILED(result)) {
    printf("ERROR: BeginBatch() failed. (%d)\n", result);
    return result;
  }

  for (i = 1; i <= 20; i++) {
    tximpl = factory->create(mgr, TRANSIENT_FLAG);

    if (!tximpl) {
      printf("ERROR: Failed to allocate transaction %d.\n", i);
      return NS_ERROR_OUT_OF_MEMORY;
    }

    tx = 0;
    result = tximpl->QueryInterface(NS_GET_IID(nsITransaction), (void **)&tx);
    if (NS_FAILED(result)) {
      printf("ERROR: QueryInterface() failed for transaction %d. (%d)\n",
             i, result);
      return result;
    }

    result = mgr->DoTransaction(tx);
    if (NS_FAILED(result)) {
      printf("ERROR: Failed to execute transaction %d. (%d)\n", i, result);
      return result;
    }

    tx->Release();
  }

  result = mgr->EndBatch();

  if (NS_FAILED(result)) {
    printf("ERROR: EndBatch() failed. (%d)\n", result);
    return result;
  }

  result = mgr->PeekUndoStack(&u2);

  TEST_TXMGR_IF_RELEASE(u2); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Second PeekUndoStack() failed. (%d)\n", result);
    return result;
  }

  if (u1 != u2) {
    printf("ERROR: Top of undo stack changed. (%d)\n", result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->PeekRedoStack(&r2);

  TEST_TXMGR_IF_RELEASE(r2); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Second PeekRedoStack() failed. (%d)\n", result);
    return result;
  }

  if (r1 != r2) {
    printf("ERROR: Top of redo stack changed. (%d)\n", result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->GetNumberOfUndoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfUndoItems() on undo stack with 1 item failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 1) {
    printf("ERROR: GetNumberOfUndoItems() expected 1 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->GetNumberOfRedoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfRedoItems() on empty redo stack failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 0) {
    printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  printf("passed\n");

  /*******************************************************************
   *
   * Test nested batching. Afterwards, we should have 2 transactions
   * on the undo stack:
   *
   *******************************************************************/

  printf("Test nested batched transactions ... ");

  result = mgr->BeginBatch();

  if (NS_FAILED(result)) {
    printf("ERROR: BeginBatch() failed. (%d)\n", result);
    return result;
  }

  tximpl = factory->create(mgr, NONE_FLAG);

  if (!tximpl) {
    printf("ERROR: Failed to allocate transaction.\n");
    return NS_ERROR_OUT_OF_MEMORY;
  }

  tx = 0;
  result = tximpl->QueryInterface(NS_GET_IID(nsITransaction), (void **)&tx);
  if (NS_FAILED(result)) {
    printf("ERROR: QueryInterface() failed for transaction. (%d)\n", result);
    return result;
  }

  result = mgr->DoTransaction(tx);
  if (NS_FAILED(result)) {
    printf("ERROR: Failed to execute transaction. (%d)\n", result);
    return result;
  }

  tx->Release();

  result = mgr->GetNumberOfUndoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfUndoItems() on undo stack with 1 item failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 1) {
    printf("ERROR: GetNumberOfUndoItems() expected 1 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->BeginBatch();

  if (NS_FAILED(result)) {
    printf("ERROR: BeginBatch() failed. (%d)\n", result);
    return result;
  }

  tximpl = factory->create(mgr, NONE_FLAG);

  if (!tximpl) {
    printf("ERROR: Failed to allocate transaction.\n");
    return NS_ERROR_OUT_OF_MEMORY;
  }

  tx = 0;
  result = tximpl->QueryInterface(NS_GET_IID(nsITransaction), (void **)&tx);
  if (NS_FAILED(result)) {
    printf("ERROR: QueryInterface() failed for transaction. (%d)\n", result);
    return result;
  }

  result = mgr->DoTransaction(tx);
  if (NS_FAILED(result)) {
    printf("ERROR: Failed to execute transaction. (%d)\n", result);
    return result;
  }

  tx->Release();

  result = mgr->GetNumberOfUndoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfUndoItems() on undo stack with 1 item failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 1) {
    printf("ERROR: GetNumberOfUndoItems() expected 1 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->BeginBatch();

  if (NS_FAILED(result)) {
    printf("ERROR: BeginBatch() failed. (%d)\n", result);
    return result;
  }

  tximpl = factory->create(mgr, NONE_FLAG);

  if (!tximpl) {
    printf("ERROR: Failed to allocate transaction.\n");
    return NS_ERROR_OUT_OF_MEMORY;
  }

  tx = 0;
  result = tximpl->QueryInterface(NS_GET_IID(nsITransaction), (void **)&tx);
  if (NS_FAILED(result)) {
    printf("ERROR: QueryInterface() failed for transaction. (%d)\n", result);
    return result;
  }

  result = mgr->DoTransaction(tx);
  if (NS_FAILED(result)) {
    printf("ERROR: Failed to execute transaction. (%d)\n", result);
    return result;
  }

  tx->Release();

  result = mgr->GetNumberOfUndoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfUndoItems() on undo stack with 1 item failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 1) {
    printf("ERROR: GetNumberOfUndoItems() expected 1 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->EndBatch();

  if (NS_FAILED(result)) {
    printf("ERROR: EndBatch() failed. (%d)\n", result);
    return result;
  }

  result = mgr->EndBatch();

  if (NS_FAILED(result)) {
    printf("ERROR: EndBatch() failed. (%d)\n", result);
    return result;
  }

  result = mgr->EndBatch();

  if (NS_FAILED(result)) {
    printf("ERROR: EndBatch() failed. (%d)\n", result);
    return result;
  }

  result = mgr->GetNumberOfUndoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfUndoItems() on undo stack with 2 items failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 2) {
    printf("ERROR: GetNumberOfUndoItems() expected 1 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  printf("passed\n");

  /*******************************************************************
   *
   * Undo 2 batch transactions. Afterwards, we should have 0
   * transactions on the undo stack and 2 on the redo stack.
   *
   *******************************************************************/

  printf("Undo 2 batch transactions ... ");

  for (i = 1; i <= 2; ++i) {
    result = mgr->UndoTransaction();
    if (NS_FAILED(result)) {
      printf("ERROR: Failed to undo transaction %d. (%d)\n", i, result);
      return result;
    }
  }

  result = mgr->GetNumberOfUndoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfUndoItems() on empty undo stack failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 0) {
    printf("ERROR: GetNumberOfUndoItems() expected 0 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->GetNumberOfRedoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfRedoItems() on redo stack with 2 items failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 2) {
    printf("ERROR: GetNumberOfRedoItems() expected 2 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  printf("passed\n");

  /*******************************************************************
   *
   * Redo 2 batch transactions. Afterwards, we should have 2
   * transactions on the undo stack and 0 on the redo stack.
   *
   *******************************************************************/


  printf("Redo 2 batch transactions ... ");

  for (i = 1; i <= 2; ++i) {
    result = mgr->RedoTransaction();
    if (NS_FAILED(result)) {
      printf("ERROR: Failed to undo transaction %d. (%d)\n", i, result);
      return result;
    }
  }

  result = mgr->GetNumberOfUndoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfUndoItems() on undo stack with 2 items failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 2) {
    printf("ERROR: GetNumberOfUndoItems() expected 2 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->GetNumberOfRedoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfRedoItems() on empty redo stack failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 0) {
    printf("ERROR: GetNumberOfRedoItems() expected 2 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  printf("passed\n");

  /*******************************************************************
   *
   * Call undo. Afterwards, we should have 1 transaction
   * on the undo stack, and 1 on the redo stack:
   *
   *******************************************************************/

  printf("Undo a batched transaction that was redone ... ");

  result = mgr->UndoTransaction();

  if (NS_FAILED(result)) {
    printf("ERROR: Failed to undo transaction. (%d)\n", result);
    return result;
  }

  result = mgr->GetNumberOfUndoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfUndoItems() on undo stack with 1 item failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 1) {
    printf("ERROR: GetNumberOfUndoItems() expected 1 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->GetNumberOfRedoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfRedoItems() on stack with 1 item failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 1) {
    printf("ERROR: GetNumberOfRedoItems() expected 1 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  printf("passed\n");

  /*******************************************************************
   *
   * Make sure an unbalanced call to EndBatch() throws an error and
   * doesn't affect the undo and redo stacks!
   *
   *******************************************************************/

  printf("Test effect of unbalanced EndBatch() on undo and redo stacks ... ");

  result = mgr->EndBatch();

  if (result != NS_ERROR_FAILURE) {
    printf("ERROR: EndBatch() returned unexpected status. (%d)\n", result);
    return result;
  }

  result = mgr->GetNumberOfUndoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfUndoItems() on undo stack with 1 item failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 1) {
    printf("ERROR: GetNumberOfUndoItems() expected 1 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->GetNumberOfRedoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfRedoItems() on stack with 1 item failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 1) {
    printf("ERROR: GetNumberOfRedoItems() expected 1 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  printf("passed\n");

  /*******************************************************************
   *
   * Make sure that an empty batch is not added to the undo stack
   * when it is closed, and that it does not affect the undo and redo
   * stacks.
   *
   *******************************************************************/

  printf("Test effect of empty batch on undo and redo stacks ... ");

  result = mgr->BeginBatch();

  if (NS_FAILED(result)) {
    printf("ERROR: BeginBatch() failed. (%d)\n", result);
    return result;
  }

  result = mgr->GetNumberOfUndoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfUndoItems() on undo stack with 1 item failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 1) {
    printf("ERROR: GetNumberOfUndoItems() expected 1 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->GetNumberOfRedoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfRedoItems() on stack with 1 item failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 1) {
    printf("ERROR: GetNumberOfRedoItems() expected 1 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->EndBatch();

  if (NS_FAILED(result)) {
    printf("ERROR: EndBatch() failed. (%d)\n", result);
    return result;
  }

  result = mgr->GetNumberOfUndoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfUndoItems() on undo stack with 1 item failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 1) {
    printf("ERROR: GetNumberOfUndoItems() expected 1 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->GetNumberOfRedoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfRedoItems() on stack with 1 item failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 1) {
    printf("ERROR: GetNumberOfRedoItems() expected 1 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }


  printf("passed\n");


  /*******************************************************************
   *
   * Execute a new transaction. The redo stack should get pruned!
   *
   *******************************************************************/

  printf("Check if new batched transactions prune the redo stack ... ");

  result = mgr->BeginBatch();

  if (NS_FAILED(result)) {
    printf("ERROR: BeginBatch() failed. (%d)\n", result);
    return result;
  }

  for (i = 1; i <= 20; i++) {
    tximpl = factory->create(mgr, NONE_FLAG);

    if (!tximpl) {
      printf("ERROR: Failed to allocate transaction %d.\n", i);
      return NS_ERROR_OUT_OF_MEMORY;
    }

    tx = 0;
    result = tximpl->QueryInterface(NS_GET_IID(nsITransaction), (void **)&tx);
    if (NS_FAILED(result)) {
      printf("ERROR: QueryInterface() failed for transaction %d. (%d)\n",
             i, result);
      return result;
    }

    result = mgr->DoTransaction(tx);
    if (NS_FAILED(result)) {
      printf("ERROR: Failed to execute transaction %d. (%d)\n", i, result);
      return result;
    }

    tx->Release();
  }

  result = mgr->GetNumberOfUndoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfUndoItems() on undo stack with 1 item failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 1) {
    printf("ERROR: GetNumberOfUndoItems() expected 1 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->GetNumberOfRedoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfRedoItems() on redo stack with 1 items failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 1) {
    printf("ERROR: GetNumberOfRedoItems() expected 1 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->EndBatch();

  if (NS_FAILED(result)) {
    printf("ERROR: EndBatch() failed. (%d)\n", result);
    return result;
  }

  result = mgr->GetNumberOfUndoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfUndoItems() on undo stack with 2 items failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 2) {
    printf("ERROR: GetNumberOfUndoItems() expected 2 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->GetNumberOfRedoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfRedoItems() on empty redo stack failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 0) {
    printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  printf("passed\n");

  /*******************************************************************
   *
   * Call undo.
   *
   *******************************************************************/

  printf("Call undo ... ");

  // Move a transaction over to the redo stack, so that we have one
  // transaction on the undo stack, and one on the redo stack!

  result = mgr->UndoTransaction();

  if (NS_FAILED(result)) {
    printf("ERROR: Failed to undo transaction. (%d)\n", result);
    return result;
  }

  result = mgr->GetNumberOfUndoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfUndoItems() on undo stack with 1 item failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 1) {
    printf("ERROR: GetNumberOfUndoItems() expected 1 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->GetNumberOfRedoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfRedoItems() on redo stack with 1 items failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 1) {
    printf("ERROR: GetNumberOfRedoItems() expected 1 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  printf("passed\n");

  /*******************************************************************
   *
   * Test transaction DoTransaction() error:
   *
   *******************************************************************/

  printf("Test transaction DoTransaction() error ... ");


  tximpl = factory->create(mgr, THROWS_DO_ERROR_FLAG);

  if (!tximpl) {
    printf("ERROR: Failed to allocate transaction.\n");
    return NS_ERROR_OUT_OF_MEMORY;
  }

  tx     = 0;

  result = tximpl->QueryInterface(NS_GET_IID(nsITransaction), (void **)&tx);

  if (NS_FAILED(result)) {
    printf("ERROR: QueryInterface() failed for transaction. (%d)\n", result);
    return result;
  }

  u1 = u2 = r1 = r2 = 0;

  result = mgr->PeekUndoStack(&u1);

  TEST_TXMGR_IF_RELEASE(u1); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Initial PeekUndoStack() failed. (%d)\n", result);
    return result;
  }

  result = mgr->PeekRedoStack(&r1);

  TEST_TXMGR_IF_RELEASE(r1); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Initial PeekRedoStack() failed. (%d)\n", result);
    return result;
  }

  result = mgr->BeginBatch();

  if (NS_FAILED(result)) {
    printf("ERROR: BeginBatch() failed. (%d)\n", result);
    return result;
  }

  result = mgr->DoTransaction(tx);

  if (NS_FAILED(result) && result != NS_ERROR_FAILURE) {
    printf("ERROR: DoTransaction() returned unexpected error. (%d)\n", result);
    return result;
  }

  tx->Release();

  result = mgr->EndBatch();

  if (NS_FAILED(result)) {
    printf("ERROR: EndBatch() failed. (%d)\n", result);
    return result;
  }

  result = mgr->PeekUndoStack(&u2);

  TEST_TXMGR_IF_RELEASE(u2); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Second PeekUndoStack() failed. (%d)\n", result);
    return result;
  }

  if (u1 != u2) {
    printf("ERROR: Top of undo stack changed. (%d)\n", result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->PeekRedoStack(&r2);

  TEST_TXMGR_IF_RELEASE(r2); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Second PeekRedoStack() failed. (%d)\n", result);
    return result;
  }

  if (r1 != r2) {
    printf("ERROR: Top of redo stack changed. (%d)\n", result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->GetNumberOfUndoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfUndoItems() on undo stack with 5 items failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 1) {
    printf("ERROR: GetNumberOfUndoItems() expected 5 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->GetNumberOfRedoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfRedoItems() on empty redo stack. (%d)\n",
           result);
    return result;
  }

  if (numitems != 1) {
    printf("ERROR: GetNumberOfRedoItems() expected 1 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  printf("passed\n");

  /*******************************************************************
   *
   * Test transaction UndoTransaction() error:
   *
   *******************************************************************/

  printf("Test transaction UndoTransaction() error ... ");

  tximpl = factory->create(mgr, THROWS_UNDO_ERROR_FLAG);

  if (!tximpl) {
    printf("ERROR: Failed to allocate transaction.\n");
    return NS_ERROR_OUT_OF_MEMORY;
  }

  tx     = 0;

  result = tximpl->QueryInterface(NS_GET_IID(nsITransaction), (void **)&tx);

  if (NS_FAILED(result)) {
    printf("ERROR: QueryInterface() failed for transaction. (%d)\n", result);
    return result;
  }

  result = mgr->BeginBatch();

  if (NS_FAILED(result)) {
    printf("ERROR: BeginBatch() failed. (%d)\n", result);
    return result;
  }

  result = mgr->DoTransaction(tx);

  if (NS_FAILED(result)) {
    printf("ERROR: DoTransaction() returned unexpected error. (%d)\n", result);
    return result;
  }

  tx->Release();

  result = mgr->EndBatch();

  if (NS_FAILED(result)) {
    printf("ERROR: EndBatch() failed. (%d)\n", result);
    return result;
  }

  u1 = u2 = r1 = r2 = 0;

  result = mgr->PeekUndoStack(&u1);

  TEST_TXMGR_IF_RELEASE(u1); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Initial PeekUndoStack() failed. (%d)\n", result);
    return result;
  }

  result = mgr->PeekRedoStack(&r1);

  TEST_TXMGR_IF_RELEASE(r1); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Initial PeekRedoStack() failed. (%d)\n", result);
    return result;
  }

  result = mgr->UndoTransaction();

  if (NS_FAILED(result) && result != NS_ERROR_FAILURE) {
    printf("ERROR: UndoTransaction() returned unexpected error. (%d)\n", result);
    return result;
  }

  result = mgr->PeekUndoStack(&u2);

  TEST_TXMGR_IF_RELEASE(u2); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Second PeekUndoStack() failed. (%d)\n", result);
    return result;
  }

  if (u1 != u2) {
    printf("ERROR: Top of undo stack changed. (%d)\n", result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->PeekRedoStack(&r2);

  TEST_TXMGR_IF_RELEASE(r2); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Second PeekRedoStack() failed. (%d)\n", result);
    return result;
  }

  if (r1 != r2) {
    printf("ERROR: Top of redo stack changed. (%d)\n", result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->GetNumberOfUndoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfUndoItems() on undo stack with 2 items failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 2) {
    printf("ERROR: GetNumberOfUndoItems() expected 2 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->GetNumberOfRedoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfRedoItems() on empty redo stack. (%d)\n",
           result);
    return result;
  }

  if (numitems != 0) {
    printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  printf("passed\n");

  /*******************************************************************
   *
   * Test transaction RedoTransaction() error:
   *
   *******************************************************************/

  printf("Test transaction RedoTransaction() error ... ");

  tximpl = factory->create(mgr, THROWS_REDO_ERROR_FLAG);

  if (!tximpl) {
    printf("ERROR: Failed to allocate transaction.\n");
    return NS_ERROR_OUT_OF_MEMORY;
  }

  tx     = 0;

  result = tximpl->QueryInterface(NS_GET_IID(nsITransaction), (void **)&tx);

  if (NS_FAILED(result)) {
    printf("ERROR: QueryInterface() failed for RedoErrorTransaction. (%d)\n",
           result);
    return result;
  }

  result = mgr->BeginBatch();

  if (NS_FAILED(result)) {
    printf("ERROR: BeginBatch() failed. (%d)\n", result);
    return result;
  }

  result = mgr->DoTransaction(tx);

  if (NS_FAILED(result)) {
    printf("ERROR: DoTransaction() returned unexpected error. (%d)\n", result);
    return result;
  }

  tx->Release();

  result = mgr->EndBatch();

  if (NS_FAILED(result)) {
    printf("ERROR: EndBatch() failed. (%d)\n", result);
    return result;
  }

  //
  // Execute a normal transaction to be used in a later test:
  //

  tximpl = factory->create(mgr, NONE_FLAG);

  if (!tximpl) {
    printf("ERROR: Failed to allocate transaction.\n");
    return NS_ERROR_OUT_OF_MEMORY;
  }

  tx     = 0;

  result = tximpl->QueryInterface(NS_GET_IID(nsITransaction), (void **)&tx);

  if (NS_FAILED(result)) {
    printf("ERROR: QueryInterface() failed for transaction. (%d)\n", result);
    return result;
  }

  result = mgr->DoTransaction(tx);

  if (NS_FAILED(result)) {
    printf("ERROR: DoTransaction() returned unexpected error. (%d)\n", result);
    return result;
  }

  tx->Release();

  //
  // Undo the 2 transactions just executed.
  //

  for (i = 1; i <= 2; ++i) {
    result = mgr->UndoTransaction();
    if (NS_FAILED(result)) {
      printf("ERROR: Failed to undo transaction %d. (%d)\n", i, result);
      return result;
    }
  }

  //
  // The RedoErrorTransaction should now be at the top of the redo stack!
  //

  u1 = u2 = r1 = r2 = 0;

  result = mgr->PeekUndoStack(&u1);

  TEST_TXMGR_IF_RELEASE(u1); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Initial PeekUndoStack() failed. (%d)\n", result);
    return result;
  }

  result = mgr->PeekRedoStack(&r1);

  TEST_TXMGR_IF_RELEASE(r1); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Initial PeekRedoStack() failed. (%d)\n", result);
    return result;
  }

  result = mgr->RedoTransaction();

  if (NS_FAILED(result) && result != NS_ERROR_FAILURE) {
    printf("ERROR: RedoTransaction() returned unexpected error. (%d)\n", result);
    return result;
  }

  result = mgr->PeekUndoStack(&u2);

  TEST_TXMGR_IF_RELEASE(u2); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Second PeekUndoStack() failed. (%d)\n", result);
    return result;
  }

  if (u1 != u2) {
    printf("ERROR: Top of undo stack changed. (%d)\n", result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->PeekRedoStack(&r2);

  TEST_TXMGR_IF_RELEASE(r2); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Second PeekRedoStack() failed. (%d)\n", result);
    return result;
  }

  if (r1 != r2) {
    printf("ERROR: Top of redo stack changed. (%d)\n", result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->GetNumberOfUndoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfUndoItems() on undo stack with 2 items failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 2) {
    printf("ERROR: GetNumberOfUndoItems() expected 2 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->GetNumberOfRedoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfRedoItems() on empty redo stack. (%d)\n",
           result);
    return result;
  }

  if (numitems != 2) {
    printf("ERROR: GetNumberOfRedoItems() expected 2 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  printf("passed\n");

  /*******************************************************************
   *
   * Make sure that setting the transaction manager's max transaction
   * count to zero, clears both the undo and redo stacks, and executes
   * all new commands without pushing them on the undo stack!
   *
   *******************************************************************/

  printf("Test max transaction count of zero ... ");

  result = mgr->SetMaxTransactionCount(0);

  if (NS_FAILED(result)) {
    printf("ERROR: SetMaxTransactionCount(0) failed. (%d)\n", result);
    return result;
  }

  result = mgr->GetNumberOfUndoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfUndoItems() on empty undo stack failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 0) {
    printf("ERROR: GetNumberOfUndoItems() expected 1 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->GetNumberOfRedoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfRedoItems() on empty redo stack failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 0) {
    printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  for (i = 1; i <= 20; i++) {
    tximpl = factory->create(mgr, NONE_FLAG);

    if (!tximpl) {
      printf("ERROR: Failed to allocate transaction %d.\n", i);
      return NS_ERROR_OUT_OF_MEMORY;
    }

    tx = 0;
    result = tximpl->QueryInterface(NS_GET_IID(nsITransaction), (void **)&tx);
    if (NS_FAILED(result)) {
      printf("ERROR: QueryInterface() failed for transaction %d. (%d)\n",
             i, result);
      return result;
    }

    result = mgr->BeginBatch();

    if (NS_FAILED(result)) {
      printf("ERROR: BeginBatch() failed. (%d)\n", result);
      return result;
    }

    result = mgr->DoTransaction(tx);
    if (NS_FAILED(result)) {
      printf("ERROR: Failed to execute transaction %d. (%d)\n", i, result);
      return result;
    }

    tx->Release();

    result = mgr->EndBatch();

    if (NS_FAILED(result)) {
      printf("ERROR: EndBatch() failed. (%d)\n", result);
      return result;
    }

    result = mgr->GetNumberOfUndoItems(&numitems);

    if (NS_FAILED(result)) {
      printf("ERROR: GetNumberOfUndoItems() on empty undo stack failed. (%d)\n",
             result);
      return result;
    }

    if (numitems != 0) {
      printf("ERROR: GetNumberOfUndoItems() expected 1 got %d. (%d)\n",
             numitems, result);
      return NS_ERROR_FAILURE;
    }

    result = mgr->GetNumberOfRedoItems(&numitems);

    if (NS_FAILED(result)) {
      printf("ERROR: GetNumberOfRedoItems() on empty redo stack failed. (%d)\n",
             result);
      return result;
    }

    if (numitems != 0) {
      printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n",
             numitems, result);
      return NS_ERROR_FAILURE;
    }
  }

  printf("passed\n");

  /*******************************************************************
   *
   * Release the transaction manager. Any transactions on the undo
   * and redo stack should automatically be released:
   *
   *******************************************************************/

  printf("Release the transaction manager ... ");

  result = mgr->SetMaxTransactionCount(-1);

  if (NS_FAILED(result)) {
    printf("ERROR: SetMaxTransactionCount(0) failed. (%d)\n", result);
    return result;
  }

  // Push 20 transactions on the undo stack:

  for (i = 1; i <= 20; i++) {
    tximpl = factory->create(mgr, NONE_FLAG);

    if (!tximpl) {
      printf("ERROR: Failed to allocate transaction %d.\n", i);
      return NS_ERROR_OUT_OF_MEMORY;
    }

    tx = 0;
    result = tximpl->QueryInterface(NS_GET_IID(nsITransaction), (void **)&tx);
    if (NS_FAILED(result)) {
      printf("ERROR: QueryInterface() failed for transaction %d. (%d)\n",
             i, result);
      return result;
    }

    result = mgr->BeginBatch();

    if (NS_FAILED(result)) {
      printf("ERROR: BeginBatch() failed. (%d)\n", result);
      return result;
    }

    result = mgr->DoTransaction(tx);
    if (NS_FAILED(result)) {
      printf("ERROR: Failed to execute transaction %d. (%d)\n", i, result);
      return result;
    }

    tx->Release();

    result = mgr->EndBatch();

    if (NS_FAILED(result)) {
      printf("ERROR: EndBatch() failed. (%d)\n", result);
      return result;
    }

    result = mgr->GetNumberOfUndoItems(&numitems);

    if (NS_FAILED(result)) {
      printf("ERROR: GetNumberOfUndoItems() on empty undo stack failed. (%d)\n",
             result);
      return result;
    }

    if (numitems != i) {
      printf("ERROR: GetNumberOfUndoItems() expected 1 got %d. (%d)\n",
             numitems, result);
      return NS_ERROR_FAILURE;
    }

    result = mgr->GetNumberOfRedoItems(&numitems);

    if (NS_FAILED(result)) {
      printf("ERROR: GetNumberOfRedoItems() on empty redo stack failed. (%d)\n",
             result);
      return result;
    }

    if (numitems != 0) {
      printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n",
             numitems, result);
      return NS_ERROR_FAILURE;
    }
  }

  for (i = 1; i <= 10; i++) {

    result = mgr->UndoTransaction();
    if (NS_FAILED(result)) {
      printf("ERROR: Failed to undo transaction %d. (%d)\n", i, result);
      return result;
    }
  }
  result = mgr->GetNumberOfUndoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfUndoItems() on empty undo stack with 10 items failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 10) {
    printf("ERROR: GetNumberOfUndoItems() expected 10 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->GetNumberOfRedoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfRedoItems() on redo stack with 10 items failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 10) {
    printf("ERROR: GetNumberOfRedoItems() expected 10 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  printf("passed\n");

  /*******************************************************************
   *
   * Make sure number of transactions created matches number of
   * transactions destroyed!
   *
   *******************************************************************/

  printf("Number of transactions created and destroyed match ... ");

  if (sConstructorCount != sDestructorCount) {
    printf("ERROR: Transaction constructor count (%d) != destructor count (%d).\n",
           sConstructorCount, sDestructorCount);
    return NS_ERROR_FAILURE;
  }

  if (NS_FAILED(result)) {
    printf("ERROR: nsITransactionManager Release() failed. (%d)\n", result);
    return result;
  }

  printf("passed\n");
  printf("%d transactions processed during quick batch test.\n",
         sConstructorCount);

  return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 778 of file TestTXMgr.cpp.

{
  /*******************************************************************
   *
   * Create a transaction manager implementation:
   *
   *******************************************************************/

  printf("Create transaction manager instance ... ");

  PRInt32 i, numitems = 0;
  nsCOMPtr<nsITransactionManager> mgr;
  nsITransaction  *tx        = 0;
  TestTransaction *tximpl    = 0;
  nsITransaction *u1 = 0, *u2 = 0;
  nsITransaction *r1 = 0, *r2 = 0;
  nsresult result;

  mgr = do_CreateInstance(NS_TRANSACTIONMANAGER_CONTRACTID, &result);
  if (NS_FAILED(result) || !mgr) {
    printf("ERROR: Failed to create Transaction Manager instance.\n");
    return NS_ERROR_OUT_OF_MEMORY;
  }

  printf("passed\n");

  /*******************************************************************
   *
   * Call DoTransaction() with a null transaction:
   *
   *******************************************************************/

  printf("Call DoTransaction() with null transaction ... ");
  result = mgr->DoTransaction(0);

  if (NS_FAILED(result)
      && result != NS_ERROR_NULL_POINTER) {
    printf("ERROR: DoTransaction() returned unexpected error. (%d)\n", result);
    return result;
  }

  printf("passed\n");

  /*******************************************************************
   *
   * Call UndoTransaction() with an empty undo stack:
   *
   *******************************************************************/

  printf("Call UndoTransaction() with empty undo stack ... ");
  result = mgr->UndoTransaction();

  if (NS_FAILED(result)) {
    printf("ERROR: Undo on empty undo stack failed. (%d)\n", result);
    return result;
  }

  printf("passed\n");

  /*******************************************************************
   *
   * Call RedoTransaction() with an empty redo stack:
   *
   *******************************************************************/

  printf("Call RedoTransaction() with empty redo stack ... ");
  result = mgr->RedoTransaction();

  if (NS_FAILED(result)) {
    printf("ERROR: Redo on empty redo stack failed. (%d)\n", result);
    return result;
  }

  printf("passed\n");

  /*******************************************************************
   *
   * Call SetMaxTransactionCount(-1) with empty undo and redo stacks:
   *
   *******************************************************************/

  printf("Call SetMaxTransactionCount(-1) with empty undo and redo stacks ... ");
  result = mgr->SetMaxTransactionCount(-1);

  if (NS_FAILED(result)) {
    printf("ERROR: SetMaxTransactionCount(-1) failed. (%d)\n", result);
    return result;
  }

  printf("passed\n");

  /*******************************************************************
   *
   * Call SetMaxTransactionCount(0) with empty undo and redo stacks:
   *
   *******************************************************************/

  printf("Call SetMaxTransactionCount(0) with empty undo and redo stacks ... ");
  result = mgr->SetMaxTransactionCount(0);

  if (NS_FAILED(result)) {
    printf("ERROR: SetMaxTransactionCount(0) failed. (%d)\n", result);
    return result;
  }

  printf("passed\n");

  /*******************************************************************
   *
   * Call SetMaxTransactionCount(10) with empty undo and redo stacks:
   *
   *******************************************************************/

  printf("Call SetMaxTransactionCount(10) with empty undo and redo stacks ... ");
  result = mgr->SetMaxTransactionCount(10);

  if (NS_FAILED(result)) {
    printf("ERROR: SetMaxTransactionCount(10) failed. (%d)\n", result);
    return result;
  }

  printf("passed\n");

  /*******************************************************************
   *
   * Call Clear() with empty undo and redo stacks:
   *
   *******************************************************************/

  printf("Call Clear() with empty undo and redo stack ... ");
  result = mgr->Clear();

  if (NS_FAILED(result)) {
    printf("ERROR: Clear on empty undo and redo stack failed. (%d)\n", result);
    return result;
  }

  printf("passed\n");

  /*******************************************************************
   *
   * Call GetNumberOfUndoItems() with an empty undo stack:
   *
   *******************************************************************/

  numitems = 0;

  printf("Call GetNumberOfUndoItems() with empty undo stack ... ");
  result = mgr->GetNumberOfUndoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfUndoItems() on empty undo stack failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 0) {
    printf("ERROR: GetNumberOfUndoItems() expected 0 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  printf("passed\n");

  /*******************************************************************
   *
   * Call GetNumberOfRedoItems() with an empty redo stack:
   *
   *******************************************************************/

  printf("Call GetNumberOfRedoItems() with empty redo stack ... ");
  result = mgr->GetNumberOfRedoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfRedoItems() on empty redo stack failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 0) {
    printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  printf("passed\n");

  /*******************************************************************
   *
   * Call PeekUndoStack() with an empty undo stack:
   *
   *******************************************************************/

  printf("Call PeekUndoStack() with empty undo stack ... ");

  tx = 0;
  result = mgr->PeekUndoStack(&tx);

  TEST_TXMGR_IF_RELEASE(tx); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: PeekUndoStack() on empty undo stack failed. (%d)\n", result);
    return result;
  }

  if (tx != 0) {
    printf("ERROR: PeekUndoStack() on empty undo stack failed. (%d)\n", result);
    return NS_ERROR_FAILURE;
  }

  printf("passed\n");

  /*******************************************************************
   *
   * Call PeekRedoStack() with an empty undo stack:
   *
   *******************************************************************/

  printf("Call PeekRedoStack() with empty undo stack ... ");

  tx = 0;
  result = mgr->PeekRedoStack(&tx);

  TEST_TXMGR_IF_RELEASE(tx); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: PeekRedoStack() on empty redo stack failed. (%d)\n", result);
    return result;
  }

  if (tx != 0) {
    printf("ERROR: PeekRedoStack() on empty redo stack failed. (%d)\n", result);
    return NS_ERROR_FAILURE;
  }

  printf("passed\n");

  /*******************************************************************
   *
   * Call AddListener() with a null listener pointer:
   *
   *******************************************************************/

  printf("Call AddListener() with null listener ... ");

  result = mgr->AddListener(0);

  if (NS_FAILED(result)
      && result != NS_ERROR_NULL_POINTER) {
    printf("ERROR: AddListener() returned unexpected error. (%d)\n", result);
    return result;
  }

  printf("passed\n");

  /*******************************************************************
   *
   * Call RemoveListener() with a null listener pointer:
   *
   *******************************************************************/

  printf("Call RemoveListener() with null listener ... ");

  result = mgr->RemoveListener(0);

  if (NS_FAILED(result)
      && result != NS_ERROR_NULL_POINTER) {
    printf("ERROR: RemoveListener() returned unexpected error. (%d)\n", result);
    return result;
  }

  printf("passed\n");

  /*******************************************************************
   *
   * Test coalescing by executing a transaction that can merge any
   * command into itself. Then execute 20 transaction. Afterwards,
   * we should still have the first transaction sitting on the undo
   * stack.
   *
   *******************************************************************/

  printf("Test coalescing of transactions ... ");

  result = mgr->SetMaxTransactionCount(10);

  if (NS_FAILED(result)) {
    printf("ERROR: SetMaxTransactionCount(0) failed. (%d)\n", result);
    return result;
  }


  tximpl = factory->create(mgr, MERGE_FLAG);

  if (!tximpl) {
    printf("ERROR: Failed to allocate initial transaction.\n");
    return NS_ERROR_OUT_OF_MEMORY;
  }

  tx = 0;

  result = tximpl->QueryInterface(NS_GET_IID(nsITransaction), (void **)&tx);

  if (NS_FAILED(result)) {
    printf("ERROR: QueryInterface() failed for initial transaction. (%d)\n",
           result);
    return result;
  }

  result = mgr->DoTransaction(tx);

  if (NS_FAILED(result)) {
    printf("ERROR: Failed to execute initial transaction. (%d)\n", result);
    return result;
  }

  tx->Release();

  u1 = u2 = r1 = r2 = 0;

  result = mgr->PeekUndoStack(&u1);

  TEST_TXMGR_IF_RELEASE(u1); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Initial PeekUndoStack() failed. (%d)\n", result);
    return result;
  }

  if (u1 != tx) {
    printf("ERROR: Top of undo stack is different!. (%d)\n", result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->PeekRedoStack(&r1);

  TEST_TXMGR_IF_RELEASE(r1); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Initial PeekRedoStack() failed. (%d)\n", result);
    return result;
  }

  for (i = 1; i <= 20; i++) {
    tximpl = factory->create(mgr, NONE_FLAG);

    if (!tximpl) {
      printf("ERROR: Failed to allocate transaction %d.\n", i);
      return NS_ERROR_OUT_OF_MEMORY;
    }

    tx = 0;
    result = tximpl->QueryInterface(NS_GET_IID(nsITransaction), (void **)&tx);
    if (NS_FAILED(result)) {
      printf("ERROR: QueryInterface() failed for transaction %d. (%d)\n",
             i, result);
      return result;
    }

    result = mgr->DoTransaction(tx);
    if (NS_FAILED(result)) {
      printf("ERROR: Failed to execute transaction %d. (%d)\n", i, result);
      return result;
    }

    tx->Release();
  }

  result = mgr->PeekUndoStack(&u2);

  TEST_TXMGR_IF_RELEASE(u2); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Second PeekUndoStack() failed. (%d)\n", result);
    return result;
  }

  if (u1 != u2) {
    printf("ERROR: Top of undo stack changed. (%d)\n", result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->PeekRedoStack(&r2);

  TEST_TXMGR_IF_RELEASE(r2); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Second PeekRedoStack() failed. (%d)\n", result);
    return result;
  }

  if (r1 != r2) {
    printf("ERROR: Top of redo stack changed. (%d)\n", result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->GetNumberOfUndoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfUndoItems() on undo stack with 1 item failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 1) {
    printf("ERROR: GetNumberOfUndoItems() expected 1 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->GetNumberOfRedoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfRedoItems() on empty redo stack failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 0) {
    printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->Clear();

  if (NS_FAILED(result)) {
    printf("ERROR: Clear() failed. (%d)\n", result);
    return result;
  }

  printf("passed\n");

  /*******************************************************************
   *
   * Execute 20 transactions. Afterwards, we should have 10
   * transactions on the undo stack:
   *
   *******************************************************************/

  printf("Execute 20 transactions ... ");

  for (i = 1; i <= 20; i++) {
    tximpl = factory->create(mgr, NONE_FLAG);

    if (!tximpl) {
      printf("ERROR: Failed to allocate transaction %d.\n", i);
      return NS_ERROR_OUT_OF_MEMORY;
    }

    tx = 0;
    result = tximpl->QueryInterface(NS_GET_IID(nsITransaction), (void **)&tx);
    if (NS_FAILED(result)) {
      printf("ERROR: QueryInterface() failed for transaction %d. (%d)\n",
             i, result);
      return result;
    }

    result = mgr->DoTransaction(tx);
    if (NS_FAILED(result)) {
      printf("ERROR: Failed to execute transaction %d. (%d)\n", i, result);
      return result;
    }

    tx->Release();
  }

  result = mgr->GetNumberOfUndoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfUndoItems() on undo stack with 10 items failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 10) {
    printf("ERROR: GetNumberOfUndoItems() expected 10 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->GetNumberOfRedoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfRedoItems() on empty redo stack failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 0) {
    printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  printf("passed\n");

  /*******************************************************************
   *
   * Execute 20 transient transactions. Afterwards, we should still
   * have the same 10 transactions on the undo stack:
   *
   *******************************************************************/

  printf("Execute 20 transient transactions ... ");

  u1 = u2 = r1 = r2 = 0;

  result = mgr->PeekUndoStack(&u1);

  TEST_TXMGR_IF_RELEASE(u1); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Initial PeekUndoStack() failed. (%d)\n", result);
    return result;
  }

  result = mgr->PeekRedoStack(&r1);

  TEST_TXMGR_IF_RELEASE(r1); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Initial PeekRedoStack() failed. (%d)\n", result);
    return result;
  }

  for (i = 1; i <= 20; i++) {
    tximpl = factory->create(mgr, TRANSIENT_FLAG);

    if (!tximpl) {
      printf("ERROR: Failed to allocate transaction %d.\n", i);
      return NS_ERROR_OUT_OF_MEMORY;
    }

    tx = 0;
    result = tximpl->QueryInterface(NS_GET_IID(nsITransaction), (void **)&tx);
    if (NS_FAILED(result)) {
      printf("ERROR: QueryInterface() failed for transaction %d. (%d)\n",
             i, result);
      return result;
    }

    result = mgr->DoTransaction(tx);
    if (NS_FAILED(result)) {
      printf("ERROR: Failed to execute transaction %d. (%d)\n", i, result);
      return result;
    }

    tx->Release();
  }

  result = mgr->PeekUndoStack(&u2);

  TEST_TXMGR_IF_RELEASE(u2); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Second PeekUndoStack() failed. (%d)\n", result);
    return result;
  }

  if (u1 != u2) {
    printf("ERROR: Top of undo stack changed. (%d)\n", result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->PeekRedoStack(&r2);

  TEST_TXMGR_IF_RELEASE(r2); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Second PeekRedoStack() failed. (%d)\n", result);
    return result;
  }

  if (r1 != r2) {
    printf("ERROR: Top of redo stack changed. (%d)\n", result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->GetNumberOfUndoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfUndoItems() on undo stack with 10 items failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 10) {
    printf("ERROR: GetNumberOfUndoItems() expected 10 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->GetNumberOfRedoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfRedoItems() on empty redo stack failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 0) {
    printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  printf("passed\n");

  /*******************************************************************
   *
   * Undo 4 transactions. Afterwards, we should have 6 transactions
   * on the undo stack, and 4 on the redo stack:
   *
   *******************************************************************/

  printf("Undo 4 transactions ... ");

  for (i = 1; i <= 4; i++) {
    result = mgr->UndoTransaction();
    if (NS_FAILED(result)) {
      printf("ERROR: Failed to undo transaction %d. (%d)\n", i, result);
      return result;
    }
  }

  result = mgr->GetNumberOfUndoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfUndoItems() on undo stack with 6 items failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 6) {
    printf("ERROR: GetNumberOfUndoItems() expected 6 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->GetNumberOfRedoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfRedoItems() on empty redo stack failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 4) {
    printf("ERROR: GetNumberOfRedoItems() expected 4 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  printf("passed\n");

  /*******************************************************************
   *
   * Redo 2 transactions. Afterwards, we should have 8 transactions
   * on the undo stack, and 2 on the redo stack:
   *
   *******************************************************************/

  printf("Redo 2 transactions ... ");

  for (i = 1; i <= 2; ++i) {
    result = mgr->RedoTransaction();
    if (NS_FAILED(result)) {
      printf("ERROR: Failed to redo transaction %d. (%d)\n", i, result);
      return result;
    }
  }

  result = mgr->GetNumberOfUndoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfUndoItems() on undo stack with 8 items failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 8) {
    printf("ERROR: GetNumberOfUndoItems() expected 8 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->GetNumberOfRedoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfRedoItems() on redo stack with 2 items failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 2) {
    printf("ERROR: GetNumberOfRedoItems() expected 2 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  printf("passed\n");

  /*******************************************************************
   *
   * Execute a new transaction. The redo stack should get pruned!
   *
   *******************************************************************/

  printf("Check if new transactions prune the redo stack ... ");

  tximpl = factory->create(mgr, NONE_FLAG);

  if (!tximpl) {
    printf("ERROR: Failed to allocate transaction.\n");
    return NS_ERROR_OUT_OF_MEMORY;
  }

  tx     = 0;

  result = tximpl->QueryInterface(NS_GET_IID(nsITransaction), (void **)&tx);

  if (NS_FAILED(result)) {
    printf("ERROR: QueryInterface() failed for transaction. (%d)\n", result);
    return result;
  }

  result = mgr->DoTransaction(tx);
  if (NS_FAILED(result)) {
    printf("ERROR: Failed to execute transaction. (%d)\n", result);
    return result;
  }

  tx->Release();

  result = mgr->GetNumberOfUndoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfUndoItems() on undo stack with 9 items failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 9) {
    printf("ERROR: GetNumberOfUndoItems() expected 9 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->GetNumberOfRedoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfRedoItems() on redo stack with 0 items failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 0) {
    printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  printf("passed\n");

  /*******************************************************************
   *
   * Undo 4 transactions then clear the undo and redo stacks.
   *
   *******************************************************************/

  printf("Undo 4 transactions then clear the undo and redo stacks ... ");

  for (i = 1; i <= 4; ++i) {
    result = mgr->UndoTransaction();
    if (NS_FAILED(result)) {
      printf("ERROR: Failed to undo transaction %d. (%d)\n", i, result);
      return result;
    }
  }

  result = mgr->GetNumberOfUndoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfUndoItems() on undo stack with 5 items failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 5) {
    printf("ERROR: GetNumberOfUndoItems() expected 5 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->GetNumberOfRedoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfRedoItems() on redo stack with 4 items failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 4) {
    printf("ERROR: GetNumberOfRedoItems() expected 4 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->Clear();

  if (NS_FAILED(result)) {
    printf("ERROR: Clear() failed. (%d)\n",
           result);
    return result;
  }

  result = mgr->GetNumberOfUndoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfUndoItems() on cleared undo stack failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 0) {
    printf("ERROR: GetNumberOfUndoItems() expected 0 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->GetNumberOfRedoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfRedoItems() on empty cleared stack failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 0) {
    printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  printf("passed\n");

  /*******************************************************************
   *
   * Execute 5 transactions.
   *
   *******************************************************************/

  printf("Execute 5 transactions ... ");

  for (i = 1; i <= 5; i++) {
    tximpl = factory->create(mgr, NONE_FLAG);

    if (!tximpl) {
      printf("ERROR: Failed to allocate transaction %d.\n", i);
      return NS_ERROR_OUT_OF_MEMORY;
    }

    tx = 0;
    result = tximpl->QueryInterface(NS_GET_IID(nsITransaction), (void **)&tx);
    if (NS_FAILED(result)) {
      printf("ERROR: QueryInterface() failed for transaction %d. (%d)\n",
             i, result);
      return result;
    }

    result = mgr->DoTransaction(tx);
    if (NS_FAILED(result)) {
      printf("ERROR: Failed to execute transaction %d. (%d)\n", i, result);
      return result;
    }

    tx->Release();
  }

  result = mgr->GetNumberOfUndoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfUndoItems() on undo stack with 5 items failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 5) {
    printf("ERROR: GetNumberOfUndoItems() expected 5 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->GetNumberOfRedoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfRedoItems() on empty redo stack failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 0) {
    printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  printf("passed\n");

  /*******************************************************************
   *
   * Test transaction DoTransaction() error:
   *
   *******************************************************************/

  printf("Test transaction DoTransaction() error ... ");

  tximpl = factory->create(mgr, THROWS_DO_ERROR_FLAG);

  if (!tximpl) {
    printf("ERROR: Failed to allocate transaction.\n");
    return NS_ERROR_OUT_OF_MEMORY;
  }

  tx     = 0;

  result = tximpl->QueryInterface(NS_GET_IID(nsITransaction), (void **)&tx);

  if (NS_FAILED(result)) {
    printf("ERROR: QueryInterface() failed for transaction. (%d)\n", result);
    return result;
  }

  u1 = u2 = r1 = r2 = 0;

  result = mgr->PeekUndoStack(&u1);

  TEST_TXMGR_IF_RELEASE(u1); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Initial PeekUndoStack() failed. (%d)\n", result);
    return result;
  }

  result = mgr->PeekRedoStack(&r1);

  TEST_TXMGR_IF_RELEASE(r1); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Initial PeekRedoStack() failed. (%d)\n", result);
    return result;
  }

  result = mgr->DoTransaction(tx);

  if (NS_FAILED(result) && result != NS_ERROR_FAILURE) {
    printf("ERROR: DoTransaction() returned unexpected error. (%d)\n", result);
    return result;
  }

  tx->Release();

  result = mgr->PeekUndoStack(&u2);

  TEST_TXMGR_IF_RELEASE(u2); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Second PeekUndoStack() failed. (%d)\n", result);
    return result;
  }

  if (u1 != u2) {
    printf("ERROR: Top of undo stack changed. (%d)\n", result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->PeekRedoStack(&r2);

  TEST_TXMGR_IF_RELEASE(r2); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Second PeekRedoStack() failed. (%d)\n", result);
    return result;
  }

  if (r1 != r2) {
    printf("ERROR: Top of redo stack changed. (%d)\n", result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->GetNumberOfUndoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfUndoItems() on undo stack with 5 items failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 5) {
    printf("ERROR: GetNumberOfUndoItems() expected 5 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->GetNumberOfRedoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfRedoItems() on empty redo stack. (%d)\n",
           result);
    return result;
  }

  if (numitems != 0) {
    printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  printf("passed\n");

  /*******************************************************************
   *
   * Test transaction UndoTransaction() error:
   *
   *******************************************************************/

  printf("Test transaction UndoTransaction() error ... ");

  tximpl = factory->create(mgr, THROWS_UNDO_ERROR_FLAG);

  if (!tximpl) {
    printf("ERROR: Failed to allocate transaction.\n");
    return NS_ERROR_OUT_OF_MEMORY;
  }

  tx     = 0;

  result = tximpl->QueryInterface(NS_GET_IID(nsITransaction), (void **)&tx);

  if (NS_FAILED(result)) {
    printf("ERROR: QueryInterface() failed for transaction. (%d)\n", result);
    return result;
  }

  result = mgr->DoTransaction(tx);

  if (NS_FAILED(result)) {
    printf("ERROR: DoTransaction() returned unexpected error. (%d)\n", result);
    return result;
  }

  tx->Release();

  u1 = u2 = r1 = r2 = 0;

  result = mgr->PeekUndoStack(&u1);

  TEST_TXMGR_IF_RELEASE(u1); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Initial PeekUndoStack() failed. (%d)\n", result);
    return result;
  }

  result = mgr->PeekRedoStack(&r1);

  TEST_TXMGR_IF_RELEASE(r1); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Initial PeekRedoStack() failed. (%d)\n", result);
    return result;
  }

  result = mgr->UndoTransaction();

  if (NS_FAILED(result) && result != NS_ERROR_FAILURE) {
    printf("ERROR: UndoTransaction() returned unexpected error. (%d)\n", result);
    return result;
  }

  result = mgr->PeekUndoStack(&u2);

  TEST_TXMGR_IF_RELEASE(u2); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Second PeekUndoStack() failed. (%d)\n", result);
    return result;
  }

  if (u1 != u2) {
    printf("ERROR: Top of undo stack changed. (%d)\n", result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->PeekRedoStack(&r2);

  TEST_TXMGR_IF_RELEASE(r2); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Second PeekRedoStack() failed. (%d)\n", result);
    return result;
  }

  if (r1 != r2) {
    printf("ERROR: Top of redo stack changed. (%d)\n", result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->GetNumberOfUndoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfUndoItems() on undo stack with 6 items failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 6) {
    printf("ERROR: GetNumberOfUndoItems() expected 6 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->GetNumberOfRedoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfRedoItems() on empty redo stack. (%d)\n",
           result);
    return result;
  }

  if (numitems != 0) {
    printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  printf("passed\n");

  /*******************************************************************
   *
   * Test transaction RedoTransaction() error:
   *
   *******************************************************************/

  printf("Test transaction RedoTransaction() error ... ");

  tximpl = factory->create(mgr, THROWS_REDO_ERROR_FLAG);

  if (!tximpl) {
    printf("ERROR: Failed to allocate transaction.\n");
    return NS_ERROR_OUT_OF_MEMORY;
  }

  tx     = 0;

  result = tximpl->QueryInterface(NS_GET_IID(nsITransaction), (void **)&tx);

  if (NS_FAILED(result)) {
    printf("ERROR: QueryInterface() failed for RedoErrorTransaction. (%d)\n",
           result);
    return result;
  }

  result = mgr->DoTransaction(tx);

  if (NS_FAILED(result)) {
    printf("ERROR: DoTransaction() returned unexpected error. (%d)\n", result);
    return result;
  }

  tx->Release();

  //
  // Execute a normal transaction to be used in a later test:
  //

  tximpl = factory->create(mgr, NONE_FLAG);

  if (!tximpl) {
    printf("ERROR: Failed to allocate transaction.\n");
    return NS_ERROR_OUT_OF_MEMORY;
  }

  tx     = 0;

  result = tximpl->QueryInterface(NS_GET_IID(nsITransaction), (void **)&tx);

  if (NS_FAILED(result)) {
    printf("ERROR: QueryInterface() failed for transaction. (%d)\n", result);
    return result;
  }

  result = mgr->DoTransaction(tx);

  if (NS_FAILED(result)) {
    printf("ERROR: DoTransaction() returned unexpected error. (%d)\n", result);
    return result;
  }

  tx->Release();

  //
  // Undo the 2 transactions just executed.
  //

  for (i = 1; i <= 2; ++i) {
    result = mgr->UndoTransaction();
    if (NS_FAILED(result)) {
      printf("ERROR: Failed to undo transaction %d. (%d)\n", i, result);
      return result;
    }
  }

  //
  // The RedoErrorTransaction should now be at the top of the redo stack!
  //

  u1 = u2 = r1 = r2 = 0;

  result = mgr->PeekUndoStack(&u1);

  TEST_TXMGR_IF_RELEASE(u1); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Initial PeekUndoStack() failed. (%d)\n", result);
    return result;
  }

  result = mgr->PeekRedoStack(&r1);

  TEST_TXMGR_IF_RELEASE(r1); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Initial PeekRedoStack() failed. (%d)\n", result);
    return result;
  }

  result = mgr->RedoTransaction();

  if (NS_FAILED(result) && result != NS_ERROR_FAILURE) {
    printf("ERROR: RedoTransaction() returned unexpected error. (%d)\n", result);
    return result;
  }

  result = mgr->PeekUndoStack(&u2);

  TEST_TXMGR_IF_RELEASE(u2); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Second PeekUndoStack() failed. (%d)\n", result);
    return result;
  }

  if (u1 != u2) {
    printf("ERROR: Top of undo stack changed. (%d)\n", result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->PeekRedoStack(&r2);

  TEST_TXMGR_IF_RELEASE(r2); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Second PeekRedoStack() failed. (%d)\n", result);
    return result;
  }

  if (r1 != r2) {
    printf("ERROR: Top of redo stack changed. (%d)\n", result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->GetNumberOfUndoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfUndoItems() on undo stack with 6 items failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 6) {
    printf("ERROR: GetNumberOfUndoItems() expected 6 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->GetNumberOfRedoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfRedoItems() on empty redo stack. (%d)\n",
           result);
    return result;
  }

  if (numitems != 2) {
    printf("ERROR: GetNumberOfRedoItems() expected 2 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  printf("passed\n");

  /*******************************************************************
   *
   * Make sure that setting the transaction manager's max transaction
   * count to zero, clears both the undo and redo stacks, and executes
   * all new commands without pushing them on the undo stack!
   *
   *******************************************************************/

  printf("Test max transaction count of zero ... ");

  result = mgr->SetMaxTransactionCount(0);

  if (NS_FAILED(result)) {
    printf("ERROR: SetMaxTransactionCount(0) failed. (%d)\n", result);
    return result;
  }

  result = mgr->GetNumberOfUndoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfUndoItems() on empty undo stack failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 0) {
    printf("ERROR: GetNumberOfUndoItems() expected 1 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->GetNumberOfRedoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfRedoItems() on empty redo stack failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 0) {
    printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  for (i = 1; i <= 20; i++) {
    tximpl = factory->create(mgr, NONE_FLAG);

    if (!tximpl) {
      printf("ERROR: Failed to allocate transaction %d.\n", i);
      return NS_ERROR_OUT_OF_MEMORY;
    }

    tx = 0;
    result = tximpl->QueryInterface(NS_GET_IID(nsITransaction), (void **)&tx);
    if (NS_FAILED(result)) {
      printf("ERROR: QueryInterface() failed for transaction %d. (%d)\n",
             i, result);
      return result;
    }

    result = mgr->DoTransaction(tx);
    if (NS_FAILED(result)) {
      printf("ERROR: Failed to execute transaction %d. (%d)\n", i, result);
      return result;
    }

    tx->Release();

    result = mgr->GetNumberOfUndoItems(&numitems);

    if (NS_FAILED(result)) {
      printf("ERROR: GetNumberOfUndoItems() on empty undo stack failed. (%d)\n",
             result);
      return result;
    }

    if (numitems != 0) {
      printf("ERROR: GetNumberOfUndoItems() expected 1 got %d. (%d)\n",
             numitems, result);
      return NS_ERROR_FAILURE;
    }

    result = mgr->GetNumberOfRedoItems(&numitems);

    if (NS_FAILED(result)) {
      printf("ERROR: GetNumberOfRedoItems() on empty redo stack failed. (%d)\n",
             result);
      return result;
    }

    if (numitems != 0) {
      printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n",
             numitems, result);
      return NS_ERROR_FAILURE;
    }
  }

  printf("passed\n");

  /*******************************************************************
   *
   * Make sure that setting the transaction manager's max transaction
   * count to something greater than the number of transactions on
   * both the undo and redo stacks causes no pruning of the stacks:
   *
   *******************************************************************/

  printf("Test SetMaxTransactionCount() greater than num stack items ... ");

  result = mgr->SetMaxTransactionCount(-1);

  if (NS_FAILED(result)) {
    printf("ERROR: SetMaxTransactionCount(0) failed. (%d)\n", result);
    return result;
  }

  // Push 20 transactions on the undo stack:

  for (i = 1; i <= 20; i++) {
    tximpl = factory->create(mgr, NONE_FLAG);

    if (!tximpl) {
      printf("ERROR: Failed to allocate transaction %d.\n", i);
      return NS_ERROR_OUT_OF_MEMORY;
    }

    tx = 0;
    result = tximpl->QueryInterface(NS_GET_IID(nsITransaction), (void **)&tx);
    if (NS_FAILED(result)) {
      printf("ERROR: QueryInterface() failed for transaction %d. (%d)\n",
             i, result);
      return result;
    }

    result = mgr->DoTransaction(tx);
    if (NS_FAILED(result)) {
      printf("ERROR: Failed to execute transaction %d. (%d)\n", i, result);
      return result;
    }

    tx->Release();

    result = mgr->GetNumberOfUndoItems(&numitems);

    if (NS_FAILED(result)) {
      printf("ERROR: GetNumberOfUndoItems() on empty undo stack failed. (%d)\n",
             result);
      return result;
    }

    if (numitems != i) {
      printf("ERROR: GetNumberOfUndoItems() expected 1 got %d. (%d)\n",
             numitems, result);
      return NS_ERROR_FAILURE;
    }

    result = mgr->GetNumberOfRedoItems(&numitems);

    if (NS_FAILED(result)) {
      printf("ERROR: GetNumberOfRedoItems() on empty redo stack failed. (%d)\n",
             result);
      return result;
    }

    if (numitems != 0) {
      printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n",
             numitems, result);
      return NS_ERROR_FAILURE;
    }
  }

  for (i = 1; i <= 10; i++) {

    result = mgr->UndoTransaction();
    if (NS_FAILED(result)) {
      printf("ERROR: Failed to undo transaction %d. (%d)\n", i, result);
      return result;
    }
  }
  result = mgr->GetNumberOfUndoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfUndoItems() on empty undo stack with 10 items failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 10) {
    printf("ERROR: GetNumberOfUndoItems() expected 10 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->GetNumberOfRedoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfRedoItems() on redo stack with 10 items failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 10) {
    printf("ERROR: GetNumberOfRedoItems() expected 10 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  u1 = u2 = r1 = r2 = 0;

  result = mgr->PeekUndoStack(&u1);

  TEST_TXMGR_IF_RELEASE(u1); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Initial PeekUndoStack() failed. (%d)\n", result);
    return result;
  }

  result = mgr->PeekRedoStack(&r1);

  TEST_TXMGR_IF_RELEASE(r1); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Initial PeekRedoStack() failed. (%d)\n", result);
    return result;
  }

  result = mgr->SetMaxTransactionCount(25);

  if (NS_FAILED(result)) {
    printf("ERROR: SetMaxTransactionCount(25) failed. (%d)\n", result);
    return result;
  }

  result = mgr->PeekUndoStack(&u2);

  TEST_TXMGR_IF_RELEASE(u2); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Second PeekUndoStack() failed. (%d)\n", result);
    return result;
  }

  if (u1 != u2) {
    printf("ERROR: Top of undo stack changed. (%d)\n", result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->PeekRedoStack(&r2);

  TEST_TXMGR_IF_RELEASE(r2); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Second PeekRedoStack() failed. (%d)\n", result);
    return result;
  }

  if (r1 != r2) {
    printf("ERROR: Top of redo stack changed. (%d)\n", result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->GetNumberOfUndoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfUndoItems() on undo stack with 10 items failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 10) {
    printf("ERROR: GetNumberOfUndoItems() expected 10 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->GetNumberOfRedoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfRedoItems() on redo stack with 10 items failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 10) {
    printf("ERROR: GetNumberOfRedoItems() expected 10 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  printf("passed\n");

  /*******************************************************************
   *
   * Test undo stack pruning by setting the transaction
   * manager's max transaction count to a number lower than the
   * number of transactions on both the undo and redo stacks:
   *
   *******************************************************************/

  printf("Test SetMaxTransactionCount() pruning undo stack ... ");

  u1 = u2 = r1 = r2 = 0;

  result = mgr->PeekUndoStack(&u1);

  TEST_TXMGR_IF_RELEASE(u1); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Initial PeekUndoStack() failed. (%d)\n", result);
    return result;
  }

  result = mgr->PeekRedoStack(&r1);

  TEST_TXMGR_IF_RELEASE(r1); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Initial PeekRedoStack() failed. (%d)\n", result);
    return result;
  }

  result = mgr->SetMaxTransactionCount(15);

  if (NS_FAILED(result)) {
    printf("ERROR: SetMaxTransactionCount(25) failed. (%d)\n", result);
    return result;
  }

  result = mgr->PeekUndoStack(&u2);

  TEST_TXMGR_IF_RELEASE(u2); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Second PeekUndoStack() failed. (%d)\n", result);
    return result;
  }

  if (u1 != u2) {
    printf("ERROR: Top of undo stack changed. (%d)\n", result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->PeekRedoStack(&r2);

  TEST_TXMGR_IF_RELEASE(r2); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Second PeekRedoStack() failed. (%d)\n", result);
    return result;
  }

  if (r1 != r2) {
    printf("ERROR: Top of redo stack changed. (%d)\n", result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->GetNumberOfUndoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfUndoItems() on undo stack with 10 items failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 5) {
    printf("ERROR: GetNumberOfUndoItems() expected 10 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->GetNumberOfRedoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfRedoItems() on redo stack with 10 items failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 10) {
    printf("ERROR: GetNumberOfRedoItems() expected 10 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  printf("passed\n");

  /*******************************************************************
   *
   * Test redo stack pruning by setting the transaction
   * manager's max transaction count to a number lower than the
   * number of transactions on both the undo and redo stacks:
   *
   *******************************************************************/

  printf("Test SetMaxTransactionCount() pruning redo stack ... ");

  u1 = u2 = r1 = r2 = 0;

  result = mgr->PeekUndoStack(&u1);

  TEST_TXMGR_IF_RELEASE(u1); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Initial PeekUndoStack() failed. (%d)\n", result);
    return result;
  }

  result = mgr->PeekRedoStack(&r1);

  TEST_TXMGR_IF_RELEASE(r1); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Initial PeekRedoStack() failed. (%d)\n", result);
    return result;
  }

  result = mgr->SetMaxTransactionCount(5);

  if (NS_FAILED(result)) {
    printf("ERROR: SetMaxTransactionCount(25) failed. (%d)\n", result);
    return result;
  }

  result = mgr->PeekUndoStack(&u2);

  TEST_TXMGR_IF_RELEASE(u2); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Second PeekUndoStack() failed. (%d)\n", result);
    return result;
  }

  if (u1 == u2 || u2) {
    printf("ERROR: Unexpected item at top of undo stack. (%d)\n", result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->PeekRedoStack(&r2);

  TEST_TXMGR_IF_RELEASE(r2); // Don't hold onto any references!

  if (NS_FAILED(result)) {
    printf("ERROR: Second PeekRedoStack() failed. (%d)\n", result);
    return result;
  }

  if (r1 != r2) {
    printf("ERROR: Top of redo stack changed. (%d)\n", result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->GetNumberOfUndoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfUndoItems() on empty undo stack failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 0) {
    printf("ERROR: GetNumberOfUndoItems() expected 0 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->GetNumberOfRedoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfRedoItems() on redo stack with 5 items failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 5) {
    printf("ERROR: GetNumberOfRedoItems() expected 5 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  printf("passed\n");

  /*******************************************************************
   *
   * Release the transaction manager. Any transactions on the undo
   * and redo stack should automatically be released:
   *
   *******************************************************************/

  printf("Release the transaction manager ... ");

  result = mgr->SetMaxTransactionCount(-1);

  if (NS_FAILED(result)) {
    printf("ERROR: SetMaxTransactionCount(0) failed. (%d)\n", result);
    return result;
  }

  // Push 20 transactions on the undo stack:

  for (i = 1; i <= 20; i++) {
    tximpl = factory->create(mgr, NONE_FLAG);

    if (!tximpl) {
      printf("ERROR: Failed to allocate transaction %d.\n", i);
      return NS_ERROR_OUT_OF_MEMORY;
    }

    tx = 0;
    result = tximpl->QueryInterface(NS_GET_IID(nsITransaction), (void **)&tx);
    if (NS_FAILED(result)) {
      printf("ERROR: QueryInterface() failed for transaction %d. (%d)\n",
             i, result);
      return result;
    }

    result = mgr->DoTransaction(tx);
    if (NS_FAILED(result)) {
      printf("ERROR: Failed to execute transaction %d. (%d)\n", i, result);
      return result;
    }

    tx->Release();

    result = mgr->GetNumberOfUndoItems(&numitems);

    if (NS_FAILED(result)) {
      printf("ERROR: GetNumberOfUndoItems() on empty undo stack failed. (%d)\n",
             result);
      return result;
    }

    if (numitems != i) {
      printf("ERROR: GetNumberOfUndoItems() expected 1 got %d. (%d)\n",
             numitems, result);
      return NS_ERROR_FAILURE;
    }

    result = mgr->GetNumberOfRedoItems(&numitems);

    if (NS_FAILED(result)) {
      printf("ERROR: GetNumberOfRedoItems() on empty redo stack failed. (%d)\n",
             result);
      return result;
    }

    if (numitems != 0) {
      printf("ERROR: GetNumberOfRedoItems() expected 0 got %d. (%d)\n",
             numitems, result);
      return NS_ERROR_FAILURE;
    }
  }

  for (i = 1; i <= 10; i++) {

    result = mgr->UndoTransaction();
    if (NS_FAILED(result)) {
      printf("ERROR: Failed to undo transaction %d. (%d)\n", i, result);
      return result;
    }
  }
  result = mgr->GetNumberOfUndoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfUndoItems() on empty undo stack with 10 items failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 10) {
    printf("ERROR: GetNumberOfUndoItems() expected 10 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  result = mgr->GetNumberOfRedoItems(&numitems);

  if (NS_FAILED(result)) {
    printf("ERROR: GetNumberOfRedoItems() on redo stack with 10 items failed. (%d)\n",
           result);
    return result;
  }

  if (numitems != 10) {
    printf("ERROR: GetNumberOfRedoItems() expected 10 got %d. (%d)\n",
           numitems, result);
    return NS_ERROR_FAILURE;
  }

  printf("passed\n");

  /*******************************************************************
   *
   * Make sure number of transactions created matches number of
   * transactions destroyed!
   *
   *******************************************************************/

  printf("Number of transactions created and destroyed match ... ");

  if (sConstructorCount != sDestructorCount) {
    printf("ERROR: Transaction constructor count (%d) != destructor count (%d).\n",
           sConstructorCount, sDestructorCount);
    return NS_ERROR_FAILURE;
  }

  if (NS_FAILED(result)) {
    printf("ERROR: nsITransactionManager Release() failed. (%d)\n", result);
    return result;
  }

  printf("passed\n");
  printf("%d transactions processed during quick test.\n", sConstructorCount);

  return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 760 of file TestTXMgr.cpp.

Here is the caller graph for this function:

Definition at line 4403 of file TestTXMgr.cpp.

{
  /*******************************************************************
   *
   * Initialize globals for test.
   *
   *******************************************************************/
  reset_globals();
  sDestructorOrderArr = sSimpleBatchTestDestructorOrderArr;
  sDoOrderArr         = sSimpleBatchTestDoOrderArr;
  sUndoOrderArr       = sSimpleBatchTestUndoOrderArr;
  sRedoOrderArr       = sSimpleBatchTestRedoOrderArr;

  /*******************************************************************
   *
   * Run the quick batch test.
   *
   *******************************************************************/

  SimpleTransactionFactory factory;

  printf("\n-----------------------------------------------------\n");
  printf("- Begin Batch Transaction Test:\n");
  printf("-----------------------------------------------------\n");

  return quick_batch_test(&factory);
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 4577 of file TestTXMgr.cpp.

{
  /*******************************************************************
   *
   * Initialize globals for test.
   *
   *******************************************************************/

  reset_globals();

  /*******************************************************************
   *
   * Do the stress test:
   *
   *******************************************************************/

  SimpleTransactionFactory factory;

  printf("\n-----------------------------------------------------\n");
  printf("- Simple Transaction Stress Test:\n");
  printf("-----------------------------------------------------\n");

  //
  // 1500 iterations sends 1,125,750 transactions through the system!!
  //
  return stress_test(&factory, 1500);
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 2700 of file TestTXMgr.cpp.

{
  /*******************************************************************
   *
   * Initialize globals for test.
   *
   *******************************************************************/
  reset_globals();
  sDestructorOrderArr = sSimpleTestDestructorOrderArr;
  sDoOrderArr         = sSimpleTestDoOrderArr;
  sUndoOrderArr       = sSimpleTestUndoOrderArr;
  sRedoOrderArr       = sSimpleTestRedoOrderArr;

  /*******************************************************************
   *
   * Run the quick test.
   *
   *******************************************************************/

  SimpleTransactionFactory factory;

  printf("\n-----------------------------------------------------\n");
  printf("- Begin Simple Transaction Test:\n");
  printf("-----------------------------------------------------\n");

  return quick_test(&factory);
}

Here is the call graph for this function:

Here is the caller graph for this function:

nsresult stress_test ( TestTransactionFactory factory,
PRInt32  iterations 
)

Definition at line 4462 of file TestTXMgr.cpp.

{
  /*******************************************************************
   *
   * Create a transaction manager:
   *
   *******************************************************************/

  printf("Stress test (may take a while) ... ");
  fflush(stdout);

  PRInt32 i, j;
  nsCOMPtr<nsITransactionManager> mgr;
  nsITransaction *tx          = 0;
  nsresult result;

  mgr = do_CreateInstance(NS_TRANSACTIONMANAGER_CONTRACTID, &result);
  if (NS_FAILED(result) || !mgr) {
    printf("ERROR: Failed to create Transaction Manager instance.\n");
    return NS_ERROR_OUT_OF_MEMORY;
  }

  for (i = 1; i <= iterations; i++) {
    /*******************************************************************
     *
     * Execute a bunch of transactions:
     *
     *******************************************************************/

    for (j = 1; j <= i; j++) {
      TestTransaction *tximpl = factory->create(mgr, NONE_FLAG);

      if (!tximpl) {
        printf("ERROR: Failed to allocate transaction %d.\n", j);
        return NS_ERROR_OUT_OF_MEMORY;
      }

      tx = 0;
      result = tximpl->QueryInterface(NS_GET_IID(nsITransaction), (void **)&tx);
      if (NS_FAILED(result)) {
        printf("ERROR: QueryInterface() failed for transaction %d. (%d)\n",
               i, result);
        return result;
      }

      result = mgr->DoTransaction(tx);
      if (NS_FAILED(result)) {
        printf("ERROR: Failed to execute transaction %d. (%d)\n", i, result);
        return result;
      }

      tx->Release();
    }

    /*******************************************************************
     *
     * Undo all the transactions:
     *
     *******************************************************************/

    for (j = 1; j <= i; j++) {
      result = mgr->UndoTransaction();
      if (NS_FAILED(result)) {
        printf("ERROR: Failed to undo transaction %d-%d. (%d)\n", i, j, result);
        return result;
      }
    }

    /*******************************************************************
     *
     * Redo all the transactions:
     *
     *******************************************************************/

    for (j = 1; j <= i; j++) {
      result = mgr->RedoTransaction();
      if (NS_FAILED(result)) {
        printf("ERROR: Failed to redo transaction %d-%d. (%d)\n", i, j, result);
        return result;
      }
    }

    /*******************************************************************
     *
     * Undo all the transactions again so that they all end up on
     * the redo stack for pruning the next time we execute a new
     * transaction
     *
     *******************************************************************/

    for (j = 1; j <= i; j++) {
      result = mgr->UndoTransaction();
      if (NS_FAILED(result)) {
        printf("ERROR: Failed to undo transaction %d-%d. (%d)\n", i, j, result);
        return result;
      }
    }
  }

  // printf("%d  %d -  ", sConstructorCount, sDestructorCount);

  if (sConstructorCount != sDestructorCount) {
    printf("ERROR: Transaction constructor count (%d) != destructor count (%d).\n",
           sConstructorCount, sDestructorCount);
    return NS_ERROR_FAILURE;
  }

  printf("passed\n");

  printf("%d transactions processed during stress test.\n", sConstructorCount);

  return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

Definition at line 277 of file TestTXMgr.cpp.

Definition at line 333 of file TestTXMgr.cpp.

Initial value:
 {
          1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,
         15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,
         29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,
         43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,
         57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  70,
         71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83,  84,
         85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,  96,  97,  98,
         99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112,
        113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126,
        127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140,
        281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294,
        295, 296, 297, 298, 299, 300, 301, 448, 449, 450, 451, 452, 453, 454,
        455, 456, 457, 458 }

Definition at line 421 of file TestTXMgr.cpp.

Definition at line 389 of file TestTXMgr.cpp.

Definition at line 88 of file TestTXMgr.cpp.

Definition at line 156 of file TestTXMgr.cpp.

Initial value:
 {
        260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273,
        476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486 }

Definition at line 242 of file TestTXMgr.cpp.

Initial value:
 {
        287, 286, 285, 284, 283, 282, 281, 280, 279, 278, 277, 276, 275, 274,
        273, 272, 271, 270, 269, 268, 267, 266, 265, 264, 263, 262, 261, 260,
        434, 433, 432, 431, 430, 429, 428, 273, 272, 271, 270, 269, 268, 267,
        266, 265, 264, 263, 262, 261, 260, 259, 258, 257, 256, 255, 254, 253,
        479, 478, 477, 476, 475, 493, 492, 491, 490, 489, 488, 487, 486, 485,
        484, 483, 482, 481, 480, 485, 484, 483, 482, 481, 480, 773, 772, 771,
        770, 769, 768, 767, 766, 765, 764, 763, 762, 761, 760, 759, 758, 757,
        756, 755, 754, 753, 752, 751, 750, 749, 748, 747, 746, 745, 744, 743,
        742, 741, 740, 739, 738, 737, 736, 735, 734, 733, 732, 731, 730, 729,
        728, 727, 726, 725, 724, 723, 722, 721, 720, 719, 718, 717, 716, 715,
        714, 713, 712, 711, 710, 709, 708, 707, 706, 705, 704, 913, 912, 911,
        910, 909, 908, 907, 906, 905, 904, 903, 902, 901, 900, 899, 898, 897,
        896, 895, 894, 893, 892, 891, 890, 889, 888, 887, 886, 885, 884, 883,
        882, 881, 880, 879, 878, 877, 876, 875, 874, 873, 872, 871, 870, 869,
        868, 867, 866, 865, 864, 863, 862, 861, 860, 859, 858, 857, 856, 855,
        854, 853, 852, 851, 850, 849, 848, 847, 846, 845, 844 }

Definition at line 224 of file TestTXMgr.cpp.

PRInt32 sConstructorCount = 0 [static]

Definition at line 44 of file TestTXMgr.cpp.

PRInt32 sDestructorCount = 0 [static]

Definition at line 45 of file TestTXMgr.cpp.

Definition at line 46 of file TestTXMgr.cpp.

PRInt32 sDoCount = 0 [static]

Definition at line 47 of file TestTXMgr.cpp.

PRInt32* sDoOrderArr = 0 [static]

Definition at line 48 of file TestTXMgr.cpp.

PRInt32 sRedoCount = 0 [static]

Definition at line 51 of file TestTXMgr.cpp.

PRInt32* sRedoOrderArr = 0 [static]

Definition at line 52 of file TestTXMgr.cpp.

Initial value:
 {
         21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31,  32,  33,  34,
         35,  36,  37,  38,  39,  40,  43,  42,  41,  64,  63,  62,  61,  60,
         59,  58,  57,  56,  55,  54,  53,  52,  51,  50,  49,  48,  47,  46,
         45,  44,  20,  19,  18,  17,  16,  15,  14,  13,  12,  11,  10,   9,
          8,   7,   6,   5,   4,   3,   2,   1,  65,  67,  66,  68,  69,  70,
         71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83,  84,
         85,  86,  87, 107, 106, 105, 104, 103, 102, 101, 100,  99,  98,  97,
         96,  95,  94,  93,  92,  91,  90,  89,  88 }

Definition at line 246 of file TestTXMgr.cpp.

Initial value:
 {
          1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,
         15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,
         29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,
         43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,
         57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  70,
         71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83,  84,
         85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,  96,  97,  98,
         99, 100, 101, 102, 103, 104, 105, 106, 107 }

Definition at line 256 of file TestTXMgr.cpp.

Initial value:
 {
          1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,
         15,  16,  17,  18,  19,  20,  41,  42,  43,  66 }

Definition at line 273 of file TestTXMgr.cpp.

Initial value:
 {
         43,  42,  41,  20,  19,  18,  17,  16,  15,  14,  13,  12,  11,  10,
          9,   8,   7,   6,   5,   4,   3,   2,   1,  43,  42,  41,  63,  62,
         61,  60,  59,  58,  57,  56,  55,  54,  53,  52,  51,  50,  49,  48,
         47,  46,  45,  44,  65,  67,  66, 107, 106, 105, 104, 103, 102, 101,
        100,  99,  98 }

Definition at line 266 of file TestTXMgr.cpp.

Initial value:
 {
          2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15,
         16,  17,  18,  19,  20,  21,   1,  22,  23,  24,  25,  26,  27,  28,
         29,  30,  31,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52,
         53,  54,  55,  56,  57,  58,  59,  60,  61,  41,  40,  62,  39,  38,
         37,  36,  35,  34,  33,  32,  68,  63,  64,  65,  66,  67,  69,  71,
         70,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83,  84,
         85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,  96,  97,  98,
         99, 100, 101, 111, 110, 109, 108, 107, 106, 105, 104, 103, 102, 131,
        130, 129, 128, 127, 126, 125, 124, 123, 122, 121, 120, 119, 118, 117,
        116, 115, 114, 113, 112 }

Definition at line 56 of file TestTXMgr.cpp.

Initial value:
 {
          1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,
         15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,
         29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,
         43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,
         57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  70,
         71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83,  84,
         85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,  96,  97,  98,
         99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112,
        113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126,
        127, 128, 129, 130, 131 }

Definition at line 68 of file TestTXMgr.cpp.

Initial value:
 {
         38,  39,  70 }

Definition at line 85 of file TestTXMgr.cpp.

Initial value:
 {
         41,  40,  39,  38,  62,  39,  38,  37,  69,  71,  70, 111, 110, 109,
        108, 107, 106, 105, 104, 103, 102, 131, 130, 129, 128, 127, 126, 125,
        124, 123, 122 }

Definition at line 80 of file TestTXMgr.cpp.

PRInt32 sUndoCount = 0 [static]

Definition at line 49 of file TestTXMgr.cpp.

PRInt32* sUndoOrderArr = 0 [static]

Definition at line 50 of file TestTXMgr.cpp.