1 /**
2  * (c) 2019 by Mega Limited, Wellsford, New Zealand
3  *
4  * This file is part of the MEGA SDK - Client Access Engine.
5  *
6  * Applications using the MEGA API must present a valid application key
7  * and comply with the the rules set forth in the Terms of Service.
8  *
9  * The MEGA SDK is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12  *
13  * @copyright Simplified (2-clause) BSD License.
14  *
15  * You should have received a copy of the license along with this
16  * program.
17  */
18 
19 #include <memory>
20 
21 #include <gtest/gtest.h>
22 
23 #include <mega/command.h>
24 #include <mega/json.h>
25 #include <mega/megaapp.h>
26 #include <mega/megaclient.h>
27 #include <mega/types.h>
28 
29 using namespace std;
30 using namespace mega;
31 
32 namespace {
33 
34 class MockApp_CommandGetRegisteredContacts : public MegaApp
35 {
36 public:
37     using DataType = vector<tuple<string, string, string>>;
38 
39     int mCallCount = 0;
40     ErrorCodes mLastError = ErrorCodes::API_EINTERNAL;
41     std::unique_ptr<DataType> mRegisteredContacts;
42 
getregisteredcontacts_result(const ErrorCodes e,DataType * const data)43     void getregisteredcontacts_result(const ErrorCodes e, DataType* const data) override
44     {
45         ++mCallCount;
46         mLastError = e;
47         if (data)
48         {
49             mRegisteredContacts = std::unique_ptr<DataType>{new DataType{*data}};
50         }
51         else
52         {
53             assert(e != ErrorCodes::API_OK);
54         }
55     }
56 };
57 
58 } // anonymous
59 
TEST(Commands,CommandGetRegisteredContacts_processResult_happyPath)60 TEST(Commands, CommandGetRegisteredContacts_processResult_happyPath)
61 {
62     MockApp_CommandGetRegisteredContacts app;
63 
64     JSON json;
65     json.pos = R"({"eud":"Zm9vQG1lZ2EuY28ubno","id":"13","ud":"Zm9vQG1lZ2EuY28ubno"},{"eud":"KzY0MjcxMjM0NTY3","id":"42","ud":"KzY0IDI3IDEyMyA0NTY3"})";
66     const auto jsonBegin = json.pos;
67     const auto jsonLength = strlen(json.pos);
68 
69     CommandGetRegisteredContacts::processResult(app, json);
70 
71     const vector<tuple<string, string, string>> expected{
72         {"foo@mega.co.nz", "13", "foo@mega.co.nz"},
73         {"+64271234567", "42", "+64 27 123 4567"},
74     };
75 
76     ASSERT_EQ(1, app.mCallCount);
77     ASSERT_EQ(API_OK, app.mLastError);
78     ASSERT_NE(nullptr, app.mRegisteredContacts);
79     ASSERT_EQ(expected, *app.mRegisteredContacts);
80     ASSERT_EQ((long)jsonLength, std::distance(jsonBegin, json.pos)); // assert json has been parsed all the way
81 }
82 
TEST(Commands,CommandGetRegisteredContacts_processResult_onlyOneContact)83 TEST(Commands, CommandGetRegisteredContacts_processResult_onlyOneContact)
84 {
85     MockApp_CommandGetRegisteredContacts app;
86 
87     JSON json;
88     json.pos = R"({"eud":"Zm9vQG1lZ2EuY28ubno","id":"13","ud":"Zm9vQG1lZ2EuY28ubno"})";
89     const auto jsonBegin = json.pos;
90     const auto jsonLength = strlen(json.pos);
91 
92     CommandGetRegisteredContacts::processResult(app, json);
93 
94     const vector<tuple<string, string, string>> expected{
95         {"foo@mega.co.nz", "13", "foo@mega.co.nz"},
96     };
97 
98     ASSERT_EQ(1, app.mCallCount);
99     ASSERT_EQ(API_OK, app.mLastError);
100     ASSERT_NE(nullptr, app.mRegisteredContacts);
101     ASSERT_EQ(expected, *app.mRegisteredContacts);
102     ASSERT_EQ(ptrdiff_t(jsonLength), std::distance(jsonBegin, json.pos)); // assert json has been parsed all the way
103 }
104 
TEST(Commands,CommandGetRegisteredContacts_processResult_extraFieldShouldBeIgnored)105 TEST(Commands, CommandGetRegisteredContacts_processResult_extraFieldShouldBeIgnored)
106 {
107     MockApp_CommandGetRegisteredContacts app;
108 
109     JSON json;
110     json.pos = R"({"eud":"Zm9vQG1lZ2EuY28ubno","id":"13","ud":"Zm9vQG1lZ2EuY28ubno","YmxhaA":"42"})";
111     const auto jsonBegin = json.pos;
112     const auto jsonLength = strlen(json.pos);
113 
114     CommandGetRegisteredContacts::processResult(app, json);
115 
116     const vector<tuple<string, string, string>> expected{
117         {"foo@mega.co.nz", "13", "foo@mega.co.nz"},
118     };
119 
120     ASSERT_EQ(1, app.mCallCount);
121     ASSERT_EQ(API_OK, app.mLastError);
122     ASSERT_NE(nullptr, app.mRegisteredContacts);
123     ASSERT_EQ(expected, *app.mRegisteredContacts);
124     ASSERT_EQ(ptrdiff_t(jsonLength), std::distance(jsonBegin, json.pos)); // assert json has been parsed all the way
125 }
126 
TEST(Commands,CommandGetRegisteredContacts_processResult_invalidResponse)127 TEST(Commands, CommandGetRegisteredContacts_processResult_invalidResponse)
128 {
129     MockApp_CommandGetRegisteredContacts app;
130 
131     JSON json;
132     json.pos = R"({"eud":"Zm9vQG1lZ2EuY28ubno","id":"13","YmxhaA":"42"})";
133     const auto jsonBegin = json.pos;
134     const auto jsonLength = strlen(json.pos);
135 
136     CommandGetRegisteredContacts::processResult(app, json);
137 
138     ASSERT_EQ(1, app.mCallCount);
139     ASSERT_EQ(API_EINTERNAL, app.mLastError);
140     ASSERT_EQ(nullptr, app.mRegisteredContacts);
141     ASSERT_EQ(ptrdiff_t(jsonLength), std::distance(jsonBegin, json.pos)); // assert json has been parsed all the way
142 }
143 
144 namespace {
145 
146 class MockApp_CommandGetCountryCallingCodes : public MegaApp
147 {
148 public:
149     using DataType = map<string, vector<string>>;
150 
151     int mCallCount = 0;
152     ErrorCodes mLastError = ErrorCodes::API_EINTERNAL;
153     std::unique_ptr<DataType> mCountryCallingCodes;
154 
getcountrycallingcodes_result(const ErrorCodes e,DataType * const data)155     void getcountrycallingcodes_result(const ErrorCodes e, DataType* const data) override
156     {
157         ++mCallCount;
158         mLastError = e;
159         if (data)
160         {
161             mCountryCallingCodes = std::unique_ptr<DataType>{new DataType{*data}};
162         }
163         else
164         {
165             assert(e != ErrorCodes::API_OK);
166         }
167     }
168 };
169 
170 } // anonymous
171 
TEST(Commands,CommandGetCountryCallingCodes_processResult_happyPath)172 TEST(Commands, CommandGetCountryCallingCodes_processResult_happyPath)
173 {
174     MockApp_CommandGetCountryCallingCodes app;
175 
176     JSON json;
177     json.pos = R"({"cc":"AD","l":[376]},{"cc":"AE","l":[971,13]},{"cc":"AF","l":[93,13,42]})";
178     const auto jsonBegin = json.pos;
179     const auto jsonLength = strlen(json.pos);
180 
181     CommandGetCountryCallingCodes::processResult(app, json);
182 
183     const map<string, vector<string>> expected{
184         {"AD", {"376"}},
185         {"AE", {"971", "13"}},
186         {"AF", {"93", "13", "42"}},
187     };
188 
189     ASSERT_EQ(1, app.mCallCount);
190     ASSERT_EQ(API_OK, app.mLastError);
191     ASSERT_NE(nullptr, app.mCountryCallingCodes);
192     ASSERT_EQ(expected, *app.mCountryCallingCodes);
193     ASSERT_EQ(ptrdiff_t(jsonLength), std::distance(jsonBegin, json.pos)); // assert json has been parsed all the way
194 }
195 
TEST(Commands,CommandGetCountryCallingCodes_processResult_onlyOneCountry)196 TEST(Commands, CommandGetCountryCallingCodes_processResult_onlyOneCountry)
197 {
198     MockApp_CommandGetCountryCallingCodes app;
199 
200     JSON json;
201     json.pos = R"({"cc":"AD","l":[12,376]})";
202     const auto jsonBegin = json.pos;
203     const auto jsonLength = strlen(json.pos);
204 
205     CommandGetCountryCallingCodes::processResult(app, json);
206 
207     const map<string, vector<string>> expected{
208         {"AD", {"12", "376"}},
209     };
210 
211     ASSERT_EQ(1, app.mCallCount);
212     ASSERT_EQ(API_OK, app.mLastError);
213     ASSERT_NE(nullptr, app.mCountryCallingCodes);
214     ASSERT_EQ(expected, *app.mCountryCallingCodes);
215     ASSERT_EQ(ptrdiff_t(jsonLength), std::distance(jsonBegin, json.pos)); // assert json has been parsed all the way
216 }
217 
TEST(Commands,CommandGetCountryCallingCodes_processResult_extraFieldShouldBeIgnored)218 TEST(Commands, CommandGetCountryCallingCodes_processResult_extraFieldShouldBeIgnored)
219 {
220     MockApp_CommandGetCountryCallingCodes app;
221 
222     JSON json;
223     json.pos = R"({"cc":"AD","l":[12,376],"blah":"42"})";
224     const auto jsonBegin = json.pos;
225     const auto jsonLength = strlen(json.pos);
226 
227     CommandGetCountryCallingCodes::processResult(app, json);
228 
229     const map<string, vector<string>> expected{
230         {"AD", {"12", "376"}},
231     };
232 
233     ASSERT_EQ(1, app.mCallCount);
234     ASSERT_EQ(API_OK, app.mLastError);
235     ASSERT_NE(nullptr, app.mCountryCallingCodes);
236     ASSERT_EQ(expected, *app.mCountryCallingCodes);
237     ASSERT_EQ(ptrdiff_t(jsonLength), std::distance(jsonBegin, json.pos)); // assert json has been parsed all the way
238 }
239 
TEST(Commands,CommandGetCountryCallingCodes_processResult_invalidResponse)240 TEST(Commands, CommandGetCountryCallingCodes_processResult_invalidResponse)
241 {
242     MockApp_CommandGetCountryCallingCodes app;
243 
244     JSON json;
245     json.pos = R"({"cc":"AD","blah":[12,376]})";
246     const auto jsonBegin = json.pos;
247     const auto jsonLength = strlen(json.pos);
248 
249     CommandGetCountryCallingCodes::processResult(app, json);
250 
251     ASSERT_EQ(1, app.mCallCount);
252     ASSERT_EQ(API_EINTERNAL, app.mLastError);
253     ASSERT_EQ(nullptr, app.mCountryCallingCodes);
254     ASSERT_EQ(ptrdiff_t(jsonLength), std::distance(jsonBegin, json.pos)); // assert json has been parsed all the way
255 }
256