toolkit/components/places/tests/cpp/places_test_harness.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/toolkit/components/places/tests/cpp/places_test_harness.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,405 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     1.5 + * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#include "TestHarness.h"
    1.11 +#include "nsMemory.h"
    1.12 +#include "nsThreadUtils.h"
    1.13 +#include "nsNetUtil.h"
    1.14 +#include "nsDocShellCID.h"
    1.15 +
    1.16 +#include "nsToolkitCompsCID.h"
    1.17 +#include "nsINavHistoryService.h"
    1.18 +#include "nsIObserverService.h"
    1.19 +#include "mozilla/IHistory.h"
    1.20 +#include "mozIStorageConnection.h"
    1.21 +#include "mozIStorageStatement.h"
    1.22 +#include "mozIStorageAsyncStatement.h"
    1.23 +#include "mozIStorageStatementCallback.h"
    1.24 +#include "mozIStoragePendingStatement.h"
    1.25 +#include "nsPIPlacesDatabase.h"
    1.26 +#include "nsIObserver.h"
    1.27 +#include "prinrval.h"
    1.28 +#include "mozilla/Attributes.h"
    1.29 +
    1.30 +#define WAITFORTOPIC_TIMEOUT_SECONDS 5
    1.31 +
    1.32 +
    1.33 +static size_t gTotalTests = 0;
    1.34 +static size_t gPassedTests = 0;
    1.35 +
    1.36 +#define do_check_true(aCondition) \
    1.37 +  PR_BEGIN_MACRO \
    1.38 +    gTotalTests++; \
    1.39 +    if (aCondition) { \
    1.40 +      gPassedTests++; \
    1.41 +    } else { \
    1.42 +      fail("%s | Expected true, got false at line %d", __FILE__, __LINE__); \
    1.43 +    } \
    1.44 +  PR_END_MACRO
    1.45 +
    1.46 +#define do_check_false(aCondition) \
    1.47 +  PR_BEGIN_MACRO \
    1.48 +    gTotalTests++; \
    1.49 +    if (!aCondition) { \
    1.50 +      gPassedTests++; \
    1.51 +    } else { \
    1.52 +      fail("%s | Expected false, got true at line %d", __FILE__, __LINE__); \
    1.53 +    } \
    1.54 +  PR_END_MACRO
    1.55 +
    1.56 +#define do_check_success(aResult) \
    1.57 +  do_check_true(NS_SUCCEEDED(aResult))
    1.58 +
    1.59 +#ifdef LINUX
    1.60 +// XXX Linux opt builds on tinderbox are orange due to linking with stdlib.
    1.61 +// This is sad and annoying, but it's a workaround that works.
    1.62 +#define do_check_eq(aExpected, aActual) \
    1.63 +  do_check_true(aExpected == aActual)
    1.64 +#else
    1.65 +#include <sstream>
    1.66 +
    1.67 +#define do_check_eq(aActual, aExpected) \
    1.68 +  PR_BEGIN_MACRO \
    1.69 +    gTotalTests++; \
    1.70 +    if (aExpected == aActual) { \
    1.71 +      gPassedTests++; \
    1.72 +    } else { \
    1.73 +      std::ostringstream temp; \
    1.74 +      temp << __FILE__ << " | Expected '" << aExpected << "', got '"; \
    1.75 +      temp << aActual <<"' at line " << __LINE__; \
    1.76 +      fail(temp.str().c_str()); \
    1.77 +    } \
    1.78 +  PR_END_MACRO
    1.79 +#endif
    1.80 +
    1.81 +struct Test
    1.82 +{
    1.83 +  void (*func)(void);
    1.84 +  const char* const name;
    1.85 +};
    1.86 +#define TEST(aName) \
    1.87 +  {aName, #aName}
    1.88 +
    1.89 +/**
    1.90 + * Runs the next text.
    1.91 + */
    1.92 +void run_next_test();
    1.93 +
    1.94 +/**
    1.95 + * To be used around asynchronous work.
    1.96 + */
    1.97 +void do_test_pending();
    1.98 +void do_test_finished();
    1.99 +
   1.100 +/**
   1.101 + * Spins current thread until a topic is received.
   1.102 + */
   1.103 +class WaitForTopicSpinner MOZ_FINAL : public nsIObserver
   1.104 +{
   1.105 +public:
   1.106 +  NS_DECL_ISUPPORTS
   1.107 +
   1.108 +  WaitForTopicSpinner(const char* const aTopic)
   1.109 +  : mTopicReceived(false)
   1.110 +  , mStartTime(PR_IntervalNow())
   1.111 +  {
   1.112 +    nsCOMPtr<nsIObserverService> observerService =
   1.113 +      do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
   1.114 +    do_check_true(observerService);
   1.115 +    (void)observerService->AddObserver(this, aTopic, false);
   1.116 +  }
   1.117 +
   1.118 +  void Spin() {
   1.119 +    while (!mTopicReceived) {
   1.120 +      if ((PR_IntervalNow() - mStartTime) > (WAITFORTOPIC_TIMEOUT_SECONDS * PR_USEC_PER_SEC)) {
   1.121 +        // Timed out waiting for the topic.
   1.122 +        do_check_true(false);
   1.123 +        break;
   1.124 +      }
   1.125 +      (void)NS_ProcessNextEvent();
   1.126 +    }
   1.127 +  }
   1.128 +
   1.129 +  NS_IMETHOD Observe(nsISupports* aSubject,
   1.130 +                     const char* aTopic,
   1.131 +                     const char16_t* aData)
   1.132 +  {
   1.133 +    mTopicReceived = true;
   1.134 +    nsCOMPtr<nsIObserverService> observerService =
   1.135 +      do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
   1.136 +    do_check_true(observerService);
   1.137 +    (void)observerService->RemoveObserver(this, aTopic);
   1.138 +    return NS_OK;
   1.139 +  }
   1.140 +
   1.141 +private:
   1.142 +  bool mTopicReceived;
   1.143 +  PRIntervalTime mStartTime;
   1.144 +};
   1.145 +NS_IMPL_ISUPPORTS(
   1.146 +  WaitForTopicSpinner,
   1.147 +  nsIObserver
   1.148 +)
   1.149 +
   1.150 +/**
   1.151 + * Spins current thread until an async statement is executed.
   1.152 + */
   1.153 +class AsyncStatementSpinner MOZ_FINAL : public mozIStorageStatementCallback
   1.154 +{
   1.155 +public:
   1.156 +  NS_DECL_ISUPPORTS
   1.157 +  NS_DECL_MOZISTORAGESTATEMENTCALLBACK
   1.158 +
   1.159 +  AsyncStatementSpinner();
   1.160 +  void SpinUntilCompleted();
   1.161 +  uint16_t completionReason;
   1.162 +
   1.163 +protected:
   1.164 +  volatile bool mCompleted;
   1.165 +};
   1.166 +
   1.167 +NS_IMPL_ISUPPORTS(AsyncStatementSpinner,
   1.168 +                  mozIStorageStatementCallback)
   1.169 +
   1.170 +AsyncStatementSpinner::AsyncStatementSpinner()
   1.171 +: completionReason(0)
   1.172 +, mCompleted(false)
   1.173 +{
   1.174 +}
   1.175 +
   1.176 +NS_IMETHODIMP
   1.177 +AsyncStatementSpinner::HandleResult(mozIStorageResultSet *aResultSet)
   1.178 +{
   1.179 +  return NS_OK;
   1.180 +}
   1.181 +
   1.182 +NS_IMETHODIMP
   1.183 +AsyncStatementSpinner::HandleError(mozIStorageError *aError)
   1.184 +{
   1.185 +  return NS_OK;
   1.186 +}
   1.187 +
   1.188 +NS_IMETHODIMP
   1.189 +AsyncStatementSpinner::HandleCompletion(uint16_t aReason)
   1.190 +{
   1.191 +  completionReason = aReason;
   1.192 +  mCompleted = true;
   1.193 +  return NS_OK;
   1.194 +}
   1.195 +
   1.196 +void AsyncStatementSpinner::SpinUntilCompleted()
   1.197 +{
   1.198 +  nsCOMPtr<nsIThread> thread(::do_GetCurrentThread());
   1.199 +  nsresult rv = NS_OK;
   1.200 +  bool processed = true;
   1.201 +  while (!mCompleted && NS_SUCCEEDED(rv)) {
   1.202 +    rv = thread->ProcessNextEvent(true, &processed);
   1.203 +  }
   1.204 +}
   1.205 +
   1.206 +struct PlaceRecord
   1.207 +{
   1.208 +  int64_t id;
   1.209 +  int32_t hidden;
   1.210 +  int32_t typed;
   1.211 +  int32_t visitCount;
   1.212 +  nsCString guid;
   1.213 +};
   1.214 +
   1.215 +struct VisitRecord
   1.216 +{
   1.217 +  int64_t id;
   1.218 +  int64_t lastVisitId;
   1.219 +  int32_t transitionType;
   1.220 +};
   1.221 +
   1.222 +already_AddRefed<mozilla::IHistory>
   1.223 +do_get_IHistory()
   1.224 +{
   1.225 +  nsCOMPtr<mozilla::IHistory> history = do_GetService(NS_IHISTORY_CONTRACTID);
   1.226 +  do_check_true(history);
   1.227 +  return history.forget();
   1.228 +}
   1.229 +
   1.230 +already_AddRefed<nsINavHistoryService>
   1.231 +do_get_NavHistory()
   1.232 +{
   1.233 +  nsCOMPtr<nsINavHistoryService> serv =
   1.234 +    do_GetService(NS_NAVHISTORYSERVICE_CONTRACTID);
   1.235 +  do_check_true(serv);
   1.236 +  return serv.forget();
   1.237 +}
   1.238 +
   1.239 +already_AddRefed<mozIStorageConnection>
   1.240 +do_get_db()
   1.241 +{
   1.242 +  nsCOMPtr<nsINavHistoryService> history = do_get_NavHistory();
   1.243 +  nsCOMPtr<nsPIPlacesDatabase> database = do_QueryInterface(history);
   1.244 +  do_check_true(database);
   1.245 +
   1.246 +  nsCOMPtr<mozIStorageConnection> dbConn;
   1.247 +  nsresult rv = database->GetDBConnection(getter_AddRefs(dbConn));
   1.248 +  do_check_success(rv);
   1.249 +  return dbConn.forget();
   1.250 +}
   1.251 +
   1.252 +/**
   1.253 + * Get the place record from the database.
   1.254 + *
   1.255 + * @param aURI The unique URI of the place we are looking up
   1.256 + * @param result Out parameter where the result is stored
   1.257 + */
   1.258 +void
   1.259 +do_get_place(nsIURI* aURI, PlaceRecord& result)
   1.260 +{
   1.261 +  nsCOMPtr<mozIStorageConnection> dbConn = do_get_db();
   1.262 +  nsCOMPtr<mozIStorageStatement> stmt;
   1.263 +
   1.264 +  nsCString spec;
   1.265 +  nsresult rv = aURI->GetSpec(spec);
   1.266 +  do_check_success(rv);
   1.267 +
   1.268 +  rv = dbConn->CreateStatement(NS_LITERAL_CSTRING(
   1.269 +    "SELECT id, hidden, typed, visit_count, guid FROM moz_places "
   1.270 +    "WHERE url=?1 "
   1.271 +  ), getter_AddRefs(stmt));
   1.272 +  do_check_success(rv);
   1.273 +
   1.274 +  rv = stmt->BindUTF8StringByIndex(0, spec);
   1.275 +  do_check_success(rv);
   1.276 +
   1.277 +  bool hasResults;
   1.278 +  rv = stmt->ExecuteStep(&hasResults);
   1.279 +  do_check_success(rv);
   1.280 +  if (!hasResults) {
   1.281 +    result.id = 0;
   1.282 +    return;
   1.283 +  }
   1.284 +
   1.285 +  rv = stmt->GetInt64(0, &result.id);
   1.286 +  do_check_success(rv);
   1.287 +  rv = stmt->GetInt32(1, &result.hidden);
   1.288 +  do_check_success(rv);
   1.289 +  rv = stmt->GetInt32(2, &result.typed);
   1.290 +  do_check_success(rv);
   1.291 +  rv = stmt->GetInt32(3, &result.visitCount);
   1.292 +  do_check_success(rv);
   1.293 +  rv = stmt->GetUTF8String(4, result.guid);
   1.294 +  do_check_success(rv);
   1.295 +}
   1.296 +
   1.297 +/**
   1.298 + * Gets the most recent visit to a place.
   1.299 + *
   1.300 + * @param placeID ID from the moz_places table
   1.301 + * @param result Out parameter where visit is stored
   1.302 + */
   1.303 +void
   1.304 +do_get_lastVisit(int64_t placeId, VisitRecord& result)
   1.305 +{
   1.306 +  nsCOMPtr<mozIStorageConnection> dbConn = do_get_db();
   1.307 +  nsCOMPtr<mozIStorageStatement> stmt;
   1.308 +
   1.309 +  nsresult rv = dbConn->CreateStatement(NS_LITERAL_CSTRING(
   1.310 +    "SELECT id, from_visit, visit_type FROM moz_historyvisits "
   1.311 +    "WHERE place_id=?1 "
   1.312 +    "LIMIT 1"
   1.313 +  ), getter_AddRefs(stmt));
   1.314 +  do_check_success(rv);
   1.315 +
   1.316 +  rv = stmt->BindInt64ByIndex(0, placeId);
   1.317 +  do_check_success(rv);
   1.318 +
   1.319 +  bool hasResults;
   1.320 +  rv = stmt->ExecuteStep(&hasResults);
   1.321 +  do_check_success(rv);
   1.322 +
   1.323 +  if (!hasResults) {
   1.324 +    result.id = 0;
   1.325 +    return;
   1.326 +  }
   1.327 +
   1.328 +  rv = stmt->GetInt64(0, &result.id);
   1.329 +  do_check_success(rv);
   1.330 +  rv = stmt->GetInt64(1, &result.lastVisitId);
   1.331 +  do_check_success(rv);
   1.332 +  rv = stmt->GetInt32(2, &result.transitionType);
   1.333 +  do_check_success(rv);
   1.334 +}
   1.335 +
   1.336 +void
   1.337 +do_wait_async_updates() {
   1.338 +  nsCOMPtr<mozIStorageConnection> db = do_get_db();
   1.339 +  nsCOMPtr<mozIStorageAsyncStatement> stmt;
   1.340 +
   1.341 +  db->CreateAsyncStatement(NS_LITERAL_CSTRING("BEGIN EXCLUSIVE"),
   1.342 +                           getter_AddRefs(stmt));
   1.343 +  nsCOMPtr<mozIStoragePendingStatement> pending;
   1.344 +  (void)stmt->ExecuteAsync(nullptr, getter_AddRefs(pending));
   1.345 +
   1.346 +  db->CreateAsyncStatement(NS_LITERAL_CSTRING("COMMIT"),
   1.347 +                           getter_AddRefs(stmt));
   1.348 +  nsRefPtr<AsyncStatementSpinner> spinner = new AsyncStatementSpinner();
   1.349 +  (void)stmt->ExecuteAsync(spinner, getter_AddRefs(pending));
   1.350 +
   1.351 +  spinner->SpinUntilCompleted();
   1.352 +}
   1.353 +
   1.354 +/**
   1.355 + * Adds a URI to the database.
   1.356 + *
   1.357 + * @param aURI
   1.358 + *        The URI to add to the database.
   1.359 + */
   1.360 +void
   1.361 +addURI(nsIURI* aURI)
   1.362 +{
   1.363 +  nsCOMPtr<mozilla::IHistory> history = do_GetService(NS_IHISTORY_CONTRACTID);
   1.364 +  do_check_true(history);
   1.365 +  nsresult rv = history->VisitURI(aURI, nullptr, mozilla::IHistory::TOP_LEVEL);
   1.366 +  do_check_success(rv);
   1.367 +
   1.368 +  do_wait_async_updates();
   1.369 +}
   1.370 +
   1.371 +static const char TOPIC_PROFILE_CHANGE[] = "profile-before-change";
   1.372 +static const char TOPIC_PLACES_CONNECTION_CLOSED[] = "places-connection-closed";
   1.373 +
   1.374 +class WaitForConnectionClosed MOZ_FINAL : public nsIObserver
   1.375 +{
   1.376 +  nsRefPtr<WaitForTopicSpinner> mSpinner;
   1.377 +public:
   1.378 +  NS_DECL_ISUPPORTS
   1.379 +
   1.380 +  WaitForConnectionClosed()
   1.381 +  {
   1.382 +    nsCOMPtr<nsIObserverService> os =
   1.383 +      do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
   1.384 +    MOZ_ASSERT(os);
   1.385 +    if (os) {
   1.386 +      MOZ_ALWAYS_TRUE(NS_SUCCEEDED(os->AddObserver(this, TOPIC_PROFILE_CHANGE, false)));
   1.387 +    }
   1.388 +    mSpinner = new WaitForTopicSpinner(TOPIC_PLACES_CONNECTION_CLOSED);
   1.389 +  }
   1.390 +
   1.391 +  NS_IMETHOD Observe(nsISupports* aSubject,
   1.392 +                     const char* aTopic,
   1.393 +                     const char16_t* aData)
   1.394 +  {
   1.395 +    nsCOMPtr<nsIObserverService> os =
   1.396 +      do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
   1.397 +    MOZ_ASSERT(os);
   1.398 +    if (os) {
   1.399 +      MOZ_ALWAYS_TRUE(NS_SUCCEEDED(os->RemoveObserver(this, aTopic)));
   1.400 +    }
   1.401 +
   1.402 +    mSpinner->Spin();
   1.403 +
   1.404 +    return NS_OK;
   1.405 +  }
   1.406 +};
   1.407 +
   1.408 +NS_IMPL_ISUPPORTS(WaitForConnectionClosed, nsIObserver)

mercurial