blob: 4063f3dc3e122c509ec01bcd1d13d0efff5cfe43 [file] [log] [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/feed/core/v2/test/proto_printer.h"
#include <sstream>
#include <type_traits>
#include "base/json/string_escape.h"
#include "components/feed/core/proto/v2/wire/action_diagnostic_info.pb.h"
#include "components/feed/core/proto/v2/wire/action_payload.pb.h"
#include "components/feed/core/proto/v2/wire/client_info.pb.h"
#include "components/feed/core/proto/v2/wire/consistency_token.pb.h"
#include "components/feed/core/proto/v2/wire/content_id.pb.h"
#include "components/feed/core/proto/v2/wire/feed_action.pb.h"
#include "components/feed/core/proto/v2/wire/upload_actions_request.pb.h"
#include "components/feed/core/proto/v2/wire/upload_actions_response.pb.h"
#include "components/feed/core/proto/v2/xsurface.pb.h"
#include "components/feed/core/v2/protocol_translator.h"
namespace feed {
namespace {} // namespace
template <typename T, typename S = void>
struct IsFieldSetHelper {
// Returns false if the |v| is a zero-value.
static bool IsSet(const T& v) { return true; }
};
template <typename T>
struct IsFieldSetHelper<T, std::enable_if_t<std::is_scalar<T>::value>> {
static bool IsSet(const T& v) { return !!v; }
};
template <>
struct IsFieldSetHelper<std::string> {
static bool IsSet(const std::string& v) { return !v.empty(); }
};
template <typename T>
struct IsFieldSetHelper<google::protobuf::RepeatedPtrField<T>> {
static bool IsSet(const google::protobuf::RepeatedPtrField<T>& v) {
return !v.empty();
}
};
template <typename T>
struct IsFieldSetHelper<google::protobuf::RepeatedField<T>> {
static bool IsSet(const google::protobuf::RepeatedField<T>& v) {
return !v.empty();
}
};
template <typename T>
bool IsFieldSet(const T& v) {
return IsFieldSetHelper<T>::IsSet(v);
}
class TextProtoPrinter {
public:
template <typename T>
static std::string ToString(const T& v) {
TextProtoPrinter pp;
pp << v;
return pp.ss_.str();
}
private:
// Use partial specialization to implement field printing for repeated
// fields and messages.
template <typename T, typename S = void>
struct FieldPrintHelper {
static void Run(const std::string& name, const T& v, TextProtoPrinter* pp) {
if (!IsFieldSet(v))
return;
pp->Indent();
pp->PrintRaw(name);
pp->PrintRaw(": ");
*pp << v;
pp->PrintRaw("\n");
}
};
template <typename T>
struct FieldPrintHelper<google::protobuf::RepeatedPtrField<T>> {
static void Run(const std::string& name,
const google::protobuf::RepeatedPtrField<T>& v,
TextProtoPrinter* pp) {
for (int i = 0; i < v.size(); ++i) {
pp->Field(name, v[i]);
}
}
};
template <typename T>
struct FieldPrintHelper<google::protobuf::RepeatedField<T>> {
static void Run(const std::string& name,
const google::protobuf::RepeatedField<T>& v,
TextProtoPrinter* pp) {
for (int i = 0; i < v.size(); ++i) {
pp->Field(name, v[i]);
}
}
};
template <typename T>
struct FieldPrintHelper<
T,
std::enable_if_t<
std::is_base_of<google::protobuf::MessageLite, T>::value>> {
static void Run(const std::string& name, const T& v, TextProtoPrinter* pp) {
// Print nothing if it's empty.
if (v.ByteSizeLong() == 0)
return;
pp->Indent();
pp->PrintRaw(name);
pp->PrintRaw(" ");
*pp << v;
}
};
#define PRINT_FIELD(name) Field(#name, v.name())
// Required only for proto2 oneof fields.
#define PRINT_ONEOF(name) \
if (v.has_##name()) { \
Field(#name, v.name()); \
}
template <typename T>
TextProtoPrinter& operator<<(const T& v) {
ss_ << v;
return *this;
}
TextProtoPrinter& operator<<(const std::string& v) {
ss_ << base::GetQuotedJSONString(v);
return *this;
}
TextProtoPrinter& operator<<(const feedwire::ContentId& v) {
BeginMessage();
PRINT_FIELD(content_domain);
PRINT_FIELD(type);
PRINT_FIELD(id);
EndMessage();
return *this;
}
TextProtoPrinter& operator<<(const feedwire::ClientInfo& v) {
BeginMessage();
PRINT_FIELD(platform_type);
PRINT_FIELD(platform_version);
PRINT_FIELD(app_type);
PRINT_FIELD(app_version);
PRINT_FIELD(locale);
PRINT_FIELD(display_info);
PRINT_FIELD(client_instance_id);
PRINT_FIELD(advertising_id);
EndMessage();
return *this;
}
TextProtoPrinter& operator<<(const feedwire::ActionPayload& v) {
BeginMessage();
PRINT_FIELD(batched_action_payload_data);
EndMessage();
return *this;
}
TextProtoPrinter& operator<<(const feedwire::Version& v) {
BeginMessage();
PRINT_FIELD(major);
PRINT_FIELD(minor);
PRINT_FIELD(build);
PRINT_FIELD(revision);
PRINT_FIELD(architecture);
PRINT_FIELD(build_type);
PRINT_FIELD(api_version);
EndMessage();
return *this;
}
TextProtoPrinter& operator<<(const feedwire::DisplayInfo& v) {
BeginMessage();
PRINT_FIELD(screen_density);
PRINT_FIELD(screen_width_in_pixels);
PRINT_FIELD(screen_height_in_pixels);
EndMessage();
return *this;
}
TextProtoPrinter& operator<<(
const feedstore::PendingWebFeedOperation::Kind kind) {
return *this << feedstore::PendingWebFeedOperation_Kind_Name(kind);
}
TextProtoPrinter& operator<<(const feedstore::Record& v) {
BeginMessage();
PRINT_ONEOF(stream_data);
PRINT_ONEOF(stream_structures);
PRINT_ONEOF(content);
PRINT_ONEOF(local_action);
PRINT_ONEOF(shared_state);
EndMessage();
return *this;
}
TextProtoPrinter& operator<<(const feedstore::StreamContentHashList& v) {
BeginMessage();
PRINT_FIELD(hashes);
EndMessage();
return *this;
}
TextProtoPrinter& operator<<(const feedstore::StreamData& v) {
BeginMessage();
PRINT_FIELD(content_id);
PRINT_FIELD(root_event_id);
PRINT_FIELD(next_page_token);
PRINT_FIELD(last_added_time_millis);
PRINT_FIELD(shared_state_ids);
PRINT_FIELD(stream_key);
PRINT_FIELD(content_hashes);
EndMessage();
return *this;
}
TextProtoPrinter& operator<<(const feedstore::Metadata& v) {
BeginMessage();
PRINT_FIELD(consistency_token);
PRINT_FIELD(next_action_id);
PRINT_FIELD(stream_schema_version);
EndMessage();
return *this;
}
TextProtoPrinter& operator<<(const feedstore::StreamStructureSet& v) {
BeginMessage();
PRINT_FIELD(stream_key);
PRINT_FIELD(sequence_number);
PRINT_FIELD(structures);
EndMessage();
return *this;
}
TextProtoPrinter& operator<<(const feedstore::StreamStructure& v) {
BeginMessage();
PRINT_FIELD(operation);
PRINT_FIELD(content_id);
PRINT_FIELD(parent_id);
PRINT_FIELD(type);
PRINT_FIELD(content_info);
EndMessage();
return *this;
}
TextProtoPrinter& operator<<(const feedstore::DataOperation& v) {
BeginMessage();
PRINT_FIELD(structure);
PRINT_FIELD(content);
EndMessage();
return *this;
}
TextProtoPrinter& operator<<(const feedstore::WebFeedInfo& v) {
BeginMessage();
PRINT_FIELD(web_feed_id);
PRINT_FIELD(title);
PRINT_FIELD(subtitle);
PRINT_FIELD(detail_text);
PRINT_FIELD(visit_uri);
PRINT_FIELD(rss_uri);
PRINT_FIELD(favicon);
PRINT_FIELD(follower_count);
PRINT_FIELD(state);
PRINT_FIELD(matchers);
EndMessage();
return *this;
}
TextProtoPrinter& operator<<(const feedstore::PendingWebFeedOperation& v) {
BeginMessage();
PRINT_FIELD(id);
PRINT_FIELD(kind);
PRINT_FIELD(web_feed_id);
PRINT_FIELD(attempts);
PRINT_FIELD(change_reason);
EndMessage();
return *this;
}
TextProtoPrinter& operator<<(
const feedstore::RecommendedWebFeedIndex::Entry& v) {
BeginMessage();
PRINT_FIELD(matchers);
PRINT_FIELD(web_feed_id);
EndMessage();
return *this;
}
TextProtoPrinter& operator<<(const feedstore::Image& v) {
BeginMessage();
PRINT_FIELD(url);
EndMessage();
return *this;
}
TextProtoPrinter& operator<<(const feedstore::RecommendedWebFeedIndex& v) {
BeginMessage();
PRINT_FIELD(entries);
PRINT_FIELD(update_time_millis);
EndMessage();
return *this;
}
TextProtoPrinter& operator<<(const feedstore::SubscribedWebFeeds& v) {
BeginMessage();
PRINT_FIELD(feeds);
PRINT_FIELD(update_time_millis);
EndMessage();
return *this;
}
TextProtoPrinter& operator<<(
const feedwire::webfeed::WebFeedMatcher::Criteria& v) {
BeginMessage();
PRINT_FIELD(text);
PRINT_FIELD(partial_match_regex);
PRINT_FIELD(criteria_type);
EndMessage();
return *this;
}
TextProtoPrinter& operator<<(const feedwire::webfeed::WebFeedMatcher& v) {
BeginMessage();
PRINT_FIELD(criteria);
EndMessage();
return *this;
}
TextProtoPrinter& operator<<(const feedstore::ContentInfo& v) {
BeginMessage();
PRINT_FIELD(score);
PRINT_FIELD(availability_time_seconds);
// PRINT_FIELD(representation_data);
// PRINT_FIELD(offline_metadata);
EndMessage();
return *this;
}
TextProtoPrinter& operator<<(const feedstore::Content& v) {
BeginMessage();
PRINT_FIELD(content_id);
PRINT_FIELD(frame);
PRINT_FIELD(stream_key);
EndMessage();
return *this;
}
TextProtoPrinter& operator<<(const feedstore::StreamSharedState& v) {
BeginMessage();
PRINT_FIELD(content_id);
PRINT_FIELD(shared_state_data);
PRINT_FIELD(stream_key);
EndMessage();
return *this;
}
TextProtoPrinter& operator<<(const feedstore::StoredAction& v) {
BeginMessage();
PRINT_FIELD(id);
PRINT_FIELD(upload_attempt_count);
// PRINT_FIELD(action);
EndMessage();
return *this;
}
TextProtoPrinter& operator<<(const feedui::StreamUpdate& v) {
BeginMessage();
PRINT_FIELD(updated_slices);
PRINT_FIELD(new_shared_states);
EndMessage();
return *this;
}
TextProtoPrinter& operator<<(const feedui::StreamUpdate_SliceUpdate& v) {
BeginMessage();
PRINT_ONEOF(slice);
PRINT_FIELD(slice_id);
EndMessage();
return *this;
}
TextProtoPrinter& operator<<(const feedui::Slice& v) {
BeginMessage();
PRINT_ONEOF(xsurface_slice);
PRINT_ONEOF(zero_state_slice);
PRINT_ONEOF(loading_spinner_slice);
EndMessage();
return *this;
}
TextProtoPrinter& operator<<(const feedui::ZeroStateSlice& v) {
BeginMessage();
PRINT_FIELD(type);
EndMessage();
return *this;
}
TextProtoPrinter& operator<<(const feedui::LoadingSpinnerSlice& v) {
BeginMessage();
PRINT_FIELD(is_at_top);
EndMessage();
return *this;
}
TextProtoPrinter& operator<<(const feedui::XSurfaceSlice& v) {
BeginMessage();
PRINT_FIELD(xsurface_frame);
EndMessage();
return *this;
}
TextProtoPrinter& operator<<(const feedui::SharedState& v) {
BeginMessage();
PRINT_FIELD(id);
PRINT_FIELD(xsurface_shared_state);
EndMessage();
return *this;
}
TextProtoPrinter& operator<<(const feedwire::ConsistencyToken& v) {
BeginMessage();
PRINT_FIELD(token);
EndMessage();
return *this;
}
TextProtoPrinter& operator<<(const feedwire::FeedAction::ClientData& v) {
BeginMessage();
PRINT_FIELD(timestamp_seconds);
PRINT_FIELD(sequence_number);
PRINT_FIELD(duration_ms);
PRINT_FIELD(action_origin);
PRINT_FIELD(action_surface);
EndMessage();
return *this;
}
TextProtoPrinter& operator<<(const feedwire::FeedAction& v) {
BeginMessage();
PRINT_FIELD(action_payload);
PRINT_FIELD(client_data);
EndMessage();
return *this;
}
TextProtoPrinter& operator<<(const feedwire::ActionDiagnosticInfo& v) {
BeginMessage();
PRINT_FIELD(actions_remaining);
EndMessage();
return *this;
}
TextProtoPrinter& operator<<(const feedwire::UploadActionsRequest& v) {
BeginMessage();
PRINT_FIELD(feed_actions);
PRINT_FIELD(consistency_token);
PRINT_FIELD(action_diagnostic_info);
EndMessage();
return *this;
}
TextProtoPrinter& operator<<(const feedwire::UploadActionsResponse& v) {
BeginMessage();
PRINT_FIELD(consistency_token);
EndMessage();
return *this;
}
TextProtoPrinter& operator<<(
const feedwire::webfeed::ListRecommendedWebFeedsRequest& v) {
BeginMessage();
EndMessage();
return *this;
}
TextProtoPrinter& operator<<(
const feedwire::webfeed::ListRecommendedWebFeedsResponse& v) {
BeginMessage();
PRINT_FIELD(recommended_web_feeds);
EndMessage();
return *this;
}
TextProtoPrinter& operator<<(
const feedwire::webfeed::ListWebFeedsRequest& v) {
BeginMessage();
EndMessage();
return *this;
}
TextProtoPrinter& operator<<(
const feedwire::webfeed::ListWebFeedsResponse& v) {
BeginMessage();
PRINT_FIELD(web_feeds);
EndMessage();
return *this;
}
TextProtoPrinter& operator<<(const feedwire::webfeed::Image& v) {
BeginMessage();
PRINT_FIELD(uri);
EndMessage();
return *this;
}
TextProtoPrinter& operator<<(const feedwire::webfeed::WebFeed& v) {
BeginMessage();
PRINT_FIELD(name);
PRINT_FIELD(title);
PRINT_FIELD(subtitle);
PRINT_FIELD(detail_text);
PRINT_FIELD(visit_uri);
PRINT_FIELD(rss_uri);
PRINT_FIELD(favicon);
PRINT_FIELD(follower_count);
PRINT_FIELD(state);
EndMessage();
return *this;
}
TextProtoPrinter& operator<<(
const feedxsurface::WebFeedFollowState::FollowState v) {
return *this << feedxsurface::WebFeedFollowState_FollowState_Name(v);
}
TextProtoPrinter& operator<<(const feedxsurface::WebFeedFollowState& v) {
BeginMessage();
PRINT_FIELD(follow_state);
EndMessage();
return *this;
}
TextProtoPrinter& operator<<(const feedwire::InfoCardTrackingState& v) {
BeginMessage();
PRINT_FIELD(type);
PRINT_FIELD(explicitly_dismissed_count);
PRINT_FIELD(view_count);
PRINT_FIELD(click_count);
PRINT_FIELD(first_view_timestamp);
PRINT_FIELD(last_view_timestamp);
EndMessage();
return *this;
}
template <typename T>
void Field(const std::string& name, const T& value) {
FieldPrintHelper<T>::Run(name, value, this);
}
void BeginMessage() {
ss_ << "{\n";
indent_ += 2;
}
void EndMessage() {
indent_ -= 2;
Indent();
ss_ << "}\n";
}
void PrintRaw(const std::string& text) { ss_ << text; }
void Indent() {
for (int i = 0; i < indent_; ++i)
ss_ << ' ';
}
int indent_ = 0;
std::stringstream ss_;
}; // namespace feed
#define DECLARE_PRINTER(NS, PROTO_TYPE) \
std::string ToTextProto(const NS::PROTO_TYPE& v) { \
return TextProtoPrinter::ToString(v); \
}
DECLARE_PRINTER(feedstore, Content)
DECLARE_PRINTER(feedstore, DataOperation)
DECLARE_PRINTER(feedstore, Image)
DECLARE_PRINTER(feedstore, Metadata)
DECLARE_PRINTER(feedstore, RecommendedWebFeedIndex)
DECLARE_PRINTER(feedstore, Record)
DECLARE_PRINTER(feedstore, StoredAction)
DECLARE_PRINTER(feedstore, StreamContentHashList)
DECLARE_PRINTER(feedstore, StreamData)
DECLARE_PRINTER(feedstore, StreamSharedState)
DECLARE_PRINTER(feedstore, StreamStructure)
DECLARE_PRINTER(feedstore, StreamStructureSet)
DECLARE_PRINTER(feedstore, SubscribedWebFeeds)
DECLARE_PRINTER(feedstore, WebFeedInfo)
DECLARE_PRINTER(feedstore, PendingWebFeedOperation)
DECLARE_PRINTER(feedui, StreamUpdate)
DECLARE_PRINTER(feedwire, ActionPayload)
DECLARE_PRINTER(feedwire, ClientInfo)
DECLARE_PRINTER(feedwire, ContentId)
DECLARE_PRINTER(feedwire, DisplayInfo)
DECLARE_PRINTER(feedwire, InfoCardTrackingState)
DECLARE_PRINTER(feedwire, UploadActionsRequest)
DECLARE_PRINTER(feedwire, UploadActionsResponse)
DECLARE_PRINTER(feedwire, Version)
DECLARE_PRINTER(feedwire::webfeed, Image)
DECLARE_PRINTER(feedwire::webfeed, ListRecommendedWebFeedsRequest)
DECLARE_PRINTER(feedwire::webfeed, ListRecommendedWebFeedsResponse)
DECLARE_PRINTER(feedwire::webfeed, ListWebFeedsRequest)
DECLARE_PRINTER(feedwire::webfeed, ListWebFeedsResponse)
DECLARE_PRINTER(feedwire::webfeed, WebFeed)
DECLARE_PRINTER(feedwire::webfeed, WebFeedMatcher)
DECLARE_PRINTER(feedxsurface, WebFeedFollowState)
#undef DECLARE_PRINTER
std::ostream& operator<<(std::ostream& os, const StreamModelUpdateRequest& v) {
os << "source: " << static_cast<int>(v.source) << '\n';
os << "stream_data: " << v.stream_data;
for (auto& content : v.content) {
os << "content: " << content;
}
for (auto& shared_state : v.shared_states) {
os << "shared_state: " << shared_state;
}
for (auto& stream_structure : v.stream_structures) {
os << "stream_structure: " << stream_structure;
}
os << "max_structure_sequence_number: " << v.max_structure_sequence_number
<< '\n';
return os;
}
} // namespace feed