DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (a81015259a98)

VCS Links

Line Code
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 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
/* Any copyright is dedicated to the Public Domain.
   http://creativecommons.org/publicdomain/zero/1.0/ */

#include "storage_test_harness.h"
#include "prthread.h"
#include "nsIEventTarget.h"
#include "nsIInterfaceRequestorUtils.h"

#include "sqlite3.h"

////////////////////////////////////////////////////////////////////////////////
//// Async Helpers

/**
 * Spins the events loop for current thread until aCondition is true.
 */
void
spin_events_loop_until_true(const bool* const aCondition)
{
  nsCOMPtr<nsIThread> thread(::do_GetCurrentThread());
  nsresult rv = NS_OK;
  bool processed = true;
  while (!(*aCondition) && NS_SUCCEEDED(rv)) {
    rv = thread->ProcessNextEvent(true, &processed);
  }
}

////////////////////////////////////////////////////////////////////////////////
//// mozIStorageStatementCallback implementation

class UnownedCallback : public mozIStorageStatementCallback
{
public:
  NS_DECL_ISUPPORTS

  // Whether the object has been destroyed.
  static bool sAlive;
  // Whether the first result was received.
  static bool sResult;
  // Whether an error was received.
  static bool sError;

  UnownedCallback(mozIStorageConnection* aDBConn)
  : mDBConn(aDBConn)
  , mCompleted(false)
  {
    sAlive = true;
    sResult = false;
    sError = false;
  }

  ~UnownedCallback()
  {
    sAlive = false;
    blocking_async_close(mDBConn);
  }

  NS_IMETHOD HandleResult(mozIStorageResultSet* aResultSet)
  {
    sResult = true;
    spin_events_loop_until_true(&mCompleted);
    if (!sAlive) {
      NS_RUNTIMEABORT("The statement callback was destroyed prematurely.");
    }
    return NS_OK;
  }

  NS_IMETHOD HandleError(mozIStorageError* aError)
  {
    sError = true;
    spin_events_loop_until_true(&mCompleted);
    if (!sAlive) {
      NS_RUNTIMEABORT("The statement callback was destroyed prematurely.");
    }
    return NS_OK;
  }

  NS_IMETHOD HandleCompletion(PRUint16 aReason)
  {
    mCompleted = true;
    return NS_OK;
  }

protected:
  nsCOMPtr<mozIStorageConnection> mDBConn;
  bool mCompleted;
};

NS_IMPL_ISUPPORTS1(UnownedCallback, mozIStorageStatementCallback)

bool UnownedCallback::sAlive = false;
bool UnownedCallback::sResult = false;
bool UnownedCallback::sError = false;

////////////////////////////////////////////////////////////////////////////////
//// Tests

void
test_SpinEventsLoopInHandleResult()
{
  nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());

  // Create a test table and populate it.
  nsCOMPtr<mozIStorageStatement> stmt;
  db->CreateStatement(NS_LITERAL_CSTRING(
    "CREATE TABLE test (id INTEGER PRIMARY KEY)"
  ), getter_AddRefs(stmt));
  stmt->Execute();
  stmt->Finalize();

  db->CreateStatement(NS_LITERAL_CSTRING(
    "INSERT INTO test (id) VALUES (?)"
  ), getter_AddRefs(stmt));
  for (PRInt32 i = 0; i < 30; ++i) {
    stmt->BindInt32ByIndex(0, i);
    stmt->Execute();
    stmt->Reset();
  }
  stmt->Finalize();

  db->CreateStatement(NS_LITERAL_CSTRING(
    "SELECT * FROM test"
  ), getter_AddRefs(stmt));
  nsCOMPtr<mozIStoragePendingStatement> ps;
  do_check_success(stmt->ExecuteAsync(new UnownedCallback(db),
                                      getter_AddRefs(ps)));
  stmt->Finalize();

  spin_events_loop_until_true(&UnownedCallback::sResult);
}

void
test_SpinEventsLoopInHandleError()
{
  nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());

  // Create a test table and populate it.
  nsCOMPtr<mozIStorageStatement> stmt;
  db->CreateStatement(NS_LITERAL_CSTRING(
    "CREATE TABLE test (id INTEGER PRIMARY KEY)"
  ), getter_AddRefs(stmt));
  stmt->Execute();
  stmt->Finalize();

  db->CreateStatement(NS_LITERAL_CSTRING(
    "INSERT INTO test (id) VALUES (1)"
  ), getter_AddRefs(stmt));
  stmt->Execute();
  stmt->Finalize();

  // This will cause a constraint error.
  db->CreateStatement(NS_LITERAL_CSTRING(
    "INSERT INTO test (id) VALUES (1)"
  ), getter_AddRefs(stmt));
  nsCOMPtr<mozIStoragePendingStatement> ps;
  do_check_success(stmt->ExecuteAsync(new UnownedCallback(db),
                                      getter_AddRefs(ps)));
  stmt->Finalize();

  spin_events_loop_until_true(&UnownedCallback::sError);
}

void (*gTests[])(void) = {
  test_SpinEventsLoopInHandleResult,
  test_SpinEventsLoopInHandleError,
};

const char *file = __FILE__;
#define TEST_NAME "test async callbacks with spun event loops"
#define TEST_FILE file
#include "storage_test_harness_tail.h"