<commit_before>/*
 * Copyright (C) 2017 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla 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.
 *
 * Scylla 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include <string_view>
#include <memory>
#include <optional>

#include <seastar/core/future.hh>
#include <seastar/core/sstring.hh>
#include <seastar/util/bool_class.hh>
#include <seastar/core/sharded.hh>

#include "auth/authenticator.hh"
#include "auth/authorizer.hh"
#include "auth/permission.hh"
#include "auth/permissions_cache.hh"
#include "auth/role_manager.hh"
#include "seastarx.hh"

namespace cql3 {
class query_processor;
}

namespace service {
class migration_manager;
class migration_notifier;
class migration_listener;
}

namespace auth {

class role_or_anonymous;

struct service_config final {
    sstring authorizer_java_name;
    sstring authenticator_java_name;
    sstring role_manager_java_name;
};

///
/// Due to poor (in this author's opinion) decisions of Apache Cassandra, certain choices of one role-manager,
/// authenticator, or authorizer imply restrictions on the rest.
///
/// This exception is thrown when an invalid combination of modules is selected, with a message explaining the
/// incompatibility.
///
class incompatible_module_combination : public std::invalid_argument {
public:
    using std::invalid_argument::invalid_argument;
};

///
/// Client for access-control in the system.
///
/// Access control encompasses user/role management, authentication, and authorization. This client provides access to
/// the dynamically-loaded implementations of these modules (through the `underlying_*` member functions), but also
/// builds on their functionality with caching and abstractions for common operations.
///
/// All state associated with access-control is stored externally to any particular instance of this class.
///
/// peering_sharded_service inheritance is needed to be able to access shard local authentication service
/// given an object from another shard. Used for bouncing lwt requests to correct shard.
class service final : public seastar::peering_sharded_service<service> {
    permissions_cache_config _permissions_cache_config;
    std::unique_ptr<permissions_cache> _permissions_cache;

    cql3::query_processor& _qp;

    ::service::migration_notifier& _mnotifier;

    std::unique_ptr<authorizer> _authorizer;

    std::unique_ptr<authenticator> _authenticator;

    std::unique_ptr<role_manager> _role_manager;

    // Only one of these should be registered, so we end up with some unused instances. Not the end of the world.
    std::unique_ptr<::service::migration_listener> _migration_listener;

public:
    service(
            permissions_cache_config,
            cql3::query_processor&,
            ::service::migration_notifier&,
            std::unique_ptr<authorizer>,
            std::unique_ptr<authenticator>,
            std::unique_ptr<role_manager>);

    ///
    /// This constructor is intended to be used when the class is sharded via \ref seastar::sharded. In that case, the
    /// arguments must be copyable, which is why we delay construction with instance-construction instructions instead
    /// of the instances themselves.
    ///
    service(
            permissions_cache_config,
            cql3::query_processor&,
            ::service::migration_notifier&,
            ::service::migration_manager&,
            const service_config&);

    future<> start(::service::migration_manager&);

    future<> stop();

    ///
    /// \returns an exceptional future with \ref nonexistant_role if the named role does not exist.
    ///
    future<permission_set> get_permissions(const role_or_anonymous&, const resource&) const;

    ///
    /// Like \ref get_permissions, but never returns cached permissions.
    ///
    future<permission_set> get_uncached_permissions(const role_or_anonymous&, const resource&) const;

    ///
    /// Query whether the named role has been granted a role that is a superuser.
    ///
    /// A role is always granted to itself. Therefore, a role that "is" a superuser also "has" superuser.
    ///
    /// \returns an exceptional future with \ref nonexistant_role if the role does not exist.
    ///
    future<bool> has_superuser(std::string_view role_name) const;

    ///
    /// Return the set of all roles granted to the given role, including itself and roles granted through other roles.
    ///
    /// \returns an exceptional future with \ref nonexistent_role if the role does not exist.
    future<role_set> get_roles(std::string_view role_name) const;

    future<bool> exists(const resource&) const;

    const authenticator& underlying_authenticator() const {
        return *_authenticator;
    }

    const authorizer& underlying_authorizer() const {
        return *_authorizer;
    }

    const role_manager& underlying_role_manager() const {
        return *_role_manager;
    }

private:
    future<bool> has_existing_legacy_users() const;

    future<> create_keyspace_if_missing(::service::migration_manager& mm) const;
};

future<bool> has_superuser(const service&, const authenticated_user&);

future<role_set> get_roles(const service&, const authenticated_user&);

future<permission_set> get_permissions(const service&, const authenticated_user&, const resource&);

///
/// Access-control is "enforcing" when either the authenticator or the authorizer are not their "allow-all" variants.
///
/// Put differently, when access control is not enforcing, all operations on resources will be allowed and users do not
/// need to authenticate themselves.
///
bool is_enforcing(const service&);

/// A description of a CQL command from which auth::service can tell whether or not this command could endanger
/// internal data on which auth::service depends.
struct command_desc {
    auth::permission permission; ///< Nature of the command's alteration.
    const resource& resource; ///< Resource impacted by this command.
    enum class type {
        ALTER_WITH_OPTS, ///< Command is ALTER ... WITH ...
        OTHER
    } type_ = type::OTHER;
};

///
/// Protected resources cannot be modified even if the performer has permissions to do so.
///
bool is_protected(const service&, command_desc) noexcept;

///
/// Create a role with optional authentication information.
///
/// \returns an exceptional future with \ref role_already_exists if the user or role exists.
///
/// \returns an exceptional future with \ref unsupported_authentication_option if an unsupported option is included.
///
future<> create_role(
        const service&,
        std::string_view name,
        const role_config&,
        const authentication_options&);

///
/// Alter an existing role and its authentication information.
///
/// \returns an exceptional future with \ref nonexistant_role if the named role does not exist.
///
/// \returns an exceptional future with \ref unsupported_authentication_option if an unsupported option is included.
///
future<> alter_role(
        const service&,
        std::string_view name,
        const role_config_update&,
        const authentication_options&);

///
/// Drop a role from the system, including all permissions and authentication information.
///
/// \returns an exceptional future with \ref nonexistant_role if the named role does not exist.
///
future<> drop_role(const service&, std::string_view name);

///
/// Check if `grantee` has been granted the named role.
///
/// \returns an exceptional future with \ref nonexistent_role if `grantee` or `name` do not exist.
///
future<bool> has_role(const service&, std::string_view grantee, std::string_view name);
///
/// Check if the authenticated user has been granted the named role.
///
/// \returns an exceptional future with \ref nonexistent_role if the user or `name` do not exist.
///
future<bool> has_role(const service&, const authenticated_user&, std::string_view name);

///
/// \returns an exceptional future with \ref nonexistent_role if the named role does not exist.
///
/// \returns an exceptional future with \ref unsupported_authorization_operation if granting permissions is not
/// supported.
///
future<> grant_permissions(
        const service&,
        std::string_view role_name,
        permission_set,
        const resource&);

///
/// Like \ref grant_permissions, but grants all applicable permissions on the resource.
///
/// \returns an exceptional future with \ref nonexistent_role if the named role does not exist.
///
/// \returns an exceptional future with \ref unsupported_authorization_operation if granting permissions is not
/// supported.
///
future<> grant_applicable_permissions(const service&, std::string_view role_name, const resource&);
future<> grant_applicable_permissions(const service&, const authenticated_user&, const resource&);

///
/// \returns an exceptional future with \ref nonexistent_role if the named role does not exist.
///
/// \returns an exceptional future with \ref unsupported_authorization_operation if revoking permissions is not
/// supported.
///
future<> revoke_permissions(
        const service&,
        std::string_view role_name,
        permission_set,
        const resource&);

using recursive_permissions = bool_class<struct recursive_permissions_tag>;

///
/// Query for all granted permissions according to filtering criteria.
///
/// Only permissions included in the provided set are included.
///
/// If a role name is provided, only permissions granted (directly or recursively) to the role are included.
///
/// If a resource filter is provided, only permissions granted on the resource are included. When \ref
/// recursive_permissions is `true`, permissions on a parent resource are included.
///
/// \returns an exceptional future with \ref nonexistent_role if a role name is included which refers to a role that
/// does not exist.
///
/// \returns an exceptional future with \ref unsupported_authorization_operation if listing permissions is not
/// supported.
///
future<std::vector<permission_details>> list_filtered_permissions(
        const service&,
        permission_set,
        std::optional<std::string_view> role_name,
        const std::optional<std::pair<resource, recursive_permissions>>& resource_filter);

}
<commit_msg>auth: Fix class name vs field name compilation by gcc<commit_after>/*
 * Copyright (C) 2017 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla 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.
 *
 * Scylla 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include <string_view>
#include <memory>
#include <optional>

#include <seastar/core/future.hh>
#include <seastar/core/sstring.hh>
#include <seastar/util/bool_class.hh>
#include <seastar/core/sharded.hh>

#include "auth/authenticator.hh"
#include "auth/authorizer.hh"
#include "auth/permission.hh"
#include "auth/permissions_cache.hh"
#include "auth/role_manager.hh"
#include "seastarx.hh"

namespace cql3 {
class query_processor;
}

namespace service {
class migration_manager;
class migration_notifier;
class migration_listener;
}

namespace auth {

class role_or_anonymous;

struct service_config final {
    sstring authorizer_java_name;
    sstring authenticator_java_name;
    sstring role_manager_java_name;
};

///
/// Due to poor (in this author's opinion) decisions of Apache Cassandra, certain choices of one role-manager,
/// authenticator, or authorizer imply restrictions on the rest.
///
/// This exception is thrown when an invalid combination of modules is selected, with a message explaining the
/// incompatibility.
///
class incompatible_module_combination : public std::invalid_argument {
public:
    using std::invalid_argument::invalid_argument;
};

///
/// Client for access-control in the system.
///
/// Access control encompasses user/role management, authentication, and authorization. This client provides access to
/// the dynamically-loaded implementations of these modules (through the `underlying_*` member functions), but also
/// builds on their functionality with caching and abstractions for common operations.
///
/// All state associated with access-control is stored externally to any particular instance of this class.
///
/// peering_sharded_service inheritance is needed to be able to access shard local authentication service
/// given an object from another shard. Used for bouncing lwt requests to correct shard.
class service final : public seastar::peering_sharded_service<service> {
    permissions_cache_config _permissions_cache_config;
    std::unique_ptr<permissions_cache> _permissions_cache;

    cql3::query_processor& _qp;

    ::service::migration_notifier& _mnotifier;

    std::unique_ptr<authorizer> _authorizer;

    std::unique_ptr<authenticator> _authenticator;

    std::unique_ptr<role_manager> _role_manager;

    // Only one of these should be registered, so we end up with some unused instances. Not the end of the world.
    std::unique_ptr<::service::migration_listener> _migration_listener;

public:
    service(
            permissions_cache_config,
            cql3::query_processor&,
            ::service::migration_notifier&,
            std::unique_ptr<authorizer>,
            std::unique_ptr<authenticator>,
            std::unique_ptr<role_manager>);

    ///
    /// This constructor is intended to be used when the class is sharded via \ref seastar::sharded. In that case, the
    /// arguments must be copyable, which is why we delay construction with instance-construction instructions instead
    /// of the instances themselves.
    ///
    service(
            permissions_cache_config,
            cql3::query_processor&,
            ::service::migration_notifier&,
            ::service::migration_manager&,
            const service_config&);

    future<> start(::service::migration_manager&);

    future<> stop();

    ///
    /// \returns an exceptional future with \ref nonexistant_role if the named role does not exist.
    ///
    future<permission_set> get_permissions(const role_or_anonymous&, const resource&) const;

    ///
    /// Like \ref get_permissions, but never returns cached permissions.
    ///
    future<permission_set> get_uncached_permissions(const role_or_anonymous&, const resource&) const;

    ///
    /// Query whether the named role has been granted a role that is a superuser.
    ///
    /// A role is always granted to itself. Therefore, a role that "is" a superuser also "has" superuser.
    ///
    /// \returns an exceptional future with \ref nonexistant_role if the role does not exist.
    ///
    future<bool> has_superuser(std::string_view role_name) const;

    ///
    /// Return the set of all roles granted to the given role, including itself and roles granted through other roles.
    ///
    /// \returns an exceptional future with \ref nonexistent_role if the role does not exist.
    future<role_set> get_roles(std::string_view role_name) const;

    future<bool> exists(const resource&) const;

    const authenticator& underlying_authenticator() const {
        return *_authenticator;
    }

    const authorizer& underlying_authorizer() const {
        return *_authorizer;
    }

    const role_manager& underlying_role_manager() const {
        return *_role_manager;
    }

private:
    future<bool> has_existing_legacy_users() const;

    future<> create_keyspace_if_missing(::service::migration_manager& mm) const;
};

future<bool> has_superuser(const service&, const authenticated_user&);

future<role_set> get_roles(const service&, const authenticated_user&);

future<permission_set> get_permissions(const service&, const authenticated_user&, const resource&);

///
/// Access-control is "enforcing" when either the authenticator or the authorizer are not their "allow-all" variants.
///
/// Put differently, when access control is not enforcing, all operations on resources will be allowed and users do not
/// need to authenticate themselves.
///
bool is_enforcing(const service&);

/// A description of a CQL command from which auth::service can tell whether or not this command could endanger
/// internal data on which auth::service depends.
struct command_desc {
    auth::permission permission; ///< Nature of the command's alteration.
    const ::auth::resource& resource; ///< Resource impacted by this command.
    enum class type {
        ALTER_WITH_OPTS, ///< Command is ALTER ... WITH ...
        OTHER
    } type_ = type::OTHER;
};

///
/// Protected resources cannot be modified even if the performer has permissions to do so.
///
bool is_protected(const service&, command_desc) noexcept;

///
/// Create a role with optional authentication information.
///
/// \returns an exceptional future with \ref role_already_exists if the user or role exists.
///
/// \returns an exceptional future with \ref unsupported_authentication_option if an unsupported option is included.
///
future<> create_role(
        const service&,
        std::string_view name,
        const role_config&,
        const authentication_options&);

///
/// Alter an existing role and its authentication information.
///
/// \returns an exceptional future with \ref nonexistant_role if the named role does not exist.
///
/// \returns an exceptional future with \ref unsupported_authentication_option if an unsupported option is included.
///
future<> alter_role(
        const service&,
        std::string_view name,
        const role_config_update&,
        const authentication_options&);

///
/// Drop a role from the system, including all permissions and authentication information.
///
/// \returns an exceptional future with \ref nonexistant_role if the named role does not exist.
///
future<> drop_role(const service&, std::string_view name);

///
/// Check if `grantee` has been granted the named role.
///
/// \returns an exceptional future with \ref nonexistent_role if `grantee` or `name` do not exist.
///
future<bool> has_role(const service&, std::string_view grantee, std::string_view name);
///
/// Check if the authenticated user has been granted the named role.
///
/// \returns an exceptional future with \ref nonexistent_role if the user or `name` do not exist.
///
future<bool> has_role(const service&, const authenticated_user&, std::string_view name);

///
/// \returns an exceptional future with \ref nonexistent_role if the named role does not exist.
///
/// \returns an exceptional future with \ref unsupported_authorization_operation if granting permissions is not
/// supported.
///
future<> grant_permissions(
        const service&,
        std::string_view role_name,
        permission_set,
        const resource&);

///
/// Like \ref grant_permissions, but grants all applicable permissions on the resource.
///
/// \returns an exceptional future with \ref nonexistent_role if the named role does not exist.
///
/// \returns an exceptional future with \ref unsupported_authorization_operation if granting permissions is not
/// supported.
///
future<> grant_applicable_permissions(const service&, std::string_view role_name, const resource&);
future<> grant_applicable_permissions(const service&, const authenticated_user&, const resource&);

///
/// \returns an exceptional future with \ref nonexistent_role if the named role does not exist.
///
/// \returns an exceptional future with \ref unsupported_authorization_operation if revoking permissions is not
/// supported.
///
future<> revoke_permissions(
        const service&,
        std::string_view role_name,
        permission_set,
        const resource&);

using recursive_permissions = bool_class<struct recursive_permissions_tag>;

///
/// Query for all granted permissions according to filtering criteria.
///
/// Only permissions included in the provided set are included.
///
/// If a role name is provided, only permissions granted (directly or recursively) to the role are included.
///
/// If a resource filter is provided, only permissions granted on the resource are included. When \ref
/// recursive_permissions is `true`, permissions on a parent resource are included.
///
/// \returns an exceptional future with \ref nonexistent_role if a role name is included which refers to a role that
/// does not exist.
///
/// \returns an exceptional future with \ref unsupported_authorization_operation if listing permissions is not
/// supported.
///
future<std::vector<permission_details>> list_filtered_permissions(
        const service&,
        permission_set,
        std::optional<std::string_view> role_name,
        const std::optional<std::pair<resource, recursive_permissions>>& resource_filter);

}
<|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/service/cloud_print/cloud_print_helpers.h"

#include "base/json/json_reader.h"
#include "base/md5.h"
#include "base/memory/scoped_ptr.h"
#include "base/rand_util.h"
#include "base/string_util.h"
#include "base/stringprintf.h"
#include "base/task.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/service/cloud_print/cloud_print_consts.h"
#include "chrome/service/cloud_print/cloud_print_token_store.h"
#include "chrome/service/service_process.h"

std::string StringFromJobStatus(cloud_print::PrintJobStatus status) {
  std::string ret;
  switch (status) {
    case cloud_print::PRINT_JOB_STATUS_IN_PROGRESS:
      ret = "in_progress";
      break;
    case cloud_print::PRINT_JOB_STATUS_ERROR:
      ret = "error";
      break;
    case cloud_print::PRINT_JOB_STATUS_COMPLETED:
      ret = "done";
      break;
    default:
      ret = "unknown";
      NOTREACHED();
      break;
  }
  return ret;
}

// Appends a relative path to the url making sure to append a '/' if the
// URL's path does not end with a slash. It is assumed that |path| does not
// begin with a '/'.
// NOTE: Since we ALWAYS want to append here, we simply append the path string
// instead of calling url_utils::ResolveRelative. The input |url| may or may not
// contain a '/' at the end.
std::string AppendPathToUrl(const GURL& url, const std::string& path) {
  DCHECK(path[0] != '/');
  std::string ret = url.path();
  if (url.has_path() && (ret[ret.length() - 1] != '/')) {
    ret += '/';
  }
  ret += path;
  return ret;
}

GURL CloudPrintHelpers::GetUrlForPrinterRegistration(
    const GURL& cloud_print_server_url) {
  std::string path(AppendPathToUrl(cloud_print_server_url, "register"));
  GURL::Replacements replacements;
  replacements.SetPathStr(path);
  return cloud_print_server_url.ReplaceComponents(replacements);
}

GURL CloudPrintHelpers::GetUrlForPrinterUpdate(
    const GURL& cloud_print_server_url, const std::string& printer_id) {
  std::string path(AppendPathToUrl(cloud_print_server_url, "update"));
  GURL::Replacements replacements;
  replacements.SetPathStr(path);
  std::string query = StringPrintf("printerid=%s", printer_id.c_str());
  replacements.SetQueryStr(query);
  return cloud_print_server_url.ReplaceComponents(replacements);
}

GURL CloudPrintHelpers::GetUrlForPrinterDelete(
    const GURL& cloud_print_server_url, const std::string& printer_id) {
  std::string path(AppendPathToUrl(cloud_print_server_url, "delete"));
  GURL::Replacements replacements;
  replacements.SetPathStr(path);
  std::string query = StringPrintf("printerid=%s", printer_id.c_str());
  replacements.SetQueryStr(query);
  return cloud_print_server_url.ReplaceComponents(replacements);
}

GURL CloudPrintHelpers::GetUrlForPrinterList(const GURL& cloud_print_server_url,
                                             const std::string& proxy_id) {
  std::string path(AppendPathToUrl(cloud_print_server_url, "list"));
  GURL::Replacements replacements;
  replacements.SetPathStr(path);
  std::string query = StringPrintf("proxy=%s", proxy_id.c_str());
  replacements.SetQueryStr(query);
  return cloud_print_server_url.ReplaceComponents(replacements);
}

GURL CloudPrintHelpers::GetUrlForJobFetch(const GURL& cloud_print_server_url,
                                          const std::string& printer_id,
                                          const std::string& reason) {
  std::string path(AppendPathToUrl(cloud_print_server_url, "fetch"));
  GURL::Replacements replacements;
  replacements.SetPathStr(path);
  std::string query = StringPrintf("printerid=%s&deb=%s",
                                   printer_id.c_str(),
                                   reason.c_str());
  replacements.SetQueryStr(query);
  return cloud_print_server_url.ReplaceComponents(replacements);
}

GURL CloudPrintHelpers::GetUrlForJobStatusUpdate(
    const GURL& cloud_print_server_url, const std::string& job_id,
    cloud_print::PrintJobStatus status) {
  std::string status_string = StringFromJobStatus(status);
  std::string path(AppendPathToUrl(cloud_print_server_url, "control"));
  GURL::Replacements replacements;
  replacements.SetPathStr(path);
  std::string query = StringPrintf("jobid=%s&status=%s",
                                   job_id.c_str(), status_string.c_str());
  replacements.SetQueryStr(query);
  return cloud_print_server_url.ReplaceComponents(replacements);
}

GURL CloudPrintHelpers::GetUrlForJobStatusUpdate(
    const GURL& cloud_print_server_url, const std::string& job_id,
    const cloud_print::PrintJobDetails& details) {
  std::string status_string = StringFromJobStatus(details.status);
  std::string path(AppendPathToUrl(cloud_print_server_url, "control"));
  GURL::Replacements replacements;
  replacements.SetPathStr(path);
  std::string query =
      StringPrintf("jobid=%s&status=%s&code=%d&message=%s"
                   "&numpages=%d&pagesprinted=%d",
                   job_id.c_str(),
                   status_string.c_str(),
                   details.platform_status_flags,
                   details.status_message.c_str(),
                   details.total_pages,
                   details.pages_printed);
  replacements.SetQueryStr(query);
  return cloud_print_server_url.ReplaceComponents(replacements);
}

GURL CloudPrintHelpers::GetUrlForUserMessage(const GURL& cloud_print_server_url,
                                             const std::string& message_id) {
  std::string path(AppendPathToUrl(cloud_print_server_url, "message"));
  GURL::Replacements replacements;
  replacements.SetPathStr(path);
  std::string query = StringPrintf("code=%s", message_id.c_str());
  replacements.SetQueryStr(query);
  return cloud_print_server_url.ReplaceComponents(replacements);
}

GURL CloudPrintHelpers::GetUrlForGetAuthCode(const GURL& cloud_print_server_url,
                                             const std::string& oauth_client_id,
                                             const std::string& proxy_id) {
  // We use the internal API "createrobot" instead of "getauthcode". This API
  // will add the robot as owner to all the existing printers for this user.
  std::string path(AppendPathToUrl(cloud_print_server_url, "createrobot"));
  GURL::Replacements replacements;
  replacements.SetPathStr(path);
  std::string query = StringPrintf("oauth_client_id=%s&proxy=%s",
                                    oauth_client_id.c_str(),
                                    proxy_id.c_str());
  replacements.SetQueryStr(query);
  return cloud_print_server_url.ReplaceComponents(replacements);
}

bool CloudPrintHelpers::ParseResponseJSON(
    const std::string& response_data, bool* succeeded,
    DictionaryValue** response_dict) {
  scoped_ptr<Value> message_value(base::JSONReader::Read(response_data, false));
  if (!message_value.get())
    return false;

  if (!message_value->IsType(Value::TYPE_DICTIONARY))
    return false;

  scoped_ptr<DictionaryValue> response_dict_local(
      static_cast<DictionaryValue*>(message_value.release()));
  if (succeeded) {
    if (!response_dict_local->GetBoolean(kSuccessValue, succeeded))
      *succeeded = false;
  }
  if (response_dict)
    *response_dict = response_dict_local.release();
  return true;
}

void CloudPrintHelpers::AddMultipartValueForUpload(
    const std::string& value_name, const std::string& value,
    const std::string& mime_boundary, const std::string& content_type,
    std::string* post_data) {
  DCHECK(post_data);
  // First line is the boundary
  post_data->append("--" + mime_boundary + "\r\n");
  // Next line is the Content-disposition
  post_data->append(StringPrintf("Content-Disposition: form-data; "
                   "name=\"%s\"\r\n", value_name.c_str()));
  if (!content_type.empty()) {
    // If Content-type is specified, the next line is that
    post_data->append(StringPrintf("Content-Type: %s\r\n",
                      content_type.c_str()));
  }
  // Leave an empty line and append the value.
  post_data->append(StringPrintf("\r\n%s\r\n", value.c_str()));
}

// Create a MIME boundary marker (27 '-' characters followed by 16 hex digits).
void CloudPrintHelpers::CreateMimeBoundaryForUpload(std::string* out) {
  int r1 = base::RandInt(0, kint32max);
  int r2 = base::RandInt(0, kint32max);
  base::SStringPrintf(out, "---------------------------%08X%08X", r1, r2);
}

std::string CloudPrintHelpers::GenerateHashOfStringMap(
    const std::map<std::string, std::string>& string_map) {
  std::string values_list;
  std::map<std::string, std::string>::const_iterator it;
  for (it = string_map.begin(); it != string_map.end(); ++it) {
    values_list.append(it->first);
    values_list.append(it->second);
  }
  return base::MD5String(values_list);
}

void CloudPrintHelpers::GenerateMultipartPostDataForPrinterTags(
    const std::map<std::string, std::string>& printer_tags,
    const std::string& mime_boundary,
    std::string* post_data) {
  // We do not use the GenerateHashOfStringMap to compute the hash because that
  // method iterates through the map again. Since we are already iterating here
  // we just compute it on the fly.
  // Also, in some cases, the code that calls this has already computed the
  // hash. We could take in the precomputed hash as an argument but that just
  // makes the code more complicated.
  std::string tags_list;
  std::map<std::string, std::string>::const_iterator it;
  for (it = printer_tags.begin(); it != printer_tags.end(); ++it) {
    // TODO(gene) Escape '=' char from name. Warning for now.
    if (it->first.find('=') != std::string::npos) {
      LOG(WARNING) <<
          "CP_PROXY: Printer option name contains '=' character";
      NOTREACHED();
    }
    tags_list.append(it->first);
    tags_list.append(it->second);

    // All our tags have a special prefix to identify them as such.
    std::string msg(kProxyTagPrefix);
    msg += it->first;
    msg += "=";
    msg += it->second;
    AddMultipartValueForUpload(kPrinterTagValue, msg, mime_boundary,
                               std::string(), post_data);
  }
  std::string tags_hash = base::MD5String(tags_list);
  std::string tags_hash_msg(kTagsHashTagName);
  tags_hash_msg += "=";
  tags_hash_msg += tags_hash;
  AddMultipartValueForUpload(kPrinterTagValue, tags_hash_msg, mime_boundary,
                             std::string(), post_data);
}

bool CloudPrintHelpers::IsDryRunJob(const std::vector<std::string>& tags) {
  std::vector<std::string>::const_iterator it;
  for (it = tags.begin(); it != tags.end(); ++it) {
    if (*it == kTagDryRunFlag)
      return true;
  }
  return false;
}

std::string CloudPrintHelpers::GetCloudPrintAuthHeader() {
  std::string header;
  CloudPrintTokenStore* token_store = CloudPrintTokenStore::current();
  if (!token_store || token_store->token().empty()) {
    // Using LOG here for critical errors. GCP connector may run in the headless
    // mode and error indication might be useful for user in that case.
    LOG(ERROR) << "CP_PROXY: Missing OAuth token for request";
  }

  if (token_store) {
    header = "Authorization: OAuth ";
    header += token_store->token();
  }
  return header;
}

<commit_msg>Revert 110369 - Fix URL on proxy/connector for sending user messages.<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/service/cloud_print/cloud_print_helpers.h"

#include "base/json/json_reader.h"
#include "base/md5.h"
#include "base/memory/scoped_ptr.h"
#include "base/rand_util.h"
#include "base/string_util.h"
#include "base/stringprintf.h"
#include "base/task.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/service/cloud_print/cloud_print_consts.h"
#include "chrome/service/cloud_print/cloud_print_token_store.h"
#include "chrome/service/service_process.h"

std::string StringFromJobStatus(cloud_print::PrintJobStatus status) {
  std::string ret;
  switch (status) {
    case cloud_print::PRINT_JOB_STATUS_IN_PROGRESS:
      ret = "in_progress";
      break;
    case cloud_print::PRINT_JOB_STATUS_ERROR:
      ret = "error";
      break;
    case cloud_print::PRINT_JOB_STATUS_COMPLETED:
      ret = "done";
      break;
    default:
      ret = "unknown";
      NOTREACHED();
      break;
  }
  return ret;
}

// Appends a relative path to the url making sure to append a '/' if the
// URL's path does not end with a slash. It is assumed that |path| does not
// begin with a '/'.
// NOTE: Since we ALWAYS want to append here, we simply append the path string
// instead of calling url_utils::ResolveRelative. The input |url| may or may not
// contain a '/' at the end.
std::string AppendPathToUrl(const GURL& url, const std::string& path) {
  DCHECK(path[0] != '/');
  std::string ret = url.path();
  if (url.has_path() && (ret[ret.length() - 1] != '/')) {
    ret += '/';
  }
  ret += path;
  return ret;
}

GURL CloudPrintHelpers::GetUrlForPrinterRegistration(
    const GURL& cloud_print_server_url) {
  std::string path(AppendPathToUrl(cloud_print_server_url, "register"));
  GURL::Replacements replacements;
  replacements.SetPathStr(path);
  return cloud_print_server_url.ReplaceComponents(replacements);
}

GURL CloudPrintHelpers::GetUrlForPrinterUpdate(
    const GURL& cloud_print_server_url, const std::string& printer_id) {
  std::string path(AppendPathToUrl(cloud_print_server_url, "update"));
  GURL::Replacements replacements;
  replacements.SetPathStr(path);
  std::string query = StringPrintf("printerid=%s", printer_id.c_str());
  replacements.SetQueryStr(query);
  return cloud_print_server_url.ReplaceComponents(replacements);
}

GURL CloudPrintHelpers::GetUrlForPrinterDelete(
    const GURL& cloud_print_server_url, const std::string& printer_id) {
  std::string path(AppendPathToUrl(cloud_print_server_url, "delete"));
  GURL::Replacements replacements;
  replacements.SetPathStr(path);
  std::string query = StringPrintf("printerid=%s", printer_id.c_str());
  replacements.SetQueryStr(query);
  return cloud_print_server_url.ReplaceComponents(replacements);
}

GURL CloudPrintHelpers::GetUrlForPrinterList(const GURL& cloud_print_server_url,
                                             const std::string& proxy_id) {
  std::string path(AppendPathToUrl(cloud_print_server_url, "list"));
  GURL::Replacements replacements;
  replacements.SetPathStr(path);
  std::string query = StringPrintf("proxy=%s", proxy_id.c_str());
  replacements.SetQueryStr(query);
  return cloud_print_server_url.ReplaceComponents(replacements);
}

GURL CloudPrintHelpers::GetUrlForJobFetch(const GURL& cloud_print_server_url,
                                          const std::string& printer_id,
                                          const std::string& reason) {
  std::string path(AppendPathToUrl(cloud_print_server_url, "fetch"));
  GURL::Replacements replacements;
  replacements.SetPathStr(path);
  std::string query = StringPrintf("printerid=%s&deb=%s",
                                   printer_id.c_str(),
                                   reason.c_str());
  replacements.SetQueryStr(query);
  return cloud_print_server_url.ReplaceComponents(replacements);
}

GURL CloudPrintHelpers::GetUrlForJobStatusUpdate(
    const GURL& cloud_print_server_url, const std::string& job_id,
    cloud_print::PrintJobStatus status) {
  std::string status_string = StringFromJobStatus(status);
  std::string path(AppendPathToUrl(cloud_print_server_url, "control"));
  GURL::Replacements replacements;
  replacements.SetPathStr(path);
  std::string query = StringPrintf("jobid=%s&status=%s",
                                   job_id.c_str(), status_string.c_str());
  replacements.SetQueryStr(query);
  return cloud_print_server_url.ReplaceComponents(replacements);
}

GURL CloudPrintHelpers::GetUrlForJobStatusUpdate(
    const GURL& cloud_print_server_url, const std::string& job_id,
    const cloud_print::PrintJobDetails& details) {
  std::string status_string = StringFromJobStatus(details.status);
  std::string path(AppendPathToUrl(cloud_print_server_url, "control"));
  GURL::Replacements replacements;
  replacements.SetPathStr(path);
  std::string query =
      StringPrintf("jobid=%s&status=%s&code=%d&message=%s"
                   "&numpages=%d&pagesprinted=%d",
                   job_id.c_str(),
                   status_string.c_str(),
                   details.platform_status_flags,
                   details.status_message.c_str(),
                   details.total_pages,
                   details.pages_printed);
  replacements.SetQueryStr(query);
  return cloud_print_server_url.ReplaceComponents(replacements);
}

GURL CloudPrintHelpers::GetUrlForUserMessage(const GURL& cloud_print_server_url,
                                             const std::string& message_id) {
  std::string path(AppendPathToUrl(cloud_print_server_url, "user/message"));
  GURL::Replacements replacements;
  replacements.SetPathStr(path);
  std::string query = StringPrintf("code=%s", message_id.c_str());
  replacements.SetQueryStr(query);
  return cloud_print_server_url.ReplaceComponents(replacements);
}

GURL CloudPrintHelpers::GetUrlForGetAuthCode(const GURL& cloud_print_server_url,
                                             const std::string& oauth_client_id,
                                             const std::string& proxy_id) {
  // We use the internal API "createrobot" instead of "getauthcode". This API
  // will add the robot as owner to all the existing printers for this user.
  std::string path(AppendPathToUrl(cloud_print_server_url, "createrobot"));
  GURL::Replacements replacements;
  replacements.SetPathStr(path);
  std::string query = StringPrintf("oauth_client_id=%s&proxy=%s",
                                    oauth_client_id.c_str(),
                                    proxy_id.c_str());
  replacements.SetQueryStr(query);
  return cloud_print_server_url.ReplaceComponents(replacements);
}

bool CloudPrintHelpers::ParseResponseJSON(
    const std::string& response_data, bool* succeeded,
    DictionaryValue** response_dict) {
  scoped_ptr<Value> message_value(base::JSONReader::Read(response_data, false));
  if (!message_value.get())
    return false;

  if (!message_value->IsType(Value::TYPE_DICTIONARY))
    return false;

  scoped_ptr<DictionaryValue> response_dict_local(
      static_cast<DictionaryValue*>(message_value.release()));
  if (succeeded) {
    if (!response_dict_local->GetBoolean(kSuccessValue, succeeded))
      *succeeded = false;
  }
  if (response_dict)
    *response_dict = response_dict_local.release();
  return true;
}

void CloudPrintHelpers::AddMultipartValueForUpload(
    const std::string& value_name, const std::string& value,
    const std::string& mime_boundary, const std::string& content_type,
    std::string* post_data) {
  DCHECK(post_data);
  // First line is the boundary
  post_data->append("--" + mime_boundary + "\r\n");
  // Next line is the Content-disposition
  post_data->append(StringPrintf("Content-Disposition: form-data; "
                   "name=\"%s\"\r\n", value_name.c_str()));
  if (!content_type.empty()) {
    // If Content-type is specified, the next line is that
    post_data->append(StringPrintf("Content-Type: %s\r\n",
                      content_type.c_str()));
  }
  // Leave an empty line and append the value.
  post_data->append(StringPrintf("\r\n%s\r\n", value.c_str()));
}

// Create a MIME boundary marker (27 '-' characters followed by 16 hex digits).
void CloudPrintHelpers::CreateMimeBoundaryForUpload(std::string* out) {
  int r1 = base::RandInt(0, kint32max);
  int r2 = base::RandInt(0, kint32max);
  base::SStringPrintf(out, "---------------------------%08X%08X", r1, r2);
}

std::string CloudPrintHelpers::GenerateHashOfStringMap(
    const std::map<std::string, std::string>& string_map) {
  std::string values_list;
  std::map<std::string, std::string>::const_iterator it;
  for (it = string_map.begin(); it != string_map.end(); ++it) {
    values_list.append(it->first);
    values_list.append(it->second);
  }
  return base::MD5String(values_list);
}

void CloudPrintHelpers::GenerateMultipartPostDataForPrinterTags(
    const std::map<std::string, std::string>& printer_tags,
    const std::string& mime_boundary,
    std::string* post_data) {
  // We do not use the GenerateHashOfStringMap to compute the hash because that
  // method iterates through the map again. Since we are already iterating here
  // we just compute it on the fly.
  // Also, in some cases, the code that calls this has already computed the
  // hash. We could take in the precomputed hash as an argument but that just
  // makes the code more complicated.
  std::string tags_list;
  std::map<std::string, std::string>::const_iterator it;
  for (it = printer_tags.begin(); it != printer_tags.end(); ++it) {
    // TODO(gene) Escape '=' char from name. Warning for now.
    if (it->first.find('=') != std::string::npos) {
      LOG(WARNING) <<
          "CP_PROXY: Printer option name contains '=' character";
      NOTREACHED();
    }
    tags_list.append(it->first);
    tags_list.append(it->second);

    // All our tags have a special prefix to identify them as such.
    std::string msg(kProxyTagPrefix);
    msg += it->first;
    msg += "=";
    msg += it->second;
    AddMultipartValueForUpload(kPrinterTagValue, msg, mime_boundary,
                               std::string(), post_data);
  }
  std::string tags_hash = base::MD5String(tags_list);
  std::string tags_hash_msg(kTagsHashTagName);
  tags_hash_msg += "=";
  tags_hash_msg += tags_hash;
  AddMultipartValueForUpload(kPrinterTagValue, tags_hash_msg, mime_boundary,
                             std::string(), post_data);
}

bool CloudPrintHelpers::IsDryRunJob(const std::vector<std::string>& tags) {
  std::vector<std::string>::const_iterator it;
  for (it = tags.begin(); it != tags.end(); ++it) {
    if (*it == kTagDryRunFlag)
      return true;
  }
  return false;
}

std::string CloudPrintHelpers::GetCloudPrintAuthHeader() {
  std::string header;
  CloudPrintTokenStore* token_store = CloudPrintTokenStore::current();
  if (!token_store || token_store->token().empty()) {
    // Using LOG here for critical errors. GCP connector may run in the headless
    // mode and error indication might be useful for user in that case.
    LOG(ERROR) << "CP_PROXY: Missing OAuth token for request";
  }

  if (token_store) {
    header = "Authorization: OAuth ";
    header += token_store->token();
  }
  return header;
}

<|endoftext|>


<commit_before>#include <set>
#include <map>
#include <iostream>
#include <cassert>
#include <memory>

#include <exception>
#include <stdexcept>

#include "structures/affectation.h"
#include "structures/formula.h"
#include "structures/clause.h"
#include "solvers/dpll.h"
#include "config.h"

#define CONFLICT_GRAPH_FILE_NAME "/tmp/conflict_graph.dot"

using namespace satsolver;

#define AS_AFF(a, l) (a.is_true(l) ? l : -l)

void handle_literal(FILE *graph_file, const std::map<int, std::set<int>> &deductions, std::set<int> *handled, std::set<int> &to_be_handled, const Affectation &aff, std::map<int, std::set<int>> &reversed_deductions, int literal) {
    // Add a literal to all reversed_deductions[i] sets if i was used to deduce the literal
    if (deductions.find(literal) == deductions.end())
        return;
    for (auto it : deductions.at(literal)) { // Iterate the literals which made us deduce the literal
        if (it == literal || it == -literal)
            continue;
        try {
            reversed_deductions[-it].insert(literal);
        }
        catch (std::out_of_range) {
            reversed_deductions[-it] = std::set<int>({literal});
        }
        to_be_handled.insert(it);
        if (handled->find(it) != handled->end() || handled->find(-it) != handled->end())
            continue;
        if (graph_file)
            fprintf(graph_file, "\t\"%d\" -> \"%d\";\n", AS_AFF(aff, it), AS_AFF(aff, literal));
    }
}

void conflict_graph_BFS(const std::map<int, std::set<int>> &reversed_deductions, int root, std::set<int> &unique_implication_points, std::set<int> &deduced_literals) {
    // We will browse the graph layer after layer from the root.
    // If a layer is a singleton, this element is a unique implication point.
    std::set<int> current_depth, next_depth({root});
    while (next_depth.size()) {
        current_depth.clear();
        current_depth.swap(next_depth);
        if (current_depth.size() == 1)
            unique_implication_points.insert(*current_depth.begin());
        for (auto it : current_depth) {
            deduced_literals.insert(it);
            try {
                for (auto it2 : reversed_deductions.at(it))
                    next_depth.insert(it2);
            }
            catch (std::out_of_range) {
                // We reached a leaf.
            }
        }
    }
}

std::set<int>* make_conflict_graph(const std::map<int, std::set<int>> deductions, const Affectation &aff, int root, int literal, bool write) {
    FILE *graph_file = NULL;
    int literal2;
    std::set<int> *handled = new std::set<int>(), // The list of literals which have already been added to the graph
                  to_be_handled({literal}); // The list of literals in that will have to be added to the graph
    std::map<int, std::set<int>> reversed_deductions;
    std::set<int> unique_implication_points, deduced_literals;
    if (write) {
        graph_file = fopen(CONFLICT_GRAPH_FILE_NAME, "w");
        fprintf(graph_file, "digraph G {\n");
    }
    while (to_be_handled.size()) {
        literal2 = *to_be_handled.begin();
        to_be_handled.erase(to_be_handled.begin());
        if (handled->find(literal2) != handled->end() || handled->find(-literal2) != handled->end())
            continue;
        handled->insert(literal2);
        assert(!aff.is_unknown(abs(literal2)));

        // The two following lines fill reversed_deductions and append items in to_be_handled.
        handle_literal(graph_file, deductions, handled, to_be_handled, aff, reversed_deductions, literal2);
        handle_literal(graph_file, deductions, handled, to_be_handled, aff, reversed_deductions, -literal2);
    }
    if (write) {
        // Fills unique_implication_points and deduced_literals
        conflict_graph_BFS(reversed_deductions, root, unique_implication_points, deduced_literals);
        for (auto it : deduced_literals)
            fprintf(graph_file, "\t%d [color = \"blue\"];\n", it);
        // Note that UIPs are also deduced, so be both blue and yellow. Thanksfully,
        // dot deterministically chooses a color (the last one).
        for (auto it : unique_implication_points)
            fprintf(graph_file, "\t%d [color = \"yellow\"];\n", it);
        fprintf(graph_file, "\t%d [color = \"red\"];\n", literal);
        fprintf(graph_file, "}\n");
        fclose(graph_file);
    }
    return handled;
}

unsigned int cl_interact(const std::map<int, std::set<int>> &deductions, const Affectation &aff, int last_bet, int literal) {
    char mode;
    unsigned int steps;
    assert(deductions.find(literal) != deductions.end() || deductions.find(-literal) != deductions.end());
    std::cout << "Conflict on literal " << literal << ". Action? [g/c/s/t] ";
    while (true) {
        std::cin >> mode;
        switch (mode) {
            case 'g':
                delete make_conflict_graph(deductions, aff, last_bet, literal, true);
                return 1;
            case 'c':
                return 1;
            case 's':
                std::cin >> steps;
                return steps;
            case 't':
                CL_INTERACT = false;
                return 0;
            default:
                std::cout << "Invalid character [g/c/s/t]. ";
                continue;
        }
    }
}

std::shared_ptr<Clause> learn_clause(const std::map<int, std::set<int>> &deductions, const std::vector<std::pair<int, bool>> &mem, const Affectation &aff, int nb_variables, int literal) {
    (void) aff;
    long unsigned int mem_top = mem.size()-1; // The index in the memory “stack” of the literal we are making the resolution on.
    std::set<int> clause(deductions.at(literal)), clause2;
    assert(clause.find(-literal) != clause.end());
    mem_top--;
    while (mem.at(mem_top).second) {
        literal = mem.at(mem_top).first;
        assert(mem.at(mem_top).first == literal);
        try {
            clause2 = deductions.at(literal); // This is the clause we will make the resolution with
        }
        catch (std::out_of_range) {
            break;
        }

        if (clause.find(-literal) == clause.end())
            break;
        assert(clause2.find(literal) != clause.end());

        // Resolution
        clause.erase(clause.find(-literal));
        clause2.erase(clause2.find(literal));
        clause.insert(clause2.begin(), clause2.end());

        mem_top--;
    }
    std::cout << Clause(nb_variables, clause).to_string() << std::endl;
    return std::shared_ptr<Clause>(new Clause(nb_variables, clause));
}

Affectation* satsolver::solve(Formula *formula) {
    int literal;
    unsigned int clause_id;
    bool contains_false_clause;
    std::map<int, std::set<int>> deductions;
    unsigned int skip_conflicts = 1; // Number of conflicts we will skip before showing another prompt
    int last_bet = 0; // Used for generating the graph.
    while(formula->get_aff()->get_nb_unknown() != 0 && !formula->only_true_clauses(NULL)) {
        if(!WITH_WL && (literal = formula->monome(&clause_id))) {
            // We set the clause identified by “claused_it” as the one which
            // made us deduce the value of the literal.
            deductions[literal] = formula->to_clauses_vector()[clause_id]->whole_to_set();
            formula->deduce_true(literal, NULL); // Return value ignored, WITH_WL is false
            contains_false_clause = formula->contains_false_clause(&clause_id);
        }
        else if((literal = formula->isolated_literal(&clause_id))) {
            // We set the clause identified by “claused_it” as the one which
            // made us deduce the value of the literal.
            deductions[literal] = formula->to_clauses_vector()[clause_id]->whole_to_set();
            if (WITH_WL)
                contains_false_clause = !formula->deduce_true(literal, &clause_id);
            else {
                formula->deduce_true(literal, NULL);
                contains_false_clause = formula->contains_false_clause(&clause_id);
            }
        }
        else {
            literal = formula->choose_literal(HEURISTIC) ;
            if (WITH_WL)
                contains_false_clause = !formula->bet_true(literal, &clause_id);
            else {
                formula->bet_true(literal, NULL);
                contains_false_clause = formula->contains_false_clause(&clause_id);
            }
            last_bet = literal;
        }
        while(contains_false_clause) {
            // We set the clause identified by “claused_it” as the one which
            // made us deduce the value of the literal.
            deductions[literal] = formula->to_clauses_vector()[clause_id]->whole_to_set();
            if (CL_INTERACT && --skip_conflicts == 0) {
                assert(last_bet);
                skip_conflicts = cl_interact(deductions, formula->get_aff(), last_bet, literal);
            }
            if (WITH_CL)
                learn_clause(deductions, formula->get_mem(), formula->get_aff(), formula->get_nb_variables(), literal);
            literal = formula->back() ;
            last_bet = -last_bet;
            if(literal == 0)
                throw Conflict() ;
            if (WITH_WL)
                contains_false_clause = !formula->deduce_false(literal, &clause_id);
            else {
                formula->deduce_false(literal, NULL);
                contains_false_clause = formula->contains_false_clause(&clause_id);
            }
        }
    }
    return formula->get_aff() ;
}
<commit_msg>Fix crash on second graph generation.<commit_after>#include <set>
#include <map>
#include <iostream>
#include <cassert>
#include <memory>

#include <exception>
#include <stdexcept>

#include "structures/affectation.h"
#include "structures/formula.h"
#include "structures/clause.h"
#include "solvers/dpll.h"
#include "config.h"

#define CONFLICT_GRAPH_FILE_NAME "/tmp/conflict_graph.dot"

using namespace satsolver;

#define AS_AFF(a, l) (a.is_true(l) ? l : -l)

void handle_literal(FILE *graph_file, const std::map<int, std::set<int>> &deductions, std::set<int> *handled, std::set<int> &to_be_handled, const Affectation &aff, std::map<int, std::set<int>> &reversed_deductions, int literal) {
    // Add a literal to all reversed_deductions[i] sets if i was used to deduce the literal
    if (deductions.find(literal) == deductions.end())
        return;
    for (auto it : deductions.at(literal)) { // Iterate the literals which made us deduce the literal
        if (it == literal || it == -literal)
            continue;
        try {
            reversed_deductions[-it].insert(literal);
        }
        catch (std::out_of_range) {
            reversed_deductions[-it] = std::set<int>({literal});
        }
        to_be_handled.insert(it);
        if (handled->find(it) != handled->end() || handled->find(-it) != handled->end())
            continue;
        if (graph_file)
            fprintf(graph_file, "\t\"%d\" -> \"%d\";\n", AS_AFF(aff, it), AS_AFF(aff, literal));
    }
}

void conflict_graph_BFS(const std::map<int, std::set<int>> &reversed_deductions, int root, std::set<int> &unique_implication_points, std::set<int> &deduced_literals) {
    // We will browse the graph layer after layer from the root.
    // If a layer is a singleton, this element is a unique implication point.
    std::set<int> current_depth, next_depth({root});
    while (next_depth.size()) {
        current_depth.clear();
        current_depth.swap(next_depth);
        if (current_depth.size() == 1)
            unique_implication_points.insert(*current_depth.begin());
        for (auto it : current_depth) {
            deduced_literals.insert(it);
            try {
                for (auto it2 : reversed_deductions.at(it))
                    next_depth.insert(it2);
            }
            catch (std::out_of_range) {
                // We reached a leaf.
            }
        }
    }
}

std::set<int>* make_conflict_graph(const std::map<int, std::set<int>> deductions, const Affectation &aff, int root, int literal, bool write) {
    FILE *graph_file = NULL;
    int literal2;
    std::set<int> *handled = new std::set<int>(), // The list of literals which have already been added to the graph
                  to_be_handled({literal}); // The list of literals in that will have to be added to the graph
    std::map<int, std::set<int>> reversed_deductions;
    std::set<int> unique_implication_points, deduced_literals;
    if (write) {
        graph_file = fopen(CONFLICT_GRAPH_FILE_NAME, "w");
        fprintf(graph_file, "digraph G {\n");
    }
    while (to_be_handled.size()) {
        literal2 = *to_be_handled.begin();
        to_be_handled.erase(to_be_handled.begin());
        if (handled->find(literal2) != handled->end() || handled->find(-literal2) != handled->end())
            continue;
        handled->insert(literal2);
        if (aff.is_unknown(abs(literal2)))
            continue;

        // The two following lines fill reversed_deductions and append items in to_be_handled.
        handle_literal(graph_file, deductions, handled, to_be_handled, aff, reversed_deductions, literal2);
        handle_literal(graph_file, deductions, handled, to_be_handled, aff, reversed_deductions, -literal2);
    }
    if (write) {
        // Fills unique_implication_points and deduced_literals
        conflict_graph_BFS(reversed_deductions, root, unique_implication_points, deduced_literals);
        for (auto it : deduced_literals)
            if (aff.is_true(it))
                fprintf(graph_file, "\t%d [color = \"blue\"];\n", it);
        // Note that UIPs are also deduced, so be both blue and yellow. Thanksfully,
        // dot deterministically chooses a color (the last one).
        for (auto it : unique_implication_points)
            if (aff.is_true(it))
                fprintf(graph_file, "\t%d [color = \"yellow\"];\n", it);
        fprintf(graph_file, "\t%d [color = \"red\"];\n", literal);
        fprintf(graph_file, "}\n");
        fclose(graph_file);
    }
    return handled;
}

unsigned int cl_interact(const std::map<int, std::set<int>> &deductions, const Affectation &aff, int last_bet, int literal) {
    char mode;
    unsigned int steps;
    assert(deductions.find(literal) != deductions.end() || deductions.find(-literal) != deductions.end());
    std::cout << "Conflict on literal " << literal << ". Action? [g/c/s/t] ";
    while (true) {
        std::cin >> mode;
        switch (mode) {
            case 'g':
                delete make_conflict_graph(deductions, aff, last_bet, literal, true);
                return 1;
            case 'c':
                return 1;
            case 's':
                std::cin >> steps;
                return steps;
            case 't':
                CL_INTERACT = false;
                return 0;
            default:
                std::cout << "Invalid character [g/c/s/t]. ";
                continue;
        }
    }
}

std::shared_ptr<Clause> learn_clause(const std::map<int, std::set<int>> &deductions, const std::vector<std::pair<int, bool>> &mem, const Affectation &aff, int nb_variables, int literal) {
    (void) aff;
    long unsigned int mem_top = mem.size()-1; // The index in the memory “stack” of the literal we are making the resolution on.
    std::set<int> clause(deductions.at(literal)), clause2;
    assert(clause.find(-literal) != clause.end());
    mem_top--;
    while (mem.at(mem_top).second) {
        literal = mem.at(mem_top).first;
        assert(mem.at(mem_top).first == literal);
        try {
            clause2 = deductions.at(literal); // This is the clause we will make the resolution with
        }
        catch (std::out_of_range) {
            break;
        }

        if (clause.find(-literal) == clause.end())
            break;
        assert(clause2.find(literal) != clause.end());

        // Resolution
        clause.erase(clause.find(-literal));
        clause2.erase(clause2.find(literal));
        clause.insert(clause2.begin(), clause2.end());

        mem_top--;
    }
    return std::shared_ptr<Clause>(new Clause(nb_variables, clause));
}

Affectation* satsolver::solve(Formula *formula) {
    int literal;
    unsigned int clause_id;
    bool contains_false_clause;
    std::map<int, std::set<int>> deductions;
    unsigned int skip_conflicts = 1; // Number of conflicts we will skip before showing another prompt
    int last_bet = 0; // Used for generating the graph.
    while(formula->get_aff()->get_nb_unknown() != 0 && !formula->only_true_clauses(NULL)) {
        if(!WITH_WL && (literal = formula->monome(&clause_id))) {
            // We set the clause identified by “claused_it” as the one which
            // made us deduce the value of the literal.
            deductions[literal] = formula->to_clauses_vector()[clause_id]->whole_to_set();
            formula->deduce_true(literal, NULL); // Return value ignored, WITH_WL is false
            contains_false_clause = formula->contains_false_clause(&clause_id);
        }
        else if((literal = formula->isolated_literal(&clause_id))) {
            // We set the clause identified by “claused_it” as the one which
            // made us deduce the value of the literal.
            deductions[literal] = formula->to_clauses_vector()[clause_id]->whole_to_set();
            if (WITH_WL)
                contains_false_clause = !formula->deduce_true(literal, &clause_id);
            else {
                formula->deduce_true(literal, NULL);
                contains_false_clause = formula->contains_false_clause(&clause_id);
            }
        }
        else {
            literal = formula->choose_literal(HEURISTIC) ;
            if (WITH_WL)
                contains_false_clause = !formula->bet_true(literal, &clause_id);
            else {
                formula->bet_true(literal, NULL);
                contains_false_clause = formula->contains_false_clause(&clause_id);
            }
            last_bet = literal;
        }
        while(contains_false_clause) {
            // We set the clause identified by “claused_it” as the one which
            // made us deduce the value of the literal.
            deductions[literal] = formula->to_clauses_vector()[clause_id]->whole_to_set();
            assert(!formula->get_aff()->is_unknown(abs(literal)));
            for (auto it : deductions[literal])
                assert(!formula->get_aff()->is_unknown(abs(it)));
            if (CL_INTERACT && --skip_conflicts == 0) {
                assert(last_bet);
                skip_conflicts = cl_interact(deductions, formula->get_aff(), last_bet, literal);
            }
            if (WITH_CL)
                learn_clause(deductions, formula->get_mem(), formula->get_aff(), formula->get_nb_variables(), literal);
            literal = formula->back() ;
            last_bet = -last_bet;
            if(literal == 0)
                throw Conflict() ;
            if (WITH_WL)
                contains_false_clause = !formula->deduce_false(literal, &clause_id);
            else {
                formula->deduce_false(literal, NULL);
                contains_false_clause = formula->contains_false_clause(&clause_id);
            }
        }
    }
    return formula->get_aff() ;
}
<|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 "chrome/test/chromedriver/command_executor_impl.h"

#include "base/bind.h"
#include "base/callback.h"
#include "base/message_loop.h"
#include "base/message_loop_proxy.h"
#include "base/values.h"
#include "chrome/test/chromedriver/command_names.h"
#include "chrome/test/chromedriver/commands.h"
#include "chrome/test/chromedriver/net/url_request_context_getter.h"
#include "chrome/test/chromedriver/session.h"
#include "chrome/test/chromedriver/session_command.h"
#include "chrome/test/chromedriver/session_map.h"
#include "chrome/test/chromedriver/status.h"

namespace {

Status ExecuteElementCommand(
    base::Callback<Status(
        Session* session,
        const std::string&,
        const base::DictionaryValue&,
        scoped_ptr<base::Value>*)> command,
    Session* session,
    const base::DictionaryValue& params,
    scoped_ptr<base::Value>* value) {
  std::string id;
  if (!params.GetString("id", &id))
    return Status(kUnknownError, "'id' of element must be a string");
  return command.Run(session, id, params, value);
}

}  // namespace

CommandExecutorImpl::CommandExecutorImpl()
    : io_thread_("ChromeDriver IO") {}

CommandExecutorImpl::~CommandExecutorImpl() {}

void CommandExecutorImpl::Init() {
  base::Thread::Options options(MessageLoop::TYPE_IO, 0);
  CHECK(io_thread_.StartWithOptions(options));
  context_getter_ = new URLRequestContextGetter(
      io_thread_.message_loop_proxy());
  socket_factory_ = CreateSyncWebSocketFactory(context_getter_);

  // Session commands.
  base::Callback<Status(
      const SessionCommand&,
      const base::DictionaryValue&,
      const std::string&,
      scoped_ptr<base::Value>*,
      std::string*)> execute_session_command = base::Bind(
          &ExecuteSessionCommand,
          &session_map_);
  command_map_.Set(
      CommandNames::kGet,
      base::Bind(execute_session_command, base::Bind(&ExecuteGet)));
  command_map_.Set(
      CommandNames::kExecuteScript,
      base::Bind(execute_session_command, base::Bind(&ExecuteExecuteScript)));
  command_map_.Set(
      CommandNames::kSwitchToFrame,
      base::Bind(execute_session_command, base::Bind(&ExecuteSwitchToFrame)));
  command_map_.Set(
      CommandNames::kGetTitle,
      base::Bind(execute_session_command, base::Bind(&ExecuteGetTitle)));
  command_map_.Set(
      CommandNames::kFindElement,
      base::Bind(execute_session_command,
          base::Bind(&ExecuteFindElement, 50)));
  command_map_.Set(
      CommandNames::kFindElements,
      base::Bind(execute_session_command,
          base::Bind(&ExecuteFindElements, 50)));
  command_map_.Set(
      CommandNames::kSetTimeout,
      base::Bind(execute_session_command, base::Bind(&ExecuteSetTimeout)));
  command_map_.Set(
      CommandNames::kGetCurrentUrl,
      base::Bind(execute_session_command, base::Bind(&ExecuteGetCurrentUrl)));
  command_map_.Set(
      CommandNames::kGoBack,
      base::Bind(execute_session_command, base::Bind(&ExecuteGoBack)));
  command_map_.Set(
      CommandNames::kGoForward,
      base::Bind(execute_session_command, base::Bind(&ExecuteGoForward)));
  command_map_.Set(
      CommandNames::kRefresh,
      base::Bind(execute_session_command, base::Bind(&ExecuteRefresh)));
  command_map_.Set(
      CommandNames::kMouseMoveTo,
      base::Bind(execute_session_command, base::Bind(&ExecuteMouseMoveTo)));
  command_map_.Set(
      CommandNames::kMouseClick,
      base::Bind(execute_session_command, base::Bind(&ExecuteMouseClick)));
  command_map_.Set(
      CommandNames::kMouseButtonDown,
      base::Bind(execute_session_command, base::Bind(&ExecuteMouseButtonDown)));
  command_map_.Set(
      CommandNames::kMouseButtonUp,
      base::Bind(execute_session_command, base::Bind(&ExecuteMouseButtonUp)));
  command_map_.Set(
      CommandNames::kMouseDoubleClick,
      base::Bind(execute_session_command,
                 base::Bind(&ExecuteMouseDoubleClick)));
  Command quit_command = base::Bind(execute_session_command,
      base::Bind(&ExecuteQuit, &session_map_));
  command_map_.Set(CommandNames::kQuit, quit_command);

  // Element commands.
  command_map_.Set(
      CommandNames::kFindChildElement,
      base::Bind(execute_session_command,
                 base::Bind(&ExecuteElementCommand,
                            base::Bind(&ExecuteFindChildElement, 50))));
  command_map_.Set(
      CommandNames::kFindChildElements,
      base::Bind(execute_session_command,
                 base::Bind(&ExecuteElementCommand,
                            base::Bind(&ExecuteFindChildElements, 50))));
  command_map_.Set(
      CommandNames::kHoverOverElement,
      base::Bind(execute_session_command,
                 base::Bind(&ExecuteElementCommand,
                            base::Bind(&ExecuteHoverOverElement))));
  command_map_.Set(
      CommandNames::kClickElement,
      base::Bind(execute_session_command,
                 base::Bind(&ExecuteElementCommand,
                            base::Bind(&ExecuteClickElement))));
  command_map_.Set(
      CommandNames::kClearElement,
      base::Bind(execute_session_command,
                 base::Bind(&ExecuteElementCommand,
                            base::Bind(&ExecuteClearElement))));
  command_map_.Set(
      CommandNames::kSendKeysToElement,
      base::Bind(execute_session_command,
                 base::Bind(&ExecuteElementCommand,
                            base::Bind(&ExecuteSendKeysToElement))));

  // Non-session commands.
  command_map_.Set(CommandNames::kStatus, base::Bind(&ExecuteGetStatus));
  command_map_.Set(
      CommandNames::kNewSession,
      base::Bind(&ExecuteNewSession, &session_map_, context_getter_,
                 socket_factory_));
  command_map_.Set(
      CommandNames::kQuitAll,
      base::Bind(&ExecuteQuitAll, quit_command, &session_map_));
}

void CommandExecutorImpl::ExecuteCommand(
    const std::string& name,
    const base::DictionaryValue& params,
    const std::string& session_id,
    StatusCode* status_code,
    scoped_ptr<base::Value>* value,
    std::string* out_session_id) {
  Command cmd;
  Status status(kOk);
  if (command_map_.Get(name, &cmd)) {
    status = cmd.Run(params, session_id, value, out_session_id);
  } else {
    status = Status(kUnknownCommand, name);
    *out_session_id = session_id;
  }
  *status_code = status.code();
  if (status.IsError()) {
    scoped_ptr<base::DictionaryValue> error(new base::DictionaryValue());
    error->SetString("message", status.message());
    value->reset(error.release());
  }
  if (!*value)
    value->reset(base::Value::CreateNullValue());
}
<commit_msg>[chromedriver] Add NS autorelease pool for mac scoped to each command execution. BUG=172325 TBR=craigdh<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 "chrome/test/chromedriver/command_executor_impl.h"

#include "base/bind.h"
#include "base/callback.h"
#include "base/message_loop.h"
#include "base/message_loop_proxy.h"
#include "base/values.h"
#include "chrome/test/chromedriver/command_names.h"
#include "chrome/test/chromedriver/commands.h"
#include "chrome/test/chromedriver/net/url_request_context_getter.h"
#include "chrome/test/chromedriver/session.h"
#include "chrome/test/chromedriver/session_command.h"
#include "chrome/test/chromedriver/session_map.h"
#include "chrome/test/chromedriver/status.h"

#if defined(OS_MACOSX)
#include "base/mac/scoped_nsautorelease_pool.h"
#endif

namespace {

Status ExecuteElementCommand(
    base::Callback<Status(
        Session* session,
        const std::string&,
        const base::DictionaryValue&,
        scoped_ptr<base::Value>*)> command,
    Session* session,
    const base::DictionaryValue& params,
    scoped_ptr<base::Value>* value) {
  std::string id;
  if (!params.GetString("id", &id))
    return Status(kUnknownError, "'id' of element must be a string");
  return command.Run(session, id, params, value);
}

}  // namespace

CommandExecutorImpl::CommandExecutorImpl()
    : io_thread_("ChromeDriver IO") {}

CommandExecutorImpl::~CommandExecutorImpl() {}

void CommandExecutorImpl::Init() {
#if defined(OS_MACOSX)
  base::mac::ScopedNSAutoreleasePool autorelease_pool;
#endif
  base::Thread::Options options(MessageLoop::TYPE_IO, 0);
  CHECK(io_thread_.StartWithOptions(options));
  context_getter_ = new URLRequestContextGetter(
      io_thread_.message_loop_proxy());
  socket_factory_ = CreateSyncWebSocketFactory(context_getter_);

  // Session commands.
  base::Callback<Status(
      const SessionCommand&,
      const base::DictionaryValue&,
      const std::string&,
      scoped_ptr<base::Value>*,
      std::string*)> execute_session_command = base::Bind(
          &ExecuteSessionCommand,
          &session_map_);
  command_map_.Set(
      CommandNames::kGet,
      base::Bind(execute_session_command, base::Bind(&ExecuteGet)));
  command_map_.Set(
      CommandNames::kExecuteScript,
      base::Bind(execute_session_command, base::Bind(&ExecuteExecuteScript)));
  command_map_.Set(
      CommandNames::kSwitchToFrame,
      base::Bind(execute_session_command, base::Bind(&ExecuteSwitchToFrame)));
  command_map_.Set(
      CommandNames::kGetTitle,
      base::Bind(execute_session_command, base::Bind(&ExecuteGetTitle)));
  command_map_.Set(
      CommandNames::kFindElement,
      base::Bind(execute_session_command,
          base::Bind(&ExecuteFindElement, 50)));
  command_map_.Set(
      CommandNames::kFindElements,
      base::Bind(execute_session_command,
          base::Bind(&ExecuteFindElements, 50)));
  command_map_.Set(
      CommandNames::kSetTimeout,
      base::Bind(execute_session_command, base::Bind(&ExecuteSetTimeout)));
  command_map_.Set(
      CommandNames::kGetCurrentUrl,
      base::Bind(execute_session_command, base::Bind(&ExecuteGetCurrentUrl)));
  command_map_.Set(
      CommandNames::kGoBack,
      base::Bind(execute_session_command, base::Bind(&ExecuteGoBack)));
  command_map_.Set(
      CommandNames::kGoForward,
      base::Bind(execute_session_command, base::Bind(&ExecuteGoForward)));
  command_map_.Set(
      CommandNames::kRefresh,
      base::Bind(execute_session_command, base::Bind(&ExecuteRefresh)));
  command_map_.Set(
      CommandNames::kMouseMoveTo,
      base::Bind(execute_session_command, base::Bind(&ExecuteMouseMoveTo)));
  command_map_.Set(
      CommandNames::kMouseClick,
      base::Bind(execute_session_command, base::Bind(&ExecuteMouseClick)));
  command_map_.Set(
      CommandNames::kMouseButtonDown,
      base::Bind(execute_session_command, base::Bind(&ExecuteMouseButtonDown)));
  command_map_.Set(
      CommandNames::kMouseButtonUp,
      base::Bind(execute_session_command, base::Bind(&ExecuteMouseButtonUp)));
  command_map_.Set(
      CommandNames::kMouseDoubleClick,
      base::Bind(execute_session_command,
                 base::Bind(&ExecuteMouseDoubleClick)));
  Command quit_command = base::Bind(execute_session_command,
      base::Bind(&ExecuteQuit, &session_map_));
  command_map_.Set(CommandNames::kQuit, quit_command);

  // Element commands.
  command_map_.Set(
      CommandNames::kFindChildElement,
      base::Bind(execute_session_command,
                 base::Bind(&ExecuteElementCommand,
                            base::Bind(&ExecuteFindChildElement, 50))));
  command_map_.Set(
      CommandNames::kFindChildElements,
      base::Bind(execute_session_command,
                 base::Bind(&ExecuteElementCommand,
                            base::Bind(&ExecuteFindChildElements, 50))));
  command_map_.Set(
      CommandNames::kHoverOverElement,
      base::Bind(execute_session_command,
                 base::Bind(&ExecuteElementCommand,
                            base::Bind(&ExecuteHoverOverElement))));
  command_map_.Set(
      CommandNames::kClickElement,
      base::Bind(execute_session_command,
                 base::Bind(&ExecuteElementCommand,
                            base::Bind(&ExecuteClickElement))));
  command_map_.Set(
      CommandNames::kClearElement,
      base::Bind(execute_session_command,
                 base::Bind(&ExecuteElementCommand,
                            base::Bind(&ExecuteClearElement))));
  command_map_.Set(
      CommandNames::kSendKeysToElement,
      base::Bind(execute_session_command,
                 base::Bind(&ExecuteElementCommand,
                            base::Bind(&ExecuteSendKeysToElement))));

  // Non-session commands.
  command_map_.Set(CommandNames::kStatus, base::Bind(&ExecuteGetStatus));
  command_map_.Set(
      CommandNames::kNewSession,
      base::Bind(&ExecuteNewSession, &session_map_, context_getter_,
                 socket_factory_));
  command_map_.Set(
      CommandNames::kQuitAll,
      base::Bind(&ExecuteQuitAll, quit_command, &session_map_));
}

void CommandExecutorImpl::ExecuteCommand(
    const std::string& name,
    const base::DictionaryValue& params,
    const std::string& session_id,
    StatusCode* status_code,
    scoped_ptr<base::Value>* value,
    std::string* out_session_id) {
#if defined(OS_MACOSX)
  base::mac::ScopedNSAutoreleasePool autorelease_pool;
#endif
  Command cmd;
  Status status(kOk);
  if (command_map_.Get(name, &cmd)) {
    status = cmd.Run(params, session_id, value, out_session_id);
  } else {
    status = Status(kUnknownCommand, name);
    *out_session_id = session_id;
  }
  *status_code = status.code();
  if (status.IsError()) {
    scoped_ptr<base::DictionaryValue> error(new base::DictionaryValue());
    error->SetString("message", status.message());
    value->reset(error.release());
  }
  if (!*value)
    value->reset(base::Value::CreateNullValue());
}
<|endoftext|>


<commit_before>// RUN: cat %s | %cling | FileCheck %s

int a = 12;
a // CHECK: (int) 12

const char* b = "b" // CHECK: (const char *) "b"

struct C {int d;} E = {22};
E // CHECK: {{\(struct C\) @0x[0-9A-Fa-f].*}}
E.d // CHECK: (int) 22

#include <string>
std::string s("abc") // CHECK: {{\(std::string\) @0x[0-9A-Fa-f].*}}
s.c_str() // CHECK: (const char * const) "abc"

.q
<commit_msg>Adapt the testcase to check the new pretty printing of std::string<commit_after>// RUN: cat %s | %cling | FileCheck %s

int a = 12;
a // CHECK: (int) 12

const char* b = "b" // CHECK: (const char *) "b"

struct C {int d;} E = {22};
E // CHECK: (struct C) @0x{{[0-9A-Fa-f].*}}
E.d // CHECK: (int) 22

#include <string>
std::string s("xyz")
// CHECK: (std::string) @0x{{[0-9A-Fa-f]{8,}.}}
// CHECK: c_str: "xyz"

.q
<|endoftext|>


<commit_before>// RUN: cat %s | %cling | FileCheck %s
// XFAIL: *
int a = 12;
a // CHECK: (int) 12

const char* b = "b" // CHECK: (const char *) "b"

struct C {int d;} E = {22};
E // CHECK: (struct C) @0x{{[0-9A-Fa-f].*}}
E.d // CHECK: (int) 22

#include <string>
std::string s("xyz")
// CHECK: (std::string) @0x{{[0-9A-Fa-f]{8,}.}}
// CHECK: c_str: "xyz"

#include <limits.h>
class Outer {
public:
  struct Inner {
    enum E{
      A = INT_MAX,
      B = 2,
      C = 2,
      D = INT_MIN
    } ABC;
  };
};
Outer::Inner::C
// CHECK: (enum Outer::Inner::E const) @0x{{[0-9A-Fa-f].*}}
// CHECK: (Outer::Inner::E::B) ? (Outer::Inner::E::C) : (int) {{[0-9].*}}
Outer::Inner::D
// CHECK: (enum Outer::Inner::E const) @0x{{[0-9A-Fa-f].*}}
// CHECK: (Outer::Inner::E::D) : (int) -{{[0-9].*}}

// Put an enum on the global scope
enum E{ e1 = -12, e2, e3=33, e4, e5 = 33};
e2
// CHECK: (E::e2) : (int) -11
::e1
// CHECK: (E::e1) : (int) -12
.q
<commit_msg>Make the test more accurate where possible<commit_after>// RUN: cat %s | %cling | FileCheck %s
// XFAIL: *
int a = 12;
a // CHECK: (int) 12

const char* b = "b" // CHECK: (const char *) "b"

struct C {int d;} E = {22};
E // CHECK: (struct C) @0x{{[0-9A-Fa-f].*}}
E.d // CHECK: (int) 22

#include <string>
std::string s("xyz")
// CHECK: (std::string) @0x{{[0-9A-Fa-f]{8,}.}}
// CHECK: c_str: "xyz"

#include <limits.h>
class Outer {
public:
  struct Inner {
    enum E{
      A = INT_MAX,
      B = 2,
      C = 2,
      D = INT_MIN
    } ABC;
  };
};
Outer::Inner::C
// CHECK: (enum Outer::Inner::E const) @0x{{[0-9A-Fa-f].*}}
// CHECK: (Outer::Inner::E::B) ? (Outer::Inner::E::C) : (int) 2
Outer::Inner::D
// CHECK: (enum Outer::Inner::E const) @0x{{[0-9A-Fa-f].*}}
// CHECK: (Outer::Inner::E::D) : (int) -{{[0-9].*}}

// Put an enum on the global scope
enum E{ e1 = -12, e2, e3=33, e4, e5 = 33};
e2
// CHECK: (E::e2) : (int) -11
::e1
// CHECK: (E::e1) : (int) -12
.q
<|endoftext|>