<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/chromeos/login/eula_view.h"

#include <signal.h>
#include <sys/types.h>
#include <string>

#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/customization_document.h"
#include "chrome/browser/chromeos/login/network_screen_delegate.h"
#include "chrome/browser/chromeos/login/rounded_rect_painter.h"
#include "chrome/browser/chromeos/login/wizard_controller.h"
#include "chrome/browser/profile_manager.h"
#include "chrome/browser/renderer_host/site_instance.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/views/dom_view.h"
#include "chrome/common/url_constants.h"
#include "chrome/installer/util/google_update_settings.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "views/controls/button/checkbox.h"
#include "views/controls/button/native_button.h"
#include "views/controls/label.h"
#include "views/grid_layout.h"
#include "views/layout_manager.h"
#include "views/standard_layout.h"

namespace {

const int kBorderSize = 10;
const int kMargin = 20;
const int kLastButtonHorizontalMargin = 10;
const int kCheckBowWidth = 22;
const int kTextMargin = 10;

// TODO(glotov): this URL should be changed to actual Google ChromeOS EULA.
// See crbug.com/4647
const char kGoogleEulaUrl[] = "about:terms";

enum kLayoutColumnsets {
  SINGLE_CONTROL_ROW,
  SINGLE_CONTROL_WITH_SHIFT_ROW,
  SINGLE_LINK_WITH_SHIFT_ROW,
  LAST_ROW
};

// A simple LayoutManager that causes the associated view's one child to be
// sized to match the bounds of its parent except the bounds, if set.
struct FillLayoutWithBorder : public views::LayoutManager {
  // Overridden from LayoutManager:
  virtual void Layout(views::View* host) {
    DCHECK(host->GetChildViewCount());
    host->GetChildViewAt(0)->SetBounds(host->GetLocalBounds(false));
  }
  virtual gfx::Size GetPreferredSize(views::View* host) {
    return gfx::Size(host->width(), host->height());
  }
};

}  // namespace

namespace chromeos {

EulaView::EulaView(chromeos::ScreenObserver* observer)
    : google_eula_label_(NULL),
      google_eula_view_(NULL),
      usage_statistics_checkbox_(NULL),
      learn_more_link_(NULL),
      oem_eula_label_(NULL),
      oem_eula_view_(NULL),
      system_security_settings_link_(NULL),
      cancel_button_(NULL),
      continue_button_(NULL),
      observer_(observer) {
}

EulaView::~EulaView() {
}

// Convenience function to set layout's columnsets for this screen.
static void SetUpGridLayout(views::GridLayout* layout) {
  static const int kPadding = kBorderSize + kMargin;
  views::ColumnSet* column_set = layout->AddColumnSet(SINGLE_CONTROL_ROW);
  column_set->AddPaddingColumn(0, kPadding);
  column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
                        views::GridLayout::USE_PREF, 0, 0);
  column_set->AddPaddingColumn(0, kPadding);

  column_set = layout->AddColumnSet(SINGLE_CONTROL_WITH_SHIFT_ROW);
  column_set->AddPaddingColumn(0, kPadding + kTextMargin);
  column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
                        views::GridLayout::USE_PREF, 0, 0);
  column_set->AddPaddingColumn(0, kPadding);

  column_set = layout->AddColumnSet(SINGLE_LINK_WITH_SHIFT_ROW);
  column_set->AddPaddingColumn(0, kPadding + kTextMargin + kCheckBowWidth);
  column_set->AddColumn(views::GridLayout::LEADING, views::GridLayout::FILL, 1,
                        views::GridLayout::USE_PREF, 0, 0);
  column_set->AddPaddingColumn(0, kPadding);

  column_set = layout->AddColumnSet(LAST_ROW);
  column_set->AddPaddingColumn(0, kPadding + kTextMargin);
  column_set->AddColumn(views::GridLayout::LEADING, views::GridLayout::FILL, 1,
                        views::GridLayout::USE_PREF, 0, 0);
  column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0,
                        views::GridLayout::USE_PREF, 0, 0);
  column_set->AddPaddingColumn(0, kRelatedControlHorizontalSpacing);
  column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0,
                        views::GridLayout::USE_PREF, 0, 0);
  column_set->AddPaddingColumn(0, kLastButtonHorizontalMargin + kBorderSize);
}

void EulaView::Init() {
  // Use rounded rect background.
  views::Painter* painter = CreateWizardPainter(
      &BorderDefinition::kScreenBorder);
  set_background(
      views::Background::CreateBackgroundPainter(true, painter));

  // Layout created controls.
  views::GridLayout* layout = new views::GridLayout(this);
  SetLayoutManager(layout);
  SetUpGridLayout(layout);

  static const int kPadding = kBorderSize + kMargin;
  layout->AddPaddingRow(0, kPadding);
  layout->StartRow(0, SINGLE_CONTROL_ROW);
  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
  gfx::Font label_font =
      rb.GetFont(ResourceBundle::MediumFont).DeriveFont(0, gfx::Font::NORMAL);
  google_eula_label_ = new views::Label(std::wstring(), label_font);
  layout->AddView(google_eula_label_, 1, 1,
                  views::GridLayout::LEADING, views::GridLayout::FILL);

  layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing);
  layout->StartRow(1, SINGLE_CONTROL_ROW);
  views::View* box_view = new views::View();
  box_view->set_border(views::Border::CreateSolidBorder(1, SK_ColorBLACK));
  box_view->SetLayoutManager(new FillLayoutWithBorder());
  layout->AddView(box_view);

  google_eula_view_ = new DOMView();
  box_view->AddChildView(google_eula_view_);

  layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing);
  layout->StartRow(0, SINGLE_CONTROL_WITH_SHIFT_ROW);
  usage_statistics_checkbox_ = new views::Checkbox();
  usage_statistics_checkbox_->SetMultiLine(true);
  usage_statistics_checkbox_->SetChecked(
      GoogleUpdateSettings::GetCollectStatsConsent());
  layout->AddView(usage_statistics_checkbox_);

  layout->StartRow(0, SINGLE_LINK_WITH_SHIFT_ROW);
  learn_more_link_ = new views::Link();
  learn_more_link_->SetController(this);
  layout->AddView(learn_more_link_);

  layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing);
  layout->StartRow(0, SINGLE_CONTROL_ROW);
  oem_eula_label_ = new views::Label(std::wstring(), label_font);
  layout->AddView(oem_eula_label_, 1, 1,
                  views::GridLayout::LEADING, views::GridLayout::FILL);

  layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing);
  layout->StartRow(1, SINGLE_CONTROL_ROW);
  box_view = new views::View();
  box_view->set_border(views::Border::CreateSolidBorder(1, SK_ColorBLACK));
  box_view->SetLayoutManager(new FillLayoutWithBorder());
  layout->AddView(box_view);

  oem_eula_view_ = new DOMView();
  box_view->AddChildView(oem_eula_view_);

  layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
  layout->StartRow(0, LAST_ROW);
  system_security_settings_link_ = new views::Link();
  system_security_settings_link_->SetController(this);
  layout->AddView(system_security_settings_link_);

  cancel_button_ = new views::NativeButton(this, std::wstring());
  cancel_button_->SetEnabled(false);
  layout->AddView(cancel_button_);

  continue_button_ = new views::NativeButton(this, std::wstring());
  layout->AddView(continue_button_);
  layout->AddPaddingRow(0, kPadding);

  UpdateLocalizedStrings();
}

void EulaView::LoadEulaView(DOMView* eula_view,
                            views::Label* eula_label,
                            const GURL& eula_url) {
  Profile* profile = ProfileManager::GetDefaultProfile();
  eula_view->Init(profile,
                  SiteInstance::CreateSiteInstanceForURL(profile, eula_url));
  eula_view->LoadURL(eula_url);
  eula_view->tab_contents()->set_delegate(this);
}

void EulaView::UpdateLocalizedStrings() {
  // Load Google EULA and its title.
  LoadEulaView(google_eula_view_, google_eula_label_, GURL(kGoogleEulaUrl));

  // Load OEM EULA and its title.
  const StartupCustomizationDocument *customization =
      WizardController::default_controller()->GetCustomization();
  if (customization) {
    const FilePath eula_page_path = customization->GetEULAPagePath(
        g_browser_process->GetApplicationLocale());
    if (!eula_page_path.empty()) {
      const std::string page_path = std::string(chrome::kFileScheme) +
          chrome::kStandardSchemeSeparator + eula_page_path.value();
      LoadEulaView(oem_eula_view_, oem_eula_label_, GURL(page_path));
    } else {
      LOG(ERROR) << "No eula found for locale: "
                 << g_browser_process->GetApplicationLocale();
    }
  } else {
    LOG(ERROR) << "No manifest found.";
  }

  // Load other labels from resources.
  usage_statistics_checkbox_->SetLabel(
      l10n_util::GetString(IDS_EULA_CHECKBOX_ENABLE_LOGGING));
  learn_more_link_->SetText(
      l10n_util::GetString(IDS_LEARN_MORE));
  system_security_settings_link_->SetText(
      l10n_util::GetString(IDS_EULA_SYSTEM_SECURITY_SETTINGS_LINK));
  continue_button_->SetLabel(
      l10n_util::GetString(IDS_EULA_ACCEPT_AND_CONTINUE_BUTTON));
  cancel_button_->SetLabel(
      l10n_util::GetString(IDS_CANCEL));
}

////////////////////////////////////////////////////////////////////////////////
// views::View: implementation:

void EulaView::OnLocaleChanged() {
  UpdateLocalizedStrings();
  Layout();
}

////////////////////////////////////////////////////////////////////////////////
// views::ButtonListener implementation:

void EulaView::ButtonPressed(views::Button* sender, const views::Event& event) {
  if (sender == continue_button_) {
    if (usage_statistics_checkbox_) {
      GoogleUpdateSettings::SetCollectStatsConsent(
        usage_statistics_checkbox_->checked());
    }
    observer_->OnExit(ScreenObserver::EULA_ACCEPTED);
  }
  // TODO(glotov): handle cancel button.
}

////////////////////////////////////////////////////////////////////////////////
// views::LinkController implementation:

void EulaView::LinkActivated(views::Link* source, int event_flags) {
  // TODO(glotov): handle link clicks.
}

////////////////////////////////////////////////////////////////////////////////
// TabContentsDelegate implementation:

// Convenience function. Queries |eula_view| for HTML title and, if it
// is ready, assigns it to |eula_label| and returns true so the caller
// view calls Layout().
static bool PublishTitleIfReady(const TabContents* contents,
                                DOMView* eula_view,
                                views::Label* eula_label) {
  if (contents != eula_view->tab_contents())
    return false;
  eula_label->SetText(UTF16ToWide(eula_view->tab_contents()->GetTitle()));
  return true;
}

void EulaView::NavigationStateChanged(const TabContents* contents,
                                      unsigned changed_flags) {
  if (changed_flags & TabContents::INVALIDATE_TITLE) {
    if (PublishTitleIfReady(contents, google_eula_view_, google_eula_label_) ||
        PublishTitleIfReady(contents, oem_eula_view_, oem_eula_label_)) {
      Layout();
    }
  }
}

}  // namespace chromeos
<commit_msg>Initial locale is used if current locale is not handled by manifest.<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/chromeos/login/eula_view.h"

#include <signal.h>
#include <sys/types.h>
#include <string>

#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/basictypes.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/customization_document.h"
#include "chrome/browser/chromeos/login/network_screen_delegate.h"
#include "chrome/browser/chromeos/login/rounded_rect_painter.h"
#include "chrome/browser/chromeos/login/wizard_controller.h"
#include "chrome/browser/profile_manager.h"
#include "chrome/browser/renderer_host/site_instance.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/views/dom_view.h"
#include "chrome/common/url_constants.h"
#include "chrome/installer/util/google_update_settings.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "views/controls/button/checkbox.h"
#include "views/controls/button/native_button.h"
#include "views/controls/label.h"
#include "views/grid_layout.h"
#include "views/layout_manager.h"
#include "views/standard_layout.h"

namespace {

const int kBorderSize = 10;
const int kMargin = 20;
const int kLastButtonHorizontalMargin = 10;
const int kCheckBowWidth = 22;
const int kTextMargin = 10;

// TODO(glotov): this URL should be changed to actual Google ChromeOS EULA.
// See crbug.com/4647
const char kGoogleEulaUrl[] = "about:terms";

enum kLayoutColumnsets {
  SINGLE_CONTROL_ROW,
  SINGLE_CONTROL_WITH_SHIFT_ROW,
  SINGLE_LINK_WITH_SHIFT_ROW,
  LAST_ROW
};

// A simple LayoutManager that causes the associated view's one child to be
// sized to match the bounds of its parent except the bounds, if set.
struct FillLayoutWithBorder : public views::LayoutManager {
  // Overridden from LayoutManager:
  virtual void Layout(views::View* host) {
    DCHECK(host->GetChildViewCount());
    host->GetChildViewAt(0)->SetBounds(host->GetLocalBounds(false));
  }
  virtual gfx::Size GetPreferredSize(views::View* host) {
    return gfx::Size(host->width(), host->height());
  }
};

}  // namespace

namespace chromeos {

EulaView::EulaView(chromeos::ScreenObserver* observer)
    : google_eula_label_(NULL),
      google_eula_view_(NULL),
      usage_statistics_checkbox_(NULL),
      learn_more_link_(NULL),
      oem_eula_label_(NULL),
      oem_eula_view_(NULL),
      system_security_settings_link_(NULL),
      cancel_button_(NULL),
      continue_button_(NULL),
      observer_(observer) {
}

EulaView::~EulaView() {
}

// Convenience function to set layout's columnsets for this screen.
static void SetUpGridLayout(views::GridLayout* layout) {
  static const int kPadding = kBorderSize + kMargin;
  views::ColumnSet* column_set = layout->AddColumnSet(SINGLE_CONTROL_ROW);
  column_set->AddPaddingColumn(0, kPadding);
  column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
                        views::GridLayout::USE_PREF, 0, 0);
  column_set->AddPaddingColumn(0, kPadding);

  column_set = layout->AddColumnSet(SINGLE_CONTROL_WITH_SHIFT_ROW);
  column_set->AddPaddingColumn(0, kPadding + kTextMargin);
  column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
                        views::GridLayout::USE_PREF, 0, 0);
  column_set->AddPaddingColumn(0, kPadding);

  column_set = layout->AddColumnSet(SINGLE_LINK_WITH_SHIFT_ROW);
  column_set->AddPaddingColumn(0, kPadding + kTextMargin + kCheckBowWidth);
  column_set->AddColumn(views::GridLayout::LEADING, views::GridLayout::FILL, 1,
                        views::GridLayout::USE_PREF, 0, 0);
  column_set->AddPaddingColumn(0, kPadding);

  column_set = layout->AddColumnSet(LAST_ROW);
  column_set->AddPaddingColumn(0, kPadding + kTextMargin);
  column_set->AddColumn(views::GridLayout::LEADING, views::GridLayout::FILL, 1,
                        views::GridLayout::USE_PREF, 0, 0);
  column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0,
                        views::GridLayout::USE_PREF, 0, 0);
  column_set->AddPaddingColumn(0, kRelatedControlHorizontalSpacing);
  column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0,
                        views::GridLayout::USE_PREF, 0, 0);
  column_set->AddPaddingColumn(0, kLastButtonHorizontalMargin + kBorderSize);
}

void EulaView::Init() {
  // Use rounded rect background.
  views::Painter* painter = CreateWizardPainter(
      &BorderDefinition::kScreenBorder);
  set_background(
      views::Background::CreateBackgroundPainter(true, painter));

  // Layout created controls.
  views::GridLayout* layout = new views::GridLayout(this);
  SetLayoutManager(layout);
  SetUpGridLayout(layout);

  static const int kPadding = kBorderSize + kMargin;
  layout->AddPaddingRow(0, kPadding);
  layout->StartRow(0, SINGLE_CONTROL_ROW);
  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
  gfx::Font label_font =
      rb.GetFont(ResourceBundle::MediumFont).DeriveFont(0, gfx::Font::NORMAL);
  google_eula_label_ = new views::Label(std::wstring(), label_font);
  layout->AddView(google_eula_label_, 1, 1,
                  views::GridLayout::LEADING, views::GridLayout::FILL);

  layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing);
  layout->StartRow(1, SINGLE_CONTROL_ROW);
  views::View* box_view = new views::View();
  box_view->set_border(views::Border::CreateSolidBorder(1, SK_ColorBLACK));
  box_view->SetLayoutManager(new FillLayoutWithBorder());
  layout->AddView(box_view);

  google_eula_view_ = new DOMView();
  box_view->AddChildView(google_eula_view_);

  layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing);
  layout->StartRow(0, SINGLE_CONTROL_WITH_SHIFT_ROW);
  usage_statistics_checkbox_ = new views::Checkbox();
  usage_statistics_checkbox_->SetMultiLine(true);
  usage_statistics_checkbox_->SetChecked(
      GoogleUpdateSettings::GetCollectStatsConsent());
  layout->AddView(usage_statistics_checkbox_);

  layout->StartRow(0, SINGLE_LINK_WITH_SHIFT_ROW);
  learn_more_link_ = new views::Link();
  learn_more_link_->SetController(this);
  layout->AddView(learn_more_link_);

  layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing);
  layout->StartRow(0, SINGLE_CONTROL_ROW);
  oem_eula_label_ = new views::Label(std::wstring(), label_font);
  layout->AddView(oem_eula_label_, 1, 1,
                  views::GridLayout::LEADING, views::GridLayout::FILL);

  layout->AddPaddingRow(0, kRelatedControlSmallVerticalSpacing);
  layout->StartRow(1, SINGLE_CONTROL_ROW);
  box_view = new views::View();
  box_view->set_border(views::Border::CreateSolidBorder(1, SK_ColorBLACK));
  box_view->SetLayoutManager(new FillLayoutWithBorder());
  layout->AddView(box_view);

  oem_eula_view_ = new DOMView();
  box_view->AddChildView(oem_eula_view_);

  layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
  layout->StartRow(0, LAST_ROW);
  system_security_settings_link_ = new views::Link();
  system_security_settings_link_->SetController(this);
  layout->AddView(system_security_settings_link_);

  cancel_button_ = new views::NativeButton(this, std::wstring());
  cancel_button_->SetEnabled(false);
  layout->AddView(cancel_button_);

  continue_button_ = new views::NativeButton(this, std::wstring());
  layout->AddView(continue_button_);
  layout->AddPaddingRow(0, kPadding);

  UpdateLocalizedStrings();
}

void EulaView::LoadEulaView(DOMView* eula_view,
                            views::Label* eula_label,
                            const GURL& eula_url) {
  Profile* profile = ProfileManager::GetDefaultProfile();
  eula_view->Init(profile,
                  SiteInstance::CreateSiteInstanceForURL(profile, eula_url));
  eula_view->LoadURL(eula_url);
  eula_view->tab_contents()->set_delegate(this);
}

void EulaView::UpdateLocalizedStrings() {
  // Load Google EULA and its title.
  LoadEulaView(google_eula_view_, google_eula_label_, GURL(kGoogleEulaUrl));

  // Load OEM EULA and its title.
  const StartupCustomizationDocument *customization =
      WizardController::default_controller()->GetCustomization();
  if (customization) {
    std::string locale = g_browser_process->GetApplicationLocale();
    FilePath eula_page_path = customization->GetEULAPagePath(locale);
    if (eula_page_path.empty()) {
      LOG(INFO) << "No eula found for locale: " << locale;
      locale = customization->initial_locale();
      eula_page_path = customization->GetEULAPagePath(locale);
    }
    if (!eula_page_path.empty()) {
      const std::string page_path = std::string(chrome::kFileScheme) +
          chrome::kStandardSchemeSeparator + eula_page_path.value();
      LoadEulaView(oem_eula_view_, oem_eula_label_, GURL(page_path));
    } else {
      LOG(INFO) << "No eula found for locale: " << locale;
    }
  } else {
    LOG(ERROR) << "No manifest found.";
  }

  // Load other labels from resources.
  usage_statistics_checkbox_->SetLabel(
      l10n_util::GetString(IDS_EULA_CHECKBOX_ENABLE_LOGGING));
  learn_more_link_->SetText(
      l10n_util::GetString(IDS_LEARN_MORE));
  system_security_settings_link_->SetText(
      l10n_util::GetString(IDS_EULA_SYSTEM_SECURITY_SETTINGS_LINK));
  continue_button_->SetLabel(
      l10n_util::GetString(IDS_EULA_ACCEPT_AND_CONTINUE_BUTTON));
  cancel_button_->SetLabel(
      l10n_util::GetString(IDS_CANCEL));
}

////////////////////////////////////////////////////////////////////////////////
// views::View: implementation:

void EulaView::OnLocaleChanged() {
  UpdateLocalizedStrings();
  Layout();
}

////////////////////////////////////////////////////////////////////////////////
// views::ButtonListener implementation:

void EulaView::ButtonPressed(views::Button* sender, const views::Event& event) {
  if (sender == continue_button_) {
    if (usage_statistics_checkbox_) {
      GoogleUpdateSettings::SetCollectStatsConsent(
        usage_statistics_checkbox_->checked());
    }
    observer_->OnExit(ScreenObserver::EULA_ACCEPTED);
  }
  // TODO(glotov): handle cancel button.
}

////////////////////////////////////////////////////////////////////////////////
// views::LinkController implementation:

void EulaView::LinkActivated(views::Link* source, int event_flags) {
  // TODO(glotov): handle link clicks.
}

////////////////////////////////////////////////////////////////////////////////
// TabContentsDelegate implementation:

// Convenience function. Queries |eula_view| for HTML title and, if it
// is ready, assigns it to |eula_label| and returns true so the caller
// view calls Layout().
static bool PublishTitleIfReady(const TabContents* contents,
                                DOMView* eula_view,
                                views::Label* eula_label) {
  if (contents != eula_view->tab_contents())
    return false;
  eula_label->SetText(UTF16ToWide(eula_view->tab_contents()->GetTitle()));
  return true;
}

void EulaView::NavigationStateChanged(const TabContents* contents,
                                      unsigned changed_flags) {
  if (changed_flags & TabContents::INVALIDATE_TITLE) {
    if (PublishTitleIfReady(contents, google_eula_view_, google_eula_label_) ||
        PublishTitleIfReady(contents, oem_eula_view_, oem_eula_label_)) {
      Layout();
    }
  }
}

}  // 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/test/ui/ui_test.h"

#include "base/file_path.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/dom_ui/new_tab_ui.h"
#include "chrome/browser/pref_service.h"
#include "chrome/browser/pref_value_store.h"
#include "chrome/common/json_pref_store.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/automation/browser_proxy.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/automation/window_proxy.h"

class NewTabUITest : public UITest {
 public:
  NewTabUITest() {
    dom_automation_enabled_ = true;
    // Set home page to the empty string so that we can set the home page using
    // preferences.
    homepage_ = L"";

    // Setup the DEFAULT_THEME profile (has fake history entries).
    set_template_user_data(UITest::ComputeTypicalUserDataSource(
        UITest::DEFAULT_THEME));
  }
};

TEST_F(NewTabUITest, NTPHasThumbnails) {
  // Switch to the "new tab" tab, which should be any new tab after the
  // first (the first is about:blank).
  scoped_refptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
  ASSERT_TRUE(window.get());

  // Bring up a new tab page.
  ASSERT_TRUE(window->RunCommand(IDC_NEW_TAB));
  int load_time;
  ASSERT_TRUE(automation()->WaitForInitialNewTabUILoad(&load_time));

  // Blank thumbnails on the NTP have the class 'filler' applied to the div.
  // If all the thumbnails load, there should be no div's with 'filler'.
  scoped_refptr<TabProxy> tab = window->GetActiveTab();
  ASSERT_TRUE(tab.get());

  ASSERT_TRUE(WaitUntilJavaScriptCondition(tab, L"",
      L"window.domAutomationController.send("
      L"document.getElementsByClassName('filler').length == 0)",
      action_max_timeout_ms()));
}

// Fails about 5% of the time on XP. http://crbug.com/45001
#if defined(OS_WIN)
#define ChromeInternalLoadsNTP FLAKY_ChromeInternalLoadsNTP
#endif
TEST_F(NewTabUITest, ChromeInternalLoadsNTP) {
  scoped_refptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
  ASSERT_TRUE(window.get());

  // Go to the "new tab page" using its old url, rather than chrome://newtab.
  scoped_refptr<TabProxy> tab = window->GetTab(0);
  ASSERT_TRUE(tab.get());
  ASSERT_TRUE(tab->NavigateToURLAsync(GURL("chrome-internal:")));
  int load_time;
  ASSERT_TRUE(automation()->WaitForInitialNewTabUILoad(&load_time));

  // Ensure there are some thumbnails loaded in the page.
  int thumbnails_count = -1;
  ASSERT_TRUE(tab->ExecuteAndExtractInt(L"",
      L"window.domAutomationController.send("
      L"document.getElementsByClassName('thumbnail-container').length)",
      &thumbnails_count));
  EXPECT_GT(thumbnails_count, 0);
}

TEST_F(NewTabUITest, UpdateUserPrefsVersion) {
  // PrefService with JSON user-pref file only, no enforced or advised prefs.
  PrefService prefs(new PrefValueStore(
      NULL, /* no enforced prefs */
      new JsonPrefStore(
          FilePath(),
          ChromeThread::GetMessageLoopProxyForThread(ChromeThread::FILE)),
          /* user prefs */
      NULL /* no advised prefs */));

  // Does the migration
  NewTabUI::RegisterUserPrefs(&prefs);

  ASSERT_EQ(NewTabUI::current_pref_version(),
            prefs.GetInteger(prefs::kNTPPrefVersion));

  // Reset the version
  prefs.ClearPref(prefs::kNTPPrefVersion);
  ASSERT_EQ(0, prefs.GetInteger(prefs::kNTPPrefVersion));

  bool migrated = NewTabUI::UpdateUserPrefsVersion(&prefs);
  ASSERT_TRUE(migrated);
  ASSERT_EQ(NewTabUI::current_pref_version(),
            prefs.GetInteger(prefs::kNTPPrefVersion));

  migrated = NewTabUI::UpdateUserPrefsVersion(&prefs);
  ASSERT_FALSE(migrated);
}

TEST_F(NewTabUITest, HomePageLink) {
  scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
  ASSERT_TRUE(browser.get());

  ASSERT_TRUE(
      browser->SetBooleanPreference(prefs::kHomePageIsNewTabPage, false));

  // Bring up a new tab page.
  ASSERT_TRUE(browser->RunCommand(IDC_NEW_TAB));
  int load_time;
  ASSERT_TRUE(automation()->WaitForInitialNewTabUILoad(&load_time));

  scoped_refptr<TabProxy> tab = browser->GetActiveTab();
  ASSERT_TRUE(tab.get());

  // TODO(arv): Extract common patterns for doing js testing.

  // Fire click. Because tip service is turned off for testing, we first
  // force the "make this my home page" tip to appear.
  // TODO(arv): Find screen position of element and use a lower level click
  // emulation.
  bool result;
  ASSERT_TRUE(tab->ExecuteAndExtractBool(L"",
    L"window.domAutomationController.send("
    L"(function() {"
    L"  tipCache = [{\"set_homepage_tip\":\"Make this the home page\"}];"
    L"  renderTip();"
    L"  var e = document.createEvent('Event');"
    L"  e.initEvent('click', true, true);"
    L"  var el = document.querySelector('#tip-line > button');"
    L"  el.dispatchEvent(e);"
    L"  return true;"
    L"})()"
    L")",
    &result));
  ASSERT_TRUE(result);

  // Make sure text of "set as home page" tip has been removed.
  std::wstring tip_text_content;
  ASSERT_TRUE(tab->ExecuteAndExtractString(L"",
    L"window.domAutomationController.send("
    L"(function() {"
    L"  var el = document.querySelector('#tip-line');"
    L"  return el.textContent;"
    L"})()"
    L")",
    &tip_text_content));
  ASSERT_EQ(L"", tip_text_content);

  // Make sure that the notification is visible
  bool has_class;
  ASSERT_TRUE(tab->ExecuteAndExtractBool(L"",
    L"window.domAutomationController.send("
    L"(function() {"
    L"  var el = document.querySelector('#notification');"
    L"  return el.classList.contains('show');"
    L"})()"
    L")",
    &has_class));
  ASSERT_TRUE(has_class);

  bool is_home_page;
  ASSERT_TRUE(browser->GetBooleanPreference(prefs::kHomePageIsNewTabPage,
              &is_home_page));
  ASSERT_TRUE(is_home_page);
}
<commit_msg>Mark NewTabUITest.ChromeInternalLoadsNTP flaky on all platforms.<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/test/ui/ui_test.h"

#include "base/file_path.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/dom_ui/new_tab_ui.h"
#include "chrome/browser/pref_service.h"
#include "chrome/browser/pref_value_store.h"
#include "chrome/common/json_pref_store.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/automation/browser_proxy.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/automation/window_proxy.h"

class NewTabUITest : public UITest {
 public:
  NewTabUITest() {
    dom_automation_enabled_ = true;
    // Set home page to the empty string so that we can set the home page using
    // preferences.
    homepage_ = L"";

    // Setup the DEFAULT_THEME profile (has fake history entries).
    set_template_user_data(UITest::ComputeTypicalUserDataSource(
        UITest::DEFAULT_THEME));
  }
};

TEST_F(NewTabUITest, NTPHasThumbnails) {
  // Switch to the "new tab" tab, which should be any new tab after the
  // first (the first is about:blank).
  scoped_refptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
  ASSERT_TRUE(window.get());

  // Bring up a new tab page.
  ASSERT_TRUE(window->RunCommand(IDC_NEW_TAB));
  int load_time;
  ASSERT_TRUE(automation()->WaitForInitialNewTabUILoad(&load_time));

  // Blank thumbnails on the NTP have the class 'filler' applied to the div.
  // If all the thumbnails load, there should be no div's with 'filler'.
  scoped_refptr<TabProxy> tab = window->GetActiveTab();
  ASSERT_TRUE(tab.get());

  ASSERT_TRUE(WaitUntilJavaScriptCondition(tab, L"",
      L"window.domAutomationController.send("
      L"document.getElementsByClassName('filler').length == 0)",
      action_max_timeout_ms()));
}

// Fails about ~5% of the time on all platforms. http://crbug.com/45001
TEST_F(NewTabUITest, FLAKY_ChromeInternalLoadsNTP) {
  scoped_refptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
  ASSERT_TRUE(window.get());

  // Go to the "new tab page" using its old url, rather than chrome://newtab.
  scoped_refptr<TabProxy> tab = window->GetTab(0);
  ASSERT_TRUE(tab.get());
  ASSERT_TRUE(tab->NavigateToURLAsync(GURL("chrome-internal:")));
  int load_time;
  ASSERT_TRUE(automation()->WaitForInitialNewTabUILoad(&load_time));

  // Ensure there are some thumbnails loaded in the page.
  int thumbnails_count = -1;
  ASSERT_TRUE(tab->ExecuteAndExtractInt(L"",
      L"window.domAutomationController.send("
      L"document.getElementsByClassName('thumbnail-container').length)",
      &thumbnails_count));
  EXPECT_GT(thumbnails_count, 0);
}

TEST_F(NewTabUITest, UpdateUserPrefsVersion) {
  // PrefService with JSON user-pref file only, no enforced or advised prefs.
  PrefService prefs(new PrefValueStore(
      NULL, /* no enforced prefs */
      new JsonPrefStore(
          FilePath(),
          ChromeThread::GetMessageLoopProxyForThread(ChromeThread::FILE)),
          /* user prefs */
      NULL /* no advised prefs */));

  // Does the migration
  NewTabUI::RegisterUserPrefs(&prefs);

  ASSERT_EQ(NewTabUI::current_pref_version(),
            prefs.GetInteger(prefs::kNTPPrefVersion));

  // Reset the version
  prefs.ClearPref(prefs::kNTPPrefVersion);
  ASSERT_EQ(0, prefs.GetInteger(prefs::kNTPPrefVersion));

  bool migrated = NewTabUI::UpdateUserPrefsVersion(&prefs);
  ASSERT_TRUE(migrated);
  ASSERT_EQ(NewTabUI::current_pref_version(),
            prefs.GetInteger(prefs::kNTPPrefVersion));

  migrated = NewTabUI::UpdateUserPrefsVersion(&prefs);
  ASSERT_FALSE(migrated);
}

TEST_F(NewTabUITest, HomePageLink) {
  scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
  ASSERT_TRUE(browser.get());

  ASSERT_TRUE(
      browser->SetBooleanPreference(prefs::kHomePageIsNewTabPage, false));

  // Bring up a new tab page.
  ASSERT_TRUE(browser->RunCommand(IDC_NEW_TAB));
  int load_time;
  ASSERT_TRUE(automation()->WaitForInitialNewTabUILoad(&load_time));

  scoped_refptr<TabProxy> tab = browser->GetActiveTab();
  ASSERT_TRUE(tab.get());

  // TODO(arv): Extract common patterns for doing js testing.

  // Fire click. Because tip service is turned off for testing, we first
  // force the "make this my home page" tip to appear.
  // TODO(arv): Find screen position of element and use a lower level click
  // emulation.
  bool result;
  ASSERT_TRUE(tab->ExecuteAndExtractBool(L"",
    L"window.domAutomationController.send("
    L"(function() {"
    L"  tipCache = [{\"set_homepage_tip\":\"Make this the home page\"}];"
    L"  renderTip();"
    L"  var e = document.createEvent('Event');"
    L"  e.initEvent('click', true, true);"
    L"  var el = document.querySelector('#tip-line > button');"
    L"  el.dispatchEvent(e);"
    L"  return true;"
    L"})()"
    L")",
    &result));
  ASSERT_TRUE(result);

  // Make sure text of "set as home page" tip has been removed.
  std::wstring tip_text_content;
  ASSERT_TRUE(tab->ExecuteAndExtractString(L"",
    L"window.domAutomationController.send("
    L"(function() {"
    L"  var el = document.querySelector('#tip-line');"
    L"  return el.textContent;"
    L"})()"
    L")",
    &tip_text_content));
  ASSERT_EQ(L"", tip_text_content);

  // Make sure that the notification is visible
  bool has_class;
  ASSERT_TRUE(tab->ExecuteAndExtractBool(L"",
    L"window.domAutomationController.send("
    L"(function() {"
    L"  var el = document.querySelector('#notification');"
    L"  return el.classList.contains('show');"
    L"})()"
    L")",
    &has_class));
  ASSERT_TRUE(has_class);

  bool is_home_page;
  ASSERT_TRUE(browser->GetBooleanPreference(prefs::kHomePageIsNewTabPage,
              &is_home_page));
  ASSERT_TRUE(is_home_page);
}
<|endoftext|>


<commit_before><commit_msg>Mark all tests in the DownloadTest suite as flaky under Windows (as discussed in this review).<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2012 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/file_util.h"
#include "base/memory/scoped_ptr.h"
#include "base/path_service.h"
#include "base/test/trace_event_analyzer.h"
#include "base/version.h"
#include "chrome/browser/gpu_blacklist.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/test_launcher_utils.h"
#include "chrome/test/base/tracing.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/gpu_data_manager.h"
#include "content/public/common/content_switches.h"
#include "net/base/net_util.h"
#include "ui/gfx/gl/gl_switches.h"

using content::GpuDataManager;
using content::GpuFeatureType;

namespace {

typedef uint32 GpuResultFlags;
#define EXPECT_NO_GPU_PROCESS         GpuResultFlags(1<<0)
// Expect a SwapBuffers to occur (see gles2_cmd_decoder.cc).
#define EXPECT_GPU_SWAP_BUFFERS       GpuResultFlags(1<<1)

class GpuFeatureTest : public InProcessBrowserTest {
 public:
  GpuFeatureTest() {}

  virtual void SetUpInProcessBrowserTestFixture() {
    FilePath test_dir;
    ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir));
    gpu_test_dir_ = test_dir.AppendASCII("gpu");
  }

  virtual void SetUpCommandLine(CommandLine* command_line) {
    // This enables DOM automation for tab contents.
    EnableDOMAutomation();

    InProcessBrowserTest::SetUpCommandLine(command_line);

    // Do not use mesa if real GPU is required.
    if (!command_line->HasSwitch("enable-gpu")) {
#if !defined(OS_MACOSX)
      CHECK(test_launcher_utils::OverrideGLImplementation(
          command_line, gfx::kGLImplementationOSMesaName)) <<
          "kUseGL must not be set by test framework code!";
#endif
    }
    command_line->AppendSwitch(switches::kDisablePopupBlocking);
  }

  void SetupBlacklist(const std::string& json_blacklist) {
    GpuBlacklist* blacklist = GpuBlacklist::GetInstance();
    ASSERT_TRUE(blacklist->LoadGpuBlacklist(
        "1.0", json_blacklist, GpuBlacklist::kAllOs));
    blacklist->UpdateGpuDataManager();
  }

  // If expected_reply is NULL, we don't check the reply content.
  void RunTest(const FilePath& url,
               const char* expected_reply,
               bool new_tab) {
    FilePath test_path;
    test_path = gpu_test_dir_.Append(url);
    ASSERT_TRUE(file_util::PathExists(test_path))
        << "Missing test file: " << test_path.value();

    ui_test_utils::DOMMessageQueue message_queue;
    if (new_tab) {
      ui_test_utils::NavigateToURLWithDisposition(
          browser(), net::FilePathToFileURL(test_path),
          NEW_FOREGROUND_TAB, ui_test_utils::BROWSER_TEST_NONE);
    } else {
      ui_test_utils::NavigateToURL(
          browser(), net::FilePathToFileURL(test_path));
    }

    std::string result;
    // Wait for message indicating the test has finished running.
    ASSERT_TRUE(message_queue.WaitForMessage(&result));
    if (expected_reply)
      EXPECT_STREQ(expected_reply, result.c_str());
  }

  void RunTest(const FilePath& url, GpuResultFlags expectations) {
    using trace_analyzer::Query;
    using trace_analyzer::TraceAnalyzer;

    ASSERT_TRUE(tracing::BeginTracing("test_gpu"));

    // Have to use a new tab for the blacklist to work.
    RunTest(url, NULL, true);

    std::string json_events;
    ASSERT_TRUE(tracing::EndTracing(&json_events));

    scoped_ptr<TraceAnalyzer> analyzer(TraceAnalyzer::Create(json_events));
    analyzer->AssociateBeginEndEvents();
    trace_analyzer::TraceEventVector events;

    // This measurement is flaky, because the GPU process is sometimes
    // started before the test (always with force-compositing-mode on CrOS).
    if (expectations & EXPECT_NO_GPU_PROCESS) {
      EXPECT_EQ(0u, analyzer->FindEvents(
          Query::MatchBeginName("OnGraphicsInfoCollected"), &events));
    }

    // Check for swap buffers if expected:
    if (expectations & EXPECT_GPU_SWAP_BUFFERS) {
      EXPECT_GT(analyzer->FindEvents(Query::EventName() ==
                                     Query::String("SwapBuffers"), &events),
                size_t(0));
    }
  }

 protected:
  FilePath gpu_test_dir_;
};

IN_PROC_BROWSER_TEST_F(GpuFeatureTest, AcceleratedCompositingAllowed) {
  GpuFeatureType type = GpuDataManager::GetInstance()->GetGpuFeatureType();
  EXPECT_EQ(type, 0);

  const FilePath url(FILE_PATH_LITERAL("feature_compositing.html"));
  RunTest(url, EXPECT_GPU_SWAP_BUFFERS);
}

IN_PROC_BROWSER_TEST_F(GpuFeatureTest, AcceleratedCompositingBlocked) {
  const std::string json_blacklist =
      "{\n"
      "  \"name\": \"gpu blacklist\",\n"
      "  \"version\": \"1.0\",\n"
      "  \"entries\": [\n"
      "    {\n"
      "      \"id\": 1,\n"
      "      \"blacklist\": [\n"
      "        \"accelerated_compositing\"\n"
      "      ]\n"
      "    }\n"
      "  ]\n"
      "}";
  SetupBlacklist(json_blacklist);
  GpuFeatureType type = GpuDataManager::GetInstance()->GetGpuFeatureType();
  EXPECT_EQ(type, content::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING);

  const FilePath url(FILE_PATH_LITERAL("feature_compositing.html"));
  RunTest(url, EXPECT_NO_GPU_PROCESS);
}

class AcceleratedCompositingTest : public GpuFeatureTest {
 public:
  virtual void SetUpCommandLine(CommandLine* command_line) {
    GpuFeatureTest::SetUpCommandLine(command_line);
    command_line->AppendSwitch(switches::kDisableAcceleratedCompositing);
  }
};

IN_PROC_BROWSER_TEST_F(AcceleratedCompositingTest,
                       AcceleratedCompositingDisabled) {
  const FilePath url(FILE_PATH_LITERAL("feature_compositing.html"));
  RunTest(url, EXPECT_NO_GPU_PROCESS);
}

IN_PROC_BROWSER_TEST_F(GpuFeatureTest, WebGLAllowed) {
  GpuFeatureType type = GpuDataManager::GetInstance()->GetGpuFeatureType();
  EXPECT_EQ(type, 0);

  const FilePath url(FILE_PATH_LITERAL("feature_webgl.html"));
  RunTest(url, EXPECT_GPU_SWAP_BUFFERS);
}

IN_PROC_BROWSER_TEST_F(GpuFeatureTest, WebGLBlocked) {
  const std::string json_blacklist =
      "{\n"
      "  \"name\": \"gpu blacklist\",\n"
      "  \"version\": \"1.0\",\n"
      "  \"entries\": [\n"
      "    {\n"
      "      \"id\": 1,\n"
      "      \"blacklist\": [\n"
      "        \"webgl\"\n"
      "      ]\n"
      "    }\n"
      "  ]\n"
      "}";
  SetupBlacklist(json_blacklist);
  GpuFeatureType type = GpuDataManager::GetInstance()->GetGpuFeatureType();
  EXPECT_EQ(type, content::GPU_FEATURE_TYPE_WEBGL);

  const FilePath url(FILE_PATH_LITERAL("feature_webgl.html"));
  RunTest(url, EXPECT_NO_GPU_PROCESS);
}

class WebGLTest : public GpuFeatureTest {
 public:
  virtual void SetUpCommandLine(CommandLine* command_line) {
    GpuFeatureTest::SetUpCommandLine(command_line);
    command_line->AppendSwitch(switches::kDisableExperimentalWebGL);
  }
};

IN_PROC_BROWSER_TEST_F(WebGLTest, WebGLDisabled) {
  const FilePath url(FILE_PATH_LITERAL("feature_webgl.html"));
  RunTest(url, EXPECT_NO_GPU_PROCESS);
}

IN_PROC_BROWSER_TEST_F(GpuFeatureTest, MultisamplingAllowed) {
  GpuFeatureType type = GpuDataManager::GetInstance()->GetGpuFeatureType();
  EXPECT_EQ(type, 0);

  // Multisampling is not supported if running on top of osmesa.
  std::string use_gl = CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
      switches::kUseGL);
  if (use_gl == gfx::kGLImplementationOSMesaName)
    return;

  const FilePath url(FILE_PATH_LITERAL("feature_multisampling.html"));
  RunTest(url, "\"TRUE\"", true);
}

IN_PROC_BROWSER_TEST_F(GpuFeatureTest, MultisamplingBlocked) {
  const std::string json_blacklist =
      "{\n"
      "  \"name\": \"gpu blacklist\",\n"
      "  \"version\": \"1.0\",\n"
      "  \"entries\": [\n"
      "    {\n"
      "      \"id\": 1,\n"
      "      \"blacklist\": [\n"
      "        \"multisampling\"\n"
      "      ]\n"
      "    }\n"
      "  ]\n"
      "}";
  SetupBlacklist(json_blacklist);
  GpuFeatureType type = GpuDataManager::GetInstance()->GetGpuFeatureType();
  EXPECT_EQ(type, content::GPU_FEATURE_TYPE_MULTISAMPLING);

  const FilePath url(FILE_PATH_LITERAL("feature_multisampling.html"));
  RunTest(url, "\"FALSE\"", true);
}

class WebGLMultisamplingTest : public GpuFeatureTest {
 public:
  virtual void SetUpCommandLine(CommandLine* command_line) {
    GpuFeatureTest::SetUpCommandLine(command_line);
    command_line->AppendSwitch(switches::kDisableGLMultisampling);
  }
};

IN_PROC_BROWSER_TEST_F(WebGLMultisamplingTest, MultisamplingDisabled) {
  const FilePath url(FILE_PATH_LITERAL("feature_multisampling.html"));
  RunTest(url, "\"FALSE\"", true);
}

class Canvas2DEnabledTest : public GpuFeatureTest {
 public:
  virtual void SetUpCommandLine(CommandLine* command_line) {
    GpuFeatureTest::SetUpCommandLine(command_line);
    command_line->AppendSwitch(switches::kEnableAccelerated2dCanvas);
  }
};

IN_PROC_BROWSER_TEST_F(Canvas2DEnabledTest, Canvas2DAllowed) {
  GpuFeatureType type = GpuDataManager::GetInstance()->GetGpuFeatureType();
  EXPECT_EQ(type, 0);

  const FilePath url(FILE_PATH_LITERAL("feature_canvas2d.html"));
  RunTest(url, EXPECT_GPU_SWAP_BUFFERS);
}

IN_PROC_BROWSER_TEST_F(Canvas2DEnabledTest, Canvas2DBlocked) {
  const std::string json_blacklist =
      "{\n"
      "  \"name\": \"gpu blacklist\",\n"
      "  \"version\": \"1.0\",\n"
      "  \"entries\": [\n"
      "    {\n"
      "      \"id\": 1,\n"
      "      \"blacklist\": [\n"
      "        \"accelerated_2d_canvas\"\n"
      "      ]\n"
      "    }\n"
      "  ]\n"
      "}";
  SetupBlacklist(json_blacklist);
  GpuFeatureType type = GpuDataManager::GetInstance()->GetGpuFeatureType();
  EXPECT_EQ(type, content::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS);

  const FilePath url(FILE_PATH_LITERAL("feature_canvas2d.html"));
  RunTest(url, EXPECT_NO_GPU_PROCESS);
}

class Canvas2DDisabledTest : public GpuFeatureTest {
 public:
  virtual void SetUpCommandLine(CommandLine* command_line) {
    GpuFeatureTest::SetUpCommandLine(command_line);
    command_line->AppendSwitch(switches::kDisableAccelerated2dCanvas);
  }
};

IN_PROC_BROWSER_TEST_F(Canvas2DDisabledTest, Canvas2DDisabled) {
  const FilePath url(FILE_PATH_LITERAL("feature_canvas2d.html"));
  RunTest(url, EXPECT_NO_GPU_PROCESS);
}

IN_PROC_BROWSER_TEST_F(GpuFeatureTest,
                       CanOpenPopupAndRenderWithWebGLCanvas) {
  const FilePath url(FILE_PATH_LITERAL("webgl_popup.html"));
  RunTest(url, "\"SUCCESS\"", false);
}

IN_PROC_BROWSER_TEST_F(GpuFeatureTest, CanOpenPopupAndRenderWith2DCanvas) {
  const FilePath url(FILE_PATH_LITERAL("canvas_popup.html"));
  RunTest(url, "\"SUCCESS\"", false);
}

class ThreadedCompositorTest : public GpuFeatureTest {
 public:
  virtual void SetUpCommandLine(CommandLine* command_line) {
    GpuFeatureTest::SetUpCommandLine(command_line);
    command_line->AppendSwitch(switches::kEnableThreadedCompositing);
  }
};

IN_PROC_BROWSER_TEST_F(ThreadedCompositorTest, ThreadedCompositor) {
  const FilePath url(FILE_PATH_LITERAL("feature_compositing.html"));
  RunTest(url, EXPECT_GPU_SWAP_BUFFERS);
}

}  // namespace anonymous

<commit_msg>Revert 124346 - Add basic threaded compositor test to gpu_feature_browsertest.cc<commit_after>// Copyright (c) 2012 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/file_util.h"
#include "base/memory/scoped_ptr.h"
#include "base/path_service.h"
#include "base/test/trace_event_analyzer.h"
#include "base/version.h"
#include "chrome/browser/gpu_blacklist.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/test_launcher_utils.h"
#include "chrome/test/base/tracing.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/gpu_data_manager.h"
#include "content/public/common/content_switches.h"
#include "net/base/net_util.h"
#include "ui/gfx/gl/gl_switches.h"

using content::GpuDataManager;
using content::GpuFeatureType;

namespace {

typedef uint32 GpuResultFlags;
#define EXPECT_NO_GPU_PROCESS         GpuResultFlags(1<<0)
// Expect a SwapBuffers to occur (see gles2_cmd_decoder.cc).
#define EXPECT_GPU_SWAP_BUFFERS       GpuResultFlags(1<<1)

class GpuFeatureTest : public InProcessBrowserTest {
 public:
  GpuFeatureTest() {}

  virtual void SetUpInProcessBrowserTestFixture() {
    FilePath test_dir;
    ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir));
    gpu_test_dir_ = test_dir.AppendASCII("gpu");
  }

  virtual void SetUpCommandLine(CommandLine* command_line) {
    // This enables DOM automation for tab contents.
    EnableDOMAutomation();

    InProcessBrowserTest::SetUpCommandLine(command_line);

    // Do not use mesa if real GPU is required.
    if (!command_line->HasSwitch("enable-gpu")) {
#if !defined(OS_MACOSX)
      CHECK(test_launcher_utils::OverrideGLImplementation(
          command_line, gfx::kGLImplementationOSMesaName)) <<
          "kUseGL must not be set by test framework code!";
#endif
    }
    command_line->AppendSwitch(switches::kDisablePopupBlocking);
  }

  void SetupBlacklist(const std::string& json_blacklist) {
    GpuBlacklist* blacklist = GpuBlacklist::GetInstance();
    ASSERT_TRUE(blacklist->LoadGpuBlacklist(
        "1.0", json_blacklist, GpuBlacklist::kAllOs));
    blacklist->UpdateGpuDataManager();
  }

  // If expected_reply is NULL, we don't check the reply content.
  void RunTest(const FilePath& url,
               const char* expected_reply,
               bool new_tab) {
    FilePath test_path;
    test_path = gpu_test_dir_.Append(url);
    ASSERT_TRUE(file_util::PathExists(test_path))
        << "Missing test file: " << test_path.value();

    ui_test_utils::DOMMessageQueue message_queue;
    if (new_tab) {
      ui_test_utils::NavigateToURLWithDisposition(
          browser(), net::FilePathToFileURL(test_path),
          NEW_FOREGROUND_TAB, ui_test_utils::BROWSER_TEST_NONE);
    } else {
      ui_test_utils::NavigateToURL(
          browser(), net::FilePathToFileURL(test_path));
    }

    std::string result;
    // Wait for message indicating the test has finished running.
    ASSERT_TRUE(message_queue.WaitForMessage(&result));
    if (expected_reply)
      EXPECT_STREQ(expected_reply, result.c_str());
  }

  void RunTest(const FilePath& url, GpuResultFlags expectations) {
    using trace_analyzer::Query;
    using trace_analyzer::TraceAnalyzer;

    ASSERT_TRUE(tracing::BeginTracing("test_gpu"));

    // Have to use a new tab for the blacklist to work.
    RunTest(url, NULL, true);

    std::string json_events;
    ASSERT_TRUE(tracing::EndTracing(&json_events));

    scoped_ptr<TraceAnalyzer> analyzer(TraceAnalyzer::Create(json_events));
    analyzer->AssociateBeginEndEvents();
    trace_analyzer::TraceEventVector events;

    // This measurement is flaky, because the GPU process is sometimes
    // started before the test (always with force-compositing-mode on CrOS).
    if (expectations & EXPECT_NO_GPU_PROCESS) {
      EXPECT_EQ(0u, analyzer->FindEvents(
          Query::MatchBeginName("OnGraphicsInfoCollected"), &events));
    }

    // Check for swap buffers if expected:
    if (expectations & EXPECT_GPU_SWAP_BUFFERS) {
      EXPECT_GT(analyzer->FindEvents(Query::EventName() ==
                                     Query::String("SwapBuffers"), &events),
                size_t(0));
    }
  }

 protected:
  FilePath gpu_test_dir_;
};

IN_PROC_BROWSER_TEST_F(GpuFeatureTest, AcceleratedCompositingAllowed) {
  GpuFeatureType type = GpuDataManager::GetInstance()->GetGpuFeatureType();
  EXPECT_EQ(type, 0);

  const FilePath url(FILE_PATH_LITERAL("feature_compositing.html"));
  RunTest(url, EXPECT_GPU_SWAP_BUFFERS);
}

IN_PROC_BROWSER_TEST_F(GpuFeatureTest, AcceleratedCompositingBlocked) {
  const std::string json_blacklist =
      "{\n"
      "  \"name\": \"gpu blacklist\",\n"
      "  \"version\": \"1.0\",\n"
      "  \"entries\": [\n"
      "    {\n"
      "      \"id\": 1,\n"
      "      \"blacklist\": [\n"
      "        \"accelerated_compositing\"\n"
      "      ]\n"
      "    }\n"
      "  ]\n"
      "}";
  SetupBlacklist(json_blacklist);
  GpuFeatureType type = GpuDataManager::GetInstance()->GetGpuFeatureType();
  EXPECT_EQ(type, content::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING);

  const FilePath url(FILE_PATH_LITERAL("feature_compositing.html"));
  RunTest(url, EXPECT_NO_GPU_PROCESS);
}

class AcceleratedCompositingTest : public GpuFeatureTest {
 public:
  virtual void SetUpCommandLine(CommandLine* command_line) {
    GpuFeatureTest::SetUpCommandLine(command_line);
    command_line->AppendSwitch(switches::kDisableAcceleratedCompositing);
  }
};

IN_PROC_BROWSER_TEST_F(AcceleratedCompositingTest,
                       AcceleratedCompositingDisabled) {
  const FilePath url(FILE_PATH_LITERAL("feature_compositing.html"));
  RunTest(url, EXPECT_NO_GPU_PROCESS);
}

IN_PROC_BROWSER_TEST_F(GpuFeatureTest, WebGLAllowed) {
  GpuFeatureType type = GpuDataManager::GetInstance()->GetGpuFeatureType();
  EXPECT_EQ(type, 0);

  const FilePath url(FILE_PATH_LITERAL("feature_webgl.html"));
  RunTest(url, EXPECT_GPU_SWAP_BUFFERS);
}

IN_PROC_BROWSER_TEST_F(GpuFeatureTest, WebGLBlocked) {
  const std::string json_blacklist =
      "{\n"
      "  \"name\": \"gpu blacklist\",\n"
      "  \"version\": \"1.0\",\n"
      "  \"entries\": [\n"
      "    {\n"
      "      \"id\": 1,\n"
      "      \"blacklist\": [\n"
      "        \"webgl\"\n"
      "      ]\n"
      "    }\n"
      "  ]\n"
      "}";
  SetupBlacklist(json_blacklist);
  GpuFeatureType type = GpuDataManager::GetInstance()->GetGpuFeatureType();
  EXPECT_EQ(type, content::GPU_FEATURE_TYPE_WEBGL);

  const FilePath url(FILE_PATH_LITERAL("feature_webgl.html"));
  RunTest(url, EXPECT_NO_GPU_PROCESS);
}

class WebGLTest : public GpuFeatureTest {
 public:
  virtual void SetUpCommandLine(CommandLine* command_line) {
    GpuFeatureTest::SetUpCommandLine(command_line);
    command_line->AppendSwitch(switches::kDisableExperimentalWebGL);
  }
};

IN_PROC_BROWSER_TEST_F(WebGLTest, WebGLDisabled) {
  const FilePath url(FILE_PATH_LITERAL("feature_webgl.html"));
  RunTest(url, EXPECT_NO_GPU_PROCESS);
}

IN_PROC_BROWSER_TEST_F(GpuFeatureTest, MultisamplingAllowed) {
  GpuFeatureType type = GpuDataManager::GetInstance()->GetGpuFeatureType();
  EXPECT_EQ(type, 0);

  // Multisampling is not supported if running on top of osmesa.
  std::string use_gl = CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
      switches::kUseGL);
  if (use_gl == gfx::kGLImplementationOSMesaName)
    return;

  const FilePath url(FILE_PATH_LITERAL("feature_multisampling.html"));
  RunTest(url, "\"TRUE\"", true);
}

IN_PROC_BROWSER_TEST_F(GpuFeatureTest, MultisamplingBlocked) {
  const std::string json_blacklist =
      "{\n"
      "  \"name\": \"gpu blacklist\",\n"
      "  \"version\": \"1.0\",\n"
      "  \"entries\": [\n"
      "    {\n"
      "      \"id\": 1,\n"
      "      \"blacklist\": [\n"
      "        \"multisampling\"\n"
      "      ]\n"
      "    }\n"
      "  ]\n"
      "}";
  SetupBlacklist(json_blacklist);
  GpuFeatureType type = GpuDataManager::GetInstance()->GetGpuFeatureType();
  EXPECT_EQ(type, content::GPU_FEATURE_TYPE_MULTISAMPLING);

  const FilePath url(FILE_PATH_LITERAL("feature_multisampling.html"));
  RunTest(url, "\"FALSE\"", true);
}

class WebGLMultisamplingTest : public GpuFeatureTest {
 public:
  virtual void SetUpCommandLine(CommandLine* command_line) {
    GpuFeatureTest::SetUpCommandLine(command_line);
    command_line->AppendSwitch(switches::kDisableGLMultisampling);
  }
};

IN_PROC_BROWSER_TEST_F(WebGLMultisamplingTest, MultisamplingDisabled) {
  const FilePath url(FILE_PATH_LITERAL("feature_multisampling.html"));
  RunTest(url, "\"FALSE\"", true);
}

class Canvas2DEnabledTest : public GpuFeatureTest {
 public:
  virtual void SetUpCommandLine(CommandLine* command_line) {
    GpuFeatureTest::SetUpCommandLine(command_line);
    command_line->AppendSwitch(switches::kEnableAccelerated2dCanvas);
  }
};

IN_PROC_BROWSER_TEST_F(Canvas2DEnabledTest, Canvas2DAllowed) {
  GpuFeatureType type = GpuDataManager::GetInstance()->GetGpuFeatureType();
  EXPECT_EQ(type, 0);

  const FilePath url(FILE_PATH_LITERAL("feature_canvas2d.html"));
  RunTest(url, EXPECT_GPU_SWAP_BUFFERS);
}

IN_PROC_BROWSER_TEST_F(Canvas2DEnabledTest, Canvas2DBlocked) {
  const std::string json_blacklist =
      "{\n"
      "  \"name\": \"gpu blacklist\",\n"
      "  \"version\": \"1.0\",\n"
      "  \"entries\": [\n"
      "    {\n"
      "      \"id\": 1,\n"
      "      \"blacklist\": [\n"
      "        \"accelerated_2d_canvas\"\n"
      "      ]\n"
      "    }\n"
      "  ]\n"
      "}";
  SetupBlacklist(json_blacklist);
  GpuFeatureType type = GpuDataManager::GetInstance()->GetGpuFeatureType();
  EXPECT_EQ(type, content::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS);

  const FilePath url(FILE_PATH_LITERAL("feature_canvas2d.html"));
  RunTest(url, EXPECT_NO_GPU_PROCESS);
}

class Canvas2DDisabledTest : public GpuFeatureTest {
 public:
  virtual void SetUpCommandLine(CommandLine* command_line) {
    GpuFeatureTest::SetUpCommandLine(command_line);
    command_line->AppendSwitch(switches::kDisableAccelerated2dCanvas);
  }
};

IN_PROC_BROWSER_TEST_F(Canvas2DDisabledTest, Canvas2DDisabled) {
  const FilePath url(FILE_PATH_LITERAL("feature_canvas2d.html"));
  RunTest(url, EXPECT_NO_GPU_PROCESS);
}

IN_PROC_BROWSER_TEST_F(GpuFeatureTest,
                       CanOpenPopupAndRenderWithWebGLCanvas) {
  const FilePath url(FILE_PATH_LITERAL("webgl_popup.html"));
  RunTest(url, "\"SUCCESS\"", false);
}

IN_PROC_BROWSER_TEST_F(GpuFeatureTest, CanOpenPopupAndRenderWith2DCanvas) {
  const FilePath url(FILE_PATH_LITERAL("canvas_popup.html"));
  RunTest(url, "\"SUCCESS\"", false);
}

}  // namespace anonymous

<|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_frame/test/net/fake_external_tab.h"

#include <exdisp.h>

#include "app/app_paths.h"
#include "app/resource_bundle.h"
#include "app/win_util.h"

#include "base/command_line.h"
#include "base/file_util.h"
#include "base/i18n/icu_util.h"
#include "base/path_service.h"
#include "base/scoped_bstr_win.h"
#include "base/scoped_comptr_win.h"
#include "base/scoped_variant_win.h"

#include "chrome/browser/browser_prefs.h"
#include "chrome/browser/plugin_service.h"
#include "chrome/browser/process_singleton.h"
#include "chrome/browser/profile_manager.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/web_cache_manager.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_paths_internal.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/pref_service.h"
#include "chrome_frame/utils.h"
#include "chrome_frame/test/chrome_frame_test_utils.h"
#include "chrome_frame/test/net/dialog_watchdog.h"
#include "chrome_frame/test/net/test_automation_resource_message_filter.h"

namespace {

// A special command line switch to allow developers to manually launch the
// browser and debug CF inside the browser.
const wchar_t kManualBrowserLaunch[] = L"manual-browser";

// Pops up a message box after the test environment has been set up
// and before tearing it down.  Useful for when debugging tests and not
// the test environment that's been set up.
const wchar_t kPromptAfterSetup[] = L"prompt-after-setup";

const int kTestServerPort = 4666;
// The test HTML we use to initialize Chrome Frame.
// Note that there's a little trick in there to avoid an extra URL request
// that the browser will otherwise make for the site's favicon.
// If we don't do this the browser will create a new URL request after
// the CF page has been initialized and that URL request will confuse the
// global URL instance counter in the unit tests and subsequently trip
// some DCHECKs.
const char kChromeFrameHtml[] = ""
    "<meta http-equiv=\"X-UA-Compatible\" content=\"chrome=1\" />"
    "<link rel=\"shortcut icon\" href=\"file://c:\\favicon.ico\"/>"
    "Chrome Frame should now be loaded";

bool ShouldLaunchBrowser() {
  return !CommandLine::ForCurrentProcess()->HasSwitch(kManualBrowserLaunch);
}

bool PromptAfterSetup() {
  return CommandLine::ForCurrentProcess()->HasSwitch(kPromptAfterSetup);
}

}  // end namespace

FakeExternalTab::FakeExternalTab() {
  PathService::Get(chrome::DIR_USER_DATA, &overridden_user_dir_);
  GetProfilePath(&user_data_dir_);
  PathService::Override(chrome::DIR_USER_DATA, user_data_dir_);
  process_singleton_.reset(new ProcessSingleton(user_data_dir_));
}

FakeExternalTab::~FakeExternalTab() {
  if (!overridden_user_dir_.empty()) {
    PathService::Override(chrome::DIR_USER_DATA, overridden_user_dir_);
  }
}

std::wstring FakeExternalTab::GetProfileName() {
  return L"iexplore";
}

bool FakeExternalTab::GetProfilePath(FilePath* path) {
  if (!chrome::GetChromeFrameUserDataDirectory(path))
    return false;
  *path = path->Append(GetProfileName());
  return true;
}

void FakeExternalTab::Initialize() {
  DCHECK(g_browser_process == NULL);
  SystemMonitor system_monitor;

  // The gears plugin causes the PluginRequestInterceptor to kick in and it
  // will cause problems when it tries to intercept URL requests.
  PathService::Override(chrome::FILE_GEARS_PLUGIN, FilePath());

  icu_util::Initialize();

  chrome::RegisterPathProvider();
  app::RegisterPathProvider();

  // Load Chrome.dll as our resource dll.
  FilePath dll;
  PathService::Get(base::DIR_MODULE, &dll);
  dll = dll.Append(chrome::kBrowserResourcesDll);
  HMODULE res_mod = ::LoadLibraryExW(dll.value().c_str(),
      NULL, LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE);
  DCHECK(res_mod);
  _AtlBaseModule.SetResourceInstance(res_mod);

  ResourceBundle::InitSharedInstance(L"en-US");

  CommandLine* cmd = CommandLine::ForCurrentProcess();
  cmd->AppendSwitch(switches::kDisableWebResources);
  cmd->AppendSwitch(switches::kSingleProcess);

  browser_process_.reset(new BrowserProcessImpl(*cmd));
  RenderProcessHost::set_run_renderer_in_process(true);
  // BrowserProcessImpl's constructor should set g_browser_process.
  DCHECK(g_browser_process);

  Profile* profile = g_browser_process->profile_manager()->
      GetDefaultProfile(FilePath(user_data()));
  PrefService* prefs = profile->GetPrefs();
  DCHECK(prefs != NULL);

  WebCacheManager::RegisterPrefs(prefs);
  PrefService* local_state = browser_process_->local_state();
  local_state->RegisterStringPref(prefs::kApplicationLocale, L"");
  local_state->RegisterBooleanPref(prefs::kMetricsReportingEnabled, false);

  browser::RegisterLocalState(local_state);

  // Override some settings to avoid hitting some preferences that have not
  // been registered.
  prefs->SetBoolean(prefs::kPasswordManagerEnabled, false);
  prefs->SetBoolean(prefs::kAlternateErrorPagesEnabled, false);
  prefs->SetBoolean(prefs::kSafeBrowsingEnabled, false);

  profile->InitExtensions();
}

void FakeExternalTab::Shutdown() {
  browser_process_.reset();
  g_browser_process = NULL;
  process_singleton_.reset();

  ResourceBundle::CleanupSharedInstance();
}

CFUrlRequestUnittestRunner::CFUrlRequestUnittestRunner(int argc, char** argv)
    : NetTestSuite(argc, argv),
      chrome_frame_html_("/chrome_frame", kChromeFrameHtml) {
  // Register the main thread by instantiating it, but don't call any methods.
  main_thread_.reset(new ChromeThread(ChromeThread::UI,
                                      MessageLoop::current()));
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
  fake_chrome_.Initialize();
  pss_subclass_.reset(new ProcessSingletonSubclass(this));
  EXPECT_TRUE(pss_subclass_->Subclass(fake_chrome_.user_data()));
  StartChromeFrameInHostBrowser();
}

CFUrlRequestUnittestRunner::~CFUrlRequestUnittestRunner() {
  fake_chrome_.Shutdown();
}

DWORD WINAPI NavigateIE(void* param) {
  return 0;
  win_util::ScopedCOMInitializer com;
  BSTR url = reinterpret_cast<BSTR>(param);

  bool found = false;
  int retries = 0;
  const int kMaxRetries = 20;
  while (!found && retries < kMaxRetries) {
    ScopedComPtr<IShellWindows> windows;
    HRESULT hr = ::CoCreateInstance(__uuidof(ShellWindows), NULL, CLSCTX_ALL,
        IID_IShellWindows, reinterpret_cast<void**>(windows.Receive()));
    DCHECK(SUCCEEDED(hr)) << "CoCreateInstance";

    if (SUCCEEDED(hr)) {
      hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
      long count = 0;  // NOLINT
      windows->get_Count(&count);
      VARIANT i = { VT_I4 };
      for (i.lVal = 0; i.lVal < count; ++i.lVal) {
        ScopedComPtr<IDispatch> folder;
        windows->Item(i, folder.Receive());
        if (folder != NULL) {
          ScopedComPtr<IWebBrowser2> browser;
          if (SUCCEEDED(browser.QueryFrom(folder))) {
            found = true;
            browser->Stop();
            Sleep(1000);
            VARIANT empty = ScopedVariant::kEmptyVariant;
            hr = browser->Navigate(url, &empty, &empty, &empty, &empty);
            DCHECK(SUCCEEDED(hr)) << "Failed to navigate";
            break;
          }
        }
      }
    }
    if (!found) {
      DLOG(INFO) << "Waiting for browser to initialize...";
      ::Sleep(100);
      retries++;
    }
  }

  DCHECK(retries < kMaxRetries);
  DCHECK(found);

  ::SysFreeString(url);

  return 0;
}

void CFUrlRequestUnittestRunner::StartChromeFrameInHostBrowser() {
  if (!ShouldLaunchBrowser())
    return;

  win_util::ScopedCOMInitializer com;
  chrome_frame_test::CloseAllIEWindows();

  test_http_server_.reset(new test_server::SimpleWebServer(kTestServerPort));
  test_http_server_->AddResponse(&chrome_frame_html_);
  std::wstring url(StringPrintf(L"http://localhost:%i/chrome_frame",
                                kTestServerPort).c_str());

  // Launch IE.  This launches IE correctly on Vista too.
  ScopedHandle ie_process(chrome_frame_test::LaunchIE(url));
  EXPECT_TRUE(ie_process.IsValid());

  // NOTE: If you're running IE8 and CF is not being loaded, you need to
  // disable IE8's prebinding until CF properly handles that situation.
  //
  // HKCU\Software\Microsoft\Internet Explorer\Main
  // Value name: EnablePreBinding (REG_DWORD)
  // Value: 0
}

void CFUrlRequestUnittestRunner::ShutDownHostBrowser() {
  if (ShouldLaunchBrowser()) {
    win_util::ScopedCOMInitializer com;
    chrome_frame_test::CloseAllIEWindows();
  }
}

// Override virtual void Initialize to not call icu initialize
void CFUrlRequestUnittestRunner::Initialize() {
  DCHECK(::GetCurrentThreadId() == test_thread_id_);

  // Start by replicating some of the steps that would otherwise be
  // done by TestSuite::Initialize.  We can't call the base class
  // directly because it will attempt to initialize some things such as
  // ICU that have already been initialized for this process.
  InitializeLogging();
  base::Time::UseHighResolutionTimer(true);

#if !defined(PURIFY) && defined(OS_WIN)
  logging::SetLogAssertHandler(UnitTestAssertHandler);
#endif  // !defined(PURIFY)

  // Next, do some initialization for NetTestSuite.
  NetTestSuite::InitializeTestThread();
}

void CFUrlRequestUnittestRunner::Shutdown() {
  DCHECK(::GetCurrentThreadId() == test_thread_id_);
  NetTestSuite::Shutdown();
}

void CFUrlRequestUnittestRunner::OnConnectAutomationProviderToChannel(
    const std::string& channel_id) {
  Profile* profile = g_browser_process->profile_manager()->
      GetDefaultProfile(fake_chrome_.user_data());

  AutomationProviderList* list =
      g_browser_process->InitAutomationProviderList();
  DCHECK(list);
  list->AddProvider(TestAutomationProvider::NewAutomationProvider(profile,
      channel_id, this));
}

void CFUrlRequestUnittestRunner::OnInitialTabLoaded() {
  test_http_server_.reset();
  StartTests();
}

void CFUrlRequestUnittestRunner::RunMainUIThread() {
  DCHECK(MessageLoop::current());
  DCHECK(MessageLoop::current()->type() == MessageLoop::TYPE_UI);
  MessageLoop::current()->Run();
}

void CFUrlRequestUnittestRunner::StartTests() {
  if (PromptAfterSetup())
    MessageBoxA(NULL, "click ok to run", "", MB_OK);

  DCHECK_EQ(test_thread_.IsValid(), false);
  test_thread_.Set(::CreateThread(NULL, 0, RunAllUnittests, this, 0,
                                  &test_thread_id_));
  DCHECK(test_thread_.IsValid());
}

// static
DWORD CFUrlRequestUnittestRunner::RunAllUnittests(void* param) {
  PlatformThread::SetName("CFUrlRequestUnittestRunner");
  // Needed for some url request tests like the intercept job tests, etc.
  NotificationService service;
  CFUrlRequestUnittestRunner* me =
      reinterpret_cast<CFUrlRequestUnittestRunner*>(param);
  me->Run();
  me->fake_chrome_.ui_loop()->PostTask(FROM_HERE,
      NewRunnableFunction(TakeDownBrowser, me));
  return 0;
}

// static
void CFUrlRequestUnittestRunner::TakeDownBrowser(
    CFUrlRequestUnittestRunner* me) {
  if (PromptAfterSetup())
    MessageBoxA(NULL, "click ok to exit", "", MB_OK);

  me->ShutDownHostBrowser();
}

void CFUrlRequestUnittestRunner::InitializeLogging() {
  FilePath exe;
  PathService::Get(base::FILE_EXE, &exe);
  FilePath log_filename = exe.ReplaceExtension(FILE_PATH_LITERAL("log"));
  logging::InitLogging(log_filename.value().c_str(),
                       logging::LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG,
                       logging::LOCK_LOG_FILE,
                       logging::DELETE_OLD_LOG_FILE);
  // We want process and thread IDs because we may have multiple processes.
  // Note: temporarily enabled timestamps in an effort to catch bug 6361.
  logging::SetLogItems(true, true, true, true);
}

void FilterDisabledTests() {
  if (::testing::FLAGS_gtest_filter.length() &&
      ::testing::FLAGS_gtest_filter.Compare("*") != 0) {
    // Don't override user specified filters.
    return;
  }

  const char* disabled_tests[] = {
    // Tests disabled since they're testing the same functionality used
    // by the TestAutomationProvider.
    "URLRequestTest.Intercept",
    "URLRequestTest.InterceptNetworkError",
    "URLRequestTest.InterceptRestartRequired",
    "URLRequestTest.InterceptRespectsCancelMain",
    "URLRequestTest.InterceptRespectsCancelRedirect",
    "URLRequestTest.InterceptRespectsCancelFinal",
    "URLRequestTest.InterceptRespectsCancelInRestart",
    "URLRequestTest.InterceptRedirect",
    "URLRequestTest.InterceptServerError",
    "URLRequestTestFTP.*",

    // Tests that are currently not working:

    // Temporarily disabled because they needs user input (login dialog).
    "URLRequestTestHTTP.BasicAuth",
    "URLRequestTestHTTP.BasicAuthWithCookies",

    // HTTPS tests temporarily disabled due to the certificate error dialog.
    // TODO(tommi): The tests currently fail though, so need to fix.
    "HTTPSRequestTest.HTTPSMismatchedTest",
    "HTTPSRequestTest.HTTPSExpiredTest",

    // Tests chrome's network stack's cache (might not apply to CF).
    "URLRequestTestHTTP.VaryHeader",

    // I suspect we can only get this one to work (if at all) on IE8 and
    // later by using the new INTERNET_OPTION_SUPPRESS_BEHAVIOR flags
    // See http://msdn.microsoft.com/en-us/library/aa385328(VS.85).aspx
    "URLRequestTest.DoNotSaveCookies",

    // TODO(ananta): This test has been consistently failing. Disabling it for
    // now.
    "URLRequestTestHTTP.GetTest_NoCache",
  };

  std::string filter("-");  // All following filters will be negative.
  for (int i = 0; i < arraysize(disabled_tests); ++i) {
    if (i > 0)
      filter += ":";
    filter += disabled_tests[i];
  }

  ::testing::FLAGS_gtest_filter = filter;
}

int main(int argc, char** argv) {
  DialogWatchdog watchdog;
  // See url_request_unittest.cc for these credentials.
  SupplyProxyCredentials credentials("user", "secret");
  watchdog.AddObserver(&credentials);
  testing::InitGoogleTest(&argc, argv);
  FilterDisabledTests();
  PluginService::EnableChromePlugins(false);
  CFUrlRequestUnittestRunner test_suite(argc, argv);
  test_suite.RunMainUIThread();
  return 0;
}
<commit_msg>Fix chrome frame net tests that were failing on some machines.  Checking in straight away as per Robert's request.<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_frame/test/net/fake_external_tab.h"

#include <exdisp.h>

#include "app/app_paths.h"
#include "app/resource_bundle.h"
#include "app/win_util.h"

#include "base/command_line.h"
#include "base/file_util.h"
#include "base/i18n/icu_util.h"
#include "base/path_service.h"
#include "base/scoped_bstr_win.h"
#include "base/scoped_comptr_win.h"
#include "base/scoped_variant_win.h"

#include "chrome/browser/browser_prefs.h"
#include "chrome/browser/plugin_service.h"
#include "chrome/browser/process_singleton.h"
#include "chrome/browser/profile_manager.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/web_cache_manager.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_paths_internal.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/pref_service.h"
#include "chrome_frame/utils.h"
#include "chrome_frame/test/chrome_frame_test_utils.h"
#include "chrome_frame/test/net/dialog_watchdog.h"
#include "chrome_frame/test/net/test_automation_resource_message_filter.h"

namespace {

// A special command line switch to allow developers to manually launch the
// browser and debug CF inside the browser.
const wchar_t kManualBrowserLaunch[] = L"manual-browser";

// Pops up a message box after the test environment has been set up
// and before tearing it down.  Useful for when debugging tests and not
// the test environment that's been set up.
const wchar_t kPromptAfterSetup[] = L"prompt-after-setup";

const int kTestServerPort = 4666;
// The test HTML we use to initialize Chrome Frame.
// Note that there's a little trick in there to avoid an extra URL request
// that the browser will otherwise make for the site's favicon.
// If we don't do this the browser will create a new URL request after
// the CF page has been initialized and that URL request will confuse the
// global URL instance counter in the unit tests and subsequently trip
// some DCHECKs.
const char kChromeFrameHtml[] = ""
    "<meta http-equiv=\"X-UA-Compatible\" content=\"chrome=1\" />"
    "<link rel=\"shortcut icon\" href=\"file://c:\\favicon.ico\"/>"
    "Chrome Frame should now be loaded";

bool ShouldLaunchBrowser() {
  return !CommandLine::ForCurrentProcess()->HasSwitch(kManualBrowserLaunch);
}

bool PromptAfterSetup() {
  return CommandLine::ForCurrentProcess()->HasSwitch(kPromptAfterSetup);
}

}  // end namespace

FakeExternalTab::FakeExternalTab() {
  PathService::Get(chrome::DIR_USER_DATA, &overridden_user_dir_);
  GetProfilePath(&user_data_dir_);
  PathService::Override(chrome::DIR_USER_DATA, user_data_dir_);
  process_singleton_.reset(new ProcessSingleton(user_data_dir_));
}

FakeExternalTab::~FakeExternalTab() {
  if (!overridden_user_dir_.empty()) {
    PathService::Override(chrome::DIR_USER_DATA, overridden_user_dir_);
  }
}

std::wstring FakeExternalTab::GetProfileName() {
  return L"iexplore";
}

bool FakeExternalTab::GetProfilePath(FilePath* path) {
  if (!chrome::GetChromeFrameUserDataDirectory(path))
    return false;
  *path = path->Append(GetProfileName());
  return true;
}

void FakeExternalTab::Initialize() {
  DCHECK(g_browser_process == NULL);
  SystemMonitor system_monitor;

  // The gears plugin causes the PluginRequestInterceptor to kick in and it
  // will cause problems when it tries to intercept URL requests.
  PathService::Override(chrome::FILE_GEARS_PLUGIN, FilePath());

  icu_util::Initialize();

  chrome::RegisterPathProvider();
  app::RegisterPathProvider();

  // Load Chrome.dll as our resource dll.
  FilePath dll;
  PathService::Get(base::DIR_MODULE, &dll);
  dll = dll.Append(chrome::kBrowserResourcesDll);
  HMODULE res_mod = ::LoadLibraryExW(dll.value().c_str(),
      NULL, LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE);
  DCHECK(res_mod);
  _AtlBaseModule.SetResourceInstance(res_mod);

  ResourceBundle::InitSharedInstance(L"en-US");

  CommandLine* cmd = CommandLine::ForCurrentProcess();
  cmd->AppendSwitch(switches::kDisableWebResources);
  cmd->AppendSwitch(switches::kSingleProcess);

  browser_process_.reset(new BrowserProcessImpl(*cmd));
  // BrowserProcessImpl's constructor should set g_browser_process.
  DCHECK(g_browser_process);
  // Set the app locale and create the child threads.
  g_browser_process->set_application_locale("en-US");
  g_browser_process->db_thread();
  g_browser_process->file_thread();
  g_browser_process->io_thread();

  RenderProcessHost::set_run_renderer_in_process(true);

  Profile* profile = g_browser_process->profile_manager()->
      GetDefaultProfile(FilePath(user_data()));
  PrefService* prefs = profile->GetPrefs();
  DCHECK(prefs != NULL);

  WebCacheManager::RegisterPrefs(prefs);
  PrefService* local_state = browser_process_->local_state();
  local_state->RegisterStringPref(prefs::kApplicationLocale, L"");
  local_state->RegisterBooleanPref(prefs::kMetricsReportingEnabled, false);

  browser::RegisterLocalState(local_state);

  // Override some settings to avoid hitting some preferences that have not
  // been registered.
  prefs->SetBoolean(prefs::kPasswordManagerEnabled, false);
  prefs->SetBoolean(prefs::kAlternateErrorPagesEnabled, false);
  prefs->SetBoolean(prefs::kSafeBrowsingEnabled, false);

  profile->InitExtensions();
}

void FakeExternalTab::Shutdown() {
  browser_process_.reset();
  g_browser_process = NULL;
  process_singleton_.reset();

  ResourceBundle::CleanupSharedInstance();
}

CFUrlRequestUnittestRunner::CFUrlRequestUnittestRunner(int argc, char** argv)
    : NetTestSuite(argc, argv),
      chrome_frame_html_("/chrome_frame", kChromeFrameHtml) {
  // Register the main thread by instantiating it, but don't call any methods.
  main_thread_.reset(new ChromeThread(ChromeThread::UI,
                                      MessageLoop::current()));
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
  fake_chrome_.Initialize();
  pss_subclass_.reset(new ProcessSingletonSubclass(this));
  EXPECT_TRUE(pss_subclass_->Subclass(fake_chrome_.user_data()));
  StartChromeFrameInHostBrowser();
}

CFUrlRequestUnittestRunner::~CFUrlRequestUnittestRunner() {
  fake_chrome_.Shutdown();
}

DWORD WINAPI NavigateIE(void* param) {
  return 0;
  win_util::ScopedCOMInitializer com;
  BSTR url = reinterpret_cast<BSTR>(param);

  bool found = false;
  int retries = 0;
  const int kMaxRetries = 20;
  while (!found && retries < kMaxRetries) {
    ScopedComPtr<IShellWindows> windows;
    HRESULT hr = ::CoCreateInstance(__uuidof(ShellWindows), NULL, CLSCTX_ALL,
        IID_IShellWindows, reinterpret_cast<void**>(windows.Receive()));
    DCHECK(SUCCEEDED(hr)) << "CoCreateInstance";

    if (SUCCEEDED(hr)) {
      hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
      long count = 0;  // NOLINT
      windows->get_Count(&count);
      VARIANT i = { VT_I4 };
      for (i.lVal = 0; i.lVal < count; ++i.lVal) {
        ScopedComPtr<IDispatch> folder;
        windows->Item(i, folder.Receive());
        if (folder != NULL) {
          ScopedComPtr<IWebBrowser2> browser;
          if (SUCCEEDED(browser.QueryFrom(folder))) {
            found = true;
            browser->Stop();
            Sleep(1000);
            VARIANT empty = ScopedVariant::kEmptyVariant;
            hr = browser->Navigate(url, &empty, &empty, &empty, &empty);
            DCHECK(SUCCEEDED(hr)) << "Failed to navigate";
            break;
          }
        }
      }
    }
    if (!found) {
      DLOG(INFO) << "Waiting for browser to initialize...";
      ::Sleep(100);
      retries++;
    }
  }

  DCHECK(retries < kMaxRetries);
  DCHECK(found);

  ::SysFreeString(url);

  return 0;
}

void CFUrlRequestUnittestRunner::StartChromeFrameInHostBrowser() {
  if (!ShouldLaunchBrowser())
    return;

  win_util::ScopedCOMInitializer com;
  chrome_frame_test::CloseAllIEWindows();

  test_http_server_.reset(new test_server::SimpleWebServer(kTestServerPort));
  test_http_server_->AddResponse(&chrome_frame_html_);
  std::wstring url(StringPrintf(L"http://localhost:%i/chrome_frame",
                                kTestServerPort).c_str());

  // Launch IE.  This launches IE correctly on Vista too.
  ScopedHandle ie_process(chrome_frame_test::LaunchIE(url));
  EXPECT_TRUE(ie_process.IsValid());

  // NOTE: If you're running IE8 and CF is not being loaded, you need to
  // disable IE8's prebinding until CF properly handles that situation.
  //
  // HKCU\Software\Microsoft\Internet Explorer\Main
  // Value name: EnablePreBinding (REG_DWORD)
  // Value: 0
}

void CFUrlRequestUnittestRunner::ShutDownHostBrowser() {
  if (ShouldLaunchBrowser()) {
    win_util::ScopedCOMInitializer com;
    chrome_frame_test::CloseAllIEWindows();
  }
}

// Override virtual void Initialize to not call icu initialize
void CFUrlRequestUnittestRunner::Initialize() {
  DCHECK(::GetCurrentThreadId() == test_thread_id_);

  // Start by replicating some of the steps that would otherwise be
  // done by TestSuite::Initialize.  We can't call the base class
  // directly because it will attempt to initialize some things such as
  // ICU that have already been initialized for this process.
  InitializeLogging();
  base::Time::UseHighResolutionTimer(true);

#if !defined(PURIFY) && defined(OS_WIN)
  logging::SetLogAssertHandler(UnitTestAssertHandler);
#endif  // !defined(PURIFY)

  // Next, do some initialization for NetTestSuite.
  NetTestSuite::InitializeTestThread();
}

void CFUrlRequestUnittestRunner::Shutdown() {
  DCHECK(::GetCurrentThreadId() == test_thread_id_);
  NetTestSuite::Shutdown();
}

void CFUrlRequestUnittestRunner::OnConnectAutomationProviderToChannel(
    const std::string& channel_id) {
  Profile* profile = g_browser_process->profile_manager()->
      GetDefaultProfile(fake_chrome_.user_data());

  AutomationProviderList* list =
      g_browser_process->InitAutomationProviderList();
  DCHECK(list);
  list->AddProvider(TestAutomationProvider::NewAutomationProvider(profile,
      channel_id, this));
}

void CFUrlRequestUnittestRunner::OnInitialTabLoaded() {
  test_http_server_.reset();
  StartTests();
}

void CFUrlRequestUnittestRunner::RunMainUIThread() {
  DCHECK(MessageLoop::current());
  DCHECK(MessageLoop::current()->type() == MessageLoop::TYPE_UI);
  MessageLoop::current()->Run();
}

void CFUrlRequestUnittestRunner::StartTests() {
  if (PromptAfterSetup())
    MessageBoxA(NULL, "click ok to run", "", MB_OK);

  DCHECK_EQ(test_thread_.IsValid(), false);
  test_thread_.Set(::CreateThread(NULL, 0, RunAllUnittests, this, 0,
                                  &test_thread_id_));
  DCHECK(test_thread_.IsValid());
}

// static
DWORD CFUrlRequestUnittestRunner::RunAllUnittests(void* param) {
  PlatformThread::SetName("CFUrlRequestUnittestRunner");
  // Needed for some url request tests like the intercept job tests, etc.
  NotificationService service;
  CFUrlRequestUnittestRunner* me =
      reinterpret_cast<CFUrlRequestUnittestRunner*>(param);
  me->Run();
  me->fake_chrome_.ui_loop()->PostTask(FROM_HERE,
      NewRunnableFunction(TakeDownBrowser, me));
  return 0;
}

// static
void CFUrlRequestUnittestRunner::TakeDownBrowser(
    CFUrlRequestUnittestRunner* me) {
  if (PromptAfterSetup())
    MessageBoxA(NULL, "click ok to exit", "", MB_OK);

  me->ShutDownHostBrowser();
}

void CFUrlRequestUnittestRunner::InitializeLogging() {
  FilePath exe;
  PathService::Get(base::FILE_EXE, &exe);
  FilePath log_filename = exe.ReplaceExtension(FILE_PATH_LITERAL("log"));
  logging::InitLogging(log_filename.value().c_str(),
                       logging::LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG,
                       logging::LOCK_LOG_FILE,
                       logging::DELETE_OLD_LOG_FILE);
  // We want process and thread IDs because we may have multiple processes.
  // Note: temporarily enabled timestamps in an effort to catch bug 6361.
  logging::SetLogItems(true, true, true, true);
}

void FilterDisabledTests() {
  if (::testing::FLAGS_gtest_filter.length() &&
      ::testing::FLAGS_gtest_filter.Compare("*") != 0) {
    // Don't override user specified filters.
    return;
  }

  const char* disabled_tests[] = {
    // Tests disabled since they're testing the same functionality used
    // by the TestAutomationProvider.
    "URLRequestTest.Intercept",
    "URLRequestTest.InterceptNetworkError",
    "URLRequestTest.InterceptRestartRequired",
    "URLRequestTest.InterceptRespectsCancelMain",
    "URLRequestTest.InterceptRespectsCancelRedirect",
    "URLRequestTest.InterceptRespectsCancelFinal",
    "URLRequestTest.InterceptRespectsCancelInRestart",
    "URLRequestTest.InterceptRedirect",
    "URLRequestTest.InterceptServerError",
    "URLRequestTestFTP.*",

    // Tests that are currently not working:

    // Temporarily disabled because they needs user input (login dialog).
    "URLRequestTestHTTP.BasicAuth",
    "URLRequestTestHTTP.BasicAuthWithCookies",

    // HTTPS tests temporarily disabled due to the certificate error dialog.
    // TODO(tommi): The tests currently fail though, so need to fix.
    "HTTPSRequestTest.HTTPSMismatchedTest",
    "HTTPSRequestTest.HTTPSExpiredTest",

    // Tests chrome's network stack's cache (might not apply to CF).
    "URLRequestTestHTTP.VaryHeader",

    // I suspect we can only get this one to work (if at all) on IE8 and
    // later by using the new INTERNET_OPTION_SUPPRESS_BEHAVIOR flags
    // See http://msdn.microsoft.com/en-us/library/aa385328(VS.85).aspx
    "URLRequestTest.DoNotSaveCookies",

    // TODO(ananta): This test has been consistently failing. Disabling it for
    // now.
    "URLRequestTestHTTP.GetTest_NoCache",
  };

  std::string filter("-");  // All following filters will be negative.
  for (int i = 0; i < arraysize(disabled_tests); ++i) {
    if (i > 0)
      filter += ":";
    filter += disabled_tests[i];
  }

  ::testing::FLAGS_gtest_filter = filter;
}

int main(int argc, char** argv) {
  DialogWatchdog watchdog;
  // See url_request_unittest.cc for these credentials.
  SupplyProxyCredentials credentials("user", "secret");
  watchdog.AddObserver(&credentials);
  testing::InitGoogleTest(&argc, argv);
  FilterDisabledTests();
  PluginService::EnableChromePlugins(false);
  CFUrlRequestUnittestRunner test_suite(argc, argv);
  test_suite.RunMainUIThread();
  return 0;
}
<|endoftext|>


<commit_before>#pragma once
#include <eos/chain/types.hpp>
#include <eos/types/generated.hpp>

namespace eos { namespace chain {
struct shared_authority {
   shared_authority( chainbase::allocator<char> alloc )
      :accounts(alloc),keys(alloc)
   {}

   shared_authority& operator=(const Authority& a) {
      threshold = a.threshold;
      accounts = decltype(accounts)(a.accounts.begin(), a.accounts.end(), accounts.get_allocator());
      keys = decltype(keys)(a.keys.begin(), a.keys.end(), keys.get_allocator());
      return *this;
   }
   shared_authority& operator=(Authority&& a) {
      threshold = a.threshold;
      accounts.reserve(a.accounts.size());
      for (auto& p : a.accounts)
         accounts.emplace_back(std::move(p));
      keys.reserve(a.keys.size());
      for (auto& p : a.keys)
         keys.emplace_back(std::move(p));
      return *this;
   }

   UInt32                                        threshold = 0;
   shared_vector<types::AccountPermissionWeight> accounts;
   shared_vector<types::KeyPermissionWeight>     keys;
};

/**
 * @brief This class determines whether a set of signing keys are sufficient to satisfy an authority or not
 *
 * To determine whether an authority is satisfied or not, we first determine which keys have approved of a message, and
 * then determine whether that list of keys is sufficient to satisfy the authority. This class takes a list of keys and
 * provides the @ref satisfied method to determine whether that list of keys satisfies a provided authority.
 *
 * @tparam F A callable which takes a single argument of type @ref AccountPermission and returns the corresponding
 * authority
 */
template<typename F>
class AuthorityChecker {
   F PermissionToAuthority;
   const flat_set<public_key_type>& signingKeys;

public:
   AuthorityChecker(F PermissionToAuthority, const flat_set<public_key_type>& signingKeys)
      : PermissionToAuthority(PermissionToAuthority), signingKeys(signingKeys) {}

   bool satisfied(const types::AccountPermission& permission) const {
      return satisfied(PermissionToAuthority(permission));
   }
   template<typename AuthorityType>
   bool satisfied(const AuthorityType& authority) const {
      UInt32 weight = 0;
      for (const auto& kpw : authority.keys)
         if (signingKeys.count(kpw.key)) {
            weight += kpw.weight;
            if (weight >= authority.threshold)
               return true;
         }
      for (const auto& apw : authority.accounts)
//#warning TODO: Recursion limit? Yes: implement as producer-configurable parameter
         if (satisfied(apw.permission)) {
            weight += apw.weight;
            if (weight >= authority.threshold)
               return true;
         }
      return false;
   }
};

inline bool operator < ( const types::AccountPermission& a, const types::AccountPermission& b ) {
   return std::tie( a.account, a.permission ) < std::tie( b.account, b.permission );
}
template<typename F>
AuthorityChecker<F> MakeAuthorityChecker(F&& pta, const flat_set<public_key_type>& signingKeys) {
   return AuthorityChecker<F>(std::forward<F>(pta), signingKeys);
}

/**
 *  Makes sure all keys are unique and sorted and all account permissions are unique and sorted
 */
inline bool validate( types::Authority& auth ) {
   const types::KeyPermissionWeight* prev = nullptr;
   for( const auto& k : auth.keys ) {
      if( !prev ) prev = &k;
      else if( prev->key < k.key ) return false;
   }
   const types::AccountPermissionWeight* pa = nullptr;
   for( const auto& a : auth.accounts ) {
      if( !pa ) pa = &a;
      else if( pa->permission < a.permission ) return false;
   }
   return true;
}

} } // namespace eos::chain

FC_REFLECT(eos::chain::shared_authority, (threshold)(accounts)(keys))
<commit_msg>Add satisfiability check to validate(Authority)<commit_after>#pragma once
#include <eos/chain/types.hpp>
#include <eos/types/generated.hpp>

namespace eos { namespace chain {
struct shared_authority {
   shared_authority( chainbase::allocator<char> alloc )
      :accounts(alloc),keys(alloc)
   {}

   shared_authority& operator=(const Authority& a) {
      threshold = a.threshold;
      accounts = decltype(accounts)(a.accounts.begin(), a.accounts.end(), accounts.get_allocator());
      keys = decltype(keys)(a.keys.begin(), a.keys.end(), keys.get_allocator());
      return *this;
   }
   shared_authority& operator=(Authority&& a) {
      threshold = a.threshold;
      accounts.reserve(a.accounts.size());
      for (auto& p : a.accounts)
         accounts.emplace_back(std::move(p));
      keys.reserve(a.keys.size());
      for (auto& p : a.keys)
         keys.emplace_back(std::move(p));
      return *this;
   }

   UInt32                                        threshold = 0;
   shared_vector<types::AccountPermissionWeight> accounts;
   shared_vector<types::KeyPermissionWeight>     keys;
};

/**
 * @brief This class determines whether a set of signing keys are sufficient to satisfy an authority or not
 *
 * To determine whether an authority is satisfied or not, we first determine which keys have approved of a message, and
 * then determine whether that list of keys is sufficient to satisfy the authority. This class takes a list of keys and
 * provides the @ref satisfied method to determine whether that list of keys satisfies a provided authority.
 *
 * @tparam F A callable which takes a single argument of type @ref AccountPermission and returns the corresponding
 * authority
 */
template<typename F>
class AuthorityChecker {
   F PermissionToAuthority;
   const flat_set<public_key_type>& signingKeys;

public:
   AuthorityChecker(F PermissionToAuthority, const flat_set<public_key_type>& signingKeys)
      : PermissionToAuthority(PermissionToAuthority), signingKeys(signingKeys) {}

   bool satisfied(const types::AccountPermission& permission) const {
      return satisfied(PermissionToAuthority(permission));
   }
   template<typename AuthorityType>
   bool satisfied(const AuthorityType& authority) const {
      UInt32 weight = 0;
      for (const auto& kpw : authority.keys)
         if (signingKeys.count(kpw.key)) {
            weight += kpw.weight;
            if (weight >= authority.threshold)
               return true;
         }
      for (const auto& apw : authority.accounts)
//#warning TODO: Recursion limit? Yes: implement as producer-configurable parameter
         if (satisfied(apw.permission)) {
            weight += apw.weight;
            if (weight >= authority.threshold)
               return true;
         }
      return false;
   }
};

inline bool operator < ( const types::AccountPermission& a, const types::AccountPermission& b ) {
   return std::tie( a.account, a.permission ) < std::tie( b.account, b.permission );
}
template<typename F>
AuthorityChecker<F> MakeAuthorityChecker(F&& pta, const flat_set<public_key_type>& signingKeys) {
   return AuthorityChecker<F>(std::forward<F>(pta), signingKeys);
}

/**
 * Makes sure all keys are unique and sorted and all account permissions are unique and sorted and that authority can
 * be satisfied
 */
inline bool validate( types::Authority& auth ) {
   const types::KeyPermissionWeight* prev = nullptr;
   decltype(auth.threshold) totalWeight = 0;

   for( const auto& k : auth.keys ) {
      if( !prev ) prev = &k;
      else if( prev->key < k.key ) return false;
      totalWeight += k.weight;
   }
   const types::AccountPermissionWeight* pa = nullptr;
   for( const auto& a : auth.accounts ) {
      if( !pa ) pa = &a;
      else if( pa->permission < a.permission ) return false;
      totalWeight += a.weight;
   }
   return totalWeight >= auth.threshold;
}

} } // namespace eos::chain

FC_REFLECT(eos::chain::shared_authority, (threshold)(accounts)(keys))
<|endoftext|>