<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.
 */

// Reusable matchers for unit testing. Useful for matching against protocol
// buffers without having to manually set up and call message differencers.
//   * EqualsProto(msg) -> matches against a message type
//   * EqualsProto(s) -> matches against a message specified by text proto
//
// The default match does precise equality comparison, but there are also
// decorator functions provided which can be used to modify the comparison logic
// that the EqualsProto matcher provides. They can be used by passing the result
// of EqualsProto into the matcher functions. For example if you use
// IgnoringRepeatedFieldOrdering(EqualsProto(s)) you will get matcher that
// matches against the text proto s, but treating repeated fields as sets
// instead of as lists.
//
// The decorator functions currently provided are:
//   * IgnoringRepeatedFieldOrdering -> treat repeated fields as sets
//
// The matching is based on what is provided by MessageDifferencer and so if new
// modifiers are needed they can be added with more decorators in the future.

#ifndef ECCLESIA_LIB_TESTING_PROTO_H_
#define ECCLESIA_LIB_TESTING_PROTO_H_

#include <iterator>
#include <memory>
#include <ostream>
#include <string>
#include <vector>

#include "google/protobuf/io/tokenizer.h"
#include "google/protobuf/message.h"
#include "google/protobuf/text_format.h"
#include "google/protobuf/util/message_differencer.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/memory/memory.h"
#include "absl/strings/str_format.h"
#include "absl/strings/str_join.h"
#include "absl/strings/string_view.h"

namespace ecclesia {
namespace internal_proto {

// Base implementation of a matcher for comparing a value against a protobuf
// message. This provide the comparison logic, but leaves the logic for
// constructing the actual protobuf value to be compared against as well as
// printing the expected value to the subclass. This allows for matchers that
// store different underlying data (e.g. strings vs actual messages).
class ProtoMatcherBase {
 public:
  virtual ~ProtoMatcherBase() = default;

  bool MatchAndExplain(const ::google::protobuf::Message &arg,
                       ::testing::MatchResultListener *listener) const {
    if (!arg.IsInitialized()) {
      *listener << "which isn't fully initialized";
      return false;
    }

    ExpectedProtoPtr expected = CreateExpectedProto(arg, listener);
    if (expected == nullptr) return false;

    // Protobufs of different types cannot be compared. So first we check if
    // they are comparable, then we compare them.
    const bool comparable = arg.GetDescriptor() == expected->GetDescriptor();
    auto differencer = MakeDifferencer();
    const bool match = comparable && differencer->Compare(arg, *expected);

    // Explaining the match result is expensive.  We don't want to waste time
    // calculating an explanation if the listener isn't interested.
    if (listener->IsInterested()) {
      if (!comparable) {
        *listener << DescribeTypeMismatch(*expected, arg);
      } else if (!match) {
        *listener << DescribeDiff(*expected, arg);
      }
    }
    return match;
  }

  void DescribeTo(std::ostream *os) const {
    *os << "is fully initialized and ";
    DescribeRelationToExpectedProto(os);
  }

  void DescribeNegationTo(std::ostream *os) const {
    *os << "is not fully initialized or not ";
    DescribeRelationToExpectedProto(os);
  }

  // Mutators which can modify the proto field comparison properties. These
  // functions should not be utilized directly by users of the matchers. Instead
  // use the matcher functions defined in the public namespace.
  void SetIgnoreRepeatedFieldOrdering() {
    repeated_field_comparison_ = ::google::protobuf::util::MessageDifferencer::AS_SET;
  }

 protected:
  // A unique pointer type used by the CreateExpectedProto function. Instead of
  // the default deleter it requires the creators to construct a custom delete
  // function. This allows different subclasses to customize the delete policy
  // for example by having deletion be a no-op if the returned object is reused
  // across calls.
  using ExpectedProtoPtr = std::unique_ptr<const ::google::protobuf::Message,<commit_msg>Internal Change.<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.
 */

// Reusable matchers for unit testing. Useful for matching against protocol
// buffers without having to manually set up and call message differencers.
//   * EqualsProto(msg) -> matches against a message type
//   * EqualsProto(s) -> matches against a message specified by text proto
//
// The default match does precise equality comparison, but there are also
// decorator functions provided which can be used to modify the comparison logic
// that the EqualsProto matcher provides. They can be used by passing the result
// of EqualsProto into the matcher functions. For example if you use
// IgnoringRepeatedFieldOrdering(EqualsProto(s)) you will get matcher that
// matches against the text proto s, but treating repeated fields as sets
// instead of as lists.
//
// The decorator functions currently provided are:
//   * IgnoringRepeatedFieldOrdering -> treat repeated fields as sets
//
// The matching is based on what is provided by MessageDifferencer and so if new
// modifiers are needed they can be added with more decorators in the future.

#ifndef ECCLESIA_LIB_TESTING_PROTO_H_
#define ECCLESIA_LIB_TESTING_PROTO_H_

#include <iterator>
#include <memory>
#include <ostream>
#include <string>
#include <type_traits>
#include <vector>

#include "google/protobuf/io/tokenizer.h"
#include "google/protobuf/message.h"
#include "google/protobuf/text_format.h"
#include "google/protobuf/util/message_differencer.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/memory/memory.h"
#include "absl/strings/str_format.h"
#include "absl/strings/str_join.h"
#include "absl/strings/string_view.h"

namespace ecclesia {
namespace internal_proto {

// Base implementation of a matcher for comparing a value against a protobuf
// message. This provide the comparison logic, but leaves the logic for
// constructing the actual protobuf value to be compared against as well as
// printing the expected value to the subclass. This allows for matchers that
// store different underlying data (e.g. strings vs actual messages).
class ProtoMatcherBase {
 public:
  virtual ~ProtoMatcherBase() = default;

  // Base matcher, that matches against any protobuf message type.
  bool MatchAndExplain(const ::google::protobuf::Message &arg,
                       ::testing::MatchResultListener *listener) const {
    if (!arg.IsInitialized()) {
      *listener << "which isn't fully initialized";
      return false;
    }

    ExpectedProtoPtr expected = CreateExpectedProto(arg, listener);
    if (expected == nullptr) return false;

    // Protobufs of different types cannot be compared. So first we check if
    // they are comparable, then we compare them.
    const bool comparable = arg.GetDescriptor() == expected->GetDescriptor();
    auto differencer = MakeDifferencer();
    const bool match = comparable && differencer->Compare(arg, *expected);

    // Explaining the match result is expensive.  We don't want to waste time
    // calculating an explanation if the listener isn't interested.
    if (listener->IsInterested()) {
      if (!comparable) {
        *listener << DescribeTypeMismatch(*expected, arg);
      } else if (!match) {
        *listener << DescribeDiff(*expected, arg);
      }
    }
    return match;
  }

  // Special overload of the matcher that also allows us to match against
  // pointers to protobufs. Written as a somewhat complex template that can
  // match against any pointer-like object (e.g. smart pointers).
  template <
      typename T,
      std::enable_if_t<
          // Check that the type can be dereferenced to get a Message.
          std::is_base_of_v<
              ::google::protobuf::Message,
              std::remove_reference_t<decltype(*std::declval<T>())>> &&
              // Check that the type can be compared against null.
              std::is_same_v<decltype(std::declval<T>() == nullptr), bool>,
          int> = 0>
  bool MatchAndExplain(const T &arg,
                       ::testing::MatchResultListener *listener) const {
    if (arg == nullptr) {
      *listener << "which is null";
      return false;
    }
    return MatchAndExplain(*arg, listener);
  }

  void DescribeTo(std::ostream *os) const {
    *os << "is fully initialized and ";
    DescribeRelationToExpectedProto(os);
  }

  void DescribeNegationTo(std::ostream *os) const {
    *os << "is not fully initialized or not ";
    DescribeRelationToExpectedProto(os);
  }

  // Mutators which can modify the proto field comparison properties. These
  // functions should not be utilized directly by users of the matchers. Instead
  // use the matcher functions defined in the public namespace.
  void SetIgnoreRepeatedFieldOrdering() {
    repeated_field_comparison_ = ::google::protobuf::util::MessageDifferencer::AS_SET;
  }

 protected:
  // A unique pointer type used by the CreateExpectedProto function. Instead of
  // the default deleter it requires the creators to construct a custom delete
  // function. This allows different subclasses to customize the delete policy
  // for example by having deletion be a no-op if the returned object is reused
  // across calls.
  using ExpectedProtoPtr = std::unique_ptr<const ::google::protobuf::Message,
{'fraction_non_alphanumeric': 0.0871279692047695, 'fraction_numerical': 0.0015960942634494415, 'mean_word_length': 3.696649029982363, 'pattern_counts': {'":': 0, '<': 45, '<?xml version=': 0, '>': 33, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3684597', 'n_tokens_mistral': 2831, 'n_tokens_neox': 2786, 'n_words': 1157}