michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* michael@0: * Test harness for XPCOM objects, providing a scoped XPCOM initializer, michael@0: * nsCOMPtr, nsRefPtr, do_CreateInstance, do_GetService, ns(Auto|C|)String, michael@0: * and stdio.h/stdlib.h. michael@0: */ michael@0: michael@0: #ifndef TestHarness_h__ michael@0: #define TestHarness_h__ michael@0: michael@0: #if defined(_MSC_VER) && defined(MOZ_STATIC_JS) michael@0: /* michael@0: * Including js/OldDebugAPI.h may cause build break with --disable-shared-js michael@0: * This is a workaround for bug 673616. michael@0: */ michael@0: #define STATIC_JS_API michael@0: #endif michael@0: michael@0: #include "mozilla/ArrayUtils.h" michael@0: michael@0: #include "prenv.h" michael@0: #include "nsComponentManagerUtils.h" michael@0: #include "nsServiceManagerUtils.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsAutoPtr.h" michael@0: #include "nsStringGlue.h" michael@0: #include "nsAppDirectoryServiceDefs.h" michael@0: #include "nsDirectoryServiceDefs.h" michael@0: #include "nsDirectoryServiceUtils.h" michael@0: #include "nsIDirectoryService.h" michael@0: #include "nsIFile.h" michael@0: #include "nsIProperties.h" michael@0: #include "nsIObserverService.h" michael@0: #include "nsXULAppAPI.h" michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: static uint32_t gFailCount = 0; michael@0: michael@0: /** michael@0: * Prints the given failure message and arguments using printf, prepending michael@0: * "TEST-UNEXPECTED-FAIL " for the benefit of the test harness and michael@0: * appending "\n" to eliminate having to type it at each call site. michael@0: */ michael@0: void fail(const char* msg, ...) michael@0: { michael@0: va_list ap; michael@0: michael@0: printf("TEST-UNEXPECTED-FAIL | "); michael@0: michael@0: va_start(ap, msg); michael@0: vprintf(msg, ap); michael@0: va_end(ap); michael@0: michael@0: putchar('\n'); michael@0: ++gFailCount; michael@0: } michael@0: michael@0: /** michael@0: * Prints the given success message and arguments using printf, prepending michael@0: * "TEST-PASS " for the benefit of the test harness and michael@0: * appending "\n" to eliminate having to type it at each call site. michael@0: */ michael@0: void passed(const char* msg, ...) michael@0: { michael@0: va_list ap; michael@0: michael@0: printf("TEST-PASS | "); michael@0: michael@0: va_start(ap, msg); michael@0: vprintf(msg, ap); michael@0: va_end(ap); michael@0: michael@0: putchar('\n'); michael@0: } michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: class ScopedLogging michael@0: { michael@0: public: michael@0: ScopedLogging() michael@0: { michael@0: NS_LogInit(); michael@0: } michael@0: michael@0: ~ScopedLogging() michael@0: { michael@0: NS_LogTerm(); michael@0: } michael@0: }; michael@0: michael@0: class ScopedXPCOM : public nsIDirectoryServiceProvider2 michael@0: { michael@0: public: michael@0: NS_DECL_ISUPPORTS michael@0: michael@0: ScopedXPCOM(const char* testName, michael@0: nsIDirectoryServiceProvider *dirSvcProvider = nullptr) michael@0: : mDirSvcProvider(dirSvcProvider) michael@0: { michael@0: mTestName = testName; michael@0: printf("Running %s tests...\n", mTestName); michael@0: michael@0: nsresult rv = NS_InitXPCOM2(&mServMgr, nullptr, this); michael@0: if (NS_FAILED(rv)) michael@0: { michael@0: fail("NS_InitXPCOM2 returned failure code 0x%x", rv); michael@0: mServMgr = nullptr; michael@0: return; michael@0: } michael@0: } michael@0: michael@0: ~ScopedXPCOM() michael@0: { michael@0: // If we created a profile directory, we need to remove it. michael@0: if (mProfD) { michael@0: nsCOMPtr os = michael@0: do_GetService(NS_OBSERVERSERVICE_CONTRACTID); michael@0: MOZ_ASSERT(os); michael@0: if (os) { michael@0: MOZ_ALWAYS_TRUE(NS_SUCCEEDED(os->NotifyObservers(nullptr, "profile-change-net-teardown", nullptr))); michael@0: MOZ_ALWAYS_TRUE(NS_SUCCEEDED(os->NotifyObservers(nullptr, "profile-change-teardown", nullptr))); michael@0: MOZ_ALWAYS_TRUE(NS_SUCCEEDED(os->NotifyObservers(nullptr, "profile-before-change", nullptr))); michael@0: MOZ_ALWAYS_TRUE(NS_SUCCEEDED(os->NotifyObservers(nullptr, "profile-before-change2", nullptr))); michael@0: } michael@0: michael@0: if (NS_FAILED(mProfD->Remove(true))) { michael@0: NS_WARNING("Problem removing profile directory"); michael@0: } michael@0: michael@0: mProfD = nullptr; michael@0: } michael@0: michael@0: if (mServMgr) michael@0: { michael@0: NS_RELEASE(mServMgr); michael@0: nsresult rv = NS_ShutdownXPCOM(nullptr); michael@0: if (NS_FAILED(rv)) michael@0: { michael@0: fail("XPCOM shutdown failed with code 0x%x", rv); michael@0: exit(1); michael@0: } michael@0: } michael@0: michael@0: printf("Finished running %s tests.\n", mTestName); michael@0: } michael@0: michael@0: bool failed() michael@0: { michael@0: return mServMgr == nullptr; michael@0: } michael@0: michael@0: already_AddRefed GetProfileDirectory() michael@0: { michael@0: if (mProfD) { michael@0: nsCOMPtr copy = mProfD; michael@0: return copy.forget(); michael@0: } michael@0: michael@0: // Create a unique temporary folder to use for this test. michael@0: // Note that runcppunittests.py will run tests with a temp michael@0: // directory as the cwd, so just put something under that. michael@0: nsCOMPtr profD; michael@0: nsresult rv = NS_GetSpecialDirectory(NS_OS_CURRENT_PROCESS_DIR, michael@0: getter_AddRefs(profD)); michael@0: NS_ENSURE_SUCCESS(rv, nullptr); michael@0: michael@0: rv = profD->Append(NS_LITERAL_STRING("cpp-unit-profd")); michael@0: NS_ENSURE_SUCCESS(rv, nullptr); michael@0: michael@0: rv = profD->CreateUnique(nsIFile::DIRECTORY_TYPE, 0755); michael@0: NS_ENSURE_SUCCESS(rv, nullptr); michael@0: michael@0: mProfD = profD; michael@0: return profD.forget(); michael@0: } michael@0: michael@0: already_AddRefed GetGREDirectory() michael@0: { michael@0: if (mGRED) { michael@0: nsCOMPtr copy = mGRED; michael@0: return copy.forget(); michael@0: } michael@0: michael@0: char* env = PR_GetEnv("MOZ_XRE_DIR"); michael@0: nsCOMPtr greD; michael@0: if (env) { michael@0: NS_NewLocalFile(NS_ConvertUTF8toUTF16(env), false, michael@0: getter_AddRefs(greD)); michael@0: } michael@0: michael@0: mGRED = greD; michael@0: return greD.forget(); michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////// michael@0: //// nsIDirectoryServiceProvider michael@0: michael@0: NS_IMETHODIMP GetFile(const char *aProperty, bool *_persistent, michael@0: nsIFile **_result) michael@0: { michael@0: // If we were supplied a directory service provider, ask it first. michael@0: if (mDirSvcProvider && michael@0: NS_SUCCEEDED(mDirSvcProvider->GetFile(aProperty, _persistent, michael@0: _result))) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: // Otherwise, the test harness provides some directories automatically. michael@0: if (0 == strcmp(aProperty, NS_APP_USER_PROFILE_50_DIR) || michael@0: 0 == strcmp(aProperty, NS_APP_USER_PROFILE_LOCAL_50_DIR) || michael@0: 0 == strcmp(aProperty, NS_APP_PROFILE_LOCAL_DIR_STARTUP)) { michael@0: nsCOMPtr profD = GetProfileDirectory(); michael@0: NS_ENSURE_TRUE(profD, NS_ERROR_FAILURE); michael@0: michael@0: nsCOMPtr clone; michael@0: nsresult rv = profD->Clone(getter_AddRefs(clone)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: *_persistent = true; michael@0: clone.forget(_result); michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (0 == strcmp(aProperty, NS_GRE_DIR)) { michael@0: nsCOMPtr greD = GetGREDirectory(); michael@0: NS_ENSURE_TRUE(greD, NS_ERROR_FAILURE); michael@0: michael@0: *_persistent = true; michael@0: greD.forget(_result); michael@0: return NS_OK; michael@0: } michael@0: michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////// michael@0: //// nsIDirectoryServiceProvider2 michael@0: michael@0: NS_IMETHODIMP GetFiles(const char *aProperty, nsISimpleEnumerator **_enum) michael@0: { michael@0: // If we were supplied a directory service provider, ask it first. michael@0: nsCOMPtr provider = michael@0: do_QueryInterface(mDirSvcProvider); michael@0: if (provider && NS_SUCCEEDED(provider->GetFiles(aProperty, _enum))) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: private: michael@0: const char* mTestName; michael@0: nsIServiceManager* mServMgr; michael@0: nsCOMPtr mDirSvcProvider; michael@0: nsCOMPtr mProfD; michael@0: nsCOMPtr mGRED; michael@0: }; michael@0: michael@0: NS_IMPL_QUERY_INTERFACE( michael@0: ScopedXPCOM, michael@0: nsIDirectoryServiceProvider, michael@0: nsIDirectoryServiceProvider2 michael@0: ) michael@0: michael@0: NS_IMETHODIMP_(MozExternalRefCountType) michael@0: ScopedXPCOM::AddRef() michael@0: { michael@0: return 2; michael@0: } michael@0: michael@0: NS_IMETHODIMP_(MozExternalRefCountType) michael@0: ScopedXPCOM::Release() michael@0: { michael@0: return 1; michael@0: } michael@0: michael@0: #endif // TestHarness_h__