<commit_before>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "google/cloud/internal/log_wrapper.h"
#include "google/cloud/testing_util/capture_log_lines_backend.h"
#include "google/cloud/tracing_options.h"
#include <google/bigtable/v2/bigtable.grpc.pb.h>
#include <google/protobuf/text_format.h>
#include <google/spanner/v1/mutation.pb.h>
#include <gmock/gmock.h>

namespace btproto = google::bigtable::v2;

namespace google {
namespace cloud {
inline namespace GOOGLE_CLOUD_CPP_NS {
namespace internal {
namespace {

using ::testing::AllOf;
using ::testing::Contains;
using ::testing::HasSubstr;

google::spanner::v1::Mutation MakeMutation() {
  auto constexpr kText = R"pb(
    insert {
      table: "Singers"
      columns: "SingerId"
      columns: "FirstName"
      columns: "LastName"
      values {
        values { string_value: "1" }
        values { string_value: "test-fname-1" }
        values { string_value: "test-lname-1" }
      }
      values {
        values { string_value: "2" }
        values { string_value: "test-fname-2" }
        values { string_value: "test-lname-2" }
      }
    }
  )pb";
  google::spanner::v1::Mutation mutation;
  EXPECT_TRUE(google::protobuf::TextFormat::ParseFromString(kText, &mutation));
  return mutation;
}

TEST(LogWrapper, DefaultOptions) {
  TracingOptions tracing_options;
  // clang-format off
  std::string const text =
      R"pb(insert { )pb"
      R"pb(table: "Singers" )pb"
      R"pb(columns: "SingerId" )pb"
      R"pb(columns: "FirstName" )pb"
      R"pb(columns: "LastName" )pb"
      R"pb(values { values { string_value: "1" } )pb"
      R"pb(values { string_value: "test-fname-1" } )pb"
      R"pb(values { string_value: "test-lname-1" } } )pb"
      R"pb(values { values { string_value: "2" } )pb"
      R"pb(values { string_value: "test-fname-2" } )pb"
      R"pb(values { string_value: "test-lname-2" } )pb"
      R"pb(} )pb"
      R"pb(} )pb";
  // clang-format on
  EXPECT_EQ(text, internal::DebugString(MakeMutation(), tracing_options));
}

TEST(LogWrapper, MultiLine) {
  TracingOptions tracing_options;
  tracing_options.SetOptions("single_line_mode=off");
  // clang-format off
  std::string const text = R"pb(insert {
  table: "Singers"
  columns: "SingerId"
  columns: "FirstName"
  columns: "LastName"
  values {
    values {
      string_value: "1"
    }
    values {
      string_value: "test-fname-1"
    }
    values {
      string_value: "test-lname-1"
    }
  }
  values {
    values {
      string_value: "2"
    }
    values {
      string_value: "test-fname-2"
    }
    values {
      string_value: "test-lname-2"
    }
  }
}
)pb";
  // clang-format on
  EXPECT_EQ(text, internal::DebugString(MakeMutation(), tracing_options));
}

TEST(LogWrapper, Truncate) {
  TracingOptions tracing_options;
  tracing_options.SetOptions("truncate_string_field_longer_than=8");
  // clang-format off
  std::string const text =R"pb(insert { )pb"
            R"pb(table: "Singers" )pb"
            R"pb(columns: "SingerId" )pb"
            R"pb(columns: "FirstNam...<truncated>..." )pb"
            R"pb(columns: "LastName" )pb"
            R"pb(values { values { string_value: "1" } )pb"
            R"pb(values { string_value: "test-fna...<truncated>..." } )pb"
            R"pb(values { string_value: "test-lna...<truncated>..." } } )pb"
            R"pb(values { values { string_value: "2" } )pb"
            R"pb(values { string_value: "test-fna...<truncated>..." } )pb"
            R"pb(values { string_value: "test-lna...<truncated>..." } )pb"
            R"pb(} )pb"
            R"pb(} )pb";
  // clang-format on
  EXPECT_EQ(text, internal::DebugString(MakeMutation(), tracing_options));
}

TEST(LogWrapper, FutureStatus) {
  struct Case {
    std::future_status actual;
    std::string expected;
  } cases[] = {
      {std::future_status::deferred, "deferred"},
      {std::future_status::timeout, "timeout"},
      {std::future_status::ready, "ready"},
  };
  for (auto const& c : cases) {
    EXPECT_EQ(c.expected, DebugFutureStatus(c.actual));
  }
}

/// @test the overload for functions returning FutureStatusOr
TEST(LogWrapper, FutureStatusOrValue) {
  auto mock = [](google::spanner::v1::Mutation m) {
    return make_ready_future(make_status_or(std::move(m)));
  };

  auto backend = std::make_shared<testing_util::CaptureLogLinesBackend>();
  auto id = google::cloud::LogSink::Instance().AddBackend(backend);

  LogWrapper(mock, MakeMutation(), "in-test", {});

  auto const log_lines = backend->ClearLogLines();
  EXPECT_THAT(log_lines,
              Contains(AllOf(HasSubstr("in-test("), HasSubstr(" << "))));
  EXPECT_THAT(log_lines, Contains(AllOf(HasSubstr("in-test("),
                                        HasSubstr(" >> response="))));
  EXPECT_THAT(log_lines, Contains(AllOf(HasSubstr("in-test("),
                                        HasSubstr(" >> future_status="))));

  google::cloud::LogSink::Instance().RemoveBackend(id);
}

/// @test the overload for functions returning FutureStatusOr
TEST(LogWrapper, FutureStatusOrError) {
  auto mock = [](google::spanner::v1::Mutation const&) {
    return make_ready_future(StatusOr<google::spanner::v1::Mutation>(
        Status(StatusCode::kPermissionDenied, "uh-oh")));
  };

  auto backend = std::make_shared<testing_util::CaptureLogLinesBackend>();
  auto id = google::cloud::LogSink::Instance().AddBackend(backend);

  LogWrapper(mock, MakeMutation(), "in-test", {});

  auto const log_lines = backend->ClearLogLines();
  EXPECT_THAT(log_lines,
              Contains(AllOf(HasSubstr("in-test("), HasSubstr(" << "))));
  EXPECT_THAT(log_lines,
              Contains(AllOf(HasSubstr("in-test("), HasSubstr(" >> status="))));
  EXPECT_THAT(log_lines,
              Contains(AllOf(HasSubstr("in-test("), HasSubstr("uh-oh"))));
  EXPECT_THAT(log_lines, Contains(AllOf(HasSubstr("in-test("),
                                        HasSubstr(" >> future_status="))));

  google::cloud::LogSink::Instance().RemoveBackend(id);
}

/// @test the overload for functions returning FutureStatusOr and using
/// CompletionQueue as input
TEST(LogWrapper, FutureStatusOrValueWithContextAndCQ) {
  auto mock = [](google::cloud::CompletionQueue&,
                 std::unique_ptr<grpc::ClientContext>,
                 google::spanner::v1::Mutation m) {
    return make_ready_future(make_status_or(std::move(m)));
  };

  auto backend = std::make_shared<testing_util::CaptureLogLinesBackend>();
  auto id = google::cloud::LogSink::Instance().AddBackend(backend);

  CompletionQueue cq;
  std::unique_ptr<grpc::ClientContext> context;
  LogWrapper(mock, cq, std::move(context), MakeMutation(), "in-test", {});

  auto const log_lines = backend->ClearLogLines();
  EXPECT_THAT(log_lines,
              Contains(AllOf(HasSubstr("in-test("), HasSubstr(" << "))));
  EXPECT_THAT(log_lines, Contains(AllOf(HasSubstr("in-test("),
                                        HasSubstr(" >> response="))));
  EXPECT_THAT(log_lines, Contains(AllOf(HasSubstr("in-test("),
                                        HasSubstr(" >> future_status="))));

  google::cloud::LogSink::Instance().RemoveBackend(id);
}

/// @test the overload for functions returning FutureStatusOr and using
/// CompletionQueue as input
TEST(LogWrapper, FutureStatusOrErrorWithContextAndCQ) {
  auto mock = [](google::cloud::CompletionQueue&,
                 std::unique_ptr<grpc::ClientContext>,
                 google::spanner::v1::Mutation const&) {
    return make_ready_future(StatusOr<google::spanner::v1::Mutation>(
        Status(StatusCode::kPermissionDenied, "uh-oh")));
  };

  auto backend = std::make_shared<testing_util::CaptureLogLinesBackend>();
  auto id = google::cloud::LogSink::Instance().AddBackend(backend);

  CompletionQueue cq;
  std::unique_ptr<grpc::ClientContext> context;
  LogWrapper(mock, cq, std::move(context), MakeMutation(), "in-test", {});

  auto const log_lines = backend->ClearLogLines();
  EXPECT_THAT(log_lines,
              Contains(AllOf(HasSubstr("in-test("), HasSubstr(" << "))));
  EXPECT_THAT(log_lines,
              Contains(AllOf(HasSubstr("in-test("), HasSubstr(" >> status="))));
  EXPECT_THAT(log_lines,
              Contains(AllOf(HasSubstr("in-test("), HasSubstr("uh-oh"))));
  EXPECT_THAT(log_lines, Contains(AllOf(HasSubstr("in-test("),
                                        HasSubstr(" >> future_status="))));

  google::cloud::LogSink::Instance().RemoveBackend(id);
}

/// @test the overload for functions returning FutureStatus and using
/// CompletionQueue as input
TEST(LogWrapper, FutureStatusWithContextAndCQ) {
  auto const status = Status(StatusCode::kPermissionDenied, "uh-oh");
  auto mock = [&](google::cloud::CompletionQueue&,
                  std::unique_ptr<grpc::ClientContext>,
                  google::spanner::v1::Mutation const&) {
    return make_ready_future(status);
  };

  auto backend = std::make_shared<testing_util::CaptureLogLinesBackend>();
  auto id = google::cloud::LogSink::Instance().AddBackend(backend);

  CompletionQueue cq;
  std::unique_ptr<grpc::ClientContext> context;
  LogWrapper(mock, cq, std::move(context), MakeMutation(), "in-test", {});

  std::ostringstream os;
  os << status;
  auto status_as_string = std::move(os).str();

  auto const log_lines = backend->ClearLogLines();
  EXPECT_THAT(log_lines,
              Contains(AllOf(HasSubstr("in-test("), HasSubstr(" << "))));
  EXPECT_THAT(log_lines,
              Contains(AllOf(HasSubstr("in-test("),
                             HasSubstr(" >> response=" + status_as_string))));
  EXPECT_THAT(log_lines, Contains(AllOf(HasSubstr("in-test("),
                                        HasSubstr(" >> future_status="))));

  google::cloud::LogSink::Instance().RemoveBackend(id);
}

/// @test the overload for functions returning Status
TEST(LogWrapper, StatusValue) {
  auto mock = [](grpc::ClientContext*, btproto::MutateRowRequest const&,
                 btproto::MutateRowResponse*) { return grpc::Status(); };

  auto backend = std::make_shared<testing_util::CaptureLogLinesBackend>();
  auto id = google::cloud::LogSink::Instance().AddBackend(backend);
  grpc::ClientContext context;
  btproto::MutateRowRequest request;
  btproto::MutateRowResponse response;
  LogWrapper(mock, &context, request, &response, "in-test", {});

  auto const log_lines = backend->ClearLogLines();

  EXPECT_THAT(log_lines,
              Contains(AllOf(HasSubstr("in-test("), HasSubstr(" << "))));

  google::cloud::LogSink::Instance().RemoveBackend(id);
}

/// @test the overload for functions returning erroneous Status
TEST(LogWrapper, StatusValueError) {
  auto status = grpc::Status(grpc::StatusCode::PERMISSION_DENIED, "uh-oh");
  auto mock = [&status](grpc::ClientContext*, btproto::MutateRowRequest const&,
                        btproto::MutateRowResponse*) { return status; };

  auto backend = std::make_shared<testing_util::CaptureLogLinesBackend>();
  auto id = google::cloud::LogSink::Instance().AddBackend(backend);
  grpc::ClientContext context;
  btproto::MutateRowRequest request;
  btproto::MutateRowResponse response;
  LogWrapper(mock, &context, request, &response, "in-test", {});

  std::ostringstream os;
  os << status.error_message();
  auto status_as_string = std::move(os).str();

  auto const log_lines = backend->ClearLogLines();

  EXPECT_THAT(log_lines,
              Contains(AllOf(HasSubstr("in-test("), HasSubstr(" << "))));
  EXPECT_THAT(log_lines,
              Contains(AllOf(HasSubstr("in-test("),
                             HasSubstr(" >> status=" + status_as_string))));

  google::cloud::LogSink::Instance().RemoveBackend(id);
}

/// @test the overload for functions returning ClientReaderInterface
TEST(LogWrapper, UniquePointerClientReaderInterface) {
  auto mock = [](grpc::ClientContext*, btproto::ReadRowsRequest const&) {
    return std::unique_ptr<
        grpc::ClientReaderInterface<btproto::ReadRowsResponse>>{};
  };

  auto backend = std::make_shared<testing_util::CaptureLogLinesBackend>();
  auto id = google::cloud::LogSink::Instance().AddBackend(backend);
  grpc::ClientContext context;
  btproto::ReadRowsRequest request;
  LogWrapper(mock, &context, request, "in-test", {});

  auto const log_lines = backend->ClearLogLines();

  EXPECT_THAT(log_lines,
              Contains(AllOf(HasSubstr("in-test("), HasSubstr(" << "))));

  google::cloud::LogSink::Instance().RemoveBackend(id);
}

}  // namespace
}  // namespace internal
}  // namespace GOOGLE_CLOUD_CPP_NS
}  // namespace cloud
}  // namespace google
<commit_msg>fix: inspect returned grpc::Status (#5558)<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "google/cloud/internal/log_wrapper.h"
#include "google/cloud/testing_util/capture_log_lines_backend.h"
#include "google/cloud/tracing_options.h"
#include <google/bigtable/v2/bigtable.grpc.pb.h>
#include <google/protobuf/text_format.h>
#include <google/spanner/v1/mutation.pb.h>
#include <gmock/gmock.h>

namespace btproto = google::bigtable::v2;

namespace google {
namespace cloud {
inline namespace GOOGLE_CLOUD_CPP_NS {
namespace internal {
namespace {

using ::testing::AllOf;
using ::testing::Contains;
using ::testing::HasSubstr;

google::spanner::v1::Mutation MakeMutation() {
  auto constexpr kText = R"pb(
    insert {
      table: "Singers"
      columns: "SingerId"
      columns: "FirstName"
      columns: "LastName"
      values {
        values { string_value: "1" }
        values { string_value: "test-fname-1" }
        values { string_value: "test-lname-1" }
      }
      values {
        values { string_value: "2" }
        values { string_value: "test-fname-2" }
        values { string_value: "test-lname-2" }
      }
    }
  )pb";
  google::spanner::v1::Mutation mutation;
  EXPECT_TRUE(google::protobuf::TextFormat::ParseFromString(kText, &mutation));
  return mutation;
}

TEST(LogWrapper, DefaultOptions) {
  TracingOptions tracing_options;
  // clang-format off
  std::string const text =
      R"pb(insert { )pb"
      R"pb(table: "Singers" )pb"
      R"pb(columns: "SingerId" )pb"
      R"pb(columns: "FirstName" )pb"
      R"pb(columns: "LastName" )pb"
      R"pb(values { values { string_value: "1" } )pb"
      R"pb(values { string_value: "test-fname-1" } )pb"
      R"pb(values { string_value: "test-lname-1" } } )pb"
      R"pb(values { values { string_value: "2" } )pb"
      R"pb(values { string_value: "test-fname-2" } )pb"
      R"pb(values { string_value: "test-lname-2" } )pb"
      R"pb(} )pb"
      R"pb(} )pb";
  // clang-format on
  EXPECT_EQ(text, internal::DebugString(MakeMutation(), tracing_options));
}

TEST(LogWrapper, MultiLine) {
  TracingOptions tracing_options;
  tracing_options.SetOptions("single_line_mode=off");
  // clang-format off
  std::string const text = R"pb(insert {
  table: "Singers"
  columns: "SingerId"
  columns: "FirstName"
  columns: "LastName"
  values {
    values {
      string_value: "1"
    }
    values {
      string_value: "test-fname-1"
    }
    values {
      string_value: "test-lname-1"
    }
  }
  values {
    values {
      string_value: "2"
    }
    values {
      string_value: "test-fname-2"
    }
    values {
      string_value: "test-lname-2"
    }
  }
}
)pb";
  // clang-format on
  EXPECT_EQ(text, internal::DebugString(MakeMutation(), tracing_options));
}

TEST(LogWrapper, Truncate) {
  TracingOptions tracing_options;
  tracing_options.SetOptions("truncate_string_field_longer_than=8");
  // clang-format off
  std::string const text =R"pb(insert { )pb"
            R"pb(table: "Singers" )pb"
            R"pb(columns: "SingerId" )pb"
            R"pb(columns: "FirstNam...<truncated>..." )pb"
            R"pb(columns: "LastName" )pb"
            R"pb(values { values { string_value: "1" } )pb"
            R"pb(values { string_value: "test-fna...<truncated>..." } )pb"
            R"pb(values { string_value: "test-lna...<truncated>..." } } )pb"
            R"pb(values { values { string_value: "2" } )pb"
            R"pb(values { string_value: "test-fna...<truncated>..." } )pb"
            R"pb(values { string_value: "test-lna...<truncated>..." } )pb"
            R"pb(} )pb"
            R"pb(} )pb";
  // clang-format on
  EXPECT_EQ(text, internal::DebugString(MakeMutation(), tracing_options));
}

TEST(LogWrapper, FutureStatus) {
  struct Case {
    std::future_status actual;
    std::string expected;
  } cases[] = {
      {std::future_status::deferred, "deferred"},
      {std::future_status::timeout, "timeout"},
      {std::future_status::ready, "ready"},
  };
  for (auto const& c : cases) {
    EXPECT_EQ(c.expected, DebugFutureStatus(c.actual));
  }
}

/// @test the overload for functions returning FutureStatusOr
TEST(LogWrapper, FutureStatusOrValue) {
  auto mock = [](google::spanner::v1::Mutation m) {
    return make_ready_future(make_status_or(std::move(m)));
  };

  auto backend = std::make_shared<testing_util::CaptureLogLinesBackend>();
  auto id = google::cloud::LogSink::Instance().AddBackend(backend);

  LogWrapper(mock, MakeMutation(), "in-test", {});

  auto const log_lines = backend->ClearLogLines();
  EXPECT_THAT(log_lines,
              Contains(AllOf(HasSubstr("in-test("), HasSubstr(" << "))));
  EXPECT_THAT(log_lines, Contains(AllOf(HasSubstr("in-test("),
                                        HasSubstr(" >> response="))));
  EXPECT_THAT(log_lines, Contains(AllOf(HasSubstr("in-test("),
                                        HasSubstr(" >> future_status="))));

  google::cloud::LogSink::Instance().RemoveBackend(id);
}

/// @test the overload for functions returning FutureStatusOr
TEST(LogWrapper, FutureStatusOrError) {
  auto mock = [](google::spanner::v1::Mutation const&) {
    return make_ready_future(StatusOr<google::spanner::v1::Mutation>(
        Status(StatusCode::kPermissionDenied, "uh-oh")));
  };

  auto backend = std::make_shared<testing_util::CaptureLogLinesBackend>();
  auto id = google::cloud::LogSink::Instance().AddBackend(backend);

  LogWrapper(mock, MakeMutation(), "in-test", {});

  auto const log_lines = backend->ClearLogLines();
  EXPECT_THAT(log_lines,
              Contains(AllOf(HasSubstr("in-test("), HasSubstr(" << "))));
  EXPECT_THAT(log_lines,
              Contains(AllOf(HasSubstr("in-test("), HasSubstr(" >> status="))));
  EXPECT_THAT(log_lines,
              Contains(AllOf(HasSubstr("in-test("), HasSubstr("uh-oh"))));
  EXPECT_THAT(log_lines, Contains(AllOf(HasSubstr("in-test("),
                                        HasSubstr(" >> future_status="))));

  google::cloud::LogSink::Instance().RemoveBackend(id);
}

/// @test the overload for functions returning FutureStatusOr and using
/// CompletionQueue as input
TEST(LogWrapper, FutureStatusOrValueWithContextAndCQ) {
  auto mock = [](google::cloud::CompletionQueue&,
                 std::unique_ptr<grpc::ClientContext>,
                 google::spanner::v1::Mutation m) {
    return make_ready_future(make_status_or(std::move(m)));
  };

  auto backend = std::make_shared<testing_util::CaptureLogLinesBackend>();
  auto id = google::cloud::LogSink::Instance().AddBackend(backend);

  CompletionQueue cq;
  std::unique_ptr<grpc::ClientContext> context;
  LogWrapper(mock, cq, std::move(context), MakeMutation(), "in-test", {});

  auto const log_lines = backend->ClearLogLines();
  EXPECT_THAT(log_lines,
              Contains(AllOf(HasSubstr("in-test("), HasSubstr(" << "))));
  EXPECT_THAT(log_lines, Contains(AllOf(HasSubstr("in-test("),
                                        HasSubstr(" >> response="))));
  EXPECT_THAT(log_lines, Contains(AllOf(HasSubstr("in-test("),
                                        HasSubstr(" >> future_status="))));

  google::cloud::LogSink::Instance().RemoveBackend(id);
}

/// @test the overload for functions returning FutureStatusOr and using
/// CompletionQueue as input
TEST(LogWrapper, FutureStatusOrErrorWithContextAndCQ) {
  auto mock = [](google::cloud::CompletionQueue&,
                 std::unique_ptr<grpc::ClientContext>,
                 google::spanner::v1::Mutation const&) {
    return make_ready_future(StatusOr<google::spanner::v1::Mutation>(
        Status(StatusCode::kPermissionDenied, "uh-oh")));
  };

  auto backend = std::make_shared<testing_util::CaptureLogLinesBackend>();
  auto id = google::cloud::LogSink::Instance().AddBackend(backend);

  CompletionQueue cq;
  std::unique_ptr<grpc::ClientContext> context;
  LogWrapper(mock, cq, std::move(context), MakeMutation(), "in-test", {});

  auto const log_lines = backend->ClearLogLines();
  EXPECT_THAT(log_lines,
              Contains(AllOf(HasSubstr("in-test("), HasSubstr(" << "))));
  EXPECT_THAT(log_lines,
              Contains(AllOf(HasSubstr("in-test("), HasSubstr(" >> status="))));
  EXPECT_THAT(log_lines,
              Contains(AllOf(HasSubstr("in-test("), HasSubstr("uh-oh"))));
  EXPECT_THAT(log_lines, Contains(AllOf(HasSubstr("in-test("),
                                        HasSubstr(" >> future_status="))));

  google::cloud::LogSink::Instance().RemoveBackend(id);
}

/// @test the overload for functions returning FutureStatus and using
/// CompletionQueue as input
TEST(LogWrapper, FutureStatusWithContextAndCQ) {
  auto const status = Status(StatusCode::kPermissionDenied, "uh-oh");
  auto mock = [&](google::cloud::CompletionQueue&,
                  std::unique_ptr<grpc::ClientContext>,
                  google::spanner::v1::Mutation const&) {
    return make_ready_future(status);
  };

  auto backend = std::make_shared<testing_util::CaptureLogLinesBackend>();
  auto id = google::cloud::LogSink::Instance().AddBackend(backend);

  CompletionQueue cq;
  std::unique_ptr<grpc::ClientContext> context;
  LogWrapper(mock, cq, std::move(context), MakeMutation(), "in-test", {});

  std::ostringstream os;
  os << status;
  auto status_as_string = std::move(os).str();

  auto const log_lines = backend->ClearLogLines();
  EXPECT_THAT(log_lines,
              Contains(AllOf(HasSubstr("in-test("), HasSubstr(" << "))));
  EXPECT_THAT(log_lines,
              Contains(AllOf(HasSubstr("in-test("),
                             HasSubstr(" >> response=" + status_as_string))));
  EXPECT_THAT(log_lines, Contains(AllOf(HasSubstr("in-test("),
                                        HasSubstr(" >> future_status="))));

  google::cloud::LogSink::Instance().RemoveBackend(id);
}

/// @test the overload for functions returning Status
TEST(LogWrapper, StatusValue) {
  auto mock = [](grpc::ClientContext*, btproto::MutateRowRequest const&,
                 btproto::MutateRowResponse*) { return grpc::Status(); };

  auto backend = std::make_shared<testing_util::CaptureLogLinesBackend>();
  auto id = google::cloud::LogSink::Instance().AddBackend(backend);
  grpc::ClientContext context;
  btproto::MutateRowRequest request;
  btproto::MutateRowResponse response;
  auto const r = LogWrapper(mock, &context, request, &response, "in-test", {});
  EXPECT_TRUE(r.ok());

  auto const log_lines = backend->ClearLogLines();

  EXPECT_THAT(log_lines,
              Contains(AllOf(HasSubstr("in-test("), HasSubstr(" << "))));

  google::cloud::LogSink::Instance().RemoveBackend(id);
}

/// @test the overload for functions returning erroneous Status
TEST(LogWrapper, StatusValueError) {
  auto status = grpc::Status(grpc::StatusCode::PERMISSION_DENIED, "uh-oh");
  auto mock = [&status](grpc::ClientContext*, btproto::MutateRowRequest const&,
                        btproto::MutateRowResponse*) { return status; };

  auto backend = std::make_shared<testing_util::CaptureLogLinesBackend>();
  auto id = google::cloud::LogSink::Instance().AddBackend(backend);
  grpc::ClientContext context;
  btproto::MutateRowRequest request;
  btproto::MutateRowResponse response;
  auto const r = LogWrapper(mock, &context, request, &response, "in-test", {});
  EXPECT_EQ(r.error_code(), status.error_code());
  EXPECT_EQ(r.error_message(), status.error_message());

  std::ostringstream os;
  os << status.error_message();
  auto status_as_string = std::move(os).str();

  auto const log_lines = backend->ClearLogLines();

  EXPECT_THAT(log_lines,
              Contains(AllOf(HasSubstr("in-test("), HasSubstr(" << "))));
  EXPECT_THAT(log_lines,
              Contains(AllOf(HasSubstr("in-test("),
                             HasSubstr(" >> status=" + status_as_string))));

  google::cloud::LogSink::Instance().RemoveBackend(id);
}

/// @test the overload for functions returning ClientReaderInterface
TEST(LogWrapper, UniquePointerClientReaderInterface) {
  auto mock = [](grpc::ClientContext*, btproto::ReadRowsRequest const&) {
    return std::unique_ptr<
        grpc::ClientReaderInterface<btproto::ReadRowsResponse>>{};
  };

  auto backend = std::make_shared<testing_util::CaptureLogLinesBackend>();
  auto id = google::cloud::LogSink::Instance().AddBackend(backend);
  grpc::ClientContext context;
  btproto::ReadRowsRequest request;
  LogWrapper(mock, &context, request, "in-test", {});

  auto const log_lines = backend->ClearLogLines();

  EXPECT_THAT(log_lines,
              Contains(AllOf(HasSubstr("in-test("), HasSubstr(" << "))));

  google::cloud::LogSink::Instance().RemoveBackend(id);
}

}  // namespace
}  // namespace internal
}  // namespace GOOGLE_CLOUD_CPP_NS
}  // namespace cloud
}  // namespace google
<|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (info@qt.nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at info@qt.nokia.com.
**
**************************************************************************/

#include "modelmerger.h"

#include "modelmerger.h"
#include "modelnode.h"
#include "abstractview.h"
#include "model.h"
#include "nodeproperty.h"
#include "nodelistproperty.h"
#include "bindingproperty.h"
#include "variantproperty.h"
#include "rewritertransaction.h"
#include <rewritingexception.h>

#include <QSet>
#include <QStringList>

#include <QtDebug>

namespace QmlDesigner {

static ModelNode createNodeFromNode(const ModelNode &modelNode,const QHash<QString, QString> &idRenamingHash, AbstractView *view);

static QString fixExpression(const QString &expression, const QHash<QString, QString> &idRenamingHash)
{
    QString newExpression = expression;
    foreach (const QString &id, idRenamingHash.keys()) {
        if (newExpression.contains(id))
            newExpression = newExpression.replace(id, idRenamingHash.value(id));
    }
    return newExpression;
}

static void syncVariantProperties(ModelNode &outputNode, const ModelNode &inputNode)
{
    foreach (const VariantProperty &variantProperty, inputNode.variantProperties()) {
        outputNode.variantProperty(variantProperty.name()) = variantProperty.value();
    }
}

static void syncBindingProperties(ModelNode &outputNode, const ModelNode &inputNode, const QHash<QString, QString> &idRenamingHash)
{
    foreach (const BindingProperty &bindingProperty, inputNode.bindingProperties()) {
        outputNode.bindingProperty(bindingProperty.name()).setExpression(fixExpression(bindingProperty.expression(), idRenamingHash));
    }
}

static void syncId(ModelNode &outputNode, const ModelNode &inputNode, const QHash<QString, QString> &idRenamingHash)
{
    if (!inputNode.id().isEmpty()) {
        outputNode.setId(idRenamingHash.value(inputNode.id()));
    }
}

static void splitIdInBaseNameAndNumber(const QString &id, QString *baseId, int *number)
{

    int counter = 0;
    while(counter < id.count()) {
        bool canConvertToInteger = false;
        int newNumber = id.right(counter +1).toInt(&canConvertToInteger);
        if (canConvertToInteger)
            *number = newNumber;
        else
            break;

        counter++;
    }

    *baseId = id.left(id.count() - counter);
}

static void setupIdRenamingHash(const ModelNode &modelNode, QHash<QString, QString> &idRenamingHash, AbstractView *view)
{
    QList<ModelNode> allNodes(modelNode.allSubModelNodes());
    allNodes.append(modelNode);
    foreach (const ModelNode &node, allNodes) {
        if (!node.id().isEmpty()) {
            QString newId = node.id();
            QString baseId;
            int number = 1;
            splitIdInBaseNameAndNumber(newId, &baseId, &number);

            while (view->hasId(newId) || idRenamingHash.values().contains(newId)) {
                newId = baseId + QString::number(number);
                number++;
            }

            idRenamingHash.insert(node.id(), newId);
        }
    }
}

static void syncNodeProperties(ModelNode &outputNode, const ModelNode &inputNode, const QHash<QString, QString> &idRenamingHash, AbstractView *view)
{
    foreach (const NodeProperty &nodeProperty, inputNode.nodeProperties()) {
        ModelNode newNode = createNodeFromNode(nodeProperty.modelNode(), idRenamingHash, view);
        outputNode.nodeProperty(nodeProperty.name()).reparentHere(newNode);
    }
}

static void syncNodeListProperties(ModelNode &outputNode, const ModelNode &inputNode, const QHash<QString, QString> &idRenamingHash, AbstractView *view)
{
    foreach (const NodeListProperty &nodeListProperty, inputNode.nodeListProperties()) {
        foreach (const ModelNode &node, nodeListProperty.toModelNodeList()) {
            ModelNode newNode = createNodeFromNode(node, idRenamingHash, view);
            outputNode.nodeListProperty(nodeListProperty.name()).reparentHere(newNode);
        }
    }
}

static ModelNode createNodeFromNode(const ModelNode &modelNode,const QHash<QString, QString> &idRenamingHash, AbstractView *view)
{
    QList<QPair<QString, QVariant> > propertyList;
    QList<QPair<QString, QVariant> > variantPropertyList;
    foreach (const VariantProperty &variantProperty, modelNode.variantProperties()) {
        propertyList.append(QPair<QString, QVariant>(variantProperty.name(), variantProperty.value()));
    }
    ModelNode newNode(view->createModelNode(modelNode.type(),modelNode.majorVersion(),modelNode.minorVersion(),
                                            propertyList, variantPropertyList, modelNode.nodeSource(), modelNode.nodeSourceType()));
    syncBindingProperties(newNode, modelNode, idRenamingHash);
    syncId(newNode, modelNode, idRenamingHash);
    syncNodeProperties(newNode, modelNode, idRenamingHash, view);
    syncNodeListProperties(newNode, modelNode, idRenamingHash, view);

    return newNode;
}

ModelNode ModelMerger::insertModel(const ModelNode &modelNode)
{
    RewriterTransaction transaction(view()->beginRewriterTransaction());

    QList<Import> newImports;

    foreach (const Import &import, modelNode.model()->imports()) {
        if (!view()->model()->hasImport(import, true)) {
            newImports.append(import);
        }
    }

    view()->model()->changeImports(newImports, QList<Import>());

    QHash<QString, QString> idRenamingHash;
    setupIdRenamingHash(modelNode, idRenamingHash, view());
    qDebug() << idRenamingHash;
    ModelNode newNode(createNodeFromNode(modelNode, idRenamingHash, view()));

    return newNode;
}

void ModelMerger::replaceModel(const ModelNode &modelNode)
{
        view()->model()->changeImports(modelNode.model()->imports(), QList<Import>());
        view()->model()->setFileUrl(modelNode.model()->fileUrl());

    try {
        RewriterTransaction transaction(view()->beginRewriterTransaction());

        ModelNode rootNode(view()->rootModelNode());

        foreach (const QString &propertyName, rootNode.propertyNames())
            rootNode.removeProperty(propertyName);

        QHash<QString, QString> idRenamingHash;
        setupIdRenamingHash(modelNode, idRenamingHash, view());

        syncVariantProperties(rootNode, modelNode);
        syncBindingProperties(rootNode, modelNode, idRenamingHash);
        syncId(rootNode, modelNode, idRenamingHash);
        syncNodeProperties(rootNode, modelNode, idRenamingHash, view());
        syncNodeListProperties(rootNode, modelNode, idRenamingHash, view());
        m_view->changeRootNodeType(modelNode.type(), modelNode.majorVersion(), modelNode.minorVersion());
    } catch (RewritingException &e) {
        qWarning() << e.description(); //silent error
    }
}

} //namespace QmlDesigner

<commit_msg>QmlDesigner.modelMerger: fix for imports<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (info@qt.nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at info@qt.nokia.com.
**
**************************************************************************/

#include "modelmerger.h"

#include "modelmerger.h"
#include "modelnode.h"
#include "abstractview.h"
#include "model.h"
#include "nodeproperty.h"
#include "nodelistproperty.h"
#include "bindingproperty.h"
#include "variantproperty.h"
#include "rewritertransaction.h"
#include <rewritingexception.h>

#include <QSet>
#include <QStringList>

#include <QtDebug>

namespace QmlDesigner {

static ModelNode createNodeFromNode(const ModelNode &modelNode,const QHash<QString, QString> &idRenamingHash, AbstractView *view);

static QString fixExpression(const QString &expression, const QHash<QString, QString> &idRenamingHash)
{
    QString newExpression = expression;
    foreach (const QString &id, idRenamingHash.keys()) {
        if (newExpression.contains(id))
            newExpression = newExpression.replace(id, idRenamingHash.value(id));
    }
    return newExpression;
}

static void syncVariantProperties(ModelNode &outputNode, const ModelNode &inputNode)
{
    foreach (const VariantProperty &variantProperty, inputNode.variantProperties()) {
        outputNode.variantProperty(variantProperty.name()) = variantProperty.value();
    }
}

static void syncBindingProperties(ModelNode &outputNode, const ModelNode &inputNode, const QHash<QString, QString> &idRenamingHash)
{
    foreach (const BindingProperty &bindingProperty, inputNode.bindingProperties()) {
        outputNode.bindingProperty(bindingProperty.name()).setExpression(fixExpression(bindingProperty.expression(), idRenamingHash));
    }
}

static void syncId(ModelNode &outputNode, const ModelNode &inputNode, const QHash<QString, QString> &idRenamingHash)
{
    if (!inputNode.id().isEmpty()) {
        outputNode.setId(idRenamingHash.value(inputNode.id()));
    }
}

static void splitIdInBaseNameAndNumber(const QString &id, QString *baseId, int *number)
{

    int counter = 0;
    while(counter < id.count()) {
        bool canConvertToInteger = false;
        int newNumber = id.right(counter +1).toInt(&canConvertToInteger);
        if (canConvertToInteger)
            *number = newNumber;
        else
            break;

        counter++;
    }

    *baseId = id.left(id.count() - counter);
}

static void setupIdRenamingHash(const ModelNode &modelNode, QHash<QString, QString> &idRenamingHash, AbstractView *view)
{
    QList<ModelNode> allNodes(modelNode.allSubModelNodes());
    allNodes.append(modelNode);
    foreach (const ModelNode &node, allNodes) {
        if (!node.id().isEmpty()) {
            QString newId = node.id();
            QString baseId;
            int number = 1;
            splitIdInBaseNameAndNumber(newId, &baseId, &number);

            while (view->hasId(newId) || idRenamingHash.values().contains(newId)) {
                newId = baseId + QString::number(number);
                number++;
            }

            idRenamingHash.insert(node.id(), newId);
        }
    }
}

static void syncNodeProperties(ModelNode &outputNode, const ModelNode &inputNode, const QHash<QString, QString> &idRenamingHash, AbstractView *view)
{
    foreach (const NodeProperty &nodeProperty, inputNode.nodeProperties()) {
        ModelNode newNode = createNodeFromNode(nodeProperty.modelNode(), idRenamingHash, view);
        outputNode.nodeProperty(nodeProperty.name()).reparentHere(newNode);
    }
}

static void syncNodeListProperties(ModelNode &outputNode, const ModelNode &inputNode, const QHash<QString, QString> &idRenamingHash, AbstractView *view)
{
    foreach (const NodeListProperty &nodeListProperty, inputNode.nodeListProperties()) {
        foreach (const ModelNode &node, nodeListProperty.toModelNodeList()) {
            ModelNode newNode = createNodeFromNode(node, idRenamingHash, view);
            outputNode.nodeListProperty(nodeListProperty.name()).reparentHere(newNode);
        }
    }
}

static ModelNode createNodeFromNode(const ModelNode &modelNode,const QHash<QString, QString> &idRenamingHash, AbstractView *view)
{
    QList<QPair<QString, QVariant> > propertyList;
    QList<QPair<QString, QVariant> > variantPropertyList;
    foreach (const VariantProperty &variantProperty, modelNode.variantProperties()) {
        propertyList.append(QPair<QString, QVariant>(variantProperty.name(), variantProperty.value()));
    }
    ModelNode newNode(view->createModelNode(modelNode.type(),modelNode.majorVersion(),modelNode.minorVersion(),
                                            propertyList, variantPropertyList, modelNode.nodeSource(), modelNode.nodeSourceType()));
    syncBindingProperties(newNode, modelNode, idRenamingHash);
    syncId(newNode, modelNode, idRenamingHash);
    syncNodeProperties(newNode, modelNode, idRenamingHash, view);
    syncNodeListProperties(newNode, modelNode, idRenamingHash, view);

    return newNode;
}

ModelNode ModelMerger::insertModel(const ModelNode &modelNode)
{
    RewriterTransaction transaction(view()->beginRewriterTransaction());

    QList<Import> newImports;

    foreach (const Import &import, modelNode.model()->imports()) {
        if (!view()->model()->hasImport(import, true, true)) {
            newImports.append(import);
        }
    }

    view()->model()->changeImports(newImports, QList<Import>());

    QHash<QString, QString> idRenamingHash;
    setupIdRenamingHash(modelNode, idRenamingHash, view());
    qDebug() << idRenamingHash;
    ModelNode newNode(createNodeFromNode(modelNode, idRenamingHash, view()));

    return newNode;
}

void ModelMerger::replaceModel(const ModelNode &modelNode)
{
        view()->model()->changeImports(modelNode.model()->imports(), QList<Import>());
        view()->model()->setFileUrl(modelNode.model()->fileUrl());

    try {
        RewriterTransaction transaction(view()->beginRewriterTransaction());

        ModelNode rootNode(view()->rootModelNode());

        foreach (const QString &propertyName, rootNode.propertyNames())
            rootNode.removeProperty(propertyName);

        QHash<QString, QString> idRenamingHash;
        setupIdRenamingHash(modelNode, idRenamingHash, view());

        syncVariantProperties(rootNode, modelNode);
        syncBindingProperties(rootNode, modelNode, idRenamingHash);
        syncId(rootNode, modelNode, idRenamingHash);
        syncNodeProperties(rootNode, modelNode, idRenamingHash, view());
        syncNodeListProperties(rootNode, modelNode, idRenamingHash, view());
        m_view->changeRootNodeType(modelNode.type(), modelNode.majorVersion(), modelNode.minorVersion());
    } catch (RewritingException &e) {
        qWarning() << e.description(); //silent error
    }
}

} //namespace QmlDesigner

<|endoftext|>


<commit_before>#include <shogun/preprocessor/DimensionReductionPreprocessor.h>
#include <shogun/kernel/GaussianKernel.h>
#include <shogun/distance/EuclidianDistance.h>

using namespace shogun;

CDimensionReductionPreprocessor::CDimensionReductionPreprocessor()
: CSimplePreprocessor<float64_t>()
{
	m_target_dim = 1;
	m_distance = new CEuclidianDistance();
	m_distance->parallel = this->parallel;
	SG_REF(this->parallel);
	m_kernel = new CGaussianKernel();
	m_kernel->parallel = this->parallel;
	SG_REF(this->parallel);

	init();
}

CDimensionReductionPreprocessor::~CDimensionReductionPreprocessor()
{
	SG_UNREF(m_distance);
	SG_UNREF(m_kernel);
}

bool CDimensionReductionPreprocessor::init(CFeatures* data)
{
	return true;
}

void CDimensionReductionPreprocessor::cleanup()
{

}

SGMatrix<float64_t> CDimensionReductionPreprocessor::apply_to_feature_matrix(CFeatures* features)
{
	return ((CSimpleFeatures<float64_t>*)features)->get_feature_matrix();
};

SGVector<float64_t> CDimensionReductionPreprocessor::apply_to_feature_vector(SGVector<float64_t> vector)
{
	return vector;
};

EPreprocessorType CDimensionReductionPreprocessor::get_type() const { return P_DIMENSIONREDUCTIONPREPROCESSOR; };

void CDimensionReductionPreprocessor::set_target_dim(int32_t dim)
{
	m_target_dim = dim;
}

int32_t CDimensionReductionPreprocessor::get_target_dim() const
{
	return m_target_dim;
}

int32_t CDimensionReductionPreprocessor::calculate_effective_target_dim(int32_t dim)
{
	if (m_target_dim<0)
	{
		if (dim+m_target_dim>0)
		{
			return dim+m_target_dim;
		}
		else
			return -1;
	}
	else
		return m_target_dim;
}

void CDimensionReductionPreprocessor::set_distance(CDistance* distance)
{
	SG_UNREF(m_distance);
	SG_REF(distance);
	m_distance = distance;
	m_distance->parallel = this->parallel;
	SG_REF(this->parallel);
}

CDistance* CDimensionReductionPreprocessor::get_distance() const
{
	SG_REF(m_distance);
	return m_distance;
}

void CDimensionReductionPreprocessor::set_kernel(CKernel* kernel)
{
	SG_UNREF(m_kernel);
	SG_REF(kernel);
	m_kernel = kernel;
	m_kernel->parallel = this->parallel;
	SG_REF(this->parallel);
}

CKernel* CDimensionReductionPreprocessor::get_kernel() const
{
	SG_REF(m_kernel);
	return m_kernel;
}

int32_t CDimensionReductionPreprocessor::detect_dim(SGMatrix<float64_t> distance_matrix)
{
	SG_NOTIMPLEMENTED;
	return 0;
}

void CDimensionReductionPreprocessor::init()
{
	m_parameters->add(&m_target_dim, "target_dim",
					  "target dimensionality of preprocessor");
	m_parameters->add((CSGObject**)&m_distance, "distance",
					  "distance to be used for embedding");
	m_parameters->add((CSGObject**)&m_kernel, "kernel",
					  "kernel to be used for embedding");
}
<commit_msg>Changed default kernel for DR preprocessor base class<commit_after>#include <shogun/preprocessor/DimensionReductionPreprocessor.h>
#include <shogun/kernel/LinearKernel.h>
#include <shogun/distance/EuclidianDistance.h>

using namespace shogun;

CDimensionReductionPreprocessor::CDimensionReductionPreprocessor()
: CSimplePreprocessor<float64_t>()
{
	m_target_dim = 1;
	m_distance = new CEuclidianDistance();
	m_distance->parallel = this->parallel;
	SG_REF(this->parallel);
	m_kernel = new CLinearKernel();
	m_kernel->parallel = this->parallel;
	SG_REF(this->parallel);

	init();
}

CDimensionReductionPreprocessor::~CDimensionReductionPreprocessor()
{
	SG_UNREF(m_distance);
	SG_UNREF(m_kernel);
}

bool CDimensionReductionPreprocessor::init(CFeatures* data)
{
	return true;
}

void CDimensionReductionPreprocessor::cleanup()
{

}

SGMatrix<float64_t> CDimensionReductionPreprocessor::apply_to_feature_matrix(CFeatures* features)
{
	return ((CSimpleFeatures<float64_t>*)features)->get_feature_matrix();
};

SGVector<float64_t> CDimensionReductionPreprocessor::apply_to_feature_vector(SGVector<float64_t> vector)
{
	return vector;
};

EPreprocessorType CDimensionReductionPreprocessor::get_type() const { return P_DIMENSIONREDUCTIONPREPROCESSOR; };

void CDimensionReductionPreprocessor::set_target_dim(int32_t dim)
{
	m_target_dim = dim;
}

int32_t CDimensionReductionPreprocessor::get_target_dim() const
{
	return m_target_dim;
}

int32_t CDimensionReductionPreprocessor::calculate_effective_target_dim(int32_t dim)
{
	if (m_target_dim<0)
	{
		if (dim+m_target_dim>0)
		{
			return dim+m_target_dim;
		}
		else
			return -1;
	}
	else
		return m_target_dim;
}

void CDimensionReductionPreprocessor::set_distance(CDistance* distance)
{
	SG_UNREF(m_distance);
	SG_REF(distance);
	m_distance = distance;
	m_distance->parallel = this->parallel;
	SG_REF(this->parallel);
}

CDistance* CDimensionReductionPreprocessor::get_distance() const
{
	SG_REF(m_distance);
	return m_distance;
}

void CDimensionReductionPreprocessor::set_kernel(CKernel* kernel)
{
	SG_UNREF(m_kernel);
	SG_REF(kernel);
	m_kernel = kernel;
	m_kernel->parallel = this->parallel;
	SG_REF(this->parallel);
}

CKernel* CDimensionReductionPreprocessor::get_kernel() const
{
	SG_REF(m_kernel);
	return m_kernel;
}

int32_t CDimensionReductionPreprocessor::detect_dim(SGMatrix<float64_t> distance_matrix)
{
	SG_NOTIMPLEMENTED;
	return 0;
}

void CDimensionReductionPreprocessor::init()
{
	m_parameters->add(&m_target_dim, "target_dim",
					  "target dimensionality of preprocessor");
	m_parameters->add((CSGObject**)&m_distance, "distance",
					  "distance to be used for embedding");
	m_parameters->add((CSGObject**)&m_kernel, "kernel",
					  "kernel to be used for embedding");
}
<|endoftext|>


<commit_before>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <list>
#include <string>

#include <glog/logging.h>

#include <stout/error.hpp>
#include <stout/foreach.hpp>
#include <stout/stringify.hpp>
#include <stout/strings.hpp>

#include <mesos/docker/v1.hpp>

#include "slave/flags.hpp"

#include "slave/containerizer/mesos/isolators/docker/runtime.hpp"

using std::list;
using std::string;

using process::Failure;
using process::Future;
using process::Owned;
using process::PID;

using mesos::slave::ContainerConfig;
using mesos::slave::ContainerLaunchInfo;
using mesos::slave::ContainerLimitation;
using mesos::slave::ContainerState;
using mesos::slave::Isolator;

namespace mesos {
namespace internal {
namespace slave {

DockerRuntimeIsolatorProcess::DockerRuntimeIsolatorProcess(
    const Flags& _flags)
  : flags(_flags) {}

DockerRuntimeIsolatorProcess::~DockerRuntimeIsolatorProcess() {}

Try<Isolator*> DockerRuntimeIsolatorProcess::create(const Flags& flags)
{
  process::Owned<MesosIsolatorProcess> process(
      new DockerRuntimeIsolatorProcess(flags));

  return new MesosIsolator(process);
}

Future<Nothing> DockerRuntimeIsolatorProcess::recover(
    const list<ContainerState>& states,
    const hashset<ContainerID>& orphans)
{
  return Nothing();
}

Future<Option<ContainerLaunchInfo>> DockerRuntimeIsolatorProcess::prepare(
    const ContainerID& containerId,
    const ContainerConfig& containerConfig)
{
  const ExecutorInfo& executorInfo = containerConfig.executor_info();

  if (!executorInfo.has_container()) {
    return None();
  }

  if (executorInfo.container().type() != ContainerInfo::MESOS) {
    return Failure("Can only prepare docker runtime for a MESOS container");
  }

  if (!containerConfig.has_docker()) {
    // No docker image default config available.
    return None();
  }

  Option<Environment> environment =
    getLaunchEnvironment(containerId, containerConfig);

  Option<string> workingDirectory =
    getWorkingDirectory(containerConfig);

  Result<CommandInfo> command =
    getExecutorLaunchCommand(containerId, containerConfig);

  if (command.isError()) {
    return Failure("Failed to determine the executor launch command: " +
                   command.error());
  }

  // Set 'launchInfo'.
  ContainerLaunchInfo launchInfo;

  if (environment.isSome()) {
    launchInfo.mutable_environment()->CopyFrom(environment.get());
  }

  // If working directory or command exists, operation has to be
  // distinguished for either custom executor or command task. For
  // custom executor case, info will be included in 'launchInfo', and
  // will be passed back to containerizer. For command task case, info
  // will be passed to command executor as flags.
  if (!containerConfig.has_task_info()) {
    // Custom executor case.
    if (workingDirectory.isSome()) {
      launchInfo.set_working_directory(workingDirectory.get());
    }

    if (command.isSome()) {
      launchInfo.mutable_command()->CopyFrom(command.get());
    }
  } else {
    // Command task case. The 'executorCommand' below is the
    // command with value as 'mesos-executor'.
    CommandInfo executorCommand = containerConfig.executor_info().command();

    // Pass working directory to command executor as a flag.
    if (workingDirectory.isSome()) {
      executorCommand.add_arguments(
          "--working_directory=" + workingDirectory.get());
    }

    // Pass task command as a flag, which will be loaded by
    // command executor.
    if (command.isSome()) {
      executorCommand.add_arguments(
          "--task_command=" +
          stringify(JSON::protobuf(command.get())));
    }

    launchInfo.mutable_command()->CopyFrom(executorCommand);
  }

  return launchInfo;
}

Option<Environment> DockerRuntimeIsolatorProcess::getLaunchEnvironment(
    const ContainerID& containerId,
    const ContainerConfig& containerConfig)
{
  CHECK(containerConfig.docker().manifest().has_config());

  if (containerConfig.docker().manifest().config().env_size() == 0) {
    return None();
  }

  Environment environment;

  foreach(const string& env,
          containerConfig.docker().manifest().config().env()) {
    // Use `find_first_of` to prevent to case that there are
    // multiple '=' existing.
    size_t position = env.find_first_of('=');
    if (position == string::npos) {
      VLOG(1) << "Skipping invalid environment variable: '"
              << env << "' in docker manifest for container "
              << containerId;

      continue;
    }

    const string name = env.substr(0, position);
    const string value = env.substr(position + 1);

    // Keep all environment from runtime isolator. If there exists
    // environment variable duplicate cases, it will be overwritten
    // in mesos containerizer.
    Environment::Variable* variable = environment.add_variables();
    variable->set_name(name);
    variable->set_value(value);
  }

  return environment;
}

// This method reads the CommandInfo form ExecutorInfo and optional
// TaskInfo, and merge them with docker image default Entrypoint and
// Cmd. It returns a merged CommandInfo which will be used to launch
// the executor. If no need to modify the command, this method will
// return none.
Result<CommandInfo> DockerRuntimeIsolatorProcess::getExecutorLaunchCommand(
    const ContainerID& containerId,
    const ContainerConfig& containerConfig)
{
  CHECK(containerConfig.docker().manifest().has_config());

  // We may or may not mutate the CommandInfo for executor depending
  // on the logic table below. For custom executor case, we make
  // changes to the command directly. For command task case, if no
  // need to change the launch command for the user task, we do not do
  // anything and return the CommandInfo from ExecutorInfo. We only
  // add a flag `--task_command` to carry command as a JSON object if
  // it is neccessary to mutate.
  CommandInfo command;

  if (!containerConfig.has_task_info()) {
    // Custom executor case.
    CHECK(containerConfig.executor_info().has_command());
    command = containerConfig.executor_info().command();
  } else {
    // Command task case.
    CHECK(containerConfig.task_info().has_command());
    command = containerConfig.task_info().command();
  }

  // We merge the CommandInfo following the logic:
  // 1. If 'shell' is true, we will ignore Entrypoint and Cmd from
  //    the docker image (row 5-8).
  // 2. If 'shell' is false and 'value' is set, we will ignore the
  //    Entrypoint and Cmd from the docker image as well (row 3-4).
  // 3. If 'shell' is false and 'value' is not set, use the docker
  //    image specified runtime configuration.
  //    i. If 'Entrypoint' is set, it is treated as executable,
  //       then 'Cmd' get appended as arguments.
  //    ii.If 'Entrypoint' is not set, use the first 'Cmd' as
  //       executable and the others as arguments.
  // +---------+--------------+--------------+--------------+--------------+
  // |         | Entrypoint=0 | Entrypoint=0 | Entrypoint=1 | Entrypoint=1 |
  // |         |     Cmd=0    |     Cmd=1    |     Cmd=0    |     Cmd=1    |
  // +---------+--------------+--------------+--------------+--------------+
  // |   sh=0  |     Error    |   ./Cmd[0]   | ./Entrypt[0] | ./Entrypt[0] |
  // | value=0 |              |   Cmd[1]..   | Entrypt[1].. | Entrypt[1].. |
  // |  argv=0 |              |              |              |     Cmd..    |
  // +---------+--------------+--------------+--------------+--------------+
  // |   sh=0  |     Error    |   ./Cmd[0]   | ./Entrypt[0] | ./Entrypt[0] |
  // | value=0 |              |     argv     | Entrypt[1].. | Entrypt[1].. |
  // |  argv=1 |              |              |     argv     |     argv     |
  // +---------+--------------+--------------+--------------+--------------+
  // |   sh=0  |    ./value   |    ./value   |    ./value   |    ./value   |
  // | value=1 |              |              |              |              |
  // |  argv=0 |              |              |              |              |
  // +---------+--------------+--------------+--------------+--------------+
  // |   sh=0  |    ./value   |    ./value   |    ./value   |    ./value   |
  // | value=1 |     argv     |     argv     |     argv     |     argv     |
  // |  argv=1 |              |              |              |              |
  // +---------+--------------+--------------+--------------+--------------+
  // |   sh=1  |     Error    |     Error    |     Error    |     Error    |
  // | value=0 |              |              |              |              |
  // |  argv=0 |              |              |              |              |
  // +---------+--------------+--------------+--------------+--------------+
  // |   sh=1  |     Error    |     Error    |     Error    |     Error    |
  // | value=0 |              |              |              |              |
  // |  argv=1 |              |              |              |              |
  // +---------+--------------+--------------+--------------+--------------+
  // |   sh=1  |  /bin/sh -c  |  /bin/sh -c  |  /bin/sh -c  |  /bin/sh -c  |
  // | value=1 |     value    |     value    |     value    |     value    |
  // |  argv=0 |              |              |              |              |
  // +---------+--------------+--------------+--------------+--------------+
  // |   sh=1  |  /bin/sh -c  |  /bin/sh -c  |  /bin/sh -c  |  /bin/sh -c  |
  // | value=1 |     value    |     value    |     value    |     value    |
  // |  argv=1 |              |              |              |              |
  // +---------+--------------+--------------+--------------+--------------+
  if (command.shell()) {
    if (!command.has_value()) {
      return Error("Shell specified but no command value provided");
    }

    // No need to mutate command (row 7-8).
    return None();
  }

  if (command.has_value()) {
    // No need to mutate command (row 3-4).
    return None();
  }

  // TODO(gilbert): Deprecate 'override' flag option in command task.
  // We do not exclude override case here.

  // We keep the arguments of commandInfo while it does not have a
  // value, so that arguments can be specified by user, which is
  // running with default image Entrypoint.
  const docker::spec::v1::ImageManifest::Config& config =
    containerConfig.docker().manifest().config();

  // Filter out executable for commandInfo value.
  if (config.entrypoint_size() > 0) {
    command.set_value(config.entrypoint(0));

    // Put user defined argv after default entrypoint argv
    // in sequence.
    command.clear_arguments();

    for (int i = 1; i < config.entrypoint_size(); i++) {
      command.add_arguments(config.entrypoint(i));
    }

    // Append all possible user argv after entrypoint arguments.
    if (!containerConfig.has_task_info()) {
      // Custom executor case.
      command.mutable_arguments()->MergeFrom(
          containerConfig.executor_info().command().arguments());
    } else {
      // Command task case.
      command.mutable_arguments()->MergeFrom(
          containerConfig.task_info().command().arguments());
    }

    // Overwrite default cmd arguments if CommandInfo arguments are
    // set by user. The logic below is the case that no argument is
    // set by user.
    if (command.arguments_size() == config.entrypoint_size() - 1) {
      foreach (const string& cmd, config.cmd()) {
        command.add_arguments(cmd);
      }
    }
  } else if (config.cmd_size() > 0) {
    command.set_value(config.cmd(0));

    // Overwrite default cmd arguments if CommandInfo arguments
    // are set by user.
    if (command.arguments_size() == 0) {
      for (int i = 1; i < config.cmd_size(); i++) {
        command.add_arguments(config.cmd(i));
      }
    }
  } else {
    return Error("No executable is found");
  }

  return command;
}

Option<string> DockerRuntimeIsolatorProcess::getWorkingDirectory(
    const ContainerConfig& containerConfig)
{
  CHECK(containerConfig.docker().manifest().has_config());

  if (!containerConfig.docker().manifest().config().has_workingdir()) {
    return None();
  }

  return containerConfig.docker().manifest().config().workingdir();
}

Future<Nothing> DockerRuntimeIsolatorProcess::isolate(
    const ContainerID& containerId,
    pid_t pid)
{
  return Nothing();
}

Future<ContainerLimitation> DockerRuntimeIsolatorProcess::watch(
    const ContainerID& containerId)
{
  return Future<ContainerLimitation>();
}

Future<Nothing> DockerRuntimeIsolatorProcess::update(
    const ContainerID& containerId,
    const Resources& resources)
{
  return Nothing();
}

Future<ResourceStatistics> DockerRuntimeIsolatorProcess::usage(
    const ContainerID& containerId)
{
  return ResourceStatistics();
}

Future<Nothing> DockerRuntimeIsolatorProcess::cleanup(
    const ContainerID& containerId)
{
  return Nothing();
}

} // namespace slave {
} // namespace internal {
} // namespace mesos {
<commit_msg>Fixed adding executable as first argv in runtime isolator.<commit_after>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <list>
#include <string>

#include <glog/logging.h>

#include <stout/error.hpp>
#include <stout/foreach.hpp>
#include <stout/stringify.hpp>
#include <stout/strings.hpp>

#include <mesos/docker/v1.hpp>

#include "slave/flags.hpp"

#include "slave/containerizer/mesos/isolators/docker/runtime.hpp"

using std::list;
using std::string;

using process::Failure;
using process::Future;
using process::Owned;
using process::PID;

using mesos::slave::ContainerConfig;
using mesos::slave::ContainerLaunchInfo;
using mesos::slave::ContainerLimitation;
using mesos::slave::ContainerState;
using mesos::slave::Isolator;

namespace mesos {
namespace internal {
namespace slave {

DockerRuntimeIsolatorProcess::DockerRuntimeIsolatorProcess(
    const Flags& _flags)
  : flags(_flags) {}

DockerRuntimeIsolatorProcess::~DockerRuntimeIsolatorProcess() {}

Try<Isolator*> DockerRuntimeIsolatorProcess::create(const Flags& flags)
{
  process::Owned<MesosIsolatorProcess> process(
      new DockerRuntimeIsolatorProcess(flags));

  return new MesosIsolator(process);
}

Future<Nothing> DockerRuntimeIsolatorProcess::recover(
    const list<ContainerState>& states,
    const hashset<ContainerID>& orphans)
{
  return Nothing();
}

Future<Option<ContainerLaunchInfo>> DockerRuntimeIsolatorProcess::prepare(
    const ContainerID& containerId,
    const ContainerConfig& containerConfig)
{
  const ExecutorInfo& executorInfo = containerConfig.executor_info();

  if (!executorInfo.has_container()) {
    return None();
  }

  if (executorInfo.container().type() != ContainerInfo::MESOS) {
    return Failure("Can only prepare docker runtime for a MESOS container");
  }

  if (!containerConfig.has_docker()) {
    // No docker image default config available.
    return None();
  }

  Option<Environment> environment =
    getLaunchEnvironment(containerId, containerConfig);

  Option<string> workingDirectory =
    getWorkingDirectory(containerConfig);

  Result<CommandInfo> command =
    getExecutorLaunchCommand(containerId, containerConfig);

  if (command.isError()) {
    return Failure("Failed to determine the executor launch command: " +
                   command.error());
  }

  // Set 'launchInfo'.
  ContainerLaunchInfo launchInfo;

  if (environment.isSome()) {
    launchInfo.mutable_environment()->CopyFrom(environment.get());
  }

  // If working directory or command exists, operation has to be
  // distinguished for either custom executor or command task. For
  // custom executor case, info will be included in 'launchInfo', and
  // will be passed back to containerizer. For command task case, info
  // will be passed to command executor as flags.
  if (!containerConfig.has_task_info()) {
    // Custom executor case.
    if (workingDirectory.isSome()) {
      launchInfo.set_working_directory(workingDirectory.get());
    }

    if (command.isSome()) {
      launchInfo.mutable_command()->CopyFrom(command.get());
    }
  } else {
    // Command task case. The 'executorCommand' below is the
    // command with value as 'mesos-executor'.
    CommandInfo executorCommand = containerConfig.executor_info().command();

    // Pass working directory to command executor as a flag.
    if (workingDirectory.isSome()) {
      executorCommand.add_arguments(
          "--working_directory=" + workingDirectory.get());
    }

    // Pass task command as a flag, which will be loaded by
    // command executor.
    if (command.isSome()) {
      executorCommand.add_arguments(
          "--task_command=" +
          stringify(JSON::protobuf(command.get())));
    }

    launchInfo.mutable_command()->CopyFrom(executorCommand);
  }

  return launchInfo;
}

Option<Environment> DockerRuntimeIsolatorProcess::getLaunchEnvironment(
    const ContainerID& containerId,
    const ContainerConfig& containerConfig)
{
  CHECK(containerConfig.docker().manifest().has_config());

  if (containerConfig.docker().manifest().config().env_size() == 0) {
    return None();
  }

  Environment environment;

  foreach(const string& env,
          containerConfig.docker().manifest().config().env()) {
    // Use `find_first_of` to prevent to case that there are
    // multiple '=' existing.
    size_t position = env.find_first_of('=');
    if (position == string::npos) {
      VLOG(1) << "Skipping invalid environment variable: '"
              << env << "' in docker manifest for container "
              << containerId;

      continue;
    }

    const string name = env.substr(0, position);
    const string value = env.substr(position + 1);

    // Keep all environment from runtime isolator. If there exists
    // environment variable duplicate cases, it will be overwritten
    // in mesos containerizer.
    Environment::Variable* variable = environment.add_variables();
    variable->set_name(name);
    variable->set_value(value);
  }

  return environment;
}

// This method reads the CommandInfo form ExecutorInfo and optional
// TaskInfo, and merge them with docker image default Entrypoint and
// Cmd. It returns a merged CommandInfo which will be used to launch
// the executor. If no need to modify the command, this method will
// return none.
Result<CommandInfo> DockerRuntimeIsolatorProcess::getExecutorLaunchCommand(
    const ContainerID& containerId,
    const ContainerConfig& containerConfig)
{
  CHECK(containerConfig.docker().manifest().has_config());

  // We may or may not mutate the CommandInfo for executor depending
  // on the logic table below. For custom executor case, we make
  // changes to the command directly. For command task case, if no
  // need to change the launch command for the user task, we do not do
  // anything and return the CommandInfo from ExecutorInfo. We only
  // add a flag `--task_command` to carry command as a JSON object if
  // it is neccessary to mutate.
  CommandInfo command;

  if (!containerConfig.has_task_info()) {
    // Custom executor case.
    CHECK(containerConfig.executor_info().has_command());
    command = containerConfig.executor_info().command();
  } else {
    // Command task case.
    CHECK(containerConfig.task_info().has_command());
    command = containerConfig.task_info().command();
  }

  // We merge the CommandInfo following the logic:
  // 1. If 'shell' is true, we will ignore Entrypoint and Cmd from
  //    the docker image (row 5-8).
  // 2. If 'shell' is false and 'value' is set, we will ignore the
  //    Entrypoint and Cmd from the docker image as well (row 3-4).
  // 3. If 'shell' is false and 'value' is not set, use the docker
  //    image specified runtime configuration.
  //    i. If 'Entrypoint' is set, it is treated as executable,
  //       then 'Cmd' get appended as arguments.
  //    ii.If 'Entrypoint' is not set, use the first 'Cmd' as
  //       executable and the others as arguments.
  // +---------+--------------+--------------+--------------+--------------+
  // |         | Entrypoint=0 | Entrypoint=0 | Entrypoint=1 | Entrypoint=1 |
  // |         |     Cmd=0    |     Cmd=1    |     Cmd=0    |     Cmd=1    |
  // +---------+--------------+--------------+--------------+--------------+
  // |   sh=0  |     Error    |   ./Cmd[0]   | ./Entrypt[0] | ./Entrypt[0] |
  // | value=0 |              |   Cmd[1]..   | Entrypt[1].. | Entrypt[1].. |
  // |  argv=0 |              |              |              |     Cmd..    |
  // +---------+--------------+--------------+--------------+--------------+
  // |   sh=0  |     Error    |   ./Cmd[0]   | ./Entrypt[0] | ./Entrypt[0] |
  // | value=0 |              |     argv     | Entrypt[1].. | Entrypt[1].. |
  // |  argv=1 |              |              |     argv     |     argv     |
  // +---------+--------------+--------------+--------------+--------------+
  // |   sh=0  |    ./value   |    ./value   |    ./value   |    ./value   |
  // | value=1 |              |              |              |              |
  // |  argv=0 |              |              |              |              |
  // +---------+--------------+--------------+--------------+--------------+
  // |   sh=0  |    ./value   |    ./value   |    ./value   |    ./value   |
  // | value=1 |     argv     |     argv     |     argv     |     argv     |
  // |  argv=1 |              |              |              |              |
  // +---------+--------------+--------------+--------------+--------------+
  // |   sh=1  |     Error    |     Error    |     Error    |     Error    |
  // | value=0 |              |              |              |              |
  // |  argv=0 |              |              |              |              |
  // +---------+--------------+--------------+--------------+--------------+
  // |   sh=1  |     Error    |     Error    |     Error    |     Error    |
  // | value=0 |              |              |              |              |
  // |  argv=1 |              |              |              |              |
  // +---------+--------------+--------------+--------------+--------------+
  // |   sh=1  |  /bin/sh -c  |  /bin/sh -c  |  /bin/sh -c  |  /bin/sh -c  |
  // | value=1 |     value    |     value    |     value    |     value    |
  // |  argv=0 |              |              |              |              |
  // +---------+--------------+--------------+--------------+--------------+
  // |   sh=1  |  /bin/sh -c  |  /bin/sh -c  |  /bin/sh -c  |  /bin/sh -c  |
  // | value=1 |     value    |     value    |     value    |     value    |
  // |  argv=1 |              |              |              |              |
  // +---------+--------------+--------------+--------------+--------------+
  if (command.shell()) {
    if (!command.has_value()) {
      return Error("Shell specified but no command value provided");
    }

    // No need to mutate command (row 7-8).
    return None();
  }

  if (command.has_value()) {
    // No need to mutate command (row 3-4).
    return None();
  }

  // TODO(gilbert): Deprecate 'override' flag option in command task.
  // We do not exclude override case here.

  // We keep the arguments of commandInfo while it does not have a
  // value, so that arguments can be specified by user, which is
  // running with default image Entrypoint.
  const docker::spec::v1::ImageManifest::Config& config =
    containerConfig.docker().manifest().config();

  // Filter out executable for commandInfo value.
  if (config.entrypoint_size() > 0) {
    command.set_value(config.entrypoint(0));

    // Put user defined argv after default entrypoint argv
    // in sequence.
    command.clear_arguments();
    command.add_arguments(config.entrypoint(0));

    for (int i = 1; i < config.entrypoint_size(); i++) {
      command.add_arguments(config.entrypoint(i));
    }

    // Append all possible user argv after entrypoint arguments.
    if (!containerConfig.has_task_info()) {
      // Custom executor case.
      command.mutable_arguments()->MergeFrom(
          containerConfig.executor_info().command().arguments());
    } else {
      // Command task case.
      command.mutable_arguments()->MergeFrom(
          containerConfig.task_info().command().arguments());
    }

    // Overwrite default cmd arguments if CommandInfo arguments are
    // set by user. The logic below is the case that no argument is
    // set by user.
    if (command.arguments_size() == config.entrypoint_size()) {
      foreach (const string& cmd, config.cmd()) {
        command.add_arguments(cmd);
      }
    }
  } else if (config.cmd_size() > 0) {
    command.set_value(config.cmd(0));
    command.add_arguments(config.cmd(0));

    // Overwrite default cmd arguments if CommandInfo arguments
    // are set by user.
    if (command.arguments_size() == 1) {
      for (int i = 1; i < config.cmd_size(); i++) {
        command.add_arguments(config.cmd(i));
      }
    }
  } else {
    return Error("No executable is found");
  }

  return command;
}

Option<string> DockerRuntimeIsolatorProcess::getWorkingDirectory(
    const ContainerConfig& containerConfig)
{
  CHECK(containerConfig.docker().manifest().has_config());

  if (!containerConfig.docker().manifest().config().has_workingdir()) {
    return None();
  }

  return containerConfig.docker().manifest().config().workingdir();
}

Future<Nothing> DockerRuntimeIsolatorProcess::isolate(
    const ContainerID& containerId,
    pid_t pid)
{
  return Nothing();
}

Future<ContainerLimitation> DockerRuntimeIsolatorProcess::watch(
    const ContainerID& containerId)
{
  return Future<ContainerLimitation>();
}

Future<Nothing> DockerRuntimeIsolatorProcess::update(
    const ContainerID& containerId,
    const Resources& resources)
{
  return Nothing();
}

Future<ResourceStatistics> DockerRuntimeIsolatorProcess::usage(
    const ContainerID& containerId)
{
  return ResourceStatistics();
}

Future<Nothing> DockerRuntimeIsolatorProcess::cleanup(
    const ContainerID& containerId)
{
  return Nothing();
}

} // namespace slave {
} // namespace internal {
} // namespace mesos {
<|endoftext|>


<commit_before>// Copyright 2020 The Pigweed Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.

#include "pw_kvs_private/format.h"

#include "pw_kvs_private/macros.h"

namespace pw::kvs {

using std::byte;
using std::string_view;

EntryHeader::EntryHeader(uint32_t magic,
                         ChecksumAlgorithm* algorithm,
                         string_view key,
                         span<const byte> value,
                         uint32_t key_version)
    : magic_(magic),
      checksum_(kNoChecksum),
      key_value_length_(value.size() << kValueLengthShift |
                        (key.size() & kKeyLengthMask)),
      key_version_(key_version) {
  if (algorithm != nullptr) {
    CalculateChecksum(algorithm, key, value);
    std::memcpy(&checksum_,
                algorithm->state().data(),
                std::min(algorithm->size_bytes(), sizeof(checksum_)));
  }
}

Status EntryHeader::VerifyChecksum(ChecksumAlgorithm* algorithm,
                                   string_view key,
                                   span<const byte> value) const {
  if (algorithm == nullptr) {
    return checksum() == kNoChecksum ? Status::OK : Status::DATA_LOSS;
  }
  CalculateChecksum(algorithm, key, value);
  return algorithm->Verify(checksum_bytes());
}

Status EntryHeader::VerifyChecksumInFlash(FlashPartition* partition,
                                          FlashPartition::Address address,
                                          ChecksumAlgorithm* algorithm) const {
  if (algorithm == nullptr) {
    return checksum() == kNoChecksum ? Status::OK : Status::DATA_LOSS;
  }

  algorithm->Reset();

  // Read the entire entry piece-by-piece into a small buffer.
  // TODO: This read may be unaligned. The partition can handle this, but
  // consider creating a API that skips the intermediate buffering.
  byte buffer[32];

  address += checked_data_offset();
  size_t bytes_to_read = size() - checked_data_offset();

  while (bytes_to_read > 0u) {
    const size_t read_size = std::min(sizeof(buffer), bytes_to_read);

    TRY(partition->Read(address, read_size, buffer));
    algorithm->Update(buffer, read_size);

    address += read_size;
    bytes_to_read -= read_size;
  }

  return algorithm->Verify(checksum_bytes());
}

void EntryHeader::CalculateChecksum(ChecksumAlgorithm* algorithm,
                                    const string_view key,
                                    span<const byte> value) const {
  algorithm->Reset();
  algorithm->Update(reinterpret_cast<const byte*>(this) + checked_data_offset(),
                    sizeof(*this) - checked_data_offset());
  algorithm->Update(as_bytes(span(key)));
  algorithm->Update(value);
}

}  // namespace pw::kvs
<commit_msg>pw_kvs: Verify magic and checksum in flash<commit_after>// Copyright 2020 The Pigweed Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.

#include "pw_kvs_private/format.h"

#include "pw_kvs_private/macros.h"
#include "pw_log/log.h"

namespace pw::kvs {

using std::byte;
using std::string_view;

EntryHeader::EntryHeader(uint32_t magic,
                         ChecksumAlgorithm* algorithm,
                         string_view key,
                         span<const byte> value,
                         uint32_t key_version)
    : magic_(magic),
      checksum_(kNoChecksum),
      key_value_length_(value.size() << kValueLengthShift |
                        (key.size() & kKeyLengthMask)),
      key_version_(key_version) {
  if (algorithm != nullptr) {
    CalculateChecksum(algorithm, key, value);
    std::memcpy(&checksum_,
                algorithm->state().data(),
                std::min(algorithm->size_bytes(), sizeof(checksum_)));
  }
}

Status EntryHeader::VerifyChecksum(ChecksumAlgorithm* algorithm,
                                   string_view key,
                                   span<const byte> value) const {
  if (algorithm == nullptr) {
    return checksum() == kNoChecksum ? Status::OK : Status::DATA_LOSS;
  }
  CalculateChecksum(algorithm, key, value);
  return algorithm->Verify(checksum_bytes());
}

Status EntryHeader::VerifyChecksumInFlash(FlashPartition* partition,
                                          FlashPartition::Address address,
                                          ChecksumAlgorithm* algorithm) const {
  if (algorithm == nullptr) {
    return checksum() == kNoChecksum ? Status::OK : Status::DATA_LOSS;
  }

  algorithm->Reset();

  // Read the entire entry piece-by-piece into a small buffer.
  // TODO: This read may be unaligned. The partition can handle this, but
  // consider creating a API that skips the intermediate buffering.
  byte buffer[32];

  // Read and compare the magic and checksum.
  TRY(partition->Read(address, checked_data_offset(), buffer));
  if (std::memcmp(this, buffer, checked_data_offset()) != 0) {
    static_assert(sizeof(unsigned) >= sizeof(uint32_t));
    unsigned actual_magic;
    std::memcpy(&actual_magic, &buffer[0], sizeof(uint32_t));
    unsigned actual_checksum;
    std::memcpy(&actual_checksum, &buffer[4], sizeof(uint32_t));

    PW_LOG_ERROR(
        "Expected: magic=%08x, checksum=%08x; "
        "Actual: magic=%08x, checksum=%08x",
        unsigned(magic()),
        unsigned(checksum()),
        actual_magic,
        actual_checksum);

    return Status::DATA_LOSS;
  }

  // Read and calculate the checksum of the remaining header, key, and value.
  address += checked_data_offset();
  size_t bytes_to_read = size() - checked_data_offset();

  while (bytes_to_read > 0u) {
    const size_t read_size = std::min(sizeof(buffer), bytes_to_read);

    TRY(partition->Read(address, read_size, buffer));
    algorithm->Update(buffer, read_size);

    address += read_size;
    bytes_to_read -= read_size;
  }

  return algorithm->Verify(checksum_bytes());
}

void EntryHeader::CalculateChecksum(ChecksumAlgorithm* algorithm,
                                    const string_view key,
                                    span<const byte> value) const {
  algorithm->Reset();
  algorithm->Update(reinterpret_cast<const byte*>(this) + checked_data_offset(),
                    sizeof(*this) - checked_data_offset());
  algorithm->Update(as_bytes(span(key)));
  algorithm->Update(value);
}

}  // namespace pw::kvs
<|endoftext|>


<commit_before>/*
 * #%L
 * %%
 * Copyright (C) 2011 - 2017 BMW Car IT GmbH
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */
#include "MqttMessagingSkeleton.h"

#include "MqttReceiver.h"
#include "joynr/DispatcherUtils.h"
#include "joynr/exceptions/JoynrException.h"
#include "joynr/JoynrMessage.h"
#include "joynr/IMessageRouter.h"
#include "joynr/serializer/Serializer.h"
#include "joynr/system/RoutingTypes/MqttAddress.h"
#include "joynr/Util.h"

namespace joynr
{

INIT_LOGGER(MqttMessagingSkeleton);

const std::string MqttMessagingSkeleton::MQTT_MULTI_LEVEL_WILDCARD("#");

std::string MqttMessagingSkeleton::translateMulticastWildcard(std::string topic)
{
    if (topic.length() > 0 && topic.back() == util::MULTI_LEVEL_WILDCARD[0]) {
        topic.back() = MQTT_MULTI_LEVEL_WILDCARD[0];
    }
    return topic;
}

MqttMessagingSkeleton::MqttMessagingSkeleton(IMessageRouter& messageRouter,
                                             std::shared_ptr<MqttReceiver> mqttReceiver,
                                             const std::string& multicastTopicPrefix,
                                             uint64_t ttlUplift)
        : messageRouter(messageRouter),
          mqttReceiver(mqttReceiver),
          ttlUplift(ttlUplift),
          multicastSubscriptionCount(),
          multicastSubscriptionCountMutex(),
          multicastTopicPrefix(multicastTopicPrefix)
{
}

void MqttMessagingSkeleton::registerMulticastSubscription(const std::string& multicastId)
{
    std::string mqttTopic = translateMulticastWildcard(multicastId);
    std::lock_guard<std::mutex> lock(multicastSubscriptionCountMutex);
    if (multicastSubscriptionCount.find(mqttTopic) == multicastSubscriptionCount.cend()) {
        mqttReceiver->subscribeToTopic(multicastTopicPrefix + mqttTopic);
        multicastSubscriptionCount[mqttTopic] = 1;
    } else {
        multicastSubscriptionCount[mqttTopic]++;
    }
}

void MqttMessagingSkeleton::unregisterMulticastSubscription(const std::string& multicastId)
{
    std::string mqttTopic = translateMulticastWildcard(multicastId);
    std::lock_guard<std::mutex> lock(multicastSubscriptionCountMutex);
    auto countIterator = multicastSubscriptionCount.find(mqttTopic);
    if (countIterator == multicastSubscriptionCount.cend()) {
        JOYNR_LOG_ERROR(
                logger, "unregister multicast subscription called for non existing subscription");
    } else if (countIterator->second == 1) {
        multicastSubscriptionCount.erase(mqttTopic);
        mqttReceiver->unsubscribeFromTopic(multicastTopicPrefix + mqttTopic);
    } else {
        countIterator->second--;
    }
}

void MqttMessagingSkeleton::transmit(
        JoynrMessage& message,
        const std::function<void(const exceptions::JoynrRuntimeException&)>& onFailure)
{
    if (message.getType() == JoynrMessage::VALUE_MESSAGE_TYPE_REQUEST ||
        message.getType() == JoynrMessage::VALUE_MESSAGE_TYPE_SUBSCRIPTION_REQUEST ||
        message.getType() == JoynrMessage::VALUE_MESSAGE_TYPE_BROADCAST_SUBSCRIPTION_REQUEST ||
        message.getType() == JoynrMessage::VALUE_MESSAGE_TYPE_MULTICAST_SUBSCRIPTION_REQUEST) {
        std::string serializedReplyAddress = message.getHeaderReplyAddress();

        try {
            using system::RoutingTypes::MqttAddress;
            MqttAddress address;
            joynr::serializer::deserializeFromJson(address, serializedReplyAddress);
            messageRouter.addNextHop(
                    message.getHeaderFrom(), std::make_shared<const MqttAddress>(address));
        } catch (const std::invalid_argument& e) {
            JOYNR_LOG_FATAL(logger,
                            "could not deserialize MqttAddress from {} - error: {}",
                            serializedReplyAddress,
                            e.what());
            // do not try to route the message if address is not valid
            return;
        }
    } else if (message.getType() == JoynrMessage::VALUE_MESSAGE_TYPE_MULTICAST) {
        message.setReceivedFromGlobal(true);
    }

    try {
        messageRouter.route(message);
    } catch (const exceptions::JoynrRuntimeException& e) {
        onFailure(e);
    }
}

void MqttMessagingSkeleton::onTextMessageReceived(const std::string& message)
{
    JoynrMessage msg;
    try {
        joynr::serializer::deserializeFromJson(msg, message);
    } catch (const std::invalid_argument& e) {
        JOYNR_LOG_ERROR(logger,
                        "Unable to deserialize message. Raw message: {} - error: {}",
                        message,
                        e.what());
    }

    if (msg.getType().empty()) {
        JOYNR_LOG_ERROR(logger, "received empty message - dropping Messages");
        return;
    }
    if (msg.getPayload().empty()) {
        JOYNR_LOG_ERROR(logger, "joynr message payload is empty: {}", message);
        return;
    }
    if (!msg.containsHeaderExpiryDate()) {
        JOYNR_LOG_ERROR(logger,
                        "received message [msgId=[{}] without decay time - dropping message",
                        msg.getHeaderMessageId());
        return;
    }
    JOYNR_LOG_DEBUG(logger, "<<< INCOMING <<< {}", msg.toLogMessage());

    const JoynrTimePoint maxAbsoluteTime = DispatcherUtils::getMaxAbsoluteTime();
    JoynrTimePoint msgExpiryDate = msg.getHeaderExpiryDate();
    std::int64_t maxDiff = std::chrono::duration_cast<std::chrono::milliseconds>(
                                   maxAbsoluteTime - msgExpiryDate).count();
    if (static_cast<std::int64_t>(ttlUplift) > maxDiff) {
        msg.setHeaderExpiryDate(maxAbsoluteTime);
    } else {
        JoynrTimePoint newExpiryDate = msgExpiryDate + std::chrono::milliseconds(ttlUplift);
        msg.setHeaderExpiryDate(newExpiryDate);
    }

    auto onFailure = [msg](const exceptions::JoynrRuntimeException& e) {
        JOYNR_LOG_ERROR(logger,
                        "Incoming Message with ID {} could not be sent! reason: {}",
                        msg.getHeaderMessageId(),
                        e.getMessage());
    };

    transmit(msg, onFailure);
}

} // namespace joynr
<commit_msg>[C++] early return after deserialization error in MqttMessagingSkeleton<commit_after>/*
 * #%L
 * %%
 * Copyright (C) 2011 - 2017 BMW Car IT GmbH
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */
#include "MqttMessagingSkeleton.h"

#include "MqttReceiver.h"
#include "joynr/DispatcherUtils.h"
#include "joynr/exceptions/JoynrException.h"
#include "joynr/JoynrMessage.h"
#include "joynr/IMessageRouter.h"
#include "joynr/serializer/Serializer.h"
#include "joynr/system/RoutingTypes/MqttAddress.h"
#include "joynr/Util.h"

namespace joynr
{

INIT_LOGGER(MqttMessagingSkeleton);

const std::string MqttMessagingSkeleton::MQTT_MULTI_LEVEL_WILDCARD("#");

std::string MqttMessagingSkeleton::translateMulticastWildcard(std::string topic)
{
    if (topic.length() > 0 && topic.back() == util::MULTI_LEVEL_WILDCARD[0]) {
        topic.back() = MQTT_MULTI_LEVEL_WILDCARD[0];
    }
    return topic;
}

MqttMessagingSkeleton::MqttMessagingSkeleton(IMessageRouter& messageRouter,
                                             std::shared_ptr<MqttReceiver> mqttReceiver,
                                             const std::string& multicastTopicPrefix,
                                             uint64_t ttlUplift)
        : messageRouter(messageRouter),
          mqttReceiver(mqttReceiver),
          ttlUplift(ttlUplift),
          multicastSubscriptionCount(),
          multicastSubscriptionCountMutex(),
          multicastTopicPrefix(multicastTopicPrefix)
{
}

void MqttMessagingSkeleton::registerMulticastSubscription(const std::string& multicastId)
{
    std::string mqttTopic = translateMulticastWildcard(multicastId);
    std::lock_guard<std::mutex> lock(multicastSubscriptionCountMutex);
    if (multicastSubscriptionCount.find(mqttTopic) == multicastSubscriptionCount.cend()) {
        mqttReceiver->subscribeToTopic(multicastTopicPrefix + mqttTopic);
        multicastSubscriptionCount[mqttTopic] = 1;
    } else {
        multicastSubscriptionCount[mqttTopic]++;
    }
}

void MqttMessagingSkeleton::unregisterMulticastSubscription(const std::string& multicastId)
{
    std::string mqttTopic = translateMulticastWildcard(multicastId);
    std::lock_guard<std::mutex> lock(multicastSubscriptionCountMutex);
    auto countIterator = multicastSubscriptionCount.find(mqttTopic);
    if (countIterator == multicastSubscriptionCount.cend()) {
        JOYNR_LOG_ERROR(
                logger, "unregister multicast subscription called for non existing subscription");
    } else if (countIterator->second == 1) {
        multicastSubscriptionCount.erase(mqttTopic);
        mqttReceiver->unsubscribeFromTopic(multicastTopicPrefix + mqttTopic);
    } else {
        countIterator->second--;
    }
}

void MqttMessagingSkeleton::transmit(
        JoynrMessage& message,
        const std::function<void(const exceptions::JoynrRuntimeException&)>& onFailure)
{
    if (message.getType() == JoynrMessage::VALUE_MESSAGE_TYPE_REQUEST ||
        message.getType() == JoynrMessage::VALUE_MESSAGE_TYPE_SUBSCRIPTION_REQUEST ||
        message.getType() == JoynrMessage::VALUE_MESSAGE_TYPE_BROADCAST_SUBSCRIPTION_REQUEST ||
        message.getType() == JoynrMessage::VALUE_MESSAGE_TYPE_MULTICAST_SUBSCRIPTION_REQUEST) {
        std::string serializedReplyAddress = message.getHeaderReplyAddress();

        try {
            using system::RoutingTypes::MqttAddress;
            MqttAddress address;
            joynr::serializer::deserializeFromJson(address, serializedReplyAddress);
            messageRouter.addNextHop(
                    message.getHeaderFrom(), std::make_shared<const MqttAddress>(address));
        } catch (const std::invalid_argument& e) {
            JOYNR_LOG_FATAL(logger,
                            "could not deserialize MqttAddress from {} - error: {}",
                            serializedReplyAddress,
                            e.what());
            // do not try to route the message if address is not valid
            return;
        }
    } else if (message.getType() == JoynrMessage::VALUE_MESSAGE_TYPE_MULTICAST) {
        message.setReceivedFromGlobal(true);
    }

    try {
        messageRouter.route(message);
    } catch (const exceptions::JoynrRuntimeException& e) {
        onFailure(e);
    }
}

void MqttMessagingSkeleton::onTextMessageReceived(const std::string& message)
{
    JoynrMessage msg;
    try {
        joynr::serializer::deserializeFromJson(msg, message);
    } catch (const std::invalid_argument& e) {
        JOYNR_LOG_ERROR(logger,
                        "Unable to deserialize message. Raw message: {} - error: {}",
                        message,
                        e.what());
        return;
    }

    if (msg.getType().empty()) {
        JOYNR_LOG_ERROR(logger, "received empty message - dropping Messages");
        return;
    }
    if (msg.getPayload().empty()) {
        JOYNR_LOG_ERROR(logger, "joynr message payload is empty: {}", message);
        return;
    }
    if (!msg.containsHeaderExpiryDate()) {
        JOYNR_LOG_ERROR(logger,
                        "received message [msgId=[{}] without decay time - dropping message",
                        msg.getHeaderMessageId());
        return;
    }
    JOYNR_LOG_DEBUG(logger, "<<< INCOMING <<< {}", msg.toLogMessage());

    const JoynrTimePoint maxAbsoluteTime = DispatcherUtils::getMaxAbsoluteTime();
    JoynrTimePoint msgExpiryDate = msg.getHeaderExpiryDate();
    std::int64_t maxDiff = std::chrono::duration_cast<std::chrono::milliseconds>(
                                   maxAbsoluteTime - msgExpiryDate).count();
    if (static_cast<std::int64_t>(ttlUplift) > maxDiff) {
        msg.setHeaderExpiryDate(maxAbsoluteTime);
    } else {
        JoynrTimePoint newExpiryDate = msgExpiryDate + std::chrono::milliseconds(ttlUplift);
        msg.setHeaderExpiryDate(newExpiryDate);
    }

    auto onFailure = [msg](const exceptions::JoynrRuntimeException& e) {
        JOYNR_LOG_ERROR(logger,
                        "Incoming Message with ID {} could not be sent! reason: {}",
                        msg.getHeaderMessageId(),
                        e.getMessage());
    };

    transmit(msg, onFailure);
}

} // namespace joynr
<|endoftext|>


<commit_before>#include <iostream>
#include <vector>

using namespace std;

class Card
{
private:
    string name_;
    int value_;

public:
    Card(string card)
    {
        name_ = card;
        value_ = stoi(card.substr(1, 1));
    };

    string name(){return name_;};
    int value(){return value_;};
};

void bubbleSort(vector<Card *> &cards);

void shellSort(vector<Card *> &cards);

int main()
{
    int length, count = 0;
    cin >> length;

    vector<Card*> bubble_cards(length);
    vector<Card*> selection_cards(length);

    for (int i = 0; i < length; i++)
    {
        string card;
        cin >> card;
        bubble_cards[i] = new Card(card);
        selection_cards[i] = new Card(card);
    }

    bubbleSort(bubble_cards);
    shellSort(selection_cards);
}

void bubbleSort(vector<Card *> &cards)
{
    for(int i = 0; i < cards.size(); i++)
    {
        for(int j = cards.size() - 1; j > i; j--)
        {
            if(cards[j-1]->value() > cards[j]->value())
            {
                Card* temp = cards[j-1];
                cards[j-1] = cards[j];
                cards[j] = temp;
            }
        }
    }
    cout << cards[0]->name();
    for(int i = 1; i < cards.size(); i++)
    {
        cout << ' ' << cards[i]->name();
    }
    cout << endl << "Stable" << endl;
}

void shellSort(vector<Card *> &cards)
{
    for(int i = 0; i < cards.size(); i++)
    {
        int mini = i;
        for(int j = i; j < cards.size(); j++)
        {
            if (cards[j]->value() < cards[mini]->value())
            {
                mini = j;
            }
        }
        Card* temp;
        temp = cards[mini];
        cards[mini] = cards[i];
        cards[i] = temp;
    }
    cout << cards[0]->name();
    for(int i = 1; i < cards.size(); i++)
    {
        cout << ' ' << cards[i]->name();
    }
    cout << endl << "Stable" << endl;
}
<commit_msg>Refactor stable_sort to produce correct answers.<commit_after>#include <iostream>
#include <vector>

using namespace std;

class Card
{
private:
    string name_;
    int value_;

public:
    Card(string card)
    {
        name_ = card;
        value_ = stoi(card.substr(1, 1));
    };

    string name(){return name_;};
    int value(){return value_;};
};

void bubbleSort(vector<Card *> &cards);

void shellSort(vector<Card *> &cards);

int main()
{
    int length, count = 0;
    cin >> length;

    vector<Card*> bubble_cards(length);
    vector<Card*> selection_cards(length);

    for (int i = 0; i < length; i++)
    {
        string card;
        cin >> card;
        bubble_cards[i] = new Card(card);
        selection_cards[i] = new Card(card);
    }

    bubbleSort(bubble_cards);
    shellSort(selection_cards);
    for (int i = 0; i< bubble_cards.size(); i++)
    {
        if(bubble_cards[i]->name() != selection_cards[i]->name())
        {
            cout << "Not stable" << endl;
            return 0;
        }
    }
    cout << "Stable" << endl;
}

void bubbleSort(vector<Card *> &cards)
{
    for(int i = 0; i < cards.size(); i++)
    {
        for(int j = cards.size() - 1; j > i; j--)
        {
            if(cards[j-1]->value() > cards[j]->value())
            {
                Card* temp = cards[j-1];
                cards[j-1] = cards[j];
                cards[j] = temp;
            }
        }
    }
    cout << cards[0]->name();
    for(int i = 1; i < cards.size(); i++)
    {
        cout << ' ' << cards[i]->name();
    }
    cout << endl << "Stable" << endl;
}

void shellSort(vector<Card *> &cards)
{
    for(int i = 0; i < cards.size(); i++)
    {
        int mini = i;
        for(int j = i; j < cards.size(); j++)
        {
            if (cards[j]->value() < cards[mini]->value())
            {
                mini = j;
            }
        }
        Card* temp;
        temp = cards[mini];
        cards[mini] = cards[i];
        cards[i] = temp;
    }
    cout << cards[0]->name();
    for(int i = 1; i < cards.size(); i++)
    {
        cout << ' ' << cards[i]->name();
    }
    cout << endl;
}
<|endoftext|>