<commit_before>// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/app_mode/kiosk_profile_loader.h"

#include "base/logging.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/string_util.h"
#include "base/sys_info.h"
#include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
#include "chrome/browser/chromeos/login/login_display_host_impl.h"
#include "chrome/browser/chromeos/login/login_status_consumer.h"
#include "chrome/browser/chromeos/login/login_utils.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/chromeos/settings/cros_settings.h"
#include "chrome/browser/lifetime/application_lifetime.h"
#include "chromeos/cryptohome/async_method_caller.h"
#include "chromeos/dbus/cryptohome_client.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "content/public/browser/browser_thread.h"
#include "google_apis/gaia/gaia_auth_util.h"

using content::BrowserThread;

namespace chromeos {

namespace {

void IgnoreResult(bool mount_success, cryptohome::MountError mount_error) {}

KioskAppLaunchError::Error LoginFailureToKioskAppLaunchError(
    const LoginFailure& error) {
  switch (error.reason()) {
    case LoginFailure::COULD_NOT_MOUNT_TMPFS:
    case LoginFailure::COULD_NOT_MOUNT_CRYPTOHOME:
      return KioskAppLaunchError::UNABLE_TO_MOUNT;
    case LoginFailure::DATA_REMOVAL_FAILED:
      return KioskAppLaunchError::UNABLE_TO_REMOVE;
    case LoginFailure::USERNAME_HASH_FAILED:
      return KioskAppLaunchError::UNABLE_TO_RETRIEVE_HASH;
    default:
      NOTREACHED();
      return KioskAppLaunchError::UNABLE_TO_MOUNT;
  }
}

}  // namespace

////////////////////////////////////////////////////////////////////////////////
// KioskProfileLoader::CryptohomedChecker ensures cryptohome daemon is up
// and running by issuing an IsMounted call. If the call does not go through
// and chromeos::DBUS_METHOD_CALL_SUCCESS is not returned, it will retry after
// some time out and at the maximum five times before it gives up. Upon
// success, it resumes the launch by logging in as a kiosk mode account.

class KioskProfileLoader::CryptohomedChecker
    : public base::SupportsWeakPtr<CryptohomedChecker> {
 public:
  explicit CryptohomedChecker(KioskProfileLoader* loader)
      : loader_(loader),
        retry_count_(0) {
  }
  ~CryptohomedChecker() {}

  void StartCheck() {
    chromeos::DBusThreadManager::Get()->GetCryptohomeClient()->IsMounted(
        base::Bind(&CryptohomedChecker::OnCryptohomeIsMounted,
                   AsWeakPtr()));
  }

 private:
  void OnCryptohomeIsMounted(chromeos::DBusMethodCallStatus call_status,
                             bool is_mounted) {
    if (call_status != chromeos::DBUS_METHOD_CALL_SUCCESS) {
      const int kMaxRetryTimes = 5;
      ++retry_count_;
      if (retry_count_ > kMaxRetryTimes) {
        LOG(ERROR) << "Could not talk to cryptohomed for launching kiosk app.";
        ReportCheckResult(KioskAppLaunchError::CRYPTOHOMED_NOT_RUNNING);
        return;
      }

      const int retry_delay_in_milliseconds = 500 * (1 << retry_count_);
      base::MessageLoop::current()->PostDelayedTask(
          FROM_HERE,
          base::Bind(&CryptohomedChecker::StartCheck, AsWeakPtr()),
          base::TimeDelta::FromMilliseconds(retry_delay_in_milliseconds));
      return;
    }

    if (is_mounted)
      LOG(ERROR) << "Cryptohome is mounted before launching kiosk app.";

    // Proceed only when cryptohome is not mounded or running on dev box.
    if (!is_mounted || !base::SysInfo::IsRunningOnChromeOS())
      ReportCheckResult(KioskAppLaunchError::NONE);
    else
      ReportCheckResult(KioskAppLaunchError::ALREADY_MOUNTED);
  }

  void ReportCheckResult(KioskAppLaunchError::Error error) {
    if (error == KioskAppLaunchError::NONE)
      loader_->LoginAsKioskAccount();
    else
      loader_->ReportLaunchResult(error);
  }

  KioskProfileLoader* loader_;
  int retry_count_;

  DISALLOW_COPY_AND_ASSIGN(CryptohomedChecker);
};

////////////////////////////////////////////////////////////////////////////////
// KioskProfileLoader

KioskProfileLoader::KioskProfileLoader(KioskAppManager* kiosk_app_manager,
                                       const std::string& app_id,
                                       Delegate* delegate)
    : kiosk_app_manager_(kiosk_app_manager),
      app_id_(app_id),
      delegate_(delegate) {
  KioskAppManager::App app;
  CHECK(kiosk_app_manager_->GetApp(app_id_, &app));
  user_id_ = app.user_id;
}

KioskProfileLoader::~KioskProfileLoader() {}

void KioskProfileLoader::Start() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  login_performer_.reset();
  cryptohomed_checker_.reset(new CryptohomedChecker(this));
  cryptohomed_checker_->StartCheck();
}

void KioskProfileLoader::LoginAsKioskAccount() {
  login_performer_.reset(new LoginPerformer(this));
  login_performer_->LoginAsKioskAccount(user_id_);
}

void KioskProfileLoader::ReportLaunchResult(KioskAppLaunchError::Error error) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  if (error != KioskAppLaunchError::NONE) {
    delegate_->OnProfileLoadFailed(error);
  }
}

void KioskProfileLoader::OnLoginSuccess(const UserContext& user_context)  {
  // LoginPerformer will delete itself.
  login_performer_->set_delegate(NULL);
  ignore_result(login_performer_.release());

  LoginUtils::Get()->PrepareProfile(user_context,
                                    std::string(),  // display email
                                    false,  // has_cookies
                                    false,  // has_active_session
                                    this);
}

void KioskProfileLoader::OnLoginFailure(const LoginFailure& error) {
  ReportLaunchResult(LoginFailureToKioskAppLaunchError(error));
}

void KioskProfileLoader::WhiteListCheckFailed(const std::string& email) {
  NOTREACHED();
}

void KioskProfileLoader::PolicyLoadFailed() {
  ReportLaunchResult(KioskAppLaunchError::POLICY_LOAD_FAILED);
}

void KioskProfileLoader::OnOnlineChecked(
    const std::string& email, bool success) {
  NOTREACHED();
}

void KioskProfileLoader::OnProfilePrepared(Profile* profile) {
  // This object could be deleted any time after successfully reporting
  // a profile load, so invalidate the LoginUtils delegate now.
  LoginUtils::Get()->DelegateDeleted(this);

  delegate_->OnProfileLoaded(profile);
  ReportLaunchResult(KioskAppLaunchError::NONE);
}

}  // namespace chromeos
<commit_msg>Revert 234430 "kiosk: Remove cryptohome migration code."<commit_after>// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/app_mode/kiosk_profile_loader.h"

#include "base/logging.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/string_util.h"
#include "base/sys_info.h"
#include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
#include "chrome/browser/chromeos/login/login_display_host_impl.h"
#include "chrome/browser/chromeos/login/login_status_consumer.h"
#include "chrome/browser/chromeos/login/login_utils.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/chromeos/settings/cros_settings.h"
#include "chrome/browser/lifetime/application_lifetime.h"
#include "chromeos/cryptohome/async_method_caller.h"
#include "chromeos/dbus/cryptohome_client.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "content/public/browser/browser_thread.h"
#include "google_apis/gaia/gaia_auth_util.h"

using content::BrowserThread;

namespace chromeos {

namespace {

void IgnoreResult(bool mount_success, cryptohome::MountError mount_error) {}

// Converts a user id to the old non-canonicalized format. We need this
// old user id to cleanup crypthomes from older verisons.
// TODO(tengs): Remove this after all clients migrated to new home.
std::string GetOldUserId(const std::string& user_id) {
  size_t separator_pos = user_id.find('@');
  if (separator_pos != user_id.npos && separator_pos < user_id.length() - 1) {
    std::string username = user_id.substr(0, separator_pos);
    std::string domain = user_id.substr(separator_pos + 1);
    StringToUpperASCII(&username);
    return username + "@" + domain;
  } else {
    LOG(ERROR) << "User id "
        << user_id << " does not seem to be a valid format";
    NOTREACHED();
    return user_id;
  }
}

KioskAppLaunchError::Error LoginFailureToKioskAppLaunchError(
    const LoginFailure& error) {
  switch (error.reason()) {
    case LoginFailure::COULD_NOT_MOUNT_TMPFS:
    case LoginFailure::COULD_NOT_MOUNT_CRYPTOHOME:
      return KioskAppLaunchError::UNABLE_TO_MOUNT;
    case LoginFailure::DATA_REMOVAL_FAILED:
      return KioskAppLaunchError::UNABLE_TO_REMOVE;
    case LoginFailure::USERNAME_HASH_FAILED:
      return KioskAppLaunchError::UNABLE_TO_RETRIEVE_HASH;
    default:
      NOTREACHED();
      return KioskAppLaunchError::UNABLE_TO_MOUNT;
  }
}

}  // namespace

////////////////////////////////////////////////////////////////////////////////
// KioskProfileLoader::CryptohomedChecker ensures cryptohome daemon is up
// and running by issuing an IsMounted call. If the call does not go through
// and chromeos::DBUS_METHOD_CALL_SUCCESS is not returned, it will retry after
// some time out and at the maximum five times before it gives up. Upon
// success, it resumes the launch by logging in as a kiosk mode account.

class KioskProfileLoader::CryptohomedChecker
    : public base::SupportsWeakPtr<CryptohomedChecker> {
 public:
  explicit CryptohomedChecker(KioskProfileLoader* loader)
      : loader_(loader),
        retry_count_(0) {
  }
  ~CryptohomedChecker() {}

  void StartCheck() {
    chromeos::DBusThreadManager::Get()->GetCryptohomeClient()->IsMounted(
        base::Bind(&CryptohomedChecker::OnCryptohomeIsMounted,
                   AsWeakPtr()));
  }

 private:
  void OnCryptohomeIsMounted(chromeos::DBusMethodCallStatus call_status,
                             bool is_mounted) {
    if (call_status != chromeos::DBUS_METHOD_CALL_SUCCESS) {
      const int kMaxRetryTimes = 5;
      ++retry_count_;
      if (retry_count_ > kMaxRetryTimes) {
        LOG(ERROR) << "Could not talk to cryptohomed for launching kiosk app.";
        ReportCheckResult(KioskAppLaunchError::CRYPTOHOMED_NOT_RUNNING);
        return;
      }

      const int retry_delay_in_milliseconds = 500 * (1 << retry_count_);
      base::MessageLoop::current()->PostDelayedTask(
          FROM_HERE,
          base::Bind(&CryptohomedChecker::StartCheck, AsWeakPtr()),
          base::TimeDelta::FromMilliseconds(retry_delay_in_milliseconds));
      return;
    }

    if (is_mounted)
      LOG(ERROR) << "Cryptohome is mounted before launching kiosk app.";

    // Proceed only when cryptohome is not mounded or running on dev box.
    if (!is_mounted || !base::SysInfo::IsRunningOnChromeOS())
      ReportCheckResult(KioskAppLaunchError::NONE);
    else
      ReportCheckResult(KioskAppLaunchError::ALREADY_MOUNTED);
  }

  void ReportCheckResult(KioskAppLaunchError::Error error) {
    if (error == KioskAppLaunchError::NONE)
      loader_->LoginAsKioskAccount();
    else
      loader_->ReportLaunchResult(error);
  }

  KioskProfileLoader* loader_;
  int retry_count_;

  DISALLOW_COPY_AND_ASSIGN(CryptohomedChecker);
};

////////////////////////////////////////////////////////////////////////////////
// KioskProfileLoader

KioskProfileLoader::KioskProfileLoader(KioskAppManager* kiosk_app_manager,
                                       const std::string& app_id,
                                       Delegate* delegate)
    : kiosk_app_manager_(kiosk_app_manager),
      app_id_(app_id),
      delegate_(delegate) {
  KioskAppManager::App app;
  CHECK(kiosk_app_manager_->GetApp(app_id_, &app));
  user_id_ = app.user_id;
}

KioskProfileLoader::~KioskProfileLoader() {}

void KioskProfileLoader::Start() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  login_performer_.reset();
  cryptohomed_checker_.reset(new CryptohomedChecker(this));
  cryptohomed_checker_->StartCheck();
}

void KioskProfileLoader::LoginAsKioskAccount() {
  // Nuke old home that uses |app_id_| as cryptohome user id.
  // TODO(xiyuan): Remove this after all clients migrated to new home.
  cryptohome::AsyncMethodCaller::GetInstance()->AsyncRemove(
      app_id_,
      base::Bind(&IgnoreResult));

  // Nuke old home that uses non-canonicalized user id.
  // TODO(tengs): Remove this after all clients migrated to new home.
  cryptohome::AsyncMethodCaller::GetInstance()->AsyncRemove(
      GetOldUserId(user_id_),
      base::Bind(&IgnoreResult));

  login_performer_.reset(new LoginPerformer(this));
  login_performer_->LoginAsKioskAccount(user_id_);
}

void KioskProfileLoader::ReportLaunchResult(KioskAppLaunchError::Error error) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  if (error != KioskAppLaunchError::NONE) {
    delegate_->OnProfileLoadFailed(error);
  }
}

void KioskProfileLoader::OnLoginSuccess(const UserContext& user_context)  {
  // LoginPerformer will delete itself.
  login_performer_->set_delegate(NULL);
  ignore_result(login_performer_.release());

  LoginUtils::Get()->PrepareProfile(user_context,
                                    std::string(),  // display email
                                    false,  // has_cookies
                                    false,  // has_active_session
                                    this);
}

void KioskProfileLoader::OnLoginFailure(const LoginFailure& error) {
  ReportLaunchResult(LoginFailureToKioskAppLaunchError(error));
}

void KioskProfileLoader::WhiteListCheckFailed(const std::string& email) {
  NOTREACHED();
}

void KioskProfileLoader::PolicyLoadFailed() {
  ReportLaunchResult(KioskAppLaunchError::POLICY_LOAD_FAILED);
}

void KioskProfileLoader::OnOnlineChecked(
    const std::string& email, bool success) {
  NOTREACHED();
}

void KioskProfileLoader::OnProfilePrepared(Profile* profile) {
  // This object could be deleted any time after successfully reporting
  // a profile load, so invalidate the LoginUtils delegate now.
  LoginUtils::Get()->DelegateDeleted(this);

  delegate_->OnProfileLoaded(profile);
  ReportLaunchResult(KioskAppLaunchError::NONE);
}

}  // namespace chromeos
<|endoftext|>


<commit_before>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/dom_ui/shown_sections_handler.h"

#include "base/file_path.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/pref_service.h"
#include "chrome/common/pref_names.h"
#include "testing/gtest/include/gtest/gtest.h"

class ShownSectionsHandlerTest : public testing::Test {
};

TEST_F(ShownSectionsHandlerTest, MigrateUserPrefs) {
  PrefService pref((FilePath()));

  // Set an *old* value
  pref.RegisterIntegerPref(prefs::kNTPShownSections, 0);
  pref.SetInteger(prefs::kNTPShownSections, THUMB);

  ShownSectionsHandler::MigrateUserPrefs(&pref, 0, 1);

  int shown_sections = pref.GetInteger(prefs::kNTPShownSections);

  EXPECT_TRUE(shown_sections & THUMB);
  EXPECT_FALSE(shown_sections & LIST);
  EXPECT_FALSE(shown_sections & RECENT);
  EXPECT_TRUE(shown_sections & TIPS);
  EXPECT_TRUE(shown_sections & SYNC);
}

TEST_F(ShownSectionsHandlerTest, MigrateUserPrefs1To2) {
  PrefService pref(new JsonPrefStore(FilePath()));

  // Set an *old* value
  pref.RegisterIntegerPref(prefs::kNTPShownSections, 0);
  pref.SetInteger(prefs::kNTPShownSections, LIST);

  ShownSectionsHandler::MigrateUserPrefs(&pref, 1, 2);

  int shown_sections = pref.GetInteger(prefs::kNTPShownSections);

  EXPECT_TRUE(shown_sections & THUMB);
  EXPECT_FALSE(shown_sections & LIST);
}
<commit_msg>Revert 45169 - Fix compile error in ShownSectionsHandlerTest.<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/dom_ui/shown_sections_handler.h"

#include "base/file_path.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/pref_service.h"
#include "chrome/common/pref_names.h"
#include "testing/gtest/include/gtest/gtest.h"

class ShownSectionsHandlerTest : public testing::Test {
};

TEST_F(ShownSectionsHandlerTest, MigrateUserPrefs) {
  PrefService pref((FilePath()));

  // Set an *old* value
  pref.RegisterIntegerPref(prefs::kNTPShownSections, 0);
  pref.SetInteger(prefs::kNTPShownSections, THUMB);

  ShownSectionsHandler::MigrateUserPrefs(&pref, 0, 1);

  int shown_sections = pref.GetInteger(prefs::kNTPShownSections);

  EXPECT_TRUE(shown_sections & THUMB);
  EXPECT_FALSE(shown_sections & LIST);
  EXPECT_FALSE(shown_sections & RECENT);
  EXPECT_TRUE(shown_sections & TIPS);
  EXPECT_TRUE(shown_sections & SYNC);
}

TEST_F(ShownSectionsHandlerTest, MigrateUserPrefs1To2) {
  PrefService pref((FilePath()));

  // Set an *old* value
  pref.RegisterIntegerPref(prefs::kNTPShownSections, 0);
  pref.SetInteger(prefs::kNTPShownSections, LIST);

  ShownSectionsHandler::MigrateUserPrefs(&pref, 1, 2);

  int shown_sections = pref.GetInteger(prefs::kNTPShownSections);

  EXPECT_TRUE(shown_sections & THUMB);
  EXPECT_FALSE(shown_sections & LIST);
}
<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/browser.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/ui_test_utils.h"
#include "net/base/mock_host_resolver.h"

class AppBackgroundPageApiTest : public ExtensionApiTest {
 public:
  void SetUpCommandLine(CommandLine* command_line) {
    ExtensionApiTest::SetUpCommandLine(command_line);
    command_line->AppendSwitch(switches::kDisablePopupBlocking);
  }
};

IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest, Basic) {
  host_resolver()->AddRule("a.com", "127.0.0.1");
  ASSERT_TRUE(test_server()->Start());

  LoadExtension(test_data_dir_.AppendASCII(
      "app_background_page/app_has_permission"));
  ASSERT_TRUE(RunExtensionTest("app_background_page/basic")) << message_;
}

IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest, LacksPermission) {
  host_resolver()->AddRule("a.com", "127.0.0.1");
  ASSERT_TRUE(test_server()->Start());

  LoadExtension(test_data_dir_.AppendASCII(
      "app_background_page/app_lacks_permission"));
  ASSERT_TRUE(RunExtensionTest("app_background_page/lacks_permission"))
      << message_;
}
<commit_msg>Disable failing Basic test that I broke.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/browser.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/ui_test_utils.h"
#include "net/base/mock_host_resolver.h"

class AppBackgroundPageApiTest : public ExtensionApiTest {
 public:
  void SetUpCommandLine(CommandLine* command_line) {
    ExtensionApiTest::SetUpCommandLine(command_line);
    command_line->AppendSwitch(switches::kDisablePopupBlocking);
  }
};

// TODO(mpcomplete): http://crbug.com/56091
IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest, DISABLED_Basic) {
  host_resolver()->AddRule("a.com", "127.0.0.1");
  ASSERT_TRUE(test_server()->Start());

  LoadExtension(test_data_dir_.AppendASCII(
      "app_background_page/app_has_permission"));
  ASSERT_TRUE(RunExtensionTest("app_background_page/basic")) << message_;
}

IN_PROC_BROWSER_TEST_F(AppBackgroundPageApiTest, LacksPermission) {
  host_resolver()->AddRule("a.com", "127.0.0.1");
  ASSERT_TRUE(test_server()->Start());

  LoadExtension(test_data_dir_.AppendASCII(
      "app_background_page/app_lacks_permission"));
  ASSERT_TRUE(RunExtensionTest("app_background_page/lacks_permission"))
      << message_;
}
<|endoftext|>


<commit_before>/**
 * \file
 * \brief ThreadPriorityChangeTestCase class implementation
 *
 * \author Copyright (C) 2014 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2014-11-19
 */

#include "ThreadPriorityChangeTestCase.hpp"

#include "SequenceAsserter.hpp"

#include "distortos/StaticThread.hpp"
#include "distortos/ThisThread.hpp"

namespace distortos
{

namespace test
{

namespace
{

/*---------------------------------------------------------------------------------------------------------------------+
| local constants
+---------------------------------------------------------------------------------------------------------------------*/

/// size of stack for test thread, bytes
constexpr size_t testThreadStackSize {192};

/// number of test threads
constexpr size_t totalThreads {10};

/*---------------------------------------------------------------------------------------------------------------------+
| local functions' declarations
+---------------------------------------------------------------------------------------------------------------------*/

void thread(SequenceAsserter& sequenceAsserter, unsigned int sequencePoint);

/*---------------------------------------------------------------------------------------------------------------------+
| local types
+---------------------------------------------------------------------------------------------------------------------*/

/// type of test thread
using TestThread = decltype(makeStaticThread<testThreadStackSize>({}, thread,
		std::ref(std::declval<SequenceAsserter&>()), std::declval<unsigned int>()));

/*---------------------------------------------------------------------------------------------------------------------+
| local functions
+---------------------------------------------------------------------------------------------------------------------*/

/**
 * \brief Test thread.
 *
 * Just marks the sequence point in SequenceAsserter.
 *
 * \param [in] sequenceAsserter is a reference to SequenceAsserter shared object
 * \param [in] sequencePoint is the sequence point of this instance
 */

void thread(SequenceAsserter& sequenceAsserter, const unsigned int sequencePoint)
{
	sequenceAsserter.sequencePoint(sequencePoint);
}

/**
 * \brief Builder of TestThread objects.
 *
 * \param [in] priority is the thread's priority
 * \param [in] sequenceAsserter is a reference to SequenceAsserter shared object
 * \param [in] sequencePoint is the sequence point of this instance
 *
 * \return constructed TestThread object
 */

TestThread makeTestThread(const uint8_t priority, SequenceAsserter& sequenceAsserter, const unsigned int sequencePoint)
{
	return makeStaticThread<testThreadStackSize>(priority, thread, std::ref(sequenceAsserter),
			static_cast<unsigned int>(sequencePoint));
}

}	// namespace

/*---------------------------------------------------------------------------------------------------------------------+
| private functions
+---------------------------------------------------------------------------------------------------------------------*/

bool ThreadPriorityChangeTestCase::Implementation::run_() const
{
	const auto thisThreadPriority = ThisThread::getPriority();
	const decltype(thisThreadPriority) testThreadPriority = thisThreadPriority / 2;

	if (thisThreadPriority - testThreadPriority < 3)	// difference required for this whole test to work
		return false;

	SequenceAsserter sequenceAsserter;

	std::array<TestThread, totalThreads> threads
	{{
			makeTestThread(testThreadPriority, sequenceAsserter, 4),	// change to same priority
			makeTestThread(testThreadPriority, sequenceAsserter, 0),	// rise
			makeTestThread(testThreadPriority, sequenceAsserter, 7),	// lower
			makeTestThread(testThreadPriority, sequenceAsserter, 8),	// lower with "always behind" mode
			makeTestThread(testThreadPriority, sequenceAsserter, 1),	// rise
			makeTestThread(testThreadPriority, sequenceAsserter, 5),	// change to same priority
			makeTestThread(testThreadPriority, sequenceAsserter, 2),	// rise
			makeTestThread(testThreadPriority, sequenceAsserter, 6),	// lower
			makeTestThread(testThreadPriority, sequenceAsserter, 9),	// lower with "always behind" mode
			makeTestThread(testThreadPriority, sequenceAsserter, 3),	// rise
	}};

	for (auto& thread : threads)
		thread.start();

	threads[0].setPriority(threads[0].getPriority());
	threads[1].setPriority(threads[1].getPriority() + 2);
	threads[2].setPriority(threads[2].getPriority() - 2);
	threads[3].setPriority(threads[3].getPriority() - 2, true);
	threads[4].setPriority(threads[4].getPriority() + 2);
	threads[5].setPriority(threads[5].getPriority(), true);			// useless "always behind" mode
	threads[6].setPriority(threads[6].getPriority() + 2, true);		// useless "always behind" mode
	threads[7].setPriority(threads[7].getPriority() - 2, false);	// explicit "always before" mode
	threads[8].setPriority(threads[8].getPriority() - 2, true);
	threads[9].setPriority(threads[9].getPriority() + 2, true);		// useless "always behind" mode

	const auto result1 = sequenceAsserter.assertSequence(0);	// no thread finished
	ThisThread::setPriority(threads[1].getPriority() - 1);
	const auto result2 = sequenceAsserter.assertSequence(4);	// high priority threads finished
	ThisThread::setPriority(threads[0].getPriority() - 1);
	const auto result3 = sequenceAsserter.assertSequence(6);	// middle priority threads finished
	ThisThread::setPriority(threads[2].getPriority() - 1);

	for (auto& thread : threads)
		thread.join();

	ThisThread::setPriority(thisThreadPriority);

	if (result1 == false || result2 == false || result3 == false ||
			sequenceAsserter.assertSequence(totalThreads) == false)
		return false;

	return true;
}

}	// namespace test

}	// namespace distortos
<commit_msg>test: use static_assert() instead of "if ()" in ThreadPriorityChangeTestCase::Implementation::run_() - priority is changed/restored in PrioritizedTestCase now, so the test case has proper priority configured<commit_after>/**
 * \file
 * \brief ThreadPriorityChangeTestCase class implementation
 *
 * \author Copyright (C) 2014 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2014-11-19
 */

#include "ThreadPriorityChangeTestCase.hpp"

#include "SequenceAsserter.hpp"

#include "distortos/StaticThread.hpp"
#include "distortos/ThisThread.hpp"

namespace distortos
{

namespace test
{

namespace
{

/*---------------------------------------------------------------------------------------------------------------------+
| local constants
+---------------------------------------------------------------------------------------------------------------------*/

/// size of stack for test thread, bytes
constexpr size_t testThreadStackSize {192};

/// number of test threads
constexpr size_t totalThreads {10};

/*---------------------------------------------------------------------------------------------------------------------+
| local functions' declarations
+---------------------------------------------------------------------------------------------------------------------*/

void thread(SequenceAsserter& sequenceAsserter, unsigned int sequencePoint);

/*---------------------------------------------------------------------------------------------------------------------+
| local types
+---------------------------------------------------------------------------------------------------------------------*/

/// type of test thread
using TestThread = decltype(makeStaticThread<testThreadStackSize>({}, thread,
		std::ref(std::declval<SequenceAsserter&>()), std::declval<unsigned int>()));

/*---------------------------------------------------------------------------------------------------------------------+
| local functions
+---------------------------------------------------------------------------------------------------------------------*/

/**
 * \brief Test thread.
 *
 * Just marks the sequence point in SequenceAsserter.
 *
 * \param [in] sequenceAsserter is a reference to SequenceAsserter shared object
 * \param [in] sequencePoint is the sequence point of this instance
 */

void thread(SequenceAsserter& sequenceAsserter, const unsigned int sequencePoint)
{
	sequenceAsserter.sequencePoint(sequencePoint);
}

/**
 * \brief Builder of TestThread objects.
 *
 * \param [in] priority is the thread's priority
 * \param [in] sequenceAsserter is a reference to SequenceAsserter shared object
 * \param [in] sequencePoint is the sequence point of this instance
 *
 * \return constructed TestThread object
 */

TestThread makeTestThread(const uint8_t priority, SequenceAsserter& sequenceAsserter, const unsigned int sequencePoint)
{
	return makeStaticThread<testThreadStackSize>(priority, thread, std::ref(sequenceAsserter),
			static_cast<unsigned int>(sequencePoint));
}

}	// namespace

/*---------------------------------------------------------------------------------------------------------------------+
| private functions
+---------------------------------------------------------------------------------------------------------------------*/

bool ThreadPriorityChangeTestCase::Implementation::run_() const
{
	// difference required for this whole test to work
	static_assert(testCasePriority_ / 2 > 3, "Invalid test case priority");

	const auto thisThreadPriority = ThisThread::getPriority();
	const decltype(thisThreadPriority) testThreadPriority = thisThreadPriority / 2;

	SequenceAsserter sequenceAsserter;

	std::array<TestThread, totalThreads> threads
	{{
			makeTestThread(testThreadPriority, sequenceAsserter, 4),	// change to same priority
			makeTestThread(testThreadPriority, sequenceAsserter, 0),	// rise
			makeTestThread(testThreadPriority, sequenceAsserter, 7),	// lower
			makeTestThread(testThreadPriority, sequenceAsserter, 8),	// lower with "always behind" mode
			makeTestThread(testThreadPriority, sequenceAsserter, 1),	// rise
			makeTestThread(testThreadPriority, sequenceAsserter, 5),	// change to same priority
			makeTestThread(testThreadPriority, sequenceAsserter, 2),	// rise
			makeTestThread(testThreadPriority, sequenceAsserter, 6),	// lower
			makeTestThread(testThreadPriority, sequenceAsserter, 9),	// lower with "always behind" mode
			makeTestThread(testThreadPriority, sequenceAsserter, 3),	// rise
	}};

	for (auto& thread : threads)
		thread.start();

	threads[0].setPriority(threads[0].getPriority());
	threads[1].setPriority(threads[1].getPriority() + 2);
	threads[2].setPriority(threads[2].getPriority() - 2);
	threads[3].setPriority(threads[3].getPriority() - 2, true);
	threads[4].setPriority(threads[4].getPriority() + 2);
	threads[5].setPriority(threads[5].getPriority(), true);			// useless "always behind" mode
	threads[6].setPriority(threads[6].getPriority() + 2, true);		// useless "always behind" mode
	threads[7].setPriority(threads[7].getPriority() - 2, false);	// explicit "always before" mode
	threads[8].setPriority(threads[8].getPriority() - 2, true);
	threads[9].setPriority(threads[9].getPriority() + 2, true);		// useless "always behind" mode

	const auto result1 = sequenceAsserter.assertSequence(0);	// no thread finished
	ThisThread::setPriority(threads[1].getPriority() - 1);
	const auto result2 = sequenceAsserter.assertSequence(4);	// high priority threads finished
	ThisThread::setPriority(threads[0].getPriority() - 1);
	const auto result3 = sequenceAsserter.assertSequence(6);	// middle priority threads finished
	ThisThread::setPriority(threads[2].getPriority() - 1);

	for (auto& thread : threads)
		thread.join();

	ThisThread::setPriority(thisThreadPriority);

	if (result1 == false || result2 == false || result3 == false ||
			sequenceAsserter.assertSequence(totalThreads) == false)
		return false;

	return true;
}

}	// namespace test

}	// namespace distortos
<|endoftext|>


<commit_before>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/extensions/extension_message_service.h"
#include "chrome/common/render_messages.h"
#include "chrome/renderer/extensions/event_bindings.h"
#include "chrome/renderer/extensions/renderer_extension_bindings.h"
#include "chrome/test/render_view_test.h"
#include "testing/gtest/include/gtest/gtest.h"

static void DispatchOnConnect(int source_port_id, const std::string& name,
                              const std::string& tab_json) {
  ListValue args;
  args.Set(0, Value::CreateIntegerValue(source_port_id));
  args.Set(1, Value::CreateStringValue(name));
  args.Set(2, Value::CreateStringValue(tab_json));
  args.Set(3, Value::CreateStringValue(""));  // extension ID is empty for tests
  args.Set(4, Value::CreateStringValue(""));  // extension ID is empty for tests
  RendererExtensionBindings::Invoke(
      ExtensionMessageService::kDispatchOnConnect, args, NULL, false, GURL());
}

static void DispatchOnDisconnect(int source_port_id) {
  ListValue args;
  args.Set(0, Value::CreateIntegerValue(source_port_id));
  RendererExtensionBindings::Invoke(
      ExtensionMessageService::kDispatchOnDisconnect, args, NULL, false,
      GURL());
}

static void DispatchOnMessage(const std::string& message, int source_port_id) {
  ListValue args;
  args.Set(0, Value::CreateStringValue(message));
  args.Set(1, Value::CreateIntegerValue(source_port_id));
  RendererExtensionBindings::Invoke(
      ExtensionMessageService::kDispatchOnMessage, args, NULL, false, GURL());
}

// Tests that the bindings for opening a channel to an extension and sending
// and receiving messages through that channel all works.
TEST_F(RenderViewTest, ExtensionMessagesOpenChannel) {
  render_thread_.sink().ClearMessages();
  LoadHTML("");
  ExecuteJavaScript(
    "var port = chrome.extension.connect({name:'testName'});"
    "port.onMessage.addListener(doOnMessage);"
    "port.postMessage({message: 'content ready'});"
    "function doOnMessage(msg, port) {"
    "  alert('content got: ' + msg.val);"
    "}");

  // Verify that we opened a channel and sent a message through it.
  const IPC::Message* open_channel_msg =
      render_thread_.sink().GetUniqueMessageMatching(
          ViewHostMsg_OpenChannelToExtension::ID);
  ASSERT_TRUE(open_channel_msg);
  void* iter = IPC::SyncMessage::GetDataIterator(open_channel_msg);
  ViewHostMsg_OpenChannelToExtension::SendParam open_params;
  ASSERT_TRUE(IPC::ReadParam(open_channel_msg, &iter, &open_params));
  EXPECT_EQ("testName", open_params.d);

  const IPC::Message* post_msg =
      render_thread_.sink().GetUniqueMessageMatching(
          ViewHostMsg_ExtensionPostMessage::ID);
  ASSERT_TRUE(post_msg);
  ViewHostMsg_ExtensionPostMessage::Param post_params;
  ViewHostMsg_ExtensionPostMessage::Read(post_msg, &post_params);
  EXPECT_EQ("{\"message\":\"content ready\"}", post_params.b);

  // Now simulate getting a message back from the other side.
  render_thread_.sink().ClearMessages();
  const int kPortId = 0;
  DispatchOnMessage("{\"val\": 42}", kPortId);

  // Verify that we got it.
  const IPC::Message* alert_msg =
      render_thread_.sink().GetUniqueMessageMatching(
          ViewHostMsg_RunJavaScriptMessage::ID);
  ASSERT_TRUE(alert_msg);
  iter = IPC::SyncMessage::GetDataIterator(alert_msg);
  ViewHostMsg_RunJavaScriptMessage::SendParam alert_param;
  ASSERT_TRUE(IPC::ReadParam(alert_msg, &iter, &alert_param));
  EXPECT_EQ(L"content got: 42", alert_param.a);
}

// Tests that the bindings for handling a new channel connection and channel
// closing all works.
TEST_F(RenderViewTest, ExtensionMessagesOnConnect) {
  LoadHTML("");
  ExecuteJavaScript(
    "chrome.extension.onConnect.addListener(function (port) {"
    "  port.test = 24;"
    "  port.onMessage.addListener(doOnMessage);"
    "  port.onDisconnect.addListener(doOnDisconnect);"
    "  port.postMessage({message: 'onconnect from ' + port.tab.url + "
    "                   ' name ' + port.name});"
    "});"
    "function doOnMessage(msg, port) {"
    "  alert('got: ' + msg.val);"
    "}"
    "function doOnDisconnect(port) {"
    "  alert('disconnected: ' + port.test);"
    "}");

  render_thread_.sink().ClearMessages();

  // Simulate a new connection being opened.
  const int kPortId = 0;
  const std::string kPortName = "testName";
  DispatchOnConnect(kPortId, kPortName, "{\"url\":\"foo://bar\"}");

  // Verify that we handled the new connection by posting a message.
  const IPC::Message* post_msg =
      render_thread_.sink().GetUniqueMessageMatching(
          ViewHostMsg_ExtensionPostMessage::ID);
  ASSERT_TRUE(post_msg);
  ViewHostMsg_ExtensionPostMessage::Param post_params;
  ViewHostMsg_ExtensionPostMessage::Read(post_msg, &post_params);
  std::string expected_msg =
      "{\"message\":\"onconnect from foo://bar name " + kPortName + "\"}";
  EXPECT_EQ(expected_msg, post_params.b);

  // Now simulate getting a message back from the channel opener.
  render_thread_.sink().ClearMessages();
  DispatchOnMessage("{\"val\": 42}", kPortId);

  // Verify that we got it.
  const IPC::Message* alert_msg =
      render_thread_.sink().GetUniqueMessageMatching(
          ViewHostMsg_RunJavaScriptMessage::ID);
  ASSERT_TRUE(alert_msg);
  void* iter = IPC::SyncMessage::GetDataIterator(alert_msg);
  ViewHostMsg_RunJavaScriptMessage::SendParam alert_param;
  ASSERT_TRUE(IPC::ReadParam(alert_msg, &iter, &alert_param));
  EXPECT_EQ(L"got: 42", alert_param.a);

  // Now simulate the channel closing.
  render_thread_.sink().ClearMessages();
  DispatchOnDisconnect(kPortId);

  // Verify that we got it.
  alert_msg =
      render_thread_.sink().GetUniqueMessageMatching(
          ViewHostMsg_RunJavaScriptMessage::ID);
  ASSERT_TRUE(alert_msg);
  iter = IPC::SyncMessage::GetDataIterator(alert_msg);
  ASSERT_TRUE(IPC::ReadParam(alert_msg, &iter, &alert_param));
  EXPECT_EQ(L"disconnected: 24", alert_param.a);
}
<commit_msg>Disable RenderViewTest.ExtensionMessages* since they consistently crash localy and on the bots.<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/extensions/extension_message_service.h"
#include "chrome/common/render_messages.h"
#include "chrome/renderer/extensions/event_bindings.h"
#include "chrome/renderer/extensions/renderer_extension_bindings.h"
#include "chrome/test/render_view_test.h"
#include "testing/gtest/include/gtest/gtest.h"

static void DispatchOnConnect(int source_port_id, const std::string& name,
                              const std::string& tab_json) {
  ListValue args;
  args.Set(0, Value::CreateIntegerValue(source_port_id));
  args.Set(1, Value::CreateStringValue(name));
  args.Set(2, Value::CreateStringValue(tab_json));
  args.Set(3, Value::CreateStringValue(""));  // extension ID is empty for tests
  args.Set(4, Value::CreateStringValue(""));  // extension ID is empty for tests
  RendererExtensionBindings::Invoke(
      ExtensionMessageService::kDispatchOnConnect, args, NULL, false, GURL());
}

static void DispatchOnDisconnect(int source_port_id) {
  ListValue args;
  args.Set(0, Value::CreateIntegerValue(source_port_id));
  RendererExtensionBindings::Invoke(
      ExtensionMessageService::kDispatchOnDisconnect, args, NULL, false,
      GURL());
}

static void DispatchOnMessage(const std::string& message, int source_port_id) {
  ListValue args;
  args.Set(0, Value::CreateStringValue(message));
  args.Set(1, Value::CreateIntegerValue(source_port_id));
  RendererExtensionBindings::Invoke(
      ExtensionMessageService::kDispatchOnMessage, args, NULL, false, GURL());
}

// Tests that the bindings for opening a channel to an extension and sending
// and receiving messages through that channel all works.
TEST_F(RenderViewTest, DISABLED_ExtensionMessagesOpenChannel) {
  render_thread_.sink().ClearMessages();
  LoadHTML("");
  ExecuteJavaScript(
    "var port = chrome.extension.connect({name:'testName'});"
    "port.onMessage.addListener(doOnMessage);"
    "port.postMessage({message: 'content ready'});"
    "function doOnMessage(msg, port) {"
    "  alert('content got: ' + msg.val);"
    "}");

  // Verify that we opened a channel and sent a message through it.
  const IPC::Message* open_channel_msg =
      render_thread_.sink().GetUniqueMessageMatching(
          ViewHostMsg_OpenChannelToExtension::ID);
  ASSERT_TRUE(open_channel_msg);
  void* iter = IPC::SyncMessage::GetDataIterator(open_channel_msg);
  ViewHostMsg_OpenChannelToExtension::SendParam open_params;
  ASSERT_TRUE(IPC::ReadParam(open_channel_msg, &iter, &open_params));
  EXPECT_EQ("testName", open_params.d);

  const IPC::Message* post_msg =
      render_thread_.sink().GetUniqueMessageMatching(
          ViewHostMsg_ExtensionPostMessage::ID);
  ASSERT_TRUE(post_msg);
  ViewHostMsg_ExtensionPostMessage::Param post_params;
  ViewHostMsg_ExtensionPostMessage::Read(post_msg, &post_params);
  EXPECT_EQ("{\"message\":\"content ready\"}", post_params.b);

  // Now simulate getting a message back from the other side.
  render_thread_.sink().ClearMessages();
  const int kPortId = 0;
  DispatchOnMessage("{\"val\": 42}", kPortId);

  // Verify that we got it.
  const IPC::Message* alert_msg =
      render_thread_.sink().GetUniqueMessageMatching(
          ViewHostMsg_RunJavaScriptMessage::ID);
  ASSERT_TRUE(alert_msg);
  iter = IPC::SyncMessage::GetDataIterator(alert_msg);
  ViewHostMsg_RunJavaScriptMessage::SendParam alert_param;
  ASSERT_TRUE(IPC::ReadParam(alert_msg, &iter, &alert_param));
  EXPECT_EQ(L"content got: 42", alert_param.a);
}

// Tests that the bindings for handling a new channel connection and channel
// closing all works.
TEST_F(RenderViewTest, DISABLED_ExtensionMessagesOnConnect) {
  LoadHTML("");
  ExecuteJavaScript(
    "chrome.extension.onConnect.addListener(function (port) {"
    "  port.test = 24;"
    "  port.onMessage.addListener(doOnMessage);"
    "  port.onDisconnect.addListener(doOnDisconnect);"
    "  port.postMessage({message: 'onconnect from ' + port.tab.url + "
    "                   ' name ' + port.name});"
    "});"
    "function doOnMessage(msg, port) {"
    "  alert('got: ' + msg.val);"
    "}"
    "function doOnDisconnect(port) {"
    "  alert('disconnected: ' + port.test);"
    "}");

  render_thread_.sink().ClearMessages();

  // Simulate a new connection being opened.
  const int kPortId = 0;
  const std::string kPortName = "testName";
  DispatchOnConnect(kPortId, kPortName, "{\"url\":\"foo://bar\"}");

  // Verify that we handled the new connection by posting a message.
  const IPC::Message* post_msg =
      render_thread_.sink().GetUniqueMessageMatching(
          ViewHostMsg_ExtensionPostMessage::ID);
  ASSERT_TRUE(post_msg);
  ViewHostMsg_ExtensionPostMessage::Param post_params;
  ViewHostMsg_ExtensionPostMessage::Read(post_msg, &post_params);
  std::string expected_msg =
      "{\"message\":\"onconnect from foo://bar name " + kPortName + "\"}";
  EXPECT_EQ(expected_msg, post_params.b);

  // Now simulate getting a message back from the channel opener.
  render_thread_.sink().ClearMessages();
  DispatchOnMessage("{\"val\": 42}", kPortId);

  // Verify that we got it.
  const IPC::Message* alert_msg =
      render_thread_.sink().GetUniqueMessageMatching(
          ViewHostMsg_RunJavaScriptMessage::ID);
  ASSERT_TRUE(alert_msg);
  void* iter = IPC::SyncMessage::GetDataIterator(alert_msg);
  ViewHostMsg_RunJavaScriptMessage::SendParam alert_param;
  ASSERT_TRUE(IPC::ReadParam(alert_msg, &iter, &alert_param));
  EXPECT_EQ(L"got: 42", alert_param.a);

  // Now simulate the channel closing.
  render_thread_.sink().ClearMessages();
  DispatchOnDisconnect(kPortId);

  // Verify that we got it.
  alert_msg =
      render_thread_.sink().GetUniqueMessageMatching(
          ViewHostMsg_RunJavaScriptMessage::ID);
  ASSERT_TRUE(alert_msg);
  iter = IPC::SyncMessage::GetDataIterator(alert_msg);
  ASSERT_TRUE(IPC::ReadParam(alert_msg, &iter, &alert_param));
  EXPECT_EQ(L"disconnected: 24", alert_param.a);
}
<|endoftext|>


<commit_before>// @(#)root/hist:$Name:  $:$Id: TLimit.cxx,v 1.2 2002/09/06 20:24:18 brun Exp $
// Author: Christophe.Delaere@cern.ch   21/08/2002

///////////////////////////////////////////////////////////////////////////
//
// TLimit
//
// Class to compute 95% CL limits
//
///////////////////////////////////////////////////////////////////////////

/*************************************************************************
 * C.Delaere                                                             *
 * adapted from the mclimit code from Tom Junk                           *
 * see http://cern.ch/thomasj/searchlimits/ecl.html                      *
 *************************************************************************/

#include "TLimit.h"
#include "TArrayF.h"
#include "TOrdCollection.h"
#include "TConfidenceLevel.h"
#include "TLimitDataSource.h"
#include "TRandom3.h"
#include "TH1.h"
#include "TObjArray.h"
#include "TMath.h"
#include "TIterator.h"
#include "TObjString.h"
#include "TClassTable.h"
#include "Riostream.h"

ClassImp(TLimit)

TArrayF *TLimit::fgTable = new TArrayF(0);
TOrdCollection *TLimit::fgSystNames = new TOrdCollection();

TConfidenceLevel *TLimit::ComputeLimit(TLimitDataSource * data,
                                       Int_t nmc, TRandom * generator,
                                       Double_t(*statistic) (Double_t,
                                                             Double_t,
                                                             Double_t))
{
   // class TLimit
   // ------------
   //
   // Algorithm to compute 95% C.L. limits using the Likelihood ratio
   // semi-bayesian method.
   // It takes signal, background and data histograms wrapped in a
   // TLimitDataSource as input and runs a set of Monte Carlo experiments in
   // order to compute the limits. If needed, inputs are fluctuated according
   // to systematics. The output is a TConfidenceLevel.
   //
   // class TLimitDataSource
   // ----------------------
   //
   // Takes the signal, background and data histograms as well as different
   // systematics sources to form the TLimit input.
   //
   //  class TConfidenceLevel
   //  ----------------------
   //
   // Final result of the TLimit algorithm. It is created just after the
   // time-consuming part and can be stored in a TFile for further processing.
   // It contains light methods to return CLs, CLb and other interesting
   // quantities.
   //
   // The actual algorithm...
   // From an input (TLimitDataSource) it produces an output TConfidenceLevel.
   // For this, nmc Monte Carlo experiments are performed.
   // As usual, the larger this number, the longer the compute time,
   // but the better the result.
   //Begin_Html
   /*

Supposing that there is a plotfile.root file containing 3 histograms
           (signal, background and data), you can imagine doing things like:

    TFile* infile=new TFile("plotfile.root","READ");
    infile->cd();
    TH1F* sh=(TH1F*)infile->Get("signal");
    TH1F* bh=(TH1F*)infile->Get("background");
    TH1F* dh=(TH1F*)infile->Get("data");
    TLimitDataSource* mydatasource = new TLimitDataSource(sh,bh,dh);
    TConfidenceLevel *myconfidence = TLimit::ComputeLimit(mydatasource,50000);
    cout &lt&lt "  CLs    : " &lt&lt myconfidence->CLs()  &lt&lt endl;
    cout &lt&lt "  CLsb   : " &lt&lt myconfidence->CLsb() &lt&lt endl;
    cout &lt&lt "  CLb    : " &lt&lt myconfidence->CLb()  &lt&lt endl;
    cout &lt&lt "&lt CLs &gt  : " &lt&lt myconfidence->GetExpectedCLs_b()  &lt&lt endl;
    cout &lt&lt "&lt CLsb &gt : " &lt&lt myconfidence->GetExpectedCLsb_b() &lt&lt endl;
    cout &lt&lt "&lt CLb &gt  : " &lt&lt myconfidence->GetExpectedCLb_b()  &lt&lt endl;
    delete myconfidence;
    delete mydatasource;
    infile->Close();

More informations can still be found on
   this page.

   */
   //End_Html

   // The final object returned...
   TConfidenceLevel *result = new TConfidenceLevel(nmc);
   // The random generator used...
   TRandom *myrandom = generator ? generator : new TRandom3;
   // Compute some total quantities on all the channels
   Int_t nbins   = 0;
   Int_t maxbins = 0;
   Double_t nsig = 0;
   Double_t nbg  = 0;
   Int_t ncand   = 0;
   Int_t i;
   for (i = 0; i <= data->GetSignal()->GetLast(); i++) {
      nbins  += ((TH1F *) (data->GetSignal()->At(i)))->GetNbinsX();
      maxbins = ((TH1F *) (data->GetSignal()->At(i)))->GetNbinsX() > maxbins ?
	        ((TH1F *) (data->GetSignal()->At(i)))->GetNbinsX() + 1 : maxbins;
      nsig   += ((TH1F *) (data->GetSignal()->At(i)))->Integral();
      nbg    += ((TH1F *) (data->GetBackground()->At(i)))->Integral();
      ncand  += (Int_t) ((TH1F *) (data->GetCandidates()->At(i)))->Integral();
   }
   result->SetBtot(nbg);
   result->SetStot(nsig);
   result->SetDtot(ncand);
   Double_t buffer = 0;
   fgTable->Set(maxbins * (data->GetSignal()->GetLast() + 1));
   for (Int_t channel = 0; channel <= data->GetSignal()->GetLast(); channel++)
      for (Int_t bin = 0;
           bin <= ((TH1F *) (data->GetSignal()->At(channel)))->GetNbinsX();
           bin++) {
         Double_t s = (Double_t) ((TH1F *) (data->GetSignal()->At(channel)))->GetBinContent(bin);
         Double_t b = (Double_t) ((TH1F *) (data->GetBackground()->At(channel)))->GetBinContent(bin);
         Double_t d = (Double_t) ((TH1F *) (data->GetCandidates()->At(channel)))->GetBinContent(bin);
         // Compute the value of the "-2lnQ" for the actual data
         if ((b == 0) && (s > 0)) {
            cout << "WARNING: Ignoring bin " << bin << " of channel "
                 << channel << " which has s=" << s << " but b=" << b << endl;
            cout << "         Maybe the MC statistic has to be improved..." << endl;
         }
         if ((s > 0) && (b > 0))
            buffer += statistic(s, b, d);
         // precompute the log(1+s/b)'s in an array to speed up computation
         // background-free bins are set to have a maximum t.s. value
         // for protection (corresponding to s/b of about 5E8)
         if ((s > 0) && (b > 0))
            fgTable->AddAt(statistic(s, b, 1), (channel * maxbins) + bin);
         else if ((s > 0) && (b == 0))
            fgTable->AddAt(20, (channel * maxbins) + bin);
      }
   result->SetTSD(buffer);
   // accumulate MC experiments.  Hold the test statistic function fixed, but
   // fluctuate s and b within syst. errors for computing probabilities of
   // having that outcome.  (Alex Read's prescription -- errors are on the ensemble,
   // not on the observed test statistic.  This technique does not split outcomes.)
   // keep the tstats as sum log(1+s/b). convert to -2lnQ when preparing the results
   // (reason -- like to keep the < signs right)
   Double_t *tss = new Double_t[nmc];
   Double_t *tsb = new Double_t[nmc];
   Double_t *lrs = new Double_t[nmc];
   Double_t *lrb = new Double_t[nmc];
   for (i = 0; i < nmc; i++) {
      tss[i] = 0;
      tsb[i] = 0;
      lrs[i] = 0;
      lrb[i] = 0;
      // fluctuate signal and background
      TLimitDataSource *fluctuated = Fluctuate(data, !i, myrandom);
      for (Int_t channel = 0;
           channel <= fluctuated->GetSignal()->GetLast(); channel++) {
         for (Int_t bin = 0;
              bin <=((TH1F *) (fluctuated->GetSignal()->At(channel)))->GetNbinsX();
              bin++) {
            if ((Double_t) ((TH1F *) (fluctuated->GetSignal()->At(channel)))->GetBinContent(bin) != 0) {
               // s+b hypothesis
               Double_t rate = (Double_t) ((TH1F *) (fluctuated->GetSignal()->At(channel)))->GetBinContent(bin) +
                               (Double_t) ((TH1F *) (fluctuated->GetBackground()->At(channel)))->GetBinContent(bin);
               Double_t rand = myrandom->Poisson(rate);
               tss[i] += rand * fgTable->At((channel * maxbins) + bin);
               Double_t s = (Double_t) ((TH1F *) (fluctuated->GetSignal()->At(channel)))->GetBinContent(bin);
               Double_t b = (Double_t) ((TH1F *) (fluctuated->GetBackground()->At(channel)))->GetBinContent(bin);
               if ((s > 0) && (b > 0))
                  lrs[i] += statistic(s, b, rand) - s;
               else if ((s > 0) && (b = 0))
                  lrs[i] += 20 * rand - s;
               // b hypothesis
               rate = (Double_t) ((TH1F *) (fluctuated->GetBackground()->At(channel)))->GetBinContent(bin);
               rand = myrandom->Poisson(rate);
               tsb[i] += rand * fgTable->At((channel * maxbins) + bin);
               if ((s > 0) && (b > 0))
                  lrb[i] += statistic(s, b, rand) - s;
               else if ((s > 0) && (b = 0))
                  lrb[i] += 20 * rand - s;
            }
         }
      }
      lrs[i] = TMath::Exp(lrs[i]);
      lrb[i] = TMath::Exp(lrb[i]);
      if (data != fluctuated)
         delete fluctuated;
   }
   // lrs and lrb are the LR's (no logs) = prob(s+b)/prob(b) for
   // that choice of s and b within syst. errors in the ensemble.  These are
   // the MC experiment weights for relating the s+b and b PDF's of the unsmeared
   // test statistic (in which cas one can use another test statistic if one likes).

   // Now produce the output object.
   // The final quantities are computed on-demand form the arrays tss, tsb, lrs and lrb.
   result->SetTSS(tss);
   result->SetTSB(tsb);
   result->SetLRS(lrs);
   result->SetLRB(lrb);
   if (!generator)
      delete myrandom;
   return result;
}

TLimitDataSource *TLimit::Fluctuate(TLimitDataSource * input, bool init,
                                    TRandom * generator)
{
   // initialisation: create a sorted list of all the names of systematics
   if (init) {
      // create a "map" with the systematics names
      TIterator *errornames = input->GetErrorNames()->MakeIterator();
      TObjArray *listofnames = 0;
      while ((listofnames = ((TObjArray *) errornames->Next()))) {
         TObjString *name = NULL;
         TIterator *loniter = listofnames->MakeIterator();
         while ((name = (TObjString *) (loniter->Next())))
            if ((fgSystNames->IndexOf(name)) < 0)
               fgSystNames->AddLast(name);
      }
      fgSystNames->Sort();
   }
   // if there are no systematics, just returns the input as "fluctuated" output
   if (fgSystNames->GetSize() <= 0)
      return input;
   // Find a choice for the random variation and
   // re-toss all random numbers if any background or signal
   // goes negative.  (background = 0 is bad too, so put a little protection
   // around it -- must have at least 10% of the bg estimate).
   bool retoss = kTRUE;
   Double_t *serrf = NULL;
   Double_t *berrf = NULL;
   do {
      Double_t *toss = new Double_t[fgSystNames->GetSize()];
      for (Int_t i = 0; i < fgSystNames->GetSize(); i++)
         toss[i] = generator->Gaus(0, 1);
      retoss = kFALSE;
      serrf = new Double_t[(input->GetSignal()->GetLast()) + 1];
      berrf = new Double_t[(input->GetSignal()->GetLast()) + 1];
      for (Int_t channel = 0;
           channel <= input->GetSignal()->GetLast();
           channel++) {
         serrf[channel] = 0;
         berrf[channel] = 0;
         for (Int_t bin = 0;
              bin <=((TH1F *) (input->GetErrorOnSignal()->At(channel)))->GetNbinsX();
	      bin++) {
            serrf[channel] += ((TH1F *) (input->GetErrorOnSignal()->At(channel)))->GetBinContent(bin) *
                toss[fgSystNames->BinarySearch((TObjString*) (((TObjArray *) (input->GetErrorNames()->At(channel)))->At(bin)))];
            berrf[channel] += ((TH1F *) (input->GetErrorOnBackground()->At(channel)))->GetBinContent(bin) *
                toss[fgSystNames->BinarySearch((TObjString*) (((TObjArray *) (input->GetErrorNames()->At(channel)))->At(bin)))];
         }
         if ((serrf[channel] < -1.0) || (berrf[channel] < -0.9)) {
            retoss = kTRUE;
            continue;
         }
      }
      delete[]toss;
   } while (retoss);
   // adjust the fluctuated signal and background counts with a legal set
   // of random fluctuations above.
   TLimitDataSource *result = new TLimitDataSource();
   result->SetOwner();
   for (Int_t channel = 0; channel <= input->GetSignal()->GetLast();
        channel++) {
      TH1F *newsignal = new TH1F(*(TH1F *) (input->GetSignal()->At(channel)));
      newsignal->Scale(1 + serrf[channel]);
      newsignal->SetDirectory(0);
      TH1F *newbackground = new TH1F(*(TH1F *) (input->GetBackground()->At(channel)));
      newbackground->Scale(1 + berrf[channel]);
      newbackground->SetDirectory(0);
      TH1F *newcandidates = new TH1F(*(TH1F *) (input->GetCandidates()));
      newcandidates->SetDirectory(0);
      result->AddChannel(newsignal, newbackground, newcandidates);
   }
   delete[] serrf;
   delete[] berrf;
   return result;
}

<commit_msg>change (b = 0) to (b == 0) in if statement.<commit_after>// @(#)root/hist:$Name:  $:$Id: TLimit.cxx,v 1.3 2002/09/06 21:41:23 brun Exp $
// Author: Christophe.Delaere@cern.ch   21/08/2002

///////////////////////////////////////////////////////////////////////////
//
// TLimit
//
// Class to compute 95% CL limits
//
///////////////////////////////////////////////////////////////////////////

/*************************************************************************
 * C.Delaere                                                             *
 * adapted from the mclimit code from Tom Junk                           *
 * see http://cern.ch/thomasj/searchlimits/ecl.html                      *
 *************************************************************************/

#include "TLimit.h"
#include "TArrayF.h"
#include "TOrdCollection.h"
#include "TConfidenceLevel.h"
#include "TLimitDataSource.h"
#include "TRandom3.h"
#include "TH1.h"
#include "TObjArray.h"
#include "TMath.h"
#include "TIterator.h"
#include "TObjString.h"
#include "TClassTable.h"
#include "Riostream.h"

ClassImp(TLimit)

TArrayF *TLimit::fgTable = new TArrayF(0);
TOrdCollection *TLimit::fgSystNames = new TOrdCollection();

TConfidenceLevel *TLimit::ComputeLimit(TLimitDataSource * data,
                                       Int_t nmc, TRandom * generator,
                                       Double_t(*statistic) (Double_t,
                                                             Double_t,
                                                             Double_t))
{
   // class TLimit
   // ------------
   //
   // Algorithm to compute 95% C.L. limits using the Likelihood ratio
   // semi-bayesian method.
   // It takes signal, background and data histograms wrapped in a
   // TLimitDataSource as input and runs a set of Monte Carlo experiments in
   // order to compute the limits. If needed, inputs are fluctuated according
   // to systematics. The output is a TConfidenceLevel.
   //
   // class TLimitDataSource
   // ----------------------
   //
   // Takes the signal, background and data histograms as well as different
   // systematics sources to form the TLimit input.
   //
   //  class TConfidenceLevel
   //  ----------------------
   //
   // Final result of the TLimit algorithm. It is created just after the
   // time-consuming part and can be stored in a TFile for further processing.
   // It contains light methods to return CLs, CLb and other interesting
   // quantities.
   //
   // The actual algorithm...
   // From an input (TLimitDataSource) it produces an output TConfidenceLevel.
   // For this, nmc Monte Carlo experiments are performed.
   // As usual, the larger this number, the longer the compute time,
   // but the better the result.
   //Begin_Html
   /*

Supposing that there is a plotfile.root file containing 3 histograms
           (signal, background and data), you can imagine doing things like:

    TFile* infile=new TFile("plotfile.root","READ");
    infile->cd();
    TH1F* sh=(TH1F*)infile->Get("signal");
    TH1F* bh=(TH1F*)infile->Get("background");
    TH1F* dh=(TH1F*)infile->Get("data");
    TLimitDataSource* mydatasource = new TLimitDataSource(sh,bh,dh);
    TConfidenceLevel *myconfidence = TLimit::ComputeLimit(mydatasource,50000);
    cout &lt&lt "  CLs    : " &lt&lt myconfidence->CLs()  &lt&lt endl;
    cout &lt&lt "  CLsb   : " &lt&lt myconfidence->CLsb() &lt&lt endl;
    cout &lt&lt "  CLb    : " &lt&lt myconfidence->CLb()  &lt&lt endl;
    cout &lt&lt "&lt CLs &gt  : " &lt&lt myconfidence->GetExpectedCLs_b()  &lt&lt endl;
    cout &lt&lt "&lt CLsb &gt : " &lt&lt myconfidence->GetExpectedCLsb_b() &lt&lt endl;
    cout &lt&lt "&lt CLb &gt  : " &lt&lt myconfidence->GetExpectedCLb_b()  &lt&lt endl;
    delete myconfidence;
    delete mydatasource;
    infile->Close();

More informations can still be found on
   this page.

   */
   //End_Html

   // The final object returned...
   TConfidenceLevel *result = new TConfidenceLevel(nmc);
   // The random generator used...
   TRandom *myrandom = generator ? generator : new TRandom3;
   // Compute some total quantities on all the channels
   Int_t nbins   = 0;
   Int_t maxbins = 0;
   Double_t nsig = 0;
   Double_t nbg  = 0;
   Int_t ncand   = 0;
   Int_t i;
   for (i = 0; i <= data->GetSignal()->GetLast(); i++) {
      nbins  += ((TH1F *) (data->GetSignal()->At(i)))->GetNbinsX();
      maxbins = ((TH1F *) (data->GetSignal()->At(i)))->GetNbinsX() > maxbins ?
	        ((TH1F *) (data->GetSignal()->At(i)))->GetNbinsX() + 1 : maxbins;
      nsig   += ((TH1F *) (data->GetSignal()->At(i)))->Integral();
      nbg    += ((TH1F *) (data->GetBackground()->At(i)))->Integral();
      ncand  += (Int_t) ((TH1F *) (data->GetCandidates()->At(i)))->Integral();
   }
   result->SetBtot(nbg);
   result->SetStot(nsig);
   result->SetDtot(ncand);
   Double_t buffer = 0;
   fgTable->Set(maxbins * (data->GetSignal()->GetLast() + 1));
   for (Int_t channel = 0; channel <= data->GetSignal()->GetLast(); channel++)
      for (Int_t bin = 0;
           bin <= ((TH1F *) (data->GetSignal()->At(channel)))->GetNbinsX();
           bin++) {
         Double_t s = (Double_t) ((TH1F *) (data->GetSignal()->At(channel)))->GetBinContent(bin);
         Double_t b = (Double_t) ((TH1F *) (data->GetBackground()->At(channel)))->GetBinContent(bin);
         Double_t d = (Double_t) ((TH1F *) (data->GetCandidates()->At(channel)))->GetBinContent(bin);
         // Compute the value of the "-2lnQ" for the actual data
         if ((b == 0) && (s > 0)) {
            cout << "WARNING: Ignoring bin " << bin << " of channel "
                 << channel << " which has s=" << s << " but b=" << b << endl;
            cout << "         Maybe the MC statistic has to be improved..." << endl;
         }
         if ((s > 0) && (b > 0))
            buffer += statistic(s, b, d);
         // precompute the log(1+s/b)'s in an array to speed up computation
         // background-free bins are set to have a maximum t.s. value
         // for protection (corresponding to s/b of about 5E8)
         if ((s > 0) && (b > 0))
            fgTable->AddAt(statistic(s, b, 1), (channel * maxbins) + bin);
         else if ((s > 0) && (b == 0))
            fgTable->AddAt(20, (channel * maxbins) + bin);
      }
   result->SetTSD(buffer);
   // accumulate MC experiments.  Hold the test statistic function fixed, but
   // fluctuate s and b within syst. errors for computing probabilities of
   // having that outcome.  (Alex Read's prescription -- errors are on the ensemble,
   // not on the observed test statistic.  This technique does not split outcomes.)
   // keep the tstats as sum log(1+s/b). convert to -2lnQ when preparing the results
   // (reason -- like to keep the < signs right)
   Double_t *tss = new Double_t[nmc];
   Double_t *tsb = new Double_t[nmc];
   Double_t *lrs = new Double_t[nmc];
   Double_t *lrb = new Double_t[nmc];
   for (i = 0; i < nmc; i++) {
      tss[i] = 0;
      tsb[i] = 0;
      lrs[i] = 0;
      lrb[i] = 0;
      // fluctuate signal and background
      TLimitDataSource *fluctuated = Fluctuate(data, !i, myrandom);
      for (Int_t channel = 0;
           channel <= fluctuated->GetSignal()->GetLast(); channel++) {
         for (Int_t bin = 0;
              bin <=((TH1F *) (fluctuated->GetSignal()->At(channel)))->GetNbinsX();
              bin++) {
            if ((Double_t) ((TH1F *) (fluctuated->GetSignal()->At(channel)))->GetBinContent(bin) != 0) {
               // s+b hypothesis
               Double_t rate = (Double_t) ((TH1F *) (fluctuated->GetSignal()->At(channel)))->GetBinContent(bin) +
                               (Double_t) ((TH1F *) (fluctuated->GetBackground()->At(channel)))->GetBinContent(bin);
               Double_t rand = myrandom->Poisson(rate);
               tss[i] += rand * fgTable->At((channel * maxbins) + bin);
               Double_t s = (Double_t) ((TH1F *) (fluctuated->GetSignal()->At(channel)))->GetBinContent(bin);
               Double_t b = (Double_t) ((TH1F *) (fluctuated->GetBackground()->At(channel)))->GetBinContent(bin);
               if ((s > 0) && (b > 0))
                  lrs[i] += statistic(s, b, rand) - s;
               else if ((s > 0) && (b == 0))
                  lrs[i] += 20 * rand - s;
               // b hypothesis
               rate = (Double_t) ((TH1F *) (fluctuated->GetBackground()->At(channel)))->GetBinContent(bin);
               rand = myrandom->Poisson(rate);
               tsb[i] += rand * fgTable->At((channel * maxbins) + bin);
               if ((s > 0) && (b > 0))
                  lrb[i] += statistic(s, b, rand) - s;
               else if ((s > 0) && (b == 0))
                  lrb[i] += 20 * rand - s;
            }
         }
      }
      lrs[i] = TMath::Exp(lrs[i]);
      lrb[i] = TMath::Exp(lrb[i]);
      if (data != fluctuated)
         delete fluctuated;
   }
   // lrs and lrb are the LR's (no logs) = prob(s+b)/prob(b) for
   // that choice of s and b within syst. errors in the ensemble.  These are
   // the MC experiment weights for relating the s+b and b PDF's of the unsmeared
   // test statistic (in which cas one can use another test statistic if one likes).

   // Now produce the output object.
   // The final quantities are computed on-demand form the arrays tss, tsb, lrs and lrb.
   result->SetTSS(tss);
   result->SetTSB(tsb);
   result->SetLRS(lrs);
   result->SetLRB(lrb);
   if (!generator)
      delete myrandom;
   return result;
}

TLimitDataSource *TLimit::Fluctuate(TLimitDataSource * input, bool init,
                                    TRandom * generator)
{
   // initialisation: create a sorted list of all the names of systematics
   if (init) {
      // create a "map" with the systematics names
      TIterator *errornames = input->GetErrorNames()->MakeIterator();
      TObjArray *listofnames = 0;
      while ((listofnames = ((TObjArray *) errornames->Next()))) {
         TObjString *name = NULL;
         TIterator *loniter = listofnames->MakeIterator();
         while ((name = (TObjString *) (loniter->Next())))
            if ((fgSystNames->IndexOf(name)) < 0)
               fgSystNames->AddLast(name);
      }
      fgSystNames->Sort();
   }
   // if there are no systematics, just returns the input as "fluctuated" output
   if (fgSystNames->GetSize() <= 0)
      return input;
   // Find a choice for the random variation and
   // re-toss all random numbers if any background or signal
   // goes negative.  (background = 0 is bad too, so put a little protection
   // around it -- must have at least 10% of the bg estimate).
   bool retoss = kTRUE;
   Double_t *serrf = NULL;
   Double_t *berrf = NULL;
   do {
      Double_t *toss = new Double_t[fgSystNames->GetSize()];
      for (Int_t i = 0; i < fgSystNames->GetSize(); i++)
         toss[i] = generator->Gaus(0, 1);
      retoss = kFALSE;
      serrf = new Double_t[(input->GetSignal()->GetLast()) + 1];
      berrf = new Double_t[(input->GetSignal()->GetLast()) + 1];
      for (Int_t channel = 0;
           channel <= input->GetSignal()->GetLast();
           channel++) {
         serrf[channel] = 0;
         berrf[channel] = 0;
         for (Int_t bin = 0;
              bin <=((TH1F *) (input->GetErrorOnSignal()->At(channel)))->GetNbinsX();
	      bin++) {
            serrf[channel] += ((TH1F *) (input->GetErrorOnSignal()->At(channel)))->GetBinContent(bin) *
                toss[fgSystNames->BinarySearch((TObjString*) (((TObjArray *) (input->GetErrorNames()->At(channel)))->At(bin)))];
            berrf[channel] += ((TH1F *) (input->GetErrorOnBackground()->At(channel)))->GetBinContent(bin) *
                toss[fgSystNames->BinarySearch((TObjString*) (((TObjArray *) (input->GetErrorNames()->At(channel)))->At(bin)))];
         }
         if ((serrf[channel] < -1.0) || (berrf[channel] < -0.9)) {
            retoss = kTRUE;
            continue;
         }
      }
      delete[]toss;
   } while (retoss);
   // adjust the fluctuated signal and background counts with a legal set
   // of random fluctuations above.
   TLimitDataSource *result = new TLimitDataSource();
   result->SetOwner();
   for (Int_t channel = 0; channel <= input->GetSignal()->GetLast();
        channel++) {
      TH1F *newsignal = new TH1F(*(TH1F *) (input->GetSignal()->At(channel)));
      newsignal->Scale(1 + serrf[channel]);
      newsignal->SetDirectory(0);
      TH1F *newbackground = new TH1F(*(TH1F *) (input->GetBackground()->At(channel)));
      newbackground->Scale(1 + berrf[channel]);
      newbackground->SetDirectory(0);
      TH1F *newcandidates = new TH1F(*(TH1F *) (input->GetCandidates()));
      newcandidates->SetDirectory(0);
      result->AddChannel(newsignal, newbackground, newcandidates);
   }
   delete[] serrf;
   delete[] berrf;
   return result;
}

<|endoftext|>


<commit_before>// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/command_line.h"
#include "base/files/file_enumerator.h"
#include "base/path_service.h"
#include "base/process/launch.h"
#include "base/rand_util.h"
#include "base/strings/stringprintf.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/media/webrtc_browsertest_base.h"
#include "chrome/browser/media/webrtc_browsertest_common.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_tabstrip.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/test/browser_test_utils.h"
#include "media/base/media_switches.h"
#include "net/test/python_utils.h"
#include "ui/gl/gl_switches.h"

// You need this solution to run this test. The solution will download appengine
// and the apprtc code for you.
const char kAdviseOnGclientSolution[] =
    "You need to add this solution to your .gclient to run this test:\n"
    "{\n"
    "  \"name\"        : \"webrtc.DEPS\",\n"
    "  \"url\"         : \"svn://svn.chromium.org/chrome/trunk/deps/"
    "third_party/webrtc/webrtc.DEPS\",\n"
    "}";
const char kTitlePageOfAppEngineAdminPage[] = "Instances";

const char kIsApprtcCallUpJavascript[] =
    "var remoteVideo = document.querySelector('#remote-video');"
    "var remoteVideoActive ="
    "    remoteVideo != null &&"
    "    remoteVideo.classList.contains('active');"
    "window.domAutomationController.send(remoteVideoActive.toString());";

// WebRTC-AppRTC integration test. Requires a real webcam and microphone
// on the running system. This test is not meant to run in the main browser
// test suite since normal tester machines do not have webcams. Chrome will use
// its fake camera for both tests, but Firefox will use the real webcam in the
// Firefox interop test. Thus, this test must on a machine with a real webcam.
//
// This test will bring up a AppRTC instance on localhost and verify that the
// call gets up when connecting to the same room from two tabs in a browser.
class WebRtcApprtcBrowserTest : public WebRtcTestBase {
 public:
  WebRtcApprtcBrowserTest() {}

  void SetUpCommandLine(base::CommandLine* command_line) override {
    EXPECT_FALSE(command_line->HasSwitch(switches::kUseFakeUIForMediaStream));

    // The video playback will not work without a GPU, so force its use here.
    command_line->AppendSwitch(switches::kUseGpuInTests);
    base::CommandLine::ForCurrentProcess()->AppendSwitch(
        switches::kUseFakeDeviceForMediaStream);
  }

  void TearDown() override {
    // Kill any processes we may have brought up. Note: this isn't perfect,
    // especially if the test hangs or if we're on Windows.
    LOG(INFO) << "Entering TearDown";
    if (dev_appserver_.IsValid())
      base::KillProcess(dev_appserver_.Handle(), 0, false);
    if (collider_server_.IsValid())
      base::KillProcess(collider_server_.Handle(), 0, false);
    if (firefox_.IsValid())
      base::KillProcess(firefox_.Handle(), 0, false);
    LOG(INFO) << "Exiting TearDown";
  }

 protected:
  bool LaunchApprtcInstanceOnLocalhost(const std::string& port) {
    base::FilePath appengine_dev_appserver =
        GetSourceDir().Append(
            FILE_PATH_LITERAL("../google_appengine/dev_appserver.py"));
    if (!base::PathExists(appengine_dev_appserver)) {
      LOG(ERROR) << "Missing appengine sdk at " <<
          appengine_dev_appserver.value() << ". " << kAdviseOnGclientSolution;
      return false;
    }

    base::FilePath apprtc_dir =
        GetSourceDir().Append(FILE_PATH_LITERAL(
            "out/webrtc-samples/samples/web/content/apprtc"));
    if (!base::PathExists(apprtc_dir)) {
      LOG(ERROR) << "Missing AppRTC code at " <<
          apprtc_dir.value() << ". " << kAdviseOnGclientSolution;
      return false;
    }

    base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
    EXPECT_TRUE(GetPythonCommand(&command_line));

    command_line.AppendArgPath(appengine_dev_appserver);
    command_line.AppendArgPath(apprtc_dir);
    command_line.AppendArg("--port=" + port);
    command_line.AppendArg("--admin_port=9998");
    command_line.AppendArg("--skip_sdk_update_check");
    command_line.AppendArg("--clear_datastore=yes");

    DVLOG(1) << "Running " << command_line.GetCommandLineString();
    dev_appserver_ = base::LaunchProcess(command_line, base::LaunchOptions());
    return dev_appserver_.IsValid();
  }

  bool LaunchColliderOnLocalHost(const std::string& apprtc_url,
                                 const std::string& collider_port) {
    // The go workspace should be created, and collidermain built, at the
    // runhooks stage when webrtc.DEPS/build_apprtc_collider.py runs.
#if defined(OS_WIN)
    base::FilePath collider_server = GetSourceDir().Append(
        FILE_PATH_LITERAL("out/go-workspace/bin/collidermain.exe"));
#else
    base::FilePath collider_server = GetSourceDir().Append(
        FILE_PATH_LITERAL("out/go-workspace/bin/collidermain"));
#endif
    if (!base::PathExists(collider_server)) {
      LOG(ERROR) << "Missing Collider server binary at " <<
          collider_server.value() << ". " << kAdviseOnGclientSolution;
      return false;
    }

    base::CommandLine command_line(collider_server);

    command_line.AppendArg("-tls=false");
    command_line.AppendArg("-port=" + collider_port);
    command_line.AppendArg("-room-server=" + apprtc_url);

    DVLOG(1) << "Running " << command_line.GetCommandLineString();
    collider_server_ = base::LaunchProcess(command_line, base::LaunchOptions());
    return collider_server_.IsValid();
  }

  bool LocalApprtcInstanceIsUp() {
    // Load the admin page and see if we manage to load it right.
    ui_test_utils::NavigateToURL(browser(), GURL("localhost:9998"));
    content::WebContents* tab_contents =
        browser()->tab_strip_model()->GetActiveWebContents();
    std::string javascript =
        "window.domAutomationController.send(document.title)";
    std::string result;
    if (!content::ExecuteScriptAndExtractString(tab_contents, javascript,
                                                &result))
      return false;

    return result == kTitlePageOfAppEngineAdminPage;
  }

  bool WaitForCallToComeUp(content::WebContents* tab_contents) {
    return test::PollingWaitUntil(kIsApprtcCallUpJavascript, "true",
                                  tab_contents);
  }

  bool EvalInJavascriptFile(content::WebContents* tab_contents,
                            const base::FilePath& path) {
    std::string javascript;
    if (!ReadFileToString(path, &javascript)) {
      LOG(ERROR) << "Missing javascript code at " << path.value() << ".";
      return false;
    }

    if (!content::ExecuteScript(tab_contents, javascript)) {
      LOG(ERROR) << "Failed to execute the following javascript: " <<
          javascript;
      return false;
    }
    return true;
  }

  bool DetectRemoteVideoPlaying(content::WebContents* tab_contents) {
    if (!EvalInJavascriptFile(tab_contents, GetSourceDir().Append(
        FILE_PATH_LITERAL("chrome/test/data/webrtc/test_functions.js"))))
      return false;
    if (!EvalInJavascriptFile(tab_contents, GetSourceDir().Append(
        FILE_PATH_LITERAL("chrome/test/data/webrtc/video_detector.js"))))
      return false;

    // The remote video tag is called remoteVideo in the AppRTC code.
    StartDetectingVideo(tab_contents, "remote-video");
    WaitForVideoToPlay(tab_contents);
    return true;
  }

  base::FilePath GetSourceDir() {
    base::FilePath source_dir;
    PathService::Get(base::DIR_SOURCE_ROOT, &source_dir);
    return source_dir;
  }

  bool LaunchFirefoxWithUrl(const GURL& url) {
    base::FilePath firefox_binary =
        GetSourceDir().Append(
            FILE_PATH_LITERAL("../firefox-nightly/firefox/firefox"));
    if (!base::PathExists(firefox_binary)) {
      LOG(ERROR) << "Missing firefox binary at " <<
          firefox_binary.value() << ". " << kAdviseOnGclientSolution;
      return false;
    }
    base::FilePath firefox_launcher =
        GetSourceDir().Append(
            FILE_PATH_LITERAL("../webrtc.DEPS/run_firefox_webrtc.py"));
    if (!base::PathExists(firefox_launcher)) {
      LOG(ERROR) << "Missing firefox launcher at " <<
          firefox_launcher.value() << ". " << kAdviseOnGclientSolution;
      return false;
    }

    base::CommandLine command_line(firefox_launcher);
    command_line.AppendSwitchPath("--binary", firefox_binary);
    command_line.AppendSwitchASCII("--webpage", url.spec());

    DVLOG(1) << "Running " << command_line.GetCommandLineString();
    firefox_ = base::LaunchProcess(command_line, base::LaunchOptions());
    return firefox_.IsValid();
  }

 private:
  base::Process dev_appserver_;
  base::Process firefox_;
  base::Process collider_server_;
};

IN_PROC_BROWSER_TEST_F(WebRtcApprtcBrowserTest, MANUAL_WorksOnApprtc) {
  // Disabled on Win XP: http://code.google.com/p/webrtc/issues/detail?id=2703.
  if (OnWinXp())
    return;

  DetectErrorsInJavaScript();
  ASSERT_TRUE(LaunchApprtcInstanceOnLocalhost("9999"));
  ASSERT_TRUE(LaunchColliderOnLocalHost("http://localhost:9999", "8089"));
  while (!LocalApprtcInstanceIsUp())
    DVLOG(1) << "Waiting for AppRTC to come up...";

  GURL room_url = GURL("http://localhost:9999/r/some_room"
                       "?wshpp=localhost:8089&wstls=false");

  chrome::AddTabAt(browser(), GURL(), -1, true);
  content::WebContents* left_tab = OpenPageAndAcceptUserMedia(room_url);

  chrome::AddTabAt(browser(), GURL(), -1, true);
  content::WebContents* right_tab = OpenPageAndAcceptUserMedia(room_url);

  ASSERT_TRUE(WaitForCallToComeUp(left_tab));
  ASSERT_TRUE(WaitForCallToComeUp(right_tab));

  ASSERT_TRUE(DetectRemoteVideoPlaying(left_tab));
  ASSERT_TRUE(DetectRemoteVideoPlaying(right_tab));

  chrome::CloseWebContents(browser(), left_tab, false);
  chrome::CloseWebContents(browser(), right_tab, false);
}

#if defined(OS_LINUX)
#define MAYBE_MANUAL_FirefoxApprtcInteropTest MANUAL_FirefoxApprtcInteropTest
#else
// Not implemented yet on Windows and Mac.
#define MAYBE_MANUAL_FirefoxApprtcInteropTest DISABLED_MANUAL_FirefoxApprtcInteropTest
#endif

IN_PROC_BROWSER_TEST_F(WebRtcApprtcBrowserTest,
                       MAYBE_MANUAL_FirefoxApprtcInteropTest) {
  // Disabled on Win XP: http://code.google.com/p/webrtc/issues/detail?id=2703.
  if (OnWinXp())
    return;

  DetectErrorsInJavaScript();
  ASSERT_TRUE(LaunchApprtcInstanceOnLocalhost("9999"));
  ASSERT_TRUE(LaunchColliderOnLocalHost("http://localhost:9999", "8089"));
  while (!LocalApprtcInstanceIsUp())
    DVLOG(1) << "Waiting for AppRTC to come up...";

  GURL room_url = GURL("http://localhost:9999/r/some_room"
                       "?wshpp=localhost:8089&wstls=false"
                       "&firefox_fake_device=1");
  content::WebContents* chrome_tab = OpenPageAndAcceptUserMedia(room_url);

  ASSERT_TRUE(LaunchFirefoxWithUrl(room_url));

  ASSERT_TRUE(WaitForCallToComeUp(chrome_tab));

  // Ensure Firefox manages to send video our way.
  ASSERT_TRUE(DetectRemoteVideoPlaying(chrome_tab));
}
<commit_msg>Pointing AppRTC browser test to new location.<commit_after>// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/command_line.h"
#include "base/files/file_enumerator.h"
#include "base/path_service.h"
#include "base/process/launch.h"
#include "base/rand_util.h"
#include "base/strings/stringprintf.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/media/webrtc_browsertest_base.h"
#include "chrome/browser/media/webrtc_browsertest_common.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_tabstrip.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/test/browser_test_utils.h"
#include "media/base/media_switches.h"
#include "net/test/python_utils.h"
#include "ui/gl/gl_switches.h"

// You need this solution to run this test. The solution will download appengine
// and the apprtc code for you.
const char kAdviseOnGclientSolution[] =
    "You need to add this solution to your .gclient to run this test:\n"
    "{\n"
    "  \"name\"        : \"webrtc.DEPS\",\n"
    "  \"url\"         : \"https://chromium.googlesource.com/chromium/deps/"
    "webrtc/webrtc.DEPS\",\n"
    "}";
const char kTitlePageOfAppEngineAdminPage[] = "Instances";

const char kIsApprtcCallUpJavascript[] =
    "var remoteVideo = document.querySelector('#remote-video');"
    "var remoteVideoActive ="
    "    remoteVideo != null &&"
    "    remoteVideo.classList.contains('active');"
    "window.domAutomationController.send(remoteVideoActive.toString());";

// WebRTC-AppRTC integration test. Requires a real webcam and microphone
// on the running system. This test is not meant to run in the main browser
// test suite since normal tester machines do not have webcams. Chrome will use
// its fake camera for both tests, but Firefox will use the real webcam in the
// Firefox interop test. Thus, this test must on a machine with a real webcam.
//
// This test will bring up a AppRTC instance on localhost and verify that the
// call gets up when connecting to the same room from two tabs in a browser.
class WebRtcApprtcBrowserTest : public WebRtcTestBase {
 public:
  WebRtcApprtcBrowserTest() {}

  void SetUpCommandLine(base::CommandLine* command_line) override {
    EXPECT_FALSE(command_line->HasSwitch(switches::kUseFakeUIForMediaStream));

    // The video playback will not work without a GPU, so force its use here.
    command_line->AppendSwitch(switches::kUseGpuInTests);
    base::CommandLine::ForCurrentProcess()->AppendSwitch(
        switches::kUseFakeDeviceForMediaStream);
  }

  void TearDown() override {
    // Kill any processes we may have brought up. Note: this isn't perfect,
    // especially if the test hangs or if we're on Windows.
    LOG(INFO) << "Entering TearDown";
    if (dev_appserver_.IsValid())
      base::KillProcess(dev_appserver_.Handle(), 0, false);
    if (collider_server_.IsValid())
      base::KillProcess(collider_server_.Handle(), 0, false);
    if (firefox_.IsValid())
      base::KillProcess(firefox_.Handle(), 0, false);
    LOG(INFO) << "Exiting TearDown";
  }

 protected:
  bool LaunchApprtcInstanceOnLocalhost(const std::string& port) {
    base::FilePath appengine_dev_appserver =
        GetSourceDir().Append(
            FILE_PATH_LITERAL("../google_appengine/dev_appserver.py"));
    if (!base::PathExists(appengine_dev_appserver)) {
      LOG(ERROR) << "Missing appengine sdk at " <<
          appengine_dev_appserver.value() << ". " << kAdviseOnGclientSolution;
      return false;
    }

    base::FilePath apprtc_dir =
        GetSourceDir().Append(FILE_PATH_LITERAL("out/apprtc/out/app_engine"));
    if (!base::PathExists(apprtc_dir)) {
      LOG(ERROR) << "Missing AppRTC AppEngine app at " <<
          apprtc_dir.value() << ". " << kAdviseOnGclientSolution;
      return false;
    }
    if (!base::PathExists(apprtc_dir.Append(FILE_PATH_LITERAL("app.yaml")))) {
      LOG(ERROR) << "The AppRTC AppEngine app at " <<
          apprtc_dir.value() << " appears to have not been built." <<
          "This should have been done by webrtc.DEPS scripts which invoke " <<
          "'grunt build' on AppRTC.";
      return false;
    }

    base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
    EXPECT_TRUE(GetPythonCommand(&command_line));

    command_line.AppendArgPath(appengine_dev_appserver);
    command_line.AppendArgPath(apprtc_dir);
    command_line.AppendArg("--port=" + port);
    command_line.AppendArg("--admin_port=9998");
    command_line.AppendArg("--skip_sdk_update_check");
    command_line.AppendArg("--clear_datastore=yes");

    DVLOG(1) << "Running " << command_line.GetCommandLineString();
    dev_appserver_ = base::LaunchProcess(command_line, base::LaunchOptions());
    return dev_appserver_.IsValid();
  }

  bool LaunchColliderOnLocalHost(const std::string& apprtc_url,
                                 const std::string& collider_port) {
    // The go workspace should be created, and collidermain built, at the
    // runhooks stage when webrtc.DEPS/build_apprtc_collider.py runs.
#if defined(OS_WIN)
    base::FilePath collider_server = GetSourceDir().Append(
        FILE_PATH_LITERAL("out/go-workspace/bin/collidermain.exe"));
#else
    base::FilePath collider_server = GetSourceDir().Append(
        FILE_PATH_LITERAL("out/go-workspace/bin/collidermain"));
#endif
    if (!base::PathExists(collider_server)) {
      LOG(ERROR) << "Missing Collider server binary at " <<
          collider_server.value() << ". " << kAdviseOnGclientSolution;
      return false;
    }

    base::CommandLine command_line(collider_server);

    command_line.AppendArg("-tls=false");
    command_line.AppendArg("-port=" + collider_port);
    command_line.AppendArg("-room-server=" + apprtc_url);

    DVLOG(1) << "Running " << command_line.GetCommandLineString();
    collider_server_ = base::LaunchProcess(command_line, base::LaunchOptions());
    return collider_server_.IsValid();
  }

  bool LocalApprtcInstanceIsUp() {
    // Load the admin page and see if we manage to load it right.
    ui_test_utils::NavigateToURL(browser(), GURL("localhost:9998"));
    content::WebContents* tab_contents =
        browser()->tab_strip_model()->GetActiveWebContents();
    std::string javascript =
        "window.domAutomationController.send(document.title)";
    std::string result;
    if (!content::ExecuteScriptAndExtractString(tab_contents, javascript,
                                                &result))
      return false;

    return result == kTitlePageOfAppEngineAdminPage;
  }

  bool WaitForCallToComeUp(content::WebContents* tab_contents) {
    return test::PollingWaitUntil(kIsApprtcCallUpJavascript, "true",
                                  tab_contents);
  }

  bool EvalInJavascriptFile(content::WebContents* tab_contents,
                            const base::FilePath& path) {
    std::string javascript;
    if (!ReadFileToString(path, &javascript)) {
      LOG(ERROR) << "Missing javascript code at " << path.value() << ".";
      return false;
    }

    if (!content::ExecuteScript(tab_contents, javascript)) {
      LOG(ERROR) << "Failed to execute the following javascript: " <<
          javascript;
      return false;
    }
    return true;
  }

  bool DetectRemoteVideoPlaying(content::WebContents* tab_contents) {
    if (!EvalInJavascriptFile(tab_contents, GetSourceDir().Append(
        FILE_PATH_LITERAL("chrome/test/data/webrtc/test_functions.js"))))
      return false;
    if (!EvalInJavascriptFile(tab_contents, GetSourceDir().Append(
        FILE_PATH_LITERAL("chrome/test/data/webrtc/video_detector.js"))))
      return false;

    // The remote video tag is called remoteVideo in the AppRTC code.
    StartDetectingVideo(tab_contents, "remote-video");
    WaitForVideoToPlay(tab_contents);
    return true;
  }

  base::FilePath GetSourceDir() {
    base::FilePath source_dir;
    PathService::Get(base::DIR_SOURCE_ROOT, &source_dir);
    return source_dir;
  }

  bool LaunchFirefoxWithUrl(const GURL& url) {
    base::FilePath firefox_binary =
        GetSourceDir().Append(
            FILE_PATH_LITERAL("../firefox-nightly/firefox/firefox"));
    if (!base::PathExists(firefox_binary)) {
      LOG(ERROR) << "Missing firefox binary at " <<
          firefox_binary.value() << ". " << kAdviseOnGclientSolution;
      return false;
    }
    base::FilePath firefox_launcher =
        GetSourceDir().Append(
            FILE_PATH_LITERAL("../webrtc.DEPS/run_firefox_webrtc.py"));
    if (!base::PathExists(firefox_launcher)) {
      LOG(ERROR) << "Missing firefox launcher at " <<
          firefox_launcher.value() << ". " << kAdviseOnGclientSolution;
      return false;
    }

    base::CommandLine command_line(firefox_launcher);
    command_line.AppendSwitchPath("--binary", firefox_binary);
    command_line.AppendSwitchASCII("--webpage", url.spec());

    DVLOG(1) << "Running " << command_line.GetCommandLineString();
    firefox_ = base::LaunchProcess(command_line, base::LaunchOptions());
    return firefox_.IsValid();
  }

 private:
  base::Process dev_appserver_;
  base::Process firefox_;
  base::Process collider_server_;
};

IN_PROC_BROWSER_TEST_F(WebRtcApprtcBrowserTest, MANUAL_WorksOnApprtc) {
  // Disabled on Win XP: http://code.google.com/p/webrtc/issues/detail?id=2703.
  if (OnWinXp())
    return;

  DetectErrorsInJavaScript();
  ASSERT_TRUE(LaunchApprtcInstanceOnLocalhost("9999"));
  ASSERT_TRUE(LaunchColliderOnLocalHost("http://localhost:9999", "8089"));
  while (!LocalApprtcInstanceIsUp())
    DVLOG(1) << "Waiting for AppRTC to come up...";

  GURL room_url = GURL("http://localhost:9999/r/some_room"
                       "?wshpp=localhost:8089&wstls=false");

  chrome::AddTabAt(browser(), GURL(), -1, true);
  content::WebContents* left_tab = OpenPageAndAcceptUserMedia(room_url);

  chrome::AddTabAt(browser(), GURL(), -1, true);
  content::WebContents* right_tab = OpenPageAndAcceptUserMedia(room_url);

  ASSERT_TRUE(WaitForCallToComeUp(left_tab));
  ASSERT_TRUE(WaitForCallToComeUp(right_tab));

  ASSERT_TRUE(DetectRemoteVideoPlaying(left_tab));
  ASSERT_TRUE(DetectRemoteVideoPlaying(right_tab));

  chrome::CloseWebContents(browser(), left_tab, false);
  chrome::CloseWebContents(browser(), right_tab, false);
}

#if defined(OS_LINUX)
#define MAYBE_MANUAL_FirefoxApprtcInteropTest MANUAL_FirefoxApprtcInteropTest
#else
// Not implemented yet on Windows and Mac.
#define MAYBE_MANUAL_FirefoxApprtcInteropTest DISABLED_MANUAL_FirefoxApprtcInteropTest
#endif

IN_PROC_BROWSER_TEST_F(WebRtcApprtcBrowserTest,
                       MAYBE_MANUAL_FirefoxApprtcInteropTest) {
  // Disabled on Win XP: http://code.google.com/p/webrtc/issues/detail?id=2703.
  if (OnWinXp())
    return;

  DetectErrorsInJavaScript();
  ASSERT_TRUE(LaunchApprtcInstanceOnLocalhost("9999"));
  ASSERT_TRUE(LaunchColliderOnLocalHost("http://localhost:9999", "8089"));
  while (!LocalApprtcInstanceIsUp())
    DVLOG(1) << "Waiting for AppRTC to come up...";

  GURL room_url = GURL("http://localhost:9999/r/some_room"
                       "?wshpp=localhost:8089&wstls=false"
                       "&firefox_fake_device=1");
  content::WebContents* chrome_tab = OpenPageAndAcceptUserMedia(room_url);

  ASSERT_TRUE(LaunchFirefoxWithUrl(room_url));

  ASSERT_TRUE(WaitForCallToComeUp(chrome_tab));

  // Ensure Firefox manages to send video our way.
  ASSERT_TRUE(DetectRemoteVideoPlaying(chrome_tab));
}
<|endoftext|>