@@ -27,6 +27,8 @@ using ::firebase::App;
27
27
using ::firebase::AppOptions;
28
28
using ::firebase::Future;
29
29
using ::firebase::FutureBase;
30
+ using ::firebase::Variant;
31
+ using ::firebase::auth::AdditionalUserInfo;
30
32
using ::firebase::auth::Auth;
31
33
using ::firebase::auth::AuthError;
32
34
using ::firebase::auth::Credential;
@@ -39,8 +41,10 @@ using ::firebase::auth::kAuthErrorNone;
39
41
using ::firebase::auth::OAuthProvider;
40
42
using ::firebase::auth::PhoneAuthProvider;
41
43
using ::firebase::auth::PlayGamesAuthProvider;
44
+ using ::firebase::auth::SignInResult;
42
45
using ::firebase::auth::TwitterAuthProvider;
43
46
using ::firebase::auth::User;
47
+ using ::firebase::auth::UserMetadata;
44
48
using ::firebase::auth::UserInfoInterface;
45
49
46
50
// Set this to true, and set the email/password, to test a custom email address.
@@ -73,7 +77,7 @@ static const char kFirebaseProviderId[] =
73
77
// Don't return until `future` is complete.
74
78
// Print a message for whether the result mathes our expectations.
75
79
// Returns true if the application should exit.
76
- static bool WaitForFuture (FutureBase future, const char * fn,
80
+ static bool WaitForFuture (const FutureBase& future, const char * fn,
77
81
AuthError expected_error, bool log_error = true ) {
78
82
// Note if the future has not be started properly.
79
83
if (future.status () == ::firebase::kFutureStatusInvalid ) {
@@ -125,6 +129,25 @@ static bool WaitForSignInFuture(Future<User*> sign_in_future, const char* fn,
125
129
return false ;
126
130
}
127
131
132
+ static bool WaitForSignInFuture (const Future<SignInResult>& sign_in_future,
133
+ const char * fn, AuthError expected_error,
134
+ Auth* auth) {
135
+ if (WaitForFuture (sign_in_future, fn, expected_error)) return true ;
136
+
137
+ const SignInResult* sign_in_result = sign_in_future.result ();
138
+ const User* sign_in_user = sign_in_result ? sign_in_result->user : nullptr ;
139
+ const User* auth_user = auth->current_user ();
140
+
141
+ if (expected_error == ::firebase::auth::kAuthErrorNone &&
142
+ sign_in_user != auth_user) {
143
+ LogMessage (" ERROR: future's user (%x) and current_user (%x) don't match" ,
144
+ static_cast <int >(reinterpret_cast <intptr_t >(sign_in_user)),
145
+ static_cast <int >(reinterpret_cast <intptr_t >(auth_user)));
146
+ }
147
+
148
+ return false ;
149
+ }
150
+
128
151
// Wait for the current user to sign out. Typically you should use the
129
152
// state listener to determine whether the user has signed out.
130
153
static bool WaitForSignOut (firebase::auth::Auth* auth) {
@@ -170,6 +193,77 @@ static void ExpectStringsEqual(const char* test, const char* expected,
170
193
}
171
194
}
172
195
196
+ static void LogVariantMap (const std::map<Variant, Variant>& variant_map,
197
+ int indent);
198
+
199
+ // Log a vector of variants.
200
+ static void LogVariantVector (const std::vector<Variant>& variants,
201
+ int indent) {
202
+ std::string indent_string (indent * 2 , ' ' );
203
+ LogMessage (" %s[" , indent_string.c_str ());
204
+ for (auto it = variants.begin (); it != variants.end (); ++it) {
205
+ const Variant& item = *it;
206
+ if (item.is_fundamental_type ()) {
207
+ const Variant& string_value = item.AsString ();
208
+ LogMessage (" %s %s," , indent_string.c_str (),
209
+ string_value.string_value ());
210
+ } else if (item.is_vector ()) {
211
+ LogVariantVector (item.vector (), indent + 2 );
212
+ } else if (item.is_map ()) {
213
+ LogVariantMap (item.map (), indent + 2 );
214
+ } else {
215
+ LogMessage (" %s ERROR: unknown type %d" , indent_string.c_str (),
216
+ static_cast <int >(item.type ()));
217
+ }
218
+ }
219
+ LogMessage (" %s]" , indent_string.c_str ());
220
+ }
221
+
222
+ // Log a map of variants.
223
+ static void LogVariantMap (const std::map<Variant, Variant>& variant_map,
224
+ int indent) {
225
+ std::string indent_string (indent * 2 , ' ' );
226
+ for (auto it = variant_map.begin (); it != variant_map.end (); ++it) {
227
+ const Variant& key_string = it->first .AsString ();
228
+ const Variant& value = it->second ;
229
+ if (value.is_fundamental_type ()) {
230
+ const Variant& string_value = value.AsString ();
231
+ LogMessage (" %s%s: %s," , indent_string.c_str (),
232
+ key_string.string_value (),
233
+ string_value.string_value ());
234
+ } else {
235
+ LogMessage (" %s%s:" , indent_string.c_str (),
236
+ key_string.string_value ());
237
+ if (value.is_vector ()) {
238
+ LogVariantVector (value.vector (), indent + 1 );
239
+ } else if (value.is_map ()) {
240
+ LogVariantMap (value.map (), indent + 1 );
241
+ } else {
242
+ LogMessage (" %s ERROR: unknown type %d" , indent_string.c_str (),
243
+ static_cast <int >(value.type ()));
244
+ }
245
+ }
246
+ }
247
+ }
248
+
249
+ // Display the sign-in result.
250
+ static void LogSignInResult (const SignInResult& result) {
251
+ if (!result.user ) {
252
+ LogMessage (" ERROR: User not signed in" );
253
+ return ;
254
+ }
255
+ LogMessage (" * User ID %s" , result.user ->uid ().c_str ());
256
+ const AdditionalUserInfo& info = result.info ;
257
+ LogMessage (" * Provider ID %s" , info.provider_id .c_str ());
258
+ LogMessage (" * User Name %s" , info.user_name .c_str ());
259
+ LogVariantMap (info.profile , 0 );
260
+ const UserMetadata& metadata = result.meta ;
261
+ LogMessage (" * Sign in timestamp %d" ,
262
+ static_cast <int >(metadata.last_sign_in_timestamp ));
263
+ LogMessage (" * Creation timestamp %d" ,
264
+ static_cast <int >(metadata.creation_timestamp ));
265
+ }
266
+
173
267
class AuthStateChangeCounter : public firebase ::auth::AuthStateListener {
174
268
public:
175
269
AuthStateChangeCounter () : num_state_changes_(0 ) {}
@@ -622,6 +716,43 @@ extern "C" int common_main(int argc, const char* argv[]) {
622
716
}
623
717
}
624
718
719
+ // Sign in anonymously, link an email credential, reauthenticate with the
720
+ // credential, unlink the credential and finally sign out.
721
+ {
722
+ Future<User*> sign_in_anonymously_future = auth->SignInAnonymously ();
723
+ WaitForSignInFuture (sign_in_anonymously_future,
724
+ " Auth::SignInAnonymously" , kAuthErrorNone , auth);
725
+ if (sign_in_anonymously_future.error () == kAuthErrorNone ) {
726
+ User* user = *sign_in_anonymously_future.result ();
727
+ std::string email = CreateNewEmail ();
728
+ Credential credential = EmailAuthProvider::GetCredential (
729
+ email.c_str (), kTestPassword );
730
+ // Link with an email / password credential.
731
+ Future<SignInResult> link_future =
732
+ user->LinkAndRetrieveDataWithCredential (credential);
733
+ WaitForSignInFuture (link_future,
734
+ " User::LinkAndRetrieveDataWithCredential" ,
735
+ kAuthErrorNone , auth);
736
+ if (link_future.error () == kAuthErrorNone ) {
737
+ LogSignInResult (*link_future.result ());
738
+ Future<SignInResult> reauth_future =
739
+ user->ReauthenticateAndRetrieveData (credential);
740
+ WaitForSignInFuture (reauth_future,
741
+ " User::ReauthenticateAndRetrieveData" ,
742
+ kAuthErrorNone , auth);
743
+ if (reauth_future.error () == kAuthErrorNone ) {
744
+ LogSignInResult (*reauth_future.result ());
745
+ }
746
+ // Unlink email / password from credential.
747
+ Future<User*> unlink_future = user->Unlink (
748
+ credential.provider ().c_str ());
749
+ WaitForSignInFuture (unlink_future, " User::Unlink" ,
750
+ kAuthErrorNone , auth);
751
+ }
752
+ auth->SignOut ();
753
+ }
754
+ }
755
+
625
756
// Sign in user with bad email. Should fail.
626
757
{
627
758
Future<User*> sign_in_future_bad_email =
@@ -669,6 +800,32 @@ extern "C" int common_main(int argc, const char* argv[]) {
669
800
sign_in_cred_ok == auth->SignInWithCredentialLastResult ());
670
801
}
671
802
803
+ // Test Auth::SignInAndRetrieveDataWithCredential using email & password.
804
+ // Use existing email. Should succeed.
805
+ {
806
+ Credential email_cred = EmailAuthProvider::GetCredential (
807
+ user_login.email (), user_login.password ());
808
+ Future<SignInResult> sign_in_future =
809
+ auth->SignInAndRetrieveDataWithCredential (email_cred);
810
+ WaitForSignInFuture (sign_in_future,
811
+ " Auth::SignInAndRetrieveDataWithCredential "
812
+ " existing email" , kAuthErrorNone , auth);
813
+ ExpectTrue (" SignInAndRetrieveDataWithCredentialLastResult matches "
814
+ " returned Future" ,
815
+ sign_in_future ==
816
+ auth->SignInAndRetrieveDataWithCredentialLastResult ());
817
+ if (sign_in_future.error () == kAuthErrorNone ) {
818
+ const SignInResult* sign_in_result = sign_in_future.result ();
819
+ if (sign_in_result != nullptr && sign_in_result->user ) {
820
+ LogMessage (" SignInAndRetrieveDataWithCredential" );
821
+ LogSignInResult (*sign_in_result);
822
+ } else {
823
+ LogMessage (" ERROR: SignInAndRetrieveDataWithCredential returned no "
824
+ " result" );
825
+ }
826
+ }
827
+ }
828
+
672
829
// Use bad Facebook credentials. Should fail.
673
830
{
674
831
Credential facebook_cred_bad =
0 commit comments