<commit_before>/** \file    add_subsystem_tags.cc
 *  \brief   Add additional tags for interfaces to identitify subset views of
             IxTheo like RelBib and Bibstudies
 *  \author  Johannes Riedl
 */

/*
    Copyright (C) 2018, Library of the University of Tübingen

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <fstream>
#include <iostream>
#include <map>
#include <vector>
#include <cstdlib>
#include "Compiler.h"
#include "File.h"
#include "MARC.h"
#include "RegexMatcher.h"
#include "StringUtil.h"
#include "util.h"

namespace {

unsigned int record_count;
unsigned int modified_count;
const std::string RELBIB_TAG("REL");
const std::string BIBSTUDIES_TAG("BIB");

[[noreturn]] void Usage() {
    std::cerr << "Usage: " << ::progname << " [--input-format=(marc-21|marc-xml)] marc_input marc_output\n";
    std::exit(EXIT_FAILURE);
}

bool HasRelBibSSGN(const MARC::Record& record) {
    for (const auto& field : record.getTagRange("084")) {
        const MARC::Subfields subfields(field.getSubfields());
        if (subfields.hasSubfieldWithValue('2', "ssgn") and subfields.hasSubfieldWithValue('a', "0"))
            return true;
    }
    return false;
}

bool HasRelBibIxTheoNotation(const MARC::Record& record) {
    // Integrate IxTheo Notations A*.B*,T*,V*,X*,Z*
    static const std::string RELBIB_IXTHEO_NOTATION_PATTERN("^[ABTVXZ][A-Z].*|.*:[ABTVXZ][A-Z].*");
    static RegexMatcher * const relbib_ixtheo_notations_matcher(RegexMatcher::RegexMatcherFactory(RELBIB_IXTHEO_NOTATION_PATTERN));
    for (const auto& field : record.getTagRange("652")) {
        for (const auto& subfieldA : field.getSubfields().extractSubfields("a")) {
            if (relbib_ixtheo_notations_matcher->matched(subfieldA))
                return true;
        }
    }
    return false;
}

bool HasRelBibExcludeDDC(const MARC::Record& record) {
    if (not record.hasTag("082"))
        return true;
    // Exclude DDC 220-289, i.e. do not include if a DDC code of this range occurs anywhere in the DDC code
    static const std::string RELBIB_EXCLUDE_DDC_RANGE_PATTERN("2[2-8][0-9]\\.?[^.]*");
    static RegexMatcher * const relbib_exclude_ddc_range_matcher(RegexMatcher::RegexMatcherFactory(RELBIB_EXCLUDE_DDC_RANGE_PATTERN));
    for (const auto& field : record.getTagRange("082")) {
        for (const auto& subfieldA : field.getSubfields().extractSubfields("a")) {
            if (relbib_exclude_ddc_range_matcher->matched(subfieldA))
                return true;
        }
    }
    // Exclude item if it has only DDC a 400 or 800 DDC notation
    static const std::string RELBIB_EXCLUDE_DDC_CATEGORIES_PATTERN("[48][0-9][0-9]\\.?[^.]*");
    static RegexMatcher * const relbib_exclude_ddc_categories_matcher(RegexMatcher::RegexMatcherFactory(RELBIB_EXCLUDE_DDC_CATEGORIES_PATTERN));
    for (const auto& field : record.getTagRange("082")) {
        for (const auto& subfieldA : field.getSubfields().extractSubfields("a")) {
            if (not relbib_exclude_ddc_categories_matcher->matched(subfieldA))
                return false;
        }
    }
    return true;
}

bool MatchesRelBibDDC(const MARC::Record& record) {
    return not HasRelBibExcludeDDC(record);
}

bool IsDefinitelyRelBib(const MARC::Record& record) {
   return HasRelBibSSGN(record) or HasRelBibIxTheoNotation(record) or MatchesRelBibDDC(record);
}

bool IsProbablyRelBib(const MARC::Record& record) {
    for (const auto& field : record.getTagRange("191")) {
        for (const auto& subfield : field.getSubfields().extractSubfields("a")) {
            if (subfield == "1")
                return true;
        }
    }
    return false;
}

std::set<std::string> GetTemporarySuperiorRelBibList() {
    const std::string relbib_superior_temporary_file("/usr/local/ub_tools/cpp/data/relbib_superior_temporary.txt");
    std::set<std::string> superior_temporary_list;
    File::File superior_temporary(relbib_superior_temporary_file, "r");
    std::string line;
    while (superior_temporary.getline(&line) and not superior_temporary.eof())
        superior_temporary_list.emplace(line);
    return superior_temporary_list;
}

bool IsTemporaryRelBibSuperior(const MARC::Record& record) {
    static std::set<std::string> superior_temporary_list(GetTemporarySuperiorRelBibList());
    if (superior_temporary_list.find(record.getControlNumber()) != superior_temporary_list.end())
        return true;
    return false;
}

bool ExcludeBecauseOfRWEX(const MARC::Record& record) {
    for (const auto& field : record.getTagRange("935")) {
        for (const auto& subfield : field.getSubfields().extractSubfields("a")) {
            if (subfield == "rwex")
                return true;
        }
    }
    return false;
}

bool IsRelBibRecord(const MARC::Record& record) {
    return ((IsDefinitelyRelBib(record) or
             IsProbablyRelBib(record) or
             IsTemporaryRelBibSuperior(record))
             and not ExcludeBecauseOfRWEX(record));
}

bool IsBibStudiesRecord(const MARC::Record& record) {
    // FIXME ...
    record.getControlNumber();
    return false;
}

void AddSubsystemTag(MARC::Record * const record, const std::string& tag) {
    // Don't insert twice
    if (record->getFirstField(tag) != record->end())
        return;
    MARC::Subfields subfields;
    subfields.addSubfield('a', "1");
    record->insertField(tag, subfields);
}

void AddSubsystemTags(MARC::Reader * const marc_reader, MARC::Writer * const marc_writer) {
    while (MARC::Record record = marc_reader->read()) {
        ++record_count;
        bool modified_record(false);
        if (IsRelBibRecord(record)) {
            AddSubsystemTag(&record, RELBIB_TAG);
            modified_record = true;
        }
        if (IsBibStudiesRecord(record)) {
            AddSubsystemTag(&record, BIBSTUDIES_TAG);
            modified_record = true;
        }
        marc_writer->write(record);
        modified_count =  modified_record ? ++modified_count : modified_count;
    }

    std::cerr << "Modified " << modified_count << " of " << record_count << " records\n";
}

} //unnamed namespace

int main(int argc, char **argv) {
    ::progname = argv[0];

    if (argc != 3 and argc != 4)
        Usage();

    MARC::FileType reader_type(MARC::FileType::AUTO);
    if (argc == 5) {
        if (std::strcmp(argv[1], "--input-format=marc-21") == 0)
            reader_type = MARC::FileType::BINARY;
        else if (std::strcmp(argv[1], "--input-format=marc-xml") == 0)
            reader_type = MARC::FileType::XML;
        else
            Usage();
        ++argv, --argc;
    }

    const std::string marc_input_filename(argv[1]);
    const std::string marc_output_filename(argv[2]);
    if (unlikely(marc_input_filename == marc_output_filename))
        LOG_ERROR("Title data input file name equals output file name!");
    try {
        std::unique_ptr<MARC::Reader> marc_reader(MARC::Reader::Factory(marc_input_filename, reader_type));
        std::unique_ptr<MARC::Writer> marc_writer(MARC::Writer::Factory(marc_output_filename));
        AddSubsystemTags(marc_reader.get() , marc_writer.get());
    } catch (const std::exception &x) {
        LOG_ERROR("caught exception: " + std::string(x.what()));
    }
    std::cerr << "Modified " << modified_count << " of " << record_count << " records\n";

    return 0;
}
<commit_msg>Slight changes to regex to avoid descrease of result set<commit_after>/** \file    add_subsystem_tags.cc
 *  \brief   Add additional tags for interfaces to identitify subset views of
             IxTheo like RelBib and Bibstudies
 *  \author  Johannes Riedl
 */

/*
    Copyright (C) 2018, Library of the University of Tübingen

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <fstream>
#include <iostream>
#include <map>
#include <vector>
#include <cstdlib>
#include "Compiler.h"
#include "File.h"
#include "MARC.h"
#include "RegexMatcher.h"
#include "StringUtil.h"
#include "util.h"

namespace {

unsigned int record_count;
unsigned int modified_count;
const std::string RELBIB_TAG("REL");
const std::string BIBSTUDIES_TAG("BIB");

[[noreturn]] void Usage() {
    std::cerr << "Usage: " << ::progname << " [--input-format=(marc-21|marc-xml)] marc_input marc_output\n";
    std::exit(EXIT_FAILURE);
}

bool HasRelBibSSGN(const MARC::Record& record) {
    for (const auto& field : record.getTagRange("084")) {
        const MARC::Subfields subfields(field.getSubfields());
        if (subfields.hasSubfieldWithValue('2', "ssgn") and subfields.hasSubfieldWithValue('a', "0"))
            return true;
    }
    return false;
}

bool HasRelBibIxTheoNotation(const MARC::Record& record) {
    // Integrate IxTheo Notations A*.B*,T*,V*,X*,Z*
    static const std::string RELBIB_IXTHEO_NOTATION_PATTERN("^[ABTVXZ][A-Z].*|.*:[ABTVXZ][A-Z].*");
    static RegexMatcher * const relbib_ixtheo_notations_matcher(RegexMatcher::RegexMatcherFactory(RELBIB_IXTHEO_NOTATION_PATTERN));
    for (const auto& field : record.getTagRange("652")) {
        for (const auto& subfieldA : field.getSubfields().extractSubfields("a")) {
            if (relbib_ixtheo_notations_matcher->matched(subfieldA))
                return true;
        }
    }
    return false;
}

bool HasRelBibExcludeDDC(const MARC::Record& record) {
    if (not record.hasTag("082"))
        return true;
    // Exclude DDC 220-289, i.e. do not include if a DDC code of this range occurs anywhere in the DDC code
    static const std::string RELBIB_EXCLUDE_DDC_RANGE_PATTERN("^2[2-8][0-9][/.]?[^.]*$");
    static RegexMatcher * const relbib_exclude_ddc_range_matcher(RegexMatcher::RegexMatcherFactory(RELBIB_EXCLUDE_DDC_RANGE_PATTERN));
    for (const auto& field : record.getTagRange("082")) {
        for (const auto& subfieldA : field.getSubfields().extractSubfields("a")) {
            if (relbib_exclude_ddc_range_matcher->matched(subfieldA))
                return true;
        }
    }
    // Exclude item if it has only DDC a 400 or 800 DDC notation
    static const std::string RELBIB_EXCLUDE_DDC_CATEGORIES_PATTERN("^[48][0-9][0-9]$");
    static RegexMatcher * const relbib_exclude_ddc_categories_matcher(RegexMatcher::RegexMatcherFactory(RELBIB_EXCLUDE_DDC_CATEGORIES_PATTERN));
    for (const auto& field : record.getTagRange("082")) {
        for (const auto& subfieldA : field.getSubfields().extractSubfields("a")) {
            if (not relbib_exclude_ddc_categories_matcher->matched(subfieldA))
                return false;
        }
    }
    return true;
}

bool MatchesRelBibDDC(const MARC::Record& record) {
    return not HasRelBibExcludeDDC(record);
}

bool IsDefinitelyRelBib(const MARC::Record& record) {
   return HasRelBibSSGN(record) or HasRelBibIxTheoNotation(record) or MatchesRelBibDDC(record);
}

bool IsProbablyRelBib(const MARC::Record& record) {
    for (const auto& field : record.getTagRange("191")) {
        for (const auto& subfield : field.getSubfields().extractSubfields("a")) {
            if (subfield == "1")
                return true;
        }
    }
    return false;
}

std::set<std::string> GetTemporarySuperiorRelBibList() {
    const std::string relbib_superior_temporary_file("/usr/local/ub_tools/cpp/data/relbib_superior_temporary.txt");
    std::set<std::string> superior_temporary_list;
    File::File superior_temporary(relbib_superior_temporary_file, "r");
    std::string line;
    while (superior_temporary.getline(&line) and not superior_temporary.eof())
        superior_temporary_list.emplace(line);
    return superior_temporary_list;
}

bool IsTemporaryRelBibSuperior(const MARC::Record& record) {
    static std::set<std::string> superior_temporary_list(GetTemporarySuperiorRelBibList());
    if (superior_temporary_list.find(record.getControlNumber()) != superior_temporary_list.end())
        return true;
    return false;
}

bool ExcludeBecauseOfRWEX(const MARC::Record& record) {
    for (const auto& field : record.getTagRange("935")) {
        for (const auto& subfield : field.getSubfields().extractSubfields("a")) {
            if (subfield == "rwex")
                return true;
        }
    }
    return false;
}

bool IsRelBibRecord(const MARC::Record& record) {
    return ((IsDefinitelyRelBib(record) or
             IsProbablyRelBib(record) or
             IsTemporaryRelBibSuperior(record))
             and not ExcludeBecauseOfRWEX(record));
}

bool IsBibStudiesRecord(const MARC::Record& record) {
    // FIXME ...
    record.getControlNumber();
    return false;
}

void AddSubsystemTag(MARC::Record * const record, const std::string& tag) {
    // Don't insert twice
    if (record->getFirstField(tag) != record->end())
        return;
    MARC::Subfields subfields;
    subfields.addSubfield('a', "1");
    record->insertField(tag, subfields);
}

void AddSubsystemTags(MARC::Reader * const marc_reader, MARC::Writer * const marc_writer) {
    while (MARC::Record record = marc_reader->read()) {
        ++record_count;
        bool modified_record(false);
        if (IsRelBibRecord(record)) {
            AddSubsystemTag(&record, RELBIB_TAG);
            modified_record = true;
        }
        if (IsBibStudiesRecord(record)) {
            AddSubsystemTag(&record, BIBSTUDIES_TAG);
            modified_record = true;
        }
        marc_writer->write(record);
        modified_count =  modified_record ? ++modified_count : modified_count;
    }

    std::cerr << "Modified " << modified_count << " of " << record_count << " records\n";
}

} //unnamed namespace

int main(int argc, char **argv) {
    ::progname = argv[0];

    if (argc != 3 and argc != 4)
        Usage();

    MARC::FileType reader_type(MARC::FileType::AUTO);
    if (argc == 5) {
        if (std::strcmp(argv[1], "--input-format=marc-21") == 0)
            reader_type = MARC::FileType::BINARY;
        else if (std::strcmp(argv[1], "--input-format=marc-xml") == 0)
            reader_type = MARC::FileType::XML;
        else
            Usage();
        ++argv, --argc;
    }

    const std::string marc_input_filename(argv[1]);
    const std::string marc_output_filename(argv[2]);
    if (unlikely(marc_input_filename == marc_output_filename))
        LOG_ERROR("Title data input file name equals output file name!");
    try {
        std::unique_ptr<MARC::Reader> marc_reader(MARC::Reader::Factory(marc_input_filename, reader_type));
        std::unique_ptr<MARC::Writer> marc_writer(MARC::Writer::Factory(marc_output_filename));
        AddSubsystemTags(marc_reader.get() , marc_writer.get());
    } catch (const std::exception &x) {
        LOG_ERROR("caught exception: " + std::string(x.what()));
    }
    std::cerr << "Modified " << modified_count << " of " << record_count << " records\n";

    return 0;
}
<|endoftext|>


<commit_before><commit_msg>GTK: Use rounded corners in AutocompletePopupViewGtk.<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2011 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/input_method/xkeyboard.h"

#include <algorithm>
#include <set>
#include <string>

#include <gtest/gtest.h>
#include <X11/Xlib.h>

#include "base/logging.h"
#include "chrome/browser/chromeos/input_method/input_method_util.h"
#include "ui/base/x/x11_util.h"

#if defined(TOUCH_UI)
// Since TOUCH_UI build only supports a few keyboard layouts, we skip the tests
// for now.
#define TestCreateFullXkbLayoutNameKeepAlt \
  DISABLED_TestCreateFullXkbLayoutNameKeepAlt
#define TestCreateFullXkbLayoutNameKeepCapsLock \
  DISABLED_TestCreateFullXkbLayoutNameKeepCapsLock
#endif  // TOUCH_UI

namespace chromeos {
namespace input_method {

namespace {

class TestableXKeyboard : public XKeyboard {
 public:
  explicit TestableXKeyboard(const InputMethodUtil& util) : XKeyboard(util) {
  }

  // Change access rights.
  using XKeyboard::CreateFullXkbLayoutName;
  using XKeyboard::ContainsModifierKeyAsReplacement;
};

class Testee {
 public:
  Testee() : util_(), xkey_(util_) {
  }

  InputMethodUtil util_;
  TestableXKeyboard xkey_;
};

// Returns a ModifierMap object that contains the following mapping:
// - kSearchKey is mapped to |search|.
// - kLeftControl key is mapped to |control|.
// - kLeftAlt key is mapped to |alt|.
ModifierMap GetMap(ModifierKey search, ModifierKey control, ModifierKey alt) {
  ModifierMap modifier_key;
  // Use the Search key as |search|.
  modifier_key.push_back(ModifierKeyPair(kSearchKey, search));
  modifier_key.push_back(ModifierKeyPair(kLeftControlKey, control));
  modifier_key.push_back(ModifierKeyPair(kLeftAltKey, alt));
  return modifier_key;
}

// Checks |modifier_map| and returns true if the following conditions are met:
// - kSearchKey is mapped to |search|.
// - kLeftControl key is mapped to |control|.
// - kLeftAlt key is mapped to |alt|.
bool CheckMap(const ModifierMap& modifier_map,
              ModifierKey search, ModifierKey control, ModifierKey alt) {
  ModifierMap::const_iterator begin = modifier_map.begin();
  ModifierMap::const_iterator end = modifier_map.end();
  if ((std::count(begin, end, ModifierKeyPair(kSearchKey, search)) == 1) &&
      (std::count(begin, end,
                  ModifierKeyPair(kLeftControlKey, control)) == 1) &&
      (std::count(begin, end, ModifierKeyPair(kLeftAltKey, alt)) == 1)) {
    return true;
  }
  return false;
}

// Returns true if X display is available.
bool DisplayAvailable() {
  return ui::GetXDisplay() ? true : false;
}

}  // namespace

// Tests CreateFullXkbLayoutName() function.
TEST(XKeyboardTest, TestCreateFullXkbLayoutNameBasic) {
  Testee testee;

  // CreateFullXkbLayoutName should not accept an empty |layout_name|.
  EXPECT_STREQ("", testee.xkey_.CreateFullXkbLayoutName(
      "", GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());

  // CreateFullXkbLayoutName should not accept an empty ModifierMap.
  EXPECT_STREQ("", testee.xkey_.CreateFullXkbLayoutName(
      "us", ModifierMap()).c_str());

  // CreateFullXkbLayoutName should not accept an incomplete ModifierMap.
  ModifierMap tmp_map = GetMap(kVoidKey, kVoidKey, kVoidKey);
  tmp_map.pop_back();
  EXPECT_STREQ("", testee.xkey_.CreateFullXkbLayoutName("us", tmp_map).c_str());

  // CreateFullXkbLayoutName should not accept redundant ModifierMaps.
  tmp_map = GetMap(kVoidKey, kVoidKey, kVoidKey);
  tmp_map.push_back(ModifierKeyPair(kSearchKey, kVoidKey));  // two search maps
  EXPECT_STREQ("", testee.xkey_.CreateFullXkbLayoutName("us", tmp_map).c_str());
  tmp_map = GetMap(kVoidKey, kVoidKey, kVoidKey);
  tmp_map.push_back(ModifierKeyPair(kLeftControlKey, kVoidKey));  // two ctrls
  EXPECT_STREQ("", testee.xkey_.CreateFullXkbLayoutName("us", tmp_map).c_str());
  tmp_map = GetMap(kVoidKey, kVoidKey, kVoidKey);
  tmp_map.push_back(ModifierKeyPair(kLeftAltKey, kVoidKey));  // two alts.
  EXPECT_STREQ("", testee.xkey_.CreateFullXkbLayoutName("us", tmp_map).c_str());

  // CreateFullXkbLayoutName should not accept invalid ModifierMaps.
  tmp_map = GetMap(kVoidKey, kVoidKey, kVoidKey);
  tmp_map.push_back(ModifierKeyPair(kVoidKey, kSearchKey));  // can't remap void
  EXPECT_STREQ("", testee.xkey_.CreateFullXkbLayoutName("us", tmp_map).c_str());
  tmp_map = GetMap(kVoidKey, kVoidKey, kVoidKey);
  tmp_map.push_back(ModifierKeyPair(kCapsLockKey, kSearchKey));  // ditto
  EXPECT_STREQ("", testee.xkey_.CreateFullXkbLayoutName("us", tmp_map).c_str());

  // CreateFullXkbLayoutName can remap Search/Ctrl/Alt to CapsLock.
  EXPECT_STREQ("us+chromeos(capslock_disabled_disabled)",
               testee.xkey_.CreateFullXkbLayoutName(
                   "us",
                   GetMap(kCapsLockKey, kVoidKey, kVoidKey)).c_str());
  EXPECT_STREQ("us+chromeos(disabled_capslock_disabled)",
               testee.xkey_.CreateFullXkbLayoutName(
                   "us",
                   GetMap(kVoidKey, kCapsLockKey, kVoidKey)).c_str());
  EXPECT_STREQ("us+chromeos(disabled_disabled_capslock)",
               testee.xkey_.CreateFullXkbLayoutName(
                   "us",
                   GetMap(kVoidKey, kVoidKey, kCapsLockKey)).c_str());

  // CreateFullXkbLayoutName should not accept non-alphanumeric characters
  // except "()-_".
  EXPECT_STREQ("", testee.xkey_.CreateFullXkbLayoutName(
      "us!", GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());
  EXPECT_STREQ("", testee.xkey_.CreateFullXkbLayoutName(
      "us; /bin/sh", GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());
  EXPECT_STREQ("ab-c_12+chromeos(disabled_disabled_disabled),us",
               testee.xkey_.CreateFullXkbLayoutName(
                   "ab-c_12",
                   GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());

  // CreateFullXkbLayoutName should not accept upper-case ascii characters.
  EXPECT_STREQ("", testee.xkey_.CreateFullXkbLayoutName(
      "US", GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());

  // CreateFullXkbLayoutName should accept lower-case ascii characters.
  for (int c = 'a'; c <= 'z'; ++c) {
    EXPECT_STRNE("", testee.xkey_.CreateFullXkbLayoutName(
        std::string(3, c),
        GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());
  }

  // CreateFullXkbLayoutName should accept numbers.
  for (int c = '0'; c <= '9'; ++c) {
    EXPECT_STRNE("", testee.xkey_.CreateFullXkbLayoutName(
        std::string(3, c),
        GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());
  }

  // CreateFullXkbLayoutName should accept a layout with a variant name.
  EXPECT_STREQ("us(dvorak)+chromeos(disabled_disabled_disabled)",
               testee.xkey_.CreateFullXkbLayoutName(
                   "us(dvorak)",
                   GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());
  EXPECT_STREQ("gb(extd)+chromeos(disabled_disabled_disabled_keepralt),us",
                testee.xkey_.CreateFullXkbLayoutName(
                    "gb(extd)",
                    GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());
  EXPECT_STREQ("jp+chromeos(disabled_disabled_disabled),us",
               testee.xkey_.CreateFullXkbLayoutName(
                   "jp",  // does not use AltGr, therefore no _keepralt.
                   GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());

  // When the layout name is not "us", the second layout should be added.
  EXPECT_EQ(std::string::npos, testee.xkey_.CreateFullXkbLayoutName(
      "us", GetMap(kVoidKey, kVoidKey, kVoidKey)).find(",us"));
  EXPECT_EQ(std::string::npos, testee.xkey_.CreateFullXkbLayoutName(
      "us(dvorak)", GetMap(kVoidKey, kVoidKey, kVoidKey)).find(",us"));
  EXPECT_NE(std::string::npos, testee.xkey_.CreateFullXkbLayoutName(
      "gb(extd)", GetMap(kVoidKey, kVoidKey, kVoidKey)).find(",us"));
  EXPECT_NE(std::string::npos, testee.xkey_.CreateFullXkbLayoutName(
      "jp", GetMap(kVoidKey, kVoidKey, kVoidKey)).find(",us"));
}

TEST(XKeyboardTest, TestCreateFullXkbLayoutNameKeepCapsLock) {
  Testee testee;

  EXPECT_STREQ("us(colemak)+chromeos(search_disabled_disabled)",
               testee.xkey_.CreateFullXkbLayoutName(
                   "us(colemak)",
                   // The 1st kVoidKey should be ignored.
                   GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());
  EXPECT_STREQ("de(neo)+"
               "chromeos(search_leftcontrol_leftcontrol_keepralt),us",
               testee.xkey_.CreateFullXkbLayoutName(
                   // The 1st kLeftControlKey should be ignored.
                   "de(neo)", GetMap(kLeftControlKey,
                                     kLeftControlKey,
                                     kLeftControlKey)).c_str());
}

TEST(XKeyboardTest, TestCreateFullXkbLayoutNameKeepAlt) {
  Testee testee;

  EXPECT_STREQ("us(intl)+chromeos(disabled_disabled_disabled_keepralt)",
               testee.xkey_.CreateFullXkbLayoutName(
                   "us(intl)", GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());
  EXPECT_STREQ("kr(kr104)+"
               "chromeos(leftcontrol_leftcontrol_leftcontrol_keepralt),us",
               testee.xkey_.CreateFullXkbLayoutName(
                   "kr(kr104)", GetMap(kLeftControlKey,
                                       kLeftControlKey,
                                       kLeftControlKey)).c_str());
}

// Tests if CreateFullXkbLayoutName and ExtractLayoutNameFromFullXkbLayoutName
// functions could handle all combinations of modifier remapping.
TEST(XKeyboardTest, TestCreateFullXkbLayoutNameModifierKeys) {
  Testee testee;

  std::set<std::string> layouts;
  for (int i = 0; i < static_cast<int>(kNumModifierKeys); ++i) {
    for (int j = 0; j < static_cast<int>(kNumModifierKeys); ++j) {
      for (int k = 0; k < static_cast<int>(kNumModifierKeys); ++k) {
        const std::string layout = testee.xkey_.CreateFullXkbLayoutName(
            "us", GetMap(ModifierKey(i), ModifierKey(j), ModifierKey(k)));
        // CreateFullXkbLayoutName should succeed (i.e. should not return "".)
        EXPECT_STREQ("us+", layout.substr(0, 3).c_str())
            << "layout: " << layout;
        // All 4*3*3 layouts should be different.
        EXPECT_TRUE(layouts.insert(layout).second) << "layout: " << layout;
      }
    }
  }
}

TEST(XKeyboardTest, TestSetCapsLockIsEnabled) {
  if (!DisplayAvailable()) {
    return;
  }
  const bool initial_lock_state = XKeyboard::CapsLockIsEnabled();
  XKeyboard::SetCapsLockEnabled(true);
  EXPECT_TRUE(XKeyboard::CapsLockIsEnabled());
  XKeyboard::SetCapsLockEnabled(false);
  EXPECT_FALSE(XKeyboard::CapsLockIsEnabled());
  XKeyboard::SetCapsLockEnabled(true);
  EXPECT_TRUE(XKeyboard::CapsLockIsEnabled());
  XKeyboard::SetCapsLockEnabled(false);
  EXPECT_FALSE(XKeyboard::CapsLockIsEnabled());
  XKeyboard::SetCapsLockEnabled(initial_lock_state);
}

TEST(XKeyboardTest, TestContainsModifierKeyAsReplacement) {
  EXPECT_FALSE(TestableXKeyboard::ContainsModifierKeyAsReplacement(
      GetMap(kVoidKey, kVoidKey, kVoidKey), kCapsLockKey));
  EXPECT_TRUE(TestableXKeyboard::ContainsModifierKeyAsReplacement(
      GetMap(kCapsLockKey, kVoidKey, kVoidKey), kCapsLockKey));
  EXPECT_TRUE(TestableXKeyboard::ContainsModifierKeyAsReplacement(
      GetMap(kVoidKey, kCapsLockKey, kVoidKey), kCapsLockKey));
  EXPECT_TRUE(TestableXKeyboard::ContainsModifierKeyAsReplacement(
      GetMap(kVoidKey, kVoidKey, kCapsLockKey), kCapsLockKey));
  EXPECT_TRUE(TestableXKeyboard::ContainsModifierKeyAsReplacement(
      GetMap(kCapsLockKey, kCapsLockKey, kVoidKey), kCapsLockKey));
  EXPECT_TRUE(TestableXKeyboard::ContainsModifierKeyAsReplacement(
      GetMap(kCapsLockKey, kCapsLockKey, kCapsLockKey), kCapsLockKey));
  EXPECT_TRUE(TestableXKeyboard::ContainsModifierKeyAsReplacement(
      GetMap(kSearchKey, kVoidKey, kVoidKey), kSearchKey));
}

}  // namespace input_method
}  // namespace chromeos
<commit_msg>Fix unit_tests break on TOUCH_UI build.<commit_after>// Copyright (c) 2011 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/input_method/xkeyboard.h"

#include <algorithm>
#include <set>
#include <string>

#include <gtest/gtest.h>
#include <X11/Xlib.h>

#include "base/logging.h"
#include "chrome/browser/chromeos/input_method/input_method_util.h"
#include "ui/base/x/x11_util.h"

#if defined(TOUCH_UI)
// Since TOUCH_UI build only supports a few keyboard layouts, we skip the tests
// for now.
#define TestCreateFullXkbLayoutNameKeepAlt \
  DISABLED_TestCreateFullXkbLayoutNameKeepAlt
#define TestCreateFullXkbLayoutNameKeepCapsLock \
  DISABLED_TestCreateFullXkbLayoutNameKeepCapsLock
#endif  // TOUCH_UI

namespace chromeos {
namespace input_method {

namespace {

class TestableXKeyboard : public XKeyboard {
 public:
  explicit TestableXKeyboard(const InputMethodUtil& util) : XKeyboard(util) {
  }

  // Change access rights.
  using XKeyboard::CreateFullXkbLayoutName;
  using XKeyboard::ContainsModifierKeyAsReplacement;
};

class Testee {
 public:
  Testee() : util_(), xkey_(util_) {
  }

  InputMethodUtil util_;
  TestableXKeyboard xkey_;
};

// Returns a ModifierMap object that contains the following mapping:
// - kSearchKey is mapped to |search|.
// - kLeftControl key is mapped to |control|.
// - kLeftAlt key is mapped to |alt|.
ModifierMap GetMap(ModifierKey search, ModifierKey control, ModifierKey alt) {
  ModifierMap modifier_key;
  // Use the Search key as |search|.
  modifier_key.push_back(ModifierKeyPair(kSearchKey, search));
  modifier_key.push_back(ModifierKeyPair(kLeftControlKey, control));
  modifier_key.push_back(ModifierKeyPair(kLeftAltKey, alt));
  return modifier_key;
}

// Checks |modifier_map| and returns true if the following conditions are met:
// - kSearchKey is mapped to |search|.
// - kLeftControl key is mapped to |control|.
// - kLeftAlt key is mapped to |alt|.
bool CheckMap(const ModifierMap& modifier_map,
              ModifierKey search, ModifierKey control, ModifierKey alt) {
  ModifierMap::const_iterator begin = modifier_map.begin();
  ModifierMap::const_iterator end = modifier_map.end();
  if ((std::count(begin, end, ModifierKeyPair(kSearchKey, search)) == 1) &&
      (std::count(begin, end,
                  ModifierKeyPair(kLeftControlKey, control)) == 1) &&
      (std::count(begin, end, ModifierKeyPair(kLeftAltKey, alt)) == 1)) {
    return true;
  }
  return false;
}

// Returns true if X display is available.
bool DisplayAvailable() {
  return ui::GetXDisplay() ? true : false;
}

}  // namespace

// Tests CreateFullXkbLayoutName() function.
TEST(XKeyboardTest, TestCreateFullXkbLayoutNameBasic) {
  Testee testee;

  // CreateFullXkbLayoutName should not accept an empty |layout_name|.
  EXPECT_STREQ("", testee.xkey_.CreateFullXkbLayoutName(
      "", GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());

  // CreateFullXkbLayoutName should not accept an empty ModifierMap.
  EXPECT_STREQ("", testee.xkey_.CreateFullXkbLayoutName(
      "us", ModifierMap()).c_str());

  // CreateFullXkbLayoutName should not accept an incomplete ModifierMap.
  ModifierMap tmp_map = GetMap(kVoidKey, kVoidKey, kVoidKey);
  tmp_map.pop_back();
  EXPECT_STREQ("", testee.xkey_.CreateFullXkbLayoutName("us", tmp_map).c_str());

  // CreateFullXkbLayoutName should not accept redundant ModifierMaps.
  tmp_map = GetMap(kVoidKey, kVoidKey, kVoidKey);
  tmp_map.push_back(ModifierKeyPair(kSearchKey, kVoidKey));  // two search maps
  EXPECT_STREQ("", testee.xkey_.CreateFullXkbLayoutName("us", tmp_map).c_str());
  tmp_map = GetMap(kVoidKey, kVoidKey, kVoidKey);
  tmp_map.push_back(ModifierKeyPair(kLeftControlKey, kVoidKey));  // two ctrls
  EXPECT_STREQ("", testee.xkey_.CreateFullXkbLayoutName("us", tmp_map).c_str());
  tmp_map = GetMap(kVoidKey, kVoidKey, kVoidKey);
  tmp_map.push_back(ModifierKeyPair(kLeftAltKey, kVoidKey));  // two alts.
  EXPECT_STREQ("", testee.xkey_.CreateFullXkbLayoutName("us", tmp_map).c_str());

  // CreateFullXkbLayoutName should not accept invalid ModifierMaps.
  tmp_map = GetMap(kVoidKey, kVoidKey, kVoidKey);
  tmp_map.push_back(ModifierKeyPair(kVoidKey, kSearchKey));  // can't remap void
  EXPECT_STREQ("", testee.xkey_.CreateFullXkbLayoutName("us", tmp_map).c_str());
  tmp_map = GetMap(kVoidKey, kVoidKey, kVoidKey);
  tmp_map.push_back(ModifierKeyPair(kCapsLockKey, kSearchKey));  // ditto
  EXPECT_STREQ("", testee.xkey_.CreateFullXkbLayoutName("us", tmp_map).c_str());

  // CreateFullXkbLayoutName can remap Search/Ctrl/Alt to CapsLock.
  EXPECT_STREQ("us+chromeos(capslock_disabled_disabled)",
               testee.xkey_.CreateFullXkbLayoutName(
                   "us",
                   GetMap(kCapsLockKey, kVoidKey, kVoidKey)).c_str());
  EXPECT_STREQ("us+chromeos(disabled_capslock_disabled)",
               testee.xkey_.CreateFullXkbLayoutName(
                   "us",
                   GetMap(kVoidKey, kCapsLockKey, kVoidKey)).c_str());
  EXPECT_STREQ("us+chromeos(disabled_disabled_capslock)",
               testee.xkey_.CreateFullXkbLayoutName(
                   "us",
                   GetMap(kVoidKey, kVoidKey, kCapsLockKey)).c_str());

  // CreateFullXkbLayoutName should not accept non-alphanumeric characters
  // except "()-_".
  EXPECT_STREQ("", testee.xkey_.CreateFullXkbLayoutName(
      "us!", GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());
  EXPECT_STREQ("", testee.xkey_.CreateFullXkbLayoutName(
      "us; /bin/sh", GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());
  EXPECT_STREQ("ab-c_12+chromeos(disabled_disabled_disabled),us",
               testee.xkey_.CreateFullXkbLayoutName(
                   "ab-c_12",
                   GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());

  // CreateFullXkbLayoutName should not accept upper-case ascii characters.
  EXPECT_STREQ("", testee.xkey_.CreateFullXkbLayoutName(
      "US", GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());

  // CreateFullXkbLayoutName should accept lower-case ascii characters.
  for (int c = 'a'; c <= 'z'; ++c) {
    EXPECT_STRNE("", testee.xkey_.CreateFullXkbLayoutName(
        std::string(3, c),
        GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());
  }

  // CreateFullXkbLayoutName should accept numbers.
  for (int c = '0'; c <= '9'; ++c) {
    EXPECT_STRNE("", testee.xkey_.CreateFullXkbLayoutName(
        std::string(3, c),
        GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());
  }

  // CreateFullXkbLayoutName should accept a layout with a variant name.
  EXPECT_STREQ("us(dvorak)+chromeos(disabled_disabled_disabled)",
               testee.xkey_.CreateFullXkbLayoutName(
                   "us(dvorak)",
                   GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());
  EXPECT_STREQ("jp+chromeos(disabled_disabled_disabled),us",
               testee.xkey_.CreateFullXkbLayoutName(
                   "jp",  // does not use AltGr, therefore no _keepralt.
                   GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());

  // When the layout name is not "us", the second layout should be added.
  EXPECT_EQ(std::string::npos, testee.xkey_.CreateFullXkbLayoutName(
      "us", GetMap(kVoidKey, kVoidKey, kVoidKey)).find(",us"));
  EXPECT_EQ(std::string::npos, testee.xkey_.CreateFullXkbLayoutName(
      "us(dvorak)", GetMap(kVoidKey, kVoidKey, kVoidKey)).find(",us"));
  EXPECT_NE(std::string::npos, testee.xkey_.CreateFullXkbLayoutName(
      "gb(extd)", GetMap(kVoidKey, kVoidKey, kVoidKey)).find(",us"));
  EXPECT_NE(std::string::npos, testee.xkey_.CreateFullXkbLayoutName(
      "jp", GetMap(kVoidKey, kVoidKey, kVoidKey)).find(",us"));
}

TEST(XKeyboardTest, TestCreateFullXkbLayoutNameKeepCapsLock) {
  Testee testee;

  EXPECT_STREQ("us(colemak)+chromeos(search_disabled_disabled)",
               testee.xkey_.CreateFullXkbLayoutName(
                   "us(colemak)",
                   // The 1st kVoidKey should be ignored.
                   GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());
  EXPECT_STREQ("de(neo)+"
               "chromeos(search_leftcontrol_leftcontrol_keepralt),us",
               testee.xkey_.CreateFullXkbLayoutName(
                   // The 1st kLeftControlKey should be ignored.
                   "de(neo)", GetMap(kLeftControlKey,
                                     kLeftControlKey,
                                     kLeftControlKey)).c_str());
  EXPECT_STREQ("gb(extd)+chromeos(disabled_disabled_disabled_keepralt),us",
                testee.xkey_.CreateFullXkbLayoutName(
                    "gb(extd)",
                    GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());
}

TEST(XKeyboardTest, TestCreateFullXkbLayoutNameKeepAlt) {
  Testee testee;

  EXPECT_STREQ("us(intl)+chromeos(disabled_disabled_disabled_keepralt)",
               testee.xkey_.CreateFullXkbLayoutName(
                   "us(intl)", GetMap(kVoidKey, kVoidKey, kVoidKey)).c_str());
  EXPECT_STREQ("kr(kr104)+"
               "chromeos(leftcontrol_leftcontrol_leftcontrol_keepralt),us",
               testee.xkey_.CreateFullXkbLayoutName(
                   "kr(kr104)", GetMap(kLeftControlKey,
                                       kLeftControlKey,
                                       kLeftControlKey)).c_str());
}

// Tests if CreateFullXkbLayoutName and ExtractLayoutNameFromFullXkbLayoutName
// functions could handle all combinations of modifier remapping.
TEST(XKeyboardTest, TestCreateFullXkbLayoutNameModifierKeys) {
  Testee testee;

  std::set<std::string> layouts;
  for (int i = 0; i < static_cast<int>(kNumModifierKeys); ++i) {
    for (int j = 0; j < static_cast<int>(kNumModifierKeys); ++j) {
      for (int k = 0; k < static_cast<int>(kNumModifierKeys); ++k) {
        const std::string layout = testee.xkey_.CreateFullXkbLayoutName(
            "us", GetMap(ModifierKey(i), ModifierKey(j), ModifierKey(k)));
        // CreateFullXkbLayoutName should succeed (i.e. should not return "".)
        EXPECT_STREQ("us+", layout.substr(0, 3).c_str())
            << "layout: " << layout;
        // All 4*3*3 layouts should be different.
        EXPECT_TRUE(layouts.insert(layout).second) << "layout: " << layout;
      }
    }
  }
}

TEST(XKeyboardTest, TestSetCapsLockIsEnabled) {
  if (!DisplayAvailable()) {
    return;
  }
  const bool initial_lock_state = XKeyboard::CapsLockIsEnabled();
  XKeyboard::SetCapsLockEnabled(true);
  EXPECT_TRUE(XKeyboard::CapsLockIsEnabled());
  XKeyboard::SetCapsLockEnabled(false);
  EXPECT_FALSE(XKeyboard::CapsLockIsEnabled());
  XKeyboard::SetCapsLockEnabled(true);
  EXPECT_TRUE(XKeyboard::CapsLockIsEnabled());
  XKeyboard::SetCapsLockEnabled(false);
  EXPECT_FALSE(XKeyboard::CapsLockIsEnabled());
  XKeyboard::SetCapsLockEnabled(initial_lock_state);
}

TEST(XKeyboardTest, TestContainsModifierKeyAsReplacement) {
  EXPECT_FALSE(TestableXKeyboard::ContainsModifierKeyAsReplacement(
      GetMap(kVoidKey, kVoidKey, kVoidKey), kCapsLockKey));
  EXPECT_TRUE(TestableXKeyboard::ContainsModifierKeyAsReplacement(
      GetMap(kCapsLockKey, kVoidKey, kVoidKey), kCapsLockKey));
  EXPECT_TRUE(TestableXKeyboard::ContainsModifierKeyAsReplacement(
      GetMap(kVoidKey, kCapsLockKey, kVoidKey), kCapsLockKey));
  EXPECT_TRUE(TestableXKeyboard::ContainsModifierKeyAsReplacement(
      GetMap(kVoidKey, kVoidKey, kCapsLockKey), kCapsLockKey));
  EXPECT_TRUE(TestableXKeyboard::ContainsModifierKeyAsReplacement(
      GetMap(kCapsLockKey, kCapsLockKey, kVoidKey), kCapsLockKey));
  EXPECT_TRUE(TestableXKeyboard::ContainsModifierKeyAsReplacement(
      GetMap(kCapsLockKey, kCapsLockKey, kCapsLockKey), kCapsLockKey));
  EXPECT_TRUE(TestableXKeyboard::ContainsModifierKeyAsReplacement(
      GetMap(kSearchKey, kVoidKey, kVoidKey), kSearchKey));
}

}  // namespace input_method
}  // namespace chromeos
<|endoftext|>


<commit_before>/** \brief Marc-Implementation
 *  \author Oliver Obenland (oliver.obenland@uni-tuebingen.de)
 *
 *  \copyright 2016 Universitätsbiblothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "MarcRecord.h"
#include "MarcTag.h"
#include "util.h"
#include <iostream>

const size_t MarcRecord::FIELD_NOT_FOUND;

MarcRecord &MarcRecord::operator=(const MarcRecord &rhs) {
    if (likely(&rhs != this)) {
        leader_ = rhs.leader_;
        raw_data_ = rhs.raw_data_;
        directory_entries_ = rhs.directory_entries_;
    }
    return *this;
}

std::string MarcRecord::getFieldData(const MarcTag &tag) const {
    return getFieldData(getFieldIndex(tag));
}

std::string MarcRecord::getFieldData(const size_t index) const {
    if (directory_entries_.cbegin() + index >= directory_entries_.cend())
        return "";
    const DirectoryEntry &entry(directory_entries_[index]);
    return std::string(raw_data_, entry.getFieldOffset(), entry.getFieldLength() - 1);
}

Subfields MarcRecord::getSubfields(const MarcTag &tag) const {
    return getSubfields(getFieldIndex(tag));
}

Subfields MarcRecord::getSubfields(const size_t index) const {
    if (directory_entries_.cbegin() + index >= directory_entries_.cend())
        return Subfields();
    return Subfields(getFieldData(index));
}

void MarcRecord::deleteSubfield(const size_t field_index, const char subfield_code) {
    Subfields subfields(getSubfields(field_index));
    subfields.erase(subfield_code);
    updateField(field_index, subfields.toString());
}

MarcTag MarcRecord::getTag(const size_t index) const {
    if (directory_entries_.cbegin() + index >= directory_entries_.cend())
        return "";
    return directory_entries_[index].getTag();
}

size_t MarcRecord::getFieldIndex(const MarcTag &field_tag) const {
    for (size_t i(0); i < getNumberOfFields(); ++i) {
        if (directory_entries_[i].getTag() == field_tag)
            return i;
    }
    return MarcRecord::FIELD_NOT_FOUND;
}

size_t MarcRecord::getFieldIndices(const MarcTag &field_tag, std::vector <size_t> *const field_indices) const {
    field_indices->clear();

    size_t field_index(getFieldIndex(field_tag));
    while (static_cast<size_t>(field_index) < directory_entries_.size() and
           directory_entries_[field_index].getTag() == field_tag) {
        field_indices->emplace_back(field_index);
        ++field_index;
    }

    return field_indices->size();
}

bool MarcRecord::updateField(const size_t field_index, const std::string &new_field_value) {
    DirectoryEntry &entry(directory_entries_[field_index]);
    size_t offset = raw_data_.size();
    size_t length = new_field_value.length() + 1 /* For new field separator. */;

    entry.setFieldLength(length);
    entry.setFieldOffset(offset);
    raw_data_ += new_field_value + '\x1E';

    return true;
}

bool MarcRecord::insertSubfield(const MarcTag &new_field_tag, const char subfield_code,
                                const std::string &new_subfield_value, const char indicator1, const char indicator2) {
    return insertField(new_field_tag, std::string(1, indicator1) + std::string(1, indicator2) + "\x1F"
                                      + std::string(1, subfield_code) + new_subfield_value);
}

size_t MarcRecord::insertField(const MarcTag &new_field_tag, const std::string &new_field_value) {

    // Find the insertion location:
    auto insertion_location(directory_entries_.begin());
    while (insertion_location != directory_entries_.end() and new_field_tag >= insertion_location->getTag())
        ++insertion_location;

    const size_t offset(raw_data_.size());
    const size_t length(new_field_value.length() + 1) /* For new field separator. */;
    const auto inserted_location(directory_entries_.emplace(insertion_location, new_field_tag, length, offset));
    raw_data_ += new_field_value + '\x1E';

    const size_t index(std::distance(directory_entries_.begin(), inserted_location));
    return index;
}

void MarcRecord::deleteField(const size_t field_index) {
    directory_entries_.erase(directory_entries_.begin() + field_index);
}

void MarcRecord::deleteFields(const std::vector <std::pair<size_t, size_t>> &blocks) {
    std::vector <DirectoryEntry> new_entries;
    new_entries.reserve(directory_entries_.size());

    size_t copy_start(0);
    for (const std::pair <size_t, size_t> block : blocks) {
        new_entries.insert(new_entries.end(), directory_entries_.begin() + copy_start,
                           directory_entries_.begin() + block.first);
        copy_start = block.second;
    }
    new_entries.insert(new_entries.end(), directory_entries_.begin() + copy_start, directory_entries_.end());
    new_entries.swap(directory_entries_);
}

std::string MarcRecord::extractFirstSubfield(const MarcTag &tag, const char subfield_code) const {
    const size_t index(getFieldIndex(tag));
    if (index == FIELD_NOT_FOUND)
        return "";
    return getSubfields(tag).getFirstSubfieldValue(subfield_code);
}

std::string MarcRecord::extractFirstSubfield(const size_t field_index, const char subfield_code) const {
    const Subfields subfields(getFieldData(field_index));
    return subfields.getFirstSubfieldValue(subfield_code);
}

size_t MarcRecord::extractAllSubfields(const std::string &tags, std::vector <std::string> *const values,
                                       const std::string &ignore_subfield_codes) const {
    values->clear();

    std::vector <std::string> individual_tags;
    StringUtil::Split(tags, ':', &individual_tags);
    for (const auto &tag : individual_tags) {
        size_t field_index(getFieldIndex(tag));
        while (static_cast<size_t>(field_index) < directory_entries_.size() and
               directory_entries_[field_index].getTag() == tag) {
            const Subfields subfields(getSubfields(field_index));
            for (const auto &subfield : subfields) {
                if (ignore_subfield_codes.find(subfield.code_) == std::string::npos)
                    values->emplace_back(subfield.value_);
            }
            ++field_index;
        }
    }
    return values->size();
}

size_t MarcRecord::extractSubfield(const MarcTag &tag, const char subfield_code,
                                   std::vector <std::string> *const values) const {
    values->clear();

    size_t field_index(getFieldIndex(tag));
    while (static_cast<size_t>(field_index) < directory_entries_.size() and
           tag == directory_entries_[field_index].getTag()) {
        const Subfields subfields(getSubfields(field_index));
        const auto begin_end(subfields.getIterators(subfield_code));
        for (auto subfield_code_and_value(begin_end.first);
             subfield_code_and_value != begin_end.second; ++subfield_code_and_value)
            values->emplace_back(subfield_code_and_value->value_);
        ++field_index;
    }
    return values->size();
}

size_t MarcRecord::extractSubfields(const MarcTag &tag, const std::string &subfield_codes,
                                    std::vector <std::string> *const values) const {
    values->clear();

    size_t field_index(getFieldIndex(tag));
    while (static_cast<size_t>(field_index) < directory_entries_.size() and
           tag == directory_entries_[field_index].getTag()) {
        const Subfields subfields(getSubfields(field_index));
        for (const auto &subfield : subfields) {
            if (subfield_codes.find(subfield.code_) != std::string::npos)
                values->emplace_back(subfield.value_);
        }
        ++field_index;
    }

    return values->size();
}

size_t MarcRecord::findAllLocalDataBlocks(std::vector <std::pair<size_t, size_t>> *const local_block_boundaries) const {
    local_block_boundaries->clear();

    size_t local_block_start(getFieldIndex("LOK"));
    if (local_block_start == FIELD_NOT_FOUND)
        return 0;

    size_t local_block_end(local_block_start + 1);
    while (local_block_end < directory_entries_.size()) {
        if (StringUtil::StartsWith(getFieldData(local_block_end), "  ""\x1F""0000")) {
            local_block_boundaries->emplace_back(std::make_pair(local_block_start, local_block_end));
            local_block_start = local_block_end;
        }
        ++local_block_end;
    }
    local_block_boundaries->emplace_back(std::make_pair(local_block_start, local_block_end));

    return local_block_boundaries->size();
}

static bool IndicatorsMatch(const std::string &indicator_pattern, const std::string &indicators) {
    if (indicator_pattern[0] != '?' and indicator_pattern[0] != indicators[0])
        return false;
    if (indicator_pattern[1] != '?' and indicator_pattern[1] != indicators[1])
        return false;
    return true;
}

size_t MarcRecord::findFieldsInLocalBlock(const MarcTag &field_tag, const std::string &indicators,
                                          const std::pair <size_t, size_t> &block_start_and_end,
                                          std::vector <size_t> *const field_indices) const {
    field_indices->clear();
    if (unlikely(indicators.length() != 2))
        Error("in MarcUtil::FindFieldInLocalBlock: indicators must be precisely 2 characters long!");

    const std::string FIELD_PREFIX("  ""\x1F""0" + field_tag.to_string());
    for (size_t index(block_start_and_end.first); index < block_start_and_end.second; ++index) {
        const std::string &current_field(getFieldData(index));
        if (StringUtil::StartsWith(current_field, FIELD_PREFIX)
            and IndicatorsMatch(indicators, current_field.substr(7, 2)))
            field_indices->emplace_back(index);
    }
    return field_indices->size();
}

void MarcRecord::filterTags(const std::unordered_set <MarcTag> &drop_tags) {
    std::vector <std::pair<size_t, size_t>> deleted_blocks;
    for (auto entry = directory_entries_.begin(); entry < directory_entries_.end(); ++entry) {
        const auto tag_iter = drop_tags.find(entry->getTag());
        if (tag_iter == drop_tags.cend())
            continue;
        const size_t block_start = std::distance(directory_entries_.begin(), entry);
        for (/* empty */; entry < directory_entries_.end() and entry->getTag() == *tag_iter; ++entry);
        const size_t block_end = std::distance(directory_entries_.begin(), entry);

        deleted_blocks.emplace_back(block_start, block_end);
    }
    deleteFields(deleted_blocks);
}

std::string MarcRecord::getLanguage(const std::string &default_language_code) const {
    const std::string &language(extractFirstSubfield("041", 'a'));
    if (likely(not language.empty()))
        return language;
    return default_language_code;
}

std::string MarcRecord::getLanguageCode() const {
    const size_t _008_index(getFieldIndex("008"));
    if (_008_index == FIELD_NOT_FOUND)
        return "";
    // Language codes start at offset 35 and have a length of 3.
    const auto entry = directory_entries_[_008_index];
    if (entry.getFieldLength() < 38)
        return "";

    return std::string(raw_data_, entry.getFieldOffset() + 35, 3);
}

void MarcRecord::combine(const MarcRecord &record) {
    const size_t offset(raw_data_.size());
    raw_data_ += record.raw_data_;

    // Ignore first field. We only need one 001-field.
    directory_entries_.reserve(record.directory_entries_.size() - 1);
    for (auto iter(record.directory_entries_.begin() + 1); iter < record.directory_entries_.end(); ++iter) {
        directory_entries_.emplace_back(*iter);
        directory_entries_.back().setFieldOffset(iter->getFieldOffset() + offset);
    }
}

bool MarcRecord::ProcessRecords(File *const input, File *const output, RecordFunc process_record,
                                std::string *const err_msg) {
    err_msg->clear();

    while (MarcRecord record = MarcReader::Read(input)) {
        if (not (*process_record)(&record, output, err_msg))
            return false;
        err_msg->clear();
    }

    return err_msg->empty();
}

bool MarcRecord::ProcessRecords(File *const input, XmlRecordFunc process_record, XmlWriter *const xml_writer,
                                std::string *const err_msg) {
    err_msg->clear();

    while (MarcRecord record = MarcReader::ReadXML(input)) {
        if (not (*process_record)(&record, xml_writer, err_msg))
            return false;
        err_msg->clear();
    }

    return err_msg->empty();
}
<commit_msg>Some clean-up.<commit_after>/** \brief Implementation of the MarcRecord class.
 *  \author Oliver Obenland (oliver.obenland@uni-tuebingen.de)
 *
 *  \copyright 2016 Universitätsbiblothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "MarcRecord.h"
#include "MarcTag.h"
#include "util.h"
#include <iostream>

const size_t MarcRecord::FIELD_NOT_FOUND;

MarcRecord &MarcRecord::operator=(const MarcRecord &rhs) {
    if (likely(&rhs != this)) {
        leader_ = rhs.leader_;
        raw_data_ = rhs.raw_data_;
        directory_entries_ = rhs.directory_entries_;
    }
    return *this;
}

std::string MarcRecord::getFieldData(const MarcTag &tag) const {
    return getFieldData(getFieldIndex(tag));
}

std::string MarcRecord::getFieldData(const size_t index) const {
    if (directory_entries_.cbegin() + index >= directory_entries_.cend())
        return "";
    const DirectoryEntry &entry(directory_entries_[index]);
    return std::string(raw_data_, entry.getFieldOffset(), entry.getFieldLength() - 1);
}

Subfields MarcRecord::getSubfields(const MarcTag &tag) const {
    return getSubfields(getFieldIndex(tag));
}

Subfields MarcRecord::getSubfields(const size_t index) const {
    if (directory_entries_.cbegin() + index >= directory_entries_.cend())
        return Subfields();
    return Subfields(getFieldData(index));
}

void MarcRecord::deleteSubfield(const size_t field_index, const char subfield_code) {
    Subfields subfields(getSubfields(field_index));
    subfields.erase(subfield_code);
    updateField(field_index, subfields.toString());
}

MarcTag MarcRecord::getTag(const size_t index) const {
    if (directory_entries_.cbegin() + index >= directory_entries_.cend())
        return "";
    return directory_entries_[index].getTag();
}

size_t MarcRecord::getFieldIndex(const MarcTag &field_tag) const {
    for (size_t i(0); i < getNumberOfFields(); ++i) {
        if (directory_entries_[i].getTag() == field_tag)
            return i;
    }
    return MarcRecord::FIELD_NOT_FOUND;
}

size_t MarcRecord::getFieldIndices(const MarcTag &field_tag, std::vector <size_t> *const field_indices) const {
    field_indices->clear();

    size_t field_index(getFieldIndex(field_tag));
    while (static_cast<size_t>(field_index) < directory_entries_.size() and
           directory_entries_[field_index].getTag() == field_tag) {
        field_indices->emplace_back(field_index);
        ++field_index;
    }

    return field_indices->size();
}

bool MarcRecord::updateField(const size_t field_index, const std::string &new_field_value) {
    DirectoryEntry &entry(directory_entries_[field_index]);
    size_t offset = raw_data_.size();
    size_t length = new_field_value.length() + 1 /* For new field separator. */;

    entry.setFieldLength(length);
    entry.setFieldOffset(offset);
    raw_data_ += new_field_value + '\x1E';

    return true;
}

bool MarcRecord::insertSubfield(const MarcTag &new_field_tag, const char subfield_code,
                                const std::string &new_subfield_value, const char indicator1, const char indicator2) {
    return insertField(new_field_tag, std::string(1, indicator1) + std::string(1, indicator2) + "\x1F"
                                      + std::string(1, subfield_code) + new_subfield_value);
}

size_t MarcRecord::insertField(const MarcTag &new_field_tag, const std::string &new_field_value) {

    // Find the insertion location:
    auto insertion_location(directory_entries_.begin());
    while (insertion_location != directory_entries_.end() and new_field_tag >= insertion_location->getTag())
        ++insertion_location;

    const size_t offset(raw_data_.size());
    const size_t length(new_field_value.length() + 1) /* For new field separator. */;
    const auto inserted_location(directory_entries_.emplace(insertion_location, new_field_tag, length, offset));
    raw_data_ += new_field_value + '\x1E';

    const size_t index(std::distance(directory_entries_.begin(), inserted_location));
    return index;
}

void MarcRecord::deleteField(const size_t field_index) {
    directory_entries_.erase(directory_entries_.begin() + field_index);
}

void MarcRecord::deleteFields(const std::vector <std::pair<size_t, size_t>> &blocks) {
    std::vector <DirectoryEntry> new_entries;
    new_entries.reserve(directory_entries_.size());

    size_t copy_start(0);
    for (const std::pair <size_t, size_t> block : blocks) {
        new_entries.insert(new_entries.end(), directory_entries_.begin() + copy_start,
                           directory_entries_.begin() + block.first);
        copy_start = block.second;
    }
    new_entries.insert(new_entries.end(), directory_entries_.begin() + copy_start, directory_entries_.end());
    new_entries.swap(directory_entries_);
}

std::string MarcRecord::extractFirstSubfield(const MarcTag &tag, const char subfield_code) const {
    const size_t index(getFieldIndex(tag));
    if (index == FIELD_NOT_FOUND)
        return "";
    return getSubfields(tag).getFirstSubfieldValue(subfield_code);
}

std::string MarcRecord::extractFirstSubfield(const size_t field_index, const char subfield_code) const {
    const Subfields subfields(getFieldData(field_index));
    return subfields.getFirstSubfieldValue(subfield_code);
}

size_t MarcRecord::extractAllSubfields(const std::string &tags, std::vector <std::string> *const values,
                                       const std::string &ignore_subfield_codes) const {
    values->clear();

    std::vector <std::string> individual_tags;
    StringUtil::Split(tags, ':', &individual_tags);
    for (const auto &tag : individual_tags) {
        size_t field_index(getFieldIndex(tag));
        while (static_cast<size_t>(field_index) < directory_entries_.size() and
               directory_entries_[field_index].getTag() == tag) {
            const Subfields subfields(getSubfields(field_index));
            for (const auto &subfield : subfields) {
                if (ignore_subfield_codes.find(subfield.code_) == std::string::npos)
                    values->emplace_back(subfield.value_);
            }
            ++field_index;
        }
    }
    return values->size();
}

size_t MarcRecord::extractSubfield(const MarcTag &tag, const char subfield_code,
                                   std::vector <std::string> *const values) const {
    values->clear();

    size_t field_index(getFieldIndex(tag));
    while (static_cast<size_t>(field_index) < directory_entries_.size() and
           tag == directory_entries_[field_index].getTag()) {
        const Subfields subfields(getSubfields(field_index));
        const auto begin_end(subfields.getIterators(subfield_code));
        for (auto subfield_code_and_value(begin_end.first);
             subfield_code_and_value != begin_end.second; ++subfield_code_and_value)
            values->emplace_back(subfield_code_and_value->value_);
        ++field_index;
    }
    return values->size();
}

size_t MarcRecord::extractSubfields(const MarcTag &tag, const std::string &subfield_codes,
                                    std::vector <std::string> *const values) const {
    values->clear();

    size_t field_index(getFieldIndex(tag));
    while (static_cast<size_t>(field_index) < directory_entries_.size() and
           tag == directory_entries_[field_index].getTag()) {
        const Subfields subfields(getSubfields(field_index));
        for (const auto &subfield : subfields) {
            if (subfield_codes.find(subfield.code_) != std::string::npos)
                values->emplace_back(subfield.value_);
        }
        ++field_index;
    }

    return values->size();
}

size_t MarcRecord::findAllLocalDataBlocks(std::vector <std::pair<size_t, size_t>> *const local_block_boundaries) const {
    local_block_boundaries->clear();

    size_t local_block_start(getFieldIndex("LOK"));
    if (local_block_start == FIELD_NOT_FOUND)
        return 0;

    size_t local_block_end(local_block_start + 1);
    while (local_block_end < directory_entries_.size()) {
        if (StringUtil::StartsWith(getFieldData(local_block_end), "  ""\x1F""0000")) {
            local_block_boundaries->emplace_back(std::make_pair(local_block_start, local_block_end));
            local_block_start = local_block_end;
        }
        ++local_block_end;
    }
    local_block_boundaries->emplace_back(std::make_pair(local_block_start, local_block_end));

    return local_block_boundaries->size();
}

static inline bool IndicatorsMatch(const std::string &indicator_pattern, const std::string &indicators) {
    if (indicator_pattern[0] != '?' and indicator_pattern[0] != indicators[0])
        return false;
    if (indicator_pattern[1] != '?' and indicator_pattern[1] != indicators[1])
        return false;
    return true;
}

size_t MarcRecord::findFieldsInLocalBlock(const MarcTag &field_tag, const std::string &indicators,
                                          const std::pair <size_t, size_t> &block_start_and_end,
                                          std::vector <size_t> *const field_indices) const
{
    field_indices->clear();
    if (unlikely(indicators.length() != 2))
        Error("in MarcRecord::FindFieldInLocalBlock: indicators must be precisely 2 characters long!");

    const std::string FIELD_PREFIX("  ""\x1F""0" + field_tag.to_string());
    for (size_t index(block_start_and_end.first); index < block_start_and_end.second; ++index) {
        const std::string &current_field(getFieldData(index));
        if (StringUtil::StartsWith(current_field, FIELD_PREFIX)
            and IndicatorsMatch(indicators, current_field.substr(7, 2)))
            field_indices->emplace_back(index);
    }
    return field_indices->size();
}

void MarcRecord::filterTags(const std::unordered_set <MarcTag> &drop_tags) {
    std::vector <std::pair<size_t, size_t>> deleted_blocks;
    for (auto entry = directory_entries_.begin(); entry < directory_entries_.end(); ++entry) {
        const auto tag_iter = drop_tags.find(entry->getTag());
        if (tag_iter == drop_tags.cend())
            continue;
        const size_t block_start = std::distance(directory_entries_.begin(), entry);
        for (/* empty */; entry < directory_entries_.end() and entry->getTag() == *tag_iter; ++entry);
        const size_t block_end = std::distance(directory_entries_.begin(), entry);

        deleted_blocks.emplace_back(block_start, block_end);
    }
    deleteFields(deleted_blocks);
}

std::string MarcRecord::getLanguage(const std::string &default_language_code) const {
    const std::string &language(extractFirstSubfield("041", 'a'));
    if (likely(not language.empty()))
        return language;
    return default_language_code;
}

std::string MarcRecord::getLanguageCode() const {
    const size_t _008_index(getFieldIndex("008"));
    if (_008_index == FIELD_NOT_FOUND)
        return "";
    // Language codes start at offset 35 and have a length of 3.
    const auto entry = directory_entries_[_008_index];
    if (entry.getFieldLength() < 38)
        return "";

    return std::string(raw_data_, entry.getFieldOffset() + 35, 3);
}

void MarcRecord::combine(const MarcRecord &record) {
    const size_t offset(raw_data_.size());
    raw_data_ += record.raw_data_;

    // Ignore first field. We only need one 001-field.
    directory_entries_.reserve(record.directory_entries_.size() - 1);
    for (auto iter(record.directory_entries_.begin() + 1); iter < record.directory_entries_.end(); ++iter) {
        directory_entries_.emplace_back(*iter);
        directory_entries_.back().setFieldOffset(iter->getFieldOffset() + offset);
    }
}

bool MarcRecord::ProcessRecords(File *const input, File *const output, RecordFunc process_record,
                                std::string *const err_msg) {
    err_msg->clear();

    while (MarcRecord record = MarcReader::Read(input)) {
        if (not (*process_record)(&record, output, err_msg))
            return false;
        err_msg->clear();
    }

    return err_msg->empty();
}

bool MarcRecord::ProcessRecords(File *const input, XmlRecordFunc process_record, XmlWriter *const xml_writer,
                                std::string *const err_msg) {
    err_msg->clear();

    while (MarcRecord record = MarcReader::ReadXML(input)) {
        if (not (*process_record)(&record, xml_writer, err_msg))
            return false;
        err_msg->clear();
    }

    return err_msg->empty();
}
<|endoftext|>


<commit_before>// Copyright (c) 2011 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/memory/scoped_ptr.h"
#include "base/message_loop.h"
#include "chrome/browser/automation/ui_controls.h"
#include "chrome/browser/chromeos/cros/cros_in_process_browser_test.h"
#include "chrome/browser/chromeos/cros/mock_input_method_library.h"
#include "chrome/browser/chromeos/cros/mock_screen_lock_library.h"
#include "chrome/browser/chromeos/login/mock_authenticator.h"
#include "chrome/browser/chromeos/login/screen_locker.h"
#include "chrome/browser/chromeos/login/screen_locker_tester.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/views/browser_dialogs.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/ui_test_utils.h"
#include "content/common/notification_service.h"
#include "content/common/notification_type.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "views/controls/textfield/textfield.h"
#include "views/window/window_gtk.h"

namespace {

// An object that wait for lock state and fullscreen state.
class Waiter : public NotificationObserver {
 public:
  explicit Waiter(Browser* browser)
      : browser_(browser),
        running_(false) {
    registrar_.Add(this,
                   NotificationType::SCREEN_LOCK_STATE_CHANGED,
                   NotificationService::AllSources());
    handler_id_ = g_signal_connect(
        G_OBJECT(browser_->window()->GetNativeHandle()),
        "window-state-event",
        G_CALLBACK(OnWindowStateEventThunk),
        this);
  }

  ~Waiter() {
    g_signal_handler_disconnect(
        G_OBJECT(browser_->window()->GetNativeHandle()),
        handler_id_);
  }

  virtual void Observe(NotificationType type,
                       const NotificationSource& source,
                       const NotificationDetails& details) {
    DCHECK(type == NotificationType::SCREEN_LOCK_STATE_CHANGED);
    if (running_)
      MessageLoop::current()->Quit();
  }

  // Wait until the two conditions are met.
  void Wait(bool locker_state, bool fullscreen) {
    running_ = true;
    scoped_ptr<chromeos::test::ScreenLockerTester>
        tester(chromeos::ScreenLocker::GetTester());
    while (tester->IsLocked() != locker_state ||
           browser_->window()->IsFullscreen() != fullscreen) {
      ui_test_utils::RunMessageLoop();
    }
    // Make sure all pending tasks are executed.
    ui_test_utils::RunAllPendingInMessageLoop();
    running_ = false;
  }

  CHROMEGTK_CALLBACK_1(Waiter, gboolean, OnWindowStateEvent,
                       GdkEventWindowState*);

 private:
  Browser* browser_;
  gulong handler_id_;
  NotificationRegistrar registrar_;

  // Are we currently running the message loop?
  bool running_;

  DISALLOW_COPY_AND_ASSIGN(Waiter);
};

gboolean Waiter::OnWindowStateEvent(GtkWidget* widget,
                                    GdkEventWindowState* event) {
  MessageLoop::current()->Quit();
  return false;
}

}  // namespace

namespace chromeos {

class ScreenLockerTest : public CrosInProcessBrowserTest {
 public:
  ScreenLockerTest() : mock_screen_lock_library_(NULL),
                       mock_input_method_library_(NULL) {
  }

 protected:
  MockScreenLockLibrary *mock_screen_lock_library_;
  MockInputMethodLibrary *mock_input_method_library_;

  // Test the no password mode with different unlock scheme given by
  // |unlock| function.
  void TestNoPassword(void (unlock)(views::Widget*)) {
    EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenUnlockRequested())
        .Times(1)
        .RetiresOnSaturation();
    EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenLockCompleted())
        .Times(1)
        .RetiresOnSaturation();
    UserManager::Get()->OffTheRecordUserLoggedIn();
    ScreenLocker::Show();
    scoped_ptr<test::ScreenLockerTester> tester(ScreenLocker::GetTester());
    tester->EmulateWindowManagerReady();
    if (!chromeos::ScreenLocker::GetTester()->IsLocked())
      ui_test_utils::WaitForNotification(
          NotificationType::SCREEN_LOCK_STATE_CHANGED);
    EXPECT_TRUE(tester->IsLocked());
    tester->InjectMockAuthenticator("", "");

    unlock(tester->GetWidget());

    ui_test_utils::RunAllPendingInMessageLoop();
    EXPECT_TRUE(tester->IsLocked());

    // Emulate LockScreen request from PowerManager (via SessionManager).
    ScreenLocker::Hide();
    ui_test_utils::RunAllPendingInMessageLoop();
    EXPECT_FALSE(tester->IsLocked());
  }

  void LockScreenWithUser(test::ScreenLockerTester* tester,
                          const std::string& user) {
    UserManager::Get()->UserLoggedIn(user);
    ScreenLocker::Show();
    tester->EmulateWindowManagerReady();
    if (!tester->IsLocked()) {
      ui_test_utils::WaitForNotification(
          NotificationType::SCREEN_LOCK_STATE_CHANGED);
    }
    EXPECT_TRUE(tester->IsLocked());
  }

 private:
  virtual void SetUpInProcessBrowserTestFixture() {
    cros_mock_->InitStatusAreaMocks();
    cros_mock_->InitMockScreenLockLibrary();
    mock_screen_lock_library_ = cros_mock_->mock_screen_lock_library();
    mock_input_method_library_ = cros_mock_->mock_input_method_library();
    EXPECT_CALL(*mock_screen_lock_library_, AddObserver(testing::_))
        .Times(1)
        .RetiresOnSaturation();
    EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenUnlockCompleted())
        .Times(1)
        .RetiresOnSaturation();
    // Expectations for the status are on the screen lock window.
    cros_mock_->SetStatusAreaMocksExpectations();
    // Expectations for the status area on the browser window.
    cros_mock_->SetStatusAreaMocksExpectations();
  }

  virtual void SetUpCommandLine(CommandLine* command_line) {
    command_line->AppendSwitchASCII(switches::kLoginProfile, "user");
    command_line->AppendSwitch(switches::kNoFirstRun);
  }

  DISALLOW_COPY_AND_ASSIGN(ScreenLockerTest);
};

IN_PROC_BROWSER_TEST_F(ScreenLockerTest, TestBasic) {
  EXPECT_CALL(*mock_input_method_library_, GetNumActiveInputMethods())
      .Times(1)
      .WillRepeatedly((testing::Return(0)))
      .RetiresOnSaturation();
  EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenUnlockRequested())
      .Times(1)
      .RetiresOnSaturation();
  EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenLockCompleted())
      .Times(1)
      .RetiresOnSaturation();
  UserManager::Get()->UserLoggedIn("user");
  ScreenLocker::Show();
  scoped_ptr<test::ScreenLockerTester> tester(ScreenLocker::GetTester());
  tester->EmulateWindowManagerReady();
  if (!chromeos::ScreenLocker::GetTester()->IsLocked())
    ui_test_utils::WaitForNotification(
        NotificationType::SCREEN_LOCK_STATE_CHANGED);

  // Test to make sure that the widget is actually appearing and is of
  // reasonable size, preventing a regression of
  // http://code.google.com/p/chromium-os/issues/detail?id=5987
  gfx::Rect lock_bounds = tester->GetChildWidget()->GetWindowScreenBounds();
  EXPECT_GT(lock_bounds.width(), 10);
  EXPECT_GT(lock_bounds.height(), 10);

  tester->InjectMockAuthenticator("user", "pass");
  EXPECT_TRUE(tester->IsLocked());
  tester->EnterPassword("fail");
  ui_test_utils::RunAllPendingInMessageLoop();
  EXPECT_TRUE(tester->IsLocked());
  tester->EnterPassword("pass");
  ui_test_utils::RunAllPendingInMessageLoop();
  // Successful authentication simply send a unlock request to PowerManager.
  EXPECT_TRUE(tester->IsLocked());

  // Emulate LockScreen request from PowerManager (via SessionManager).
  // TODO(oshima): Find out better way to handle this in mock.
  ScreenLocker::Hide();
  ui_test_utils::RunAllPendingInMessageLoop();
  EXPECT_FALSE(tester->IsLocked());
}

// Temporarily disabling screen locker tests while investigating the
// issue crbug.com/78764.
IN_PROC_BROWSER_TEST_F(ScreenLockerTest, DISABLED_TestFullscreenExit) {
  EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenUnlockRequested())
      .Times(1)
      .RetiresOnSaturation();
  EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenLockCompleted())
      .Times(1)
      .RetiresOnSaturation();
  scoped_ptr<test::ScreenLockerTester> tester(ScreenLocker::GetTester());
  {
    Waiter waiter(browser());
    browser()->ToggleFullscreenMode();
    waiter.Wait(false /* not locked */, true /* full screen */);
    EXPECT_TRUE(browser()->window()->IsFullscreen());
    EXPECT_FALSE(tester->IsLocked());
  }
  {
    Waiter waiter(browser());
    UserManager::Get()->UserLoggedIn("user");
    ScreenLocker::Show();
    tester->EmulateWindowManagerReady();
    waiter.Wait(true /* locked */, false /* full screen */);
    EXPECT_FALSE(browser()->window()->IsFullscreen());
    EXPECT_TRUE(tester->IsLocked());
  }
  tester->InjectMockAuthenticator("user", "pass");
  tester->EnterPassword("pass");
  ui_test_utils::RunAllPendingInMessageLoop();
  ScreenLocker::Hide();
  ui_test_utils::RunAllPendingInMessageLoop();
  EXPECT_FALSE(tester->IsLocked());
}

void MouseMove(views::Widget* widget) {
  ui_controls::SendMouseMove(10, 10);
}

IN_PROC_BROWSER_TEST_F(ScreenLockerTest,
                       DISABLED_TestNoPasswordWithMouseMove) {
  TestNoPassword(MouseMove);
}

void MouseClick(views::Widget* widget) {
  ui_controls::SendMouseClick(ui_controls::RIGHT);
}

IN_PROC_BROWSER_TEST_F(ScreenLockerTest,
                       DISABLED_TestNoPasswordWithMouseClick) {
  TestNoPassword(MouseClick);
}

void KeyPress(views::Widget* widget) {
  ui_controls::SendKeyPress(GTK_WINDOW(widget->GetNativeView()),
                            ui::VKEY_SPACE, false, false, false, false);
}

IN_PROC_BROWSER_TEST_F(ScreenLockerTest, DISABLED_TestNoPasswordWithKeyPress) {
  TestNoPassword(KeyPress);
}

IN_PROC_BROWSER_TEST_F(ScreenLockerTest, DISABLED_TestShowTwice) {
  EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenLockCompleted())
      .Times(2)
      .RetiresOnSaturation();
  scoped_ptr<test::ScreenLockerTester> tester(ScreenLocker::GetTester());
  LockScreenWithUser(tester.get(), "user");

  // Ensure there's a profile or this test crashes.
  ProfileManager::GetDefaultProfile();

  // Calling Show again simply send LockCompleted signal.
  ScreenLocker::Show();
  EXPECT_TRUE(tester->IsLocked());

  // Close the locker to match expectations.
  ScreenLocker::Hide();
  ui_test_utils::RunAllPendingInMessageLoop();
  EXPECT_FALSE(tester->IsLocked());
}

IN_PROC_BROWSER_TEST_F(ScreenLockerTest, DISABLED_TestEscape) {
  EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenLockCompleted())
      .Times(1)
      .RetiresOnSaturation();
  scoped_ptr<test::ScreenLockerTester> tester(ScreenLocker::GetTester());
  LockScreenWithUser(tester.get(), "user");

  // Ensure there's a profile or this test crashes.
  ProfileManager::GetDefaultProfile();

  tester->SetPassword("password");
  EXPECT_EQ("password", tester->GetPassword());
  // Escape clears the password.
  ui_controls::SendKeyPress(GTK_WINDOW(tester->GetWidget()->GetNativeView()),
                            ui::VKEY_ESCAPE, false, false, false, false);
  ui_test_utils::RunAllPendingInMessageLoop();
  EXPECT_EQ("", tester->GetPassword());

  // Close the locker to match expectations.
  ScreenLocker::Hide();
  ui_test_utils::RunAllPendingInMessageLoop();
  EXPECT_FALSE(tester->IsLocked());
}

}  // namespace chromeos
<commit_msg>Tag (ScreenLockerTest.TestBasic as flaky.<commit_after>// Copyright (c) 2011 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/memory/scoped_ptr.h"
#include "base/message_loop.h"
#include "chrome/browser/automation/ui_controls.h"
#include "chrome/browser/chromeos/cros/cros_in_process_browser_test.h"
#include "chrome/browser/chromeos/cros/mock_input_method_library.h"
#include "chrome/browser/chromeos/cros/mock_screen_lock_library.h"
#include "chrome/browser/chromeos/login/mock_authenticator.h"
#include "chrome/browser/chromeos/login/screen_locker.h"
#include "chrome/browser/chromeos/login/screen_locker_tester.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/views/browser_dialogs.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/ui_test_utils.h"
#include "content/common/notification_service.h"
#include "content/common/notification_type.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "views/controls/textfield/textfield.h"
#include "views/window/window_gtk.h"

namespace {

// An object that wait for lock state and fullscreen state.
class Waiter : public NotificationObserver {
 public:
  explicit Waiter(Browser* browser)
      : browser_(browser),
        running_(false) {
    registrar_.Add(this,
                   NotificationType::SCREEN_LOCK_STATE_CHANGED,
                   NotificationService::AllSources());
    handler_id_ = g_signal_connect(
        G_OBJECT(browser_->window()->GetNativeHandle()),
        "window-state-event",
        G_CALLBACK(OnWindowStateEventThunk),
        this);
  }

  ~Waiter() {
    g_signal_handler_disconnect(
        G_OBJECT(browser_->window()->GetNativeHandle()),
        handler_id_);
  }

  virtual void Observe(NotificationType type,
                       const NotificationSource& source,
                       const NotificationDetails& details) {
    DCHECK(type == NotificationType::SCREEN_LOCK_STATE_CHANGED);
    if (running_)
      MessageLoop::current()->Quit();
  }

  // Wait until the two conditions are met.
  void Wait(bool locker_state, bool fullscreen) {
    running_ = true;
    scoped_ptr<chromeos::test::ScreenLockerTester>
        tester(chromeos::ScreenLocker::GetTester());
    while (tester->IsLocked() != locker_state ||
           browser_->window()->IsFullscreen() != fullscreen) {
      ui_test_utils::RunMessageLoop();
    }
    // Make sure all pending tasks are executed.
    ui_test_utils::RunAllPendingInMessageLoop();
    running_ = false;
  }

  CHROMEGTK_CALLBACK_1(Waiter, gboolean, OnWindowStateEvent,
                       GdkEventWindowState*);

 private:
  Browser* browser_;
  gulong handler_id_;
  NotificationRegistrar registrar_;

  // Are we currently running the message loop?
  bool running_;

  DISALLOW_COPY_AND_ASSIGN(Waiter);
};

gboolean Waiter::OnWindowStateEvent(GtkWidget* widget,
                                    GdkEventWindowState* event) {
  MessageLoop::current()->Quit();
  return false;
}

}  // namespace

namespace chromeos {

class ScreenLockerTest : public CrosInProcessBrowserTest {
 public:
  ScreenLockerTest() : mock_screen_lock_library_(NULL),
                       mock_input_method_library_(NULL) {
  }

 protected:
  MockScreenLockLibrary *mock_screen_lock_library_;
  MockInputMethodLibrary *mock_input_method_library_;

  // Test the no password mode with different unlock scheme given by
  // |unlock| function.
  void TestNoPassword(void (unlock)(views::Widget*)) {
    EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenUnlockRequested())
        .Times(1)
        .RetiresOnSaturation();
    EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenLockCompleted())
        .Times(1)
        .RetiresOnSaturation();
    UserManager::Get()->OffTheRecordUserLoggedIn();
    ScreenLocker::Show();
    scoped_ptr<test::ScreenLockerTester> tester(ScreenLocker::GetTester());
    tester->EmulateWindowManagerReady();
    if (!chromeos::ScreenLocker::GetTester()->IsLocked())
      ui_test_utils::WaitForNotification(
          NotificationType::SCREEN_LOCK_STATE_CHANGED);
    EXPECT_TRUE(tester->IsLocked());
    tester->InjectMockAuthenticator("", "");

    unlock(tester->GetWidget());

    ui_test_utils::RunAllPendingInMessageLoop();
    EXPECT_TRUE(tester->IsLocked());

    // Emulate LockScreen request from PowerManager (via SessionManager).
    ScreenLocker::Hide();
    ui_test_utils::RunAllPendingInMessageLoop();
    EXPECT_FALSE(tester->IsLocked());
  }

  void LockScreenWithUser(test::ScreenLockerTester* tester,
                          const std::string& user) {
    UserManager::Get()->UserLoggedIn(user);
    ScreenLocker::Show();
    tester->EmulateWindowManagerReady();
    if (!tester->IsLocked()) {
      ui_test_utils::WaitForNotification(
          NotificationType::SCREEN_LOCK_STATE_CHANGED);
    }
    EXPECT_TRUE(tester->IsLocked());
  }

 private:
  virtual void SetUpInProcessBrowserTestFixture() {
    cros_mock_->InitStatusAreaMocks();
    cros_mock_->InitMockScreenLockLibrary();
    mock_screen_lock_library_ = cros_mock_->mock_screen_lock_library();
    mock_input_method_library_ = cros_mock_->mock_input_method_library();
    EXPECT_CALL(*mock_screen_lock_library_, AddObserver(testing::_))
        .Times(1)
        .RetiresOnSaturation();
    EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenUnlockCompleted())
        .Times(1)
        .RetiresOnSaturation();
    // Expectations for the status are on the screen lock window.
    cros_mock_->SetStatusAreaMocksExpectations();
    // Expectations for the status area on the browser window.
    cros_mock_->SetStatusAreaMocksExpectations();
  }

  virtual void SetUpCommandLine(CommandLine* command_line) {
    command_line->AppendSwitchASCII(switches::kLoginProfile, "user");
    command_line->AppendSwitch(switches::kNoFirstRun);
  }

  DISALLOW_COPY_AND_ASSIGN(ScreenLockerTest);
};

// See http://crbug.com/79374
IN_PROC_BROWSER_TEST_F(ScreenLockerTest, FLAKY_TestBasic) {
  EXPECT_CALL(*mock_input_method_library_, GetNumActiveInputMethods())
      .Times(1)
      .WillRepeatedly((testing::Return(0)))
      .RetiresOnSaturation();
  EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenUnlockRequested())
      .Times(1)
      .RetiresOnSaturation();
  EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenLockCompleted())
      .Times(1)
      .RetiresOnSaturation();
  UserManager::Get()->UserLoggedIn("user");
  ScreenLocker::Show();
  scoped_ptr<test::ScreenLockerTester> tester(ScreenLocker::GetTester());
  tester->EmulateWindowManagerReady();
  if (!chromeos::ScreenLocker::GetTester()->IsLocked())
    ui_test_utils::WaitForNotification(
        NotificationType::SCREEN_LOCK_STATE_CHANGED);

  // Test to make sure that the widget is actually appearing and is of
  // reasonable size, preventing a regression of
  // http://code.google.com/p/chromium-os/issues/detail?id=5987
  gfx::Rect lock_bounds = tester->GetChildWidget()->GetWindowScreenBounds();
  EXPECT_GT(lock_bounds.width(), 10);
  EXPECT_GT(lock_bounds.height(), 10);

  tester->InjectMockAuthenticator("user", "pass");
  EXPECT_TRUE(tester->IsLocked());
  tester->EnterPassword("fail");
  ui_test_utils::RunAllPendingInMessageLoop();
  EXPECT_TRUE(tester->IsLocked());
  tester->EnterPassword("pass");
  ui_test_utils::RunAllPendingInMessageLoop();
  // Successful authentication simply send a unlock request to PowerManager.
  EXPECT_TRUE(tester->IsLocked());

  // Emulate LockScreen request from PowerManager (via SessionManager).
  // TODO(oshima): Find out better way to handle this in mock.
  ScreenLocker::Hide();
  ui_test_utils::RunAllPendingInMessageLoop();
  EXPECT_FALSE(tester->IsLocked());
}

// Temporarily disabling screen locker tests while investigating the
// issue crbug.com/78764.
IN_PROC_BROWSER_TEST_F(ScreenLockerTest, DISABLED_TestFullscreenExit) {
  EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenUnlockRequested())
      .Times(1)
      .RetiresOnSaturation();
  EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenLockCompleted())
      .Times(1)
      .RetiresOnSaturation();
  scoped_ptr<test::ScreenLockerTester> tester(ScreenLocker::GetTester());
  {
    Waiter waiter(browser());
    browser()->ToggleFullscreenMode();
    waiter.Wait(false /* not locked */, true /* full screen */);
    EXPECT_TRUE(browser()->window()->IsFullscreen());
    EXPECT_FALSE(tester->IsLocked());
  }
  {
    Waiter waiter(browser());
    UserManager::Get()->UserLoggedIn("user");
    ScreenLocker::Show();
    tester->EmulateWindowManagerReady();
    waiter.Wait(true /* locked */, false /* full screen */);
    EXPECT_FALSE(browser()->window()->IsFullscreen());
    EXPECT_TRUE(tester->IsLocked());
  }
  tester->InjectMockAuthenticator("user", "pass");
  tester->EnterPassword("pass");
  ui_test_utils::RunAllPendingInMessageLoop();
  ScreenLocker::Hide();
  ui_test_utils::RunAllPendingInMessageLoop();
  EXPECT_FALSE(tester->IsLocked());
}

void MouseMove(views::Widget* widget) {
  ui_controls::SendMouseMove(10, 10);
}

IN_PROC_BROWSER_TEST_F(ScreenLockerTest,
                       DISABLED_TestNoPasswordWithMouseMove) {
  TestNoPassword(MouseMove);
}

void MouseClick(views::Widget* widget) {
  ui_controls::SendMouseClick(ui_controls::RIGHT);
}

IN_PROC_BROWSER_TEST_F(ScreenLockerTest,
                       DISABLED_TestNoPasswordWithMouseClick) {
  TestNoPassword(MouseClick);
}

void KeyPress(views::Widget* widget) {
  ui_controls::SendKeyPress(GTK_WINDOW(widget->GetNativeView()),
                            ui::VKEY_SPACE, false, false, false, false);
}

IN_PROC_BROWSER_TEST_F(ScreenLockerTest, DISABLED_TestNoPasswordWithKeyPress) {
  TestNoPassword(KeyPress);
}

IN_PROC_BROWSER_TEST_F(ScreenLockerTest, DISABLED_TestShowTwice) {
  EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenLockCompleted())
      .Times(2)
      .RetiresOnSaturation();
  scoped_ptr<test::ScreenLockerTester> tester(ScreenLocker::GetTester());
  LockScreenWithUser(tester.get(), "user");

  // Ensure there's a profile or this test crashes.
  ProfileManager::GetDefaultProfile();

  // Calling Show again simply send LockCompleted signal.
  ScreenLocker::Show();
  EXPECT_TRUE(tester->IsLocked());

  // Close the locker to match expectations.
  ScreenLocker::Hide();
  ui_test_utils::RunAllPendingInMessageLoop();
  EXPECT_FALSE(tester->IsLocked());
}

IN_PROC_BROWSER_TEST_F(ScreenLockerTest, DISABLED_TestEscape) {
  EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenLockCompleted())
      .Times(1)
      .RetiresOnSaturation();
  scoped_ptr<test::ScreenLockerTester> tester(ScreenLocker::GetTester());
  LockScreenWithUser(tester.get(), "user");

  // Ensure there's a profile or this test crashes.
  ProfileManager::GetDefaultProfile();

  tester->SetPassword("password");
  EXPECT_EQ("password", tester->GetPassword());
  // Escape clears the password.
  ui_controls::SendKeyPress(GTK_WINDOW(tester->GetWidget()->GetNativeView()),
                            ui::VKEY_ESCAPE, false, false, false, false);
  ui_test_utils::RunAllPendingInMessageLoop();
  EXPECT_EQ("", tester->GetPassword());

  // Close the locker to match expectations.
  ScreenLocker::Hide();
  ui_test_utils::RunAllPendingInMessageLoop();
  EXPECT_FALSE(tester->IsLocked());
}

}  // namespace chromeos
<|endoftext|>


<commit_before><commit_msg>Related fdo#87789: groups should appear like views and not like tables<commit_after><|endoftext|>