• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <binder/app_launch_event.h>
18 
19 #include <gtest/gtest.h>
20 
21 // TODO: move to app_launch_event.h
22 #include <google/protobuf/util/message_differencer.h>
23 
24 using namespace iorap::binder;  // NOLINT
25 
26 using android::Parcel;
27 
28 using Type = AppLaunchEvent::Type;
29 using Temperature = AppLaunchEvent::Temperature;
30 
31 namespace iorap::binder {
32 
ProtosEqual(const::google::protobuf::Message & lhs,const::google::protobuf::Message & rhs)33 inline bool ProtosEqual(const ::google::protobuf::Message& lhs,
34                         const ::google::protobuf::Message& rhs) {
35   return ::google::protobuf::util::MessageDifferencer::Equals(lhs, rhs);
36 }
37 
ProtosEqual(const::google::protobuf::MessageLite & lhs,const::google::protobuf::MessageLite & rhs)38 inline bool ProtosEqual(const ::google::protobuf::MessageLite& lhs,
39                         const ::google::protobuf::MessageLite& rhs) {
40   // MessageLite does not support 'MessageDifferencer' which requires protobuf-full
41   // because it uses reflection.
42   //
43   // Serialize as a string and compare. This may lead to false inequality when protobufs
44   // are actually the same but their encodings are slightly different.
45   return lhs.GetTypeName() == rhs.GetTypeName()
46       && lhs.SerializeAsString() == rhs.SerializeAsString();
47 }
48 
49 template <typename T>
ProtoPointersEqual(const T & lhs_ptr,const T & rhs_ptr)50 inline bool ProtoPointersEqual(const T& lhs_ptr, const T& rhs_ptr) {
51   if (lhs_ptr == nullptr && rhs_ptr == nullptr) {
52     return true;
53   }
54   else if (lhs_ptr != nullptr && rhs_ptr != nullptr) {
55     return ProtosEqual(*lhs_ptr, *rhs_ptr);
56   }
57   return false;
58 }
59 
60 // Field-by-field equality.
61 // Protos are compared according by checking that their serialized encodings are the same.
operator ==(const AppLaunchEvent & lhs,const AppLaunchEvent & rhs)62 inline bool operator==(const AppLaunchEvent& lhs, const AppLaunchEvent& rhs) {
63 # define EQ_OR_RETURN(l, r, val) if (!(l.val == r.val)) { return false; }
64 # define PROTO_EQ_OR_RETURN(l, r, val) if (!ProtoPointersEqual(l.val, r.val)) { return false; }
65 
66   EQ_OR_RETURN(lhs, rhs, type);
67   EQ_OR_RETURN(lhs, rhs, sequence_id);
68   PROTO_EQ_OR_RETURN(lhs, rhs, intent_proto);
69   EQ_OR_RETURN(lhs, rhs, temperature);
70   PROTO_EQ_OR_RETURN(lhs, rhs, activity_record_proto);
71 
72 # undef EQ_OR_RETURN
73 # undef PROTO_EQ_OR_RETURN
74 
75   return true;
76 }
77 
operator !=(const AppLaunchEvent & lhs,const AppLaunchEvent & rhs)78 inline bool operator!=(const AppLaunchEvent& lhs, const AppLaunchEvent& rhs) {
79   return !(lhs == rhs);
80 }
81 
MakeIntentStarted(int64_t sequence_id,std::unique_ptr<IntentProto> intent_proto)82 static AppLaunchEvent MakeIntentStarted(int64_t sequence_id,
83                                             // non-null
84                                             std::unique_ptr<IntentProto> intent_proto) {
85   DCHECK(intent_proto != nullptr);
86 
87   AppLaunchEvent e{Type::kIntentStarted, sequence_id, std::move(intent_proto)};
88   return e;
89 }
90 
MakeIntentFailed(int64_t sequence_id)91 static AppLaunchEvent MakeIntentFailed(int64_t sequence_id) {
92   AppLaunchEvent e{Type::kIntentFailed, sequence_id};
93   return e;
94 }
95 
96 static AppLaunchEvent
MakeActivityLaunched(int64_t sequence_id,Temperature temperature,std::unique_ptr<ActivityRecordProto> activity_record_proto)97 MakeActivityLaunched(int64_t sequence_id,
98                      Temperature temperature,
99                      // non-null
100                      std::unique_ptr<ActivityRecordProto> activity_record_proto) {
101   DCHECK(activity_record_proto != nullptr);
102 
103   AppLaunchEvent e{Type::kActivityLaunched,
104                    sequence_id,
105                    /*intent_proto*/nullptr,
106                    temperature,
107                    std::move(activity_record_proto)};
108   return e;
109 }
110 
111 static AppLaunchEvent
MakeActivityLaunchCancelled(int64_t sequence_id,std::unique_ptr<ActivityRecordProto> activity_record_proto=nullptr)112 MakeActivityLaunchCancelled(int64_t sequence_id,
113                             // nullable
114                             std::unique_ptr<ActivityRecordProto> activity_record_proto = nullptr) {
115   AppLaunchEvent e{Type::kActivityLaunchCancelled,
116                    sequence_id,
117                    /*intent_proto*/nullptr,
118                    Temperature::kUninitialized,
119                    std::move(activity_record_proto)};
120   return e;
121 }
122 
123 static AppLaunchEvent
MakeActivityLaunchFinished(int64_t sequence_id,std::unique_ptr<ActivityRecordProto> activity_record_proto)124 MakeActivityLaunchFinished(int64_t sequence_id,
125                            // non-null
126                            std::unique_ptr<ActivityRecordProto> activity_record_proto) {
127   DCHECK(activity_record_proto != nullptr);
128   AppLaunchEvent e{Type::kActivityLaunchFinished,
129                    sequence_id,
130                    /*intent_proto*/nullptr,
131                    Temperature::kUninitialized,
132                    std::move(activity_record_proto)};
133   return e;
134 }
135 
136 }  // namespace iorap::binder
137 
MakeDummyIntent(std::string action="package_name/.ClassName")138 auto MakeDummyIntent(std::string action = "package_name/.ClassName") {
139   std::unique_ptr<IntentProto> dummy_intent{new IntentProto{}};
140   dummy_intent->set_action(action);
141   return dummy_intent;
142 }
143 
MakeDummyActivityRecord(std::string title="package_name/.ClassName")144 auto MakeDummyActivityRecord(std::string title = "package_name/.ClassName") {
145   std::unique_ptr<ActivityRecordProto> dummy{new ActivityRecordProto{}};
146 
147   dummy->mutable_identifier()->set_title(title);
148 
149   return dummy;
150 }
151 
TEST(AppLaunchEventTest,Equals)152 TEST(AppLaunchEventTest, Equals) {
153   EXPECT_EQ(MakeIntentStarted(456, MakeDummyIntent()), MakeIntentStarted(456, MakeDummyIntent()));
154   EXPECT_NE(MakeIntentStarted(45, MakeDummyIntent()), MakeIntentStarted(45, MakeDummyIntent("a")));
155 
156   EXPECT_EQ(MakeIntentFailed(123), MakeIntentFailed(123));
157   EXPECT_NE(MakeIntentFailed(0), MakeIntentFailed(123));
158 
159   EXPECT_EQ((MakeActivityLaunched(3, Temperature::kHot, MakeDummyActivityRecord())),
160             (MakeActivityLaunched(3, Temperature::kHot, MakeDummyActivityRecord())));
161   EXPECT_NE((MakeActivityLaunched(3, Temperature::kHot, MakeDummyActivityRecord())),
162             (MakeActivityLaunched(3, Temperature::kCold, MakeDummyActivityRecord())));
163   EXPECT_NE((MakeActivityLaunched(3, Temperature::kHot, MakeDummyActivityRecord())),
164             (MakeActivityLaunched(3, Temperature::kHot, MakeDummyActivityRecord("other title"))));
165 
166   EXPECT_EQ((MakeActivityLaunchCancelled(4)),
167             (MakeActivityLaunchCancelled(4)));
168   EXPECT_EQ((MakeActivityLaunchCancelled(4, MakeDummyActivityRecord())),
169             (MakeActivityLaunchCancelled(4, MakeDummyActivityRecord())));
170   EXPECT_NE((MakeActivityLaunchCancelled(4, MakeDummyActivityRecord())),
171             (MakeActivityLaunchCancelled(4, MakeDummyActivityRecord("other"))));
172   EXPECT_NE((MakeActivityLaunchCancelled(4, MakeDummyActivityRecord())),
173             (MakeActivityLaunchCancelled(4)));
174 
175   EXPECT_EQ((MakeActivityLaunchFinished(5, MakeDummyActivityRecord())),
176             (MakeActivityLaunchFinished(5, MakeDummyActivityRecord())));
177   EXPECT_NE((MakeActivityLaunchFinished(5, MakeDummyActivityRecord())),
178             (MakeActivityLaunchFinished(5, MakeDummyActivityRecord("other title"))));
179 }
180 
181 template <typename T>
ValueParcelRoundTrip(const T & value)182 T ValueParcelRoundTrip(const T& value) {
183   ::android::Parcel p;
184   CHECK_EQ(value.writeToParcel(&p), ::android::NO_ERROR);
185 
186   T new_value;
187   p.setDataPosition(0);
188   CHECK_EQ(new_value.readFromParcel(&p), ::android::NO_ERROR);
189 
190   return new_value;
191 }
192 
193 #define EXPECT_PARCELING_ROUND_TRIP(a) EXPECT_EQ((a), ValueParcelRoundTrip((a)))
194 
TEST(AppLaunchEventTest,ParcelingRoundTrip)195 TEST(AppLaunchEventTest, ParcelingRoundTrip) {
196   EXPECT_PARCELING_ROUND_TRIP(MakeIntentStarted(456, MakeDummyIntent()));
197   EXPECT_PARCELING_ROUND_TRIP(MakeIntentFailed(123));
198   EXPECT_PARCELING_ROUND_TRIP(MakeActivityLaunched(3, Temperature::kHot, MakeDummyActivityRecord()));
199   EXPECT_PARCELING_ROUND_TRIP(MakeActivityLaunchCancelled(4));
200   EXPECT_PARCELING_ROUND_TRIP(MakeActivityLaunchCancelled(4, MakeDummyActivityRecord()));
201   EXPECT_PARCELING_ROUND_TRIP(MakeActivityLaunchFinished(5, MakeDummyActivityRecord()));
202 }
203