@@ -668,6 +668,81 @@ public async Task RemoveClaimCallsStore()
668668 store . VerifyAll ( ) ;
669669 }
670670
671+ [ Fact ]
672+ public async Task SetPasskeyAsyncCallsStore ( )
673+ {
674+ // Setup
675+ var store = new Mock < IUserPasskeyStore < PocoUser > > ( ) ;
676+ var user = new PocoUser { UserName = "Foo" } ;
677+ var passkey = new UserPasskeyInfo ( null , null , null , default , 0 , null , false , false , false , null , null ) ;
678+ store . Setup ( s => s . SetPasskeyAsync ( user , passkey , CancellationToken . None ) ) . Returns ( Task . CompletedTask ) . Verifiable ( ) ;
679+ store . Setup ( s => s . UpdateAsync ( user , CancellationToken . None ) ) . ReturnsAsync ( IdentityResult . Success ) . Verifiable ( ) ;
680+ var userManager = MockHelpers . TestUserManager < PocoUser > ( store . Object ) ;
681+
682+ // Act
683+ var result = await userManager . SetPasskeyAsync ( user , passkey ) ;
684+
685+ // Assert
686+ Assert . True ( result . Succeeded ) ;
687+ store . VerifyAll ( ) ;
688+ }
689+
690+ [ Fact ]
691+ public async Task GetPasskeysAsyncCallsStore ( )
692+ {
693+ // Setup
694+ var store = new Mock < IUserPasskeyStore < PocoUser > > ( ) ;
695+ var user = new PocoUser { UserName = "Foo" } ;
696+ var passkey = new UserPasskeyInfo ( null , null , null , default , 0 , null , false , false , false , null , null ) ;
697+ var passkeys = ( IList < UserPasskeyInfo > ) [ passkey ] ;
698+ store . Setup ( s => s . GetPasskeysAsync ( user , CancellationToken . None ) ) . Returns ( Task . FromResult ( passkeys ) ) . Verifiable ( ) ;
699+ var userManager = MockHelpers . TestUserManager < PocoUser > ( store . Object ) ;
700+
701+ // Act
702+ var result = await userManager . GetPasskeysAsync ( user ) ;
703+
704+ // Assert
705+ Assert . Same ( passkeys , result ) ;
706+ store . VerifyAll ( ) ;
707+ }
708+
709+ [ Fact ]
710+ public async Task FindByPasskeyIdCallsStore ( )
711+ {
712+ // Setup
713+ var store = new Mock < IUserPasskeyStore < PocoUser > > ( ) ;
714+ var user = new PocoUser { UserName = "Foo" } ;
715+ var credentialId = ( byte [ ] ) [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 ] ;
716+ store . Setup ( s => s . FindByPasskeyIdAsync ( credentialId , CancellationToken . None ) ) . Returns ( Task . FromResult ( user ) ) . Verifiable ( ) ;
717+ var userManager = MockHelpers . TestUserManager < PocoUser > ( store . Object ) ;
718+
719+ // Act
720+ var result = await userManager . FindByPasskeyIdAsync ( credentialId ) ;
721+
722+ // Assert
723+ Assert . Equal ( user , result ) ;
724+ store . VerifyAll ( ) ;
725+ }
726+
727+ [ Fact ]
728+ public async Task RemovePasskeyAsyncCallsStore ( )
729+ {
730+ // Setup
731+ var store = new Mock < IUserPasskeyStore < PocoUser > > ( ) ;
732+ var user = new PocoUser { UserName = "Foo" } ;
733+ var credentialId = ( byte [ ] ) [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 ] ;
734+ store . Setup ( s => s . RemovePasskeyAsync ( user , credentialId , CancellationToken . None ) ) . Returns ( Task . CompletedTask ) . Verifiable ( ) ;
735+ store . Setup ( s => s . UpdateAsync ( user , CancellationToken . None ) ) . ReturnsAsync ( IdentityResult . Success ) . Verifiable ( ) ;
736+ var userManager = MockHelpers . TestUserManager < PocoUser > ( store . Object ) ;
737+
738+ // Act
739+ var result = await userManager . RemovePasskeyAsync ( user , credentialId ) ;
740+
741+ // Assert
742+ Assert . True ( result . Succeeded ) ;
743+ store . VerifyAll ( ) ;
744+ }
745+
671746 [ Fact ]
672747 public async Task CheckPasswordWithNullUserReturnsFalse ( )
673748 {
@@ -1040,6 +1115,10 @@ await Assert.ThrowsAsync<ArgumentNullException>("providerKey",
10401115 Assert . Throws < ArgumentNullException > ( "provider" , ( ) => manager . RegisterTokenProvider ( "whatever" , null ) ) ;
10411116 await Assert . ThrowsAsync < ArgumentNullException > ( "roles" , async ( ) => await manager . AddToRolesAsync ( new PocoUser ( ) , null ) ) ;
10421117 await Assert . ThrowsAsync < ArgumentNullException > ( "roles" , async ( ) => await manager . RemoveFromRolesAsync ( new PocoUser ( ) , null ) ) ;
1118+ await Assert . ThrowsAsync < ArgumentNullException > ( "passkey" , async ( ) => await manager . SetPasskeyAsync ( new PocoUser ( ) , null ) ) ;
1119+ await Assert . ThrowsAsync < ArgumentNullException > ( "credentialId" , async ( ) => await manager . GetPasskeyAsync ( new PocoUser ( ) , null ) ) ;
1120+ await Assert . ThrowsAsync < ArgumentNullException > ( "credentialId" , async ( ) => await manager . FindByPasskeyIdAsync ( null ) ) ;
1121+ await Assert . ThrowsAsync < ArgumentNullException > ( "credentialId" , async ( ) => await manager . RemovePasskeyAsync ( new PocoUser ( ) , null ) ) ;
10431122 }
10441123
10451124 [ Fact ]
@@ -1141,6 +1220,14 @@ await Assert.ThrowsAsync<ArgumentNullException>("user",
11411220 async ( ) => await manager . GetLockoutEndDateAsync ( null ) ) ;
11421221 await Assert . ThrowsAsync < ArgumentNullException > ( "user" ,
11431222 async ( ) => await manager . IsLockedOutAsync ( null ) ) ;
1223+ await Assert . ThrowsAsync < ArgumentNullException > ( "user" ,
1224+ async ( ) => await manager . SetPasskeyAsync ( null , null ) ) ;
1225+ await Assert . ThrowsAsync < ArgumentNullException > ( "user" ,
1226+ async ( ) => await manager . GetPasskeysAsync ( null ) ) ;
1227+ await Assert . ThrowsAsync < ArgumentNullException > ( "user" ,
1228+ async ( ) => await manager . GetPasskeyAsync ( null , null ) ) ;
1229+ await Assert . ThrowsAsync < ArgumentNullException > ( "user" ,
1230+ async ( ) => await manager . RemovePasskeyAsync ( null , null ) ) ;
11441231 }
11451232
11461233 [ Fact ]
@@ -1180,6 +1267,11 @@ public async Task MethodsThrowWhenDisposedTest()
11801267 await Assert . ThrowsAsync < ObjectDisposedException > ( ( ) => manager . GenerateEmailConfirmationTokenAsync ( null ) ) ;
11811268 await Assert . ThrowsAsync < ObjectDisposedException > ( ( ) => manager . IsEmailConfirmedAsync ( null ) ) ;
11821269 await Assert . ThrowsAsync < ObjectDisposedException > ( ( ) => manager . ConfirmEmailAsync ( null , null ) ) ;
1270+ await Assert . ThrowsAsync < ObjectDisposedException > ( ( ) => manager . SetPasskeyAsync ( null , null ) ) ;
1271+ await Assert . ThrowsAsync < ObjectDisposedException > ( ( ) => manager . GetPasskeysAsync ( null ) ) ;
1272+ await Assert . ThrowsAsync < ObjectDisposedException > ( ( ) => manager . GetPasskeyAsync ( null , null ) ) ;
1273+ await Assert . ThrowsAsync < ObjectDisposedException > ( ( ) => manager . FindByPasskeyIdAsync ( null ) ) ;
1274+ await Assert . ThrowsAsync < ObjectDisposedException > ( ( ) => manager . RemovePasskeyAsync ( null , null ) ) ;
11831275 }
11841276
11851277 private class BadPasswordValidator < TUser > : IPasswordValidator < TUser > where TUser : class
@@ -1213,7 +1305,8 @@ private class EmptyStore :
12131305 IUserLockoutStore < PocoUser > ,
12141306 IUserTwoFactorStore < PocoUser > ,
12151307 IUserRoleStore < PocoUser > ,
1216- IUserSecurityStampStore < PocoUser >
1308+ IUserSecurityStampStore < PocoUser > ,
1309+ IUserPasskeyStore < PocoUser >
12171310 {
12181311 public Task < IList < Claim > > GetClaimsAsync ( PocoUser user , CancellationToken cancellationToken = default ( CancellationToken ) )
12191312 {
@@ -1463,6 +1556,31 @@ public void Dispose()
14631556 {
14641557 return Task . FromResult ( 0 ) ;
14651558 }
1559+
1560+ public Task SetPasskeyAsync ( PocoUser user , UserPasskeyInfo passkey , CancellationToken cancellationToken )
1561+ {
1562+ return Task . CompletedTask ;
1563+ }
1564+
1565+ public Task < IList < UserPasskeyInfo > > GetPasskeysAsync ( PocoUser user , CancellationToken cancellationToken )
1566+ {
1567+ return Task . FromResult < IList < UserPasskeyInfo > > ( [ ] ) ;
1568+ }
1569+
1570+ public Task < PocoUser > FindByPasskeyIdAsync ( byte [ ] credentialId , CancellationToken cancellationToken )
1571+ {
1572+ return Task . FromResult < PocoUser > ( null ) ;
1573+ }
1574+
1575+ public Task < UserPasskeyInfo > FindPasskeyAsync ( PocoUser user , byte [ ] credentialId , CancellationToken cancellationToken )
1576+ {
1577+ return Task . FromResult < UserPasskeyInfo > ( null ) ;
1578+ }
1579+
1580+ public Task RemovePasskeyAsync ( PocoUser user , byte [ ] credentialId , CancellationToken cancellationToken )
1581+ {
1582+ return Task . CompletedTask ;
1583+ }
14661584 }
14671585
14681586 private class NoOpTokenProvider : IUserTwoFactorTokenProvider < PocoUser >
@@ -1493,7 +1611,8 @@ private class NotImplementedStore :
14931611 IUserEmailStore < PocoUser > ,
14941612 IUserPhoneNumberStore < PocoUser > ,
14951613 IUserLockoutStore < PocoUser > ,
1496- IUserTwoFactorStore < PocoUser >
1614+ IUserTwoFactorStore < PocoUser > ,
1615+ IUserPasskeyStore < PocoUser >
14971616 {
14981617 public Task < IList < Claim > > GetClaimsAsync ( PocoUser user , CancellationToken cancellationToken = default ( CancellationToken ) )
14991618 {
@@ -1734,6 +1853,31 @@ Task<IdentityResult> IUserStore<PocoUser>.DeleteAsync(PocoUser user, Cancellatio
17341853 {
17351854 throw new NotImplementedException ( ) ;
17361855 }
1856+
1857+ public Task SetPasskeyAsync ( PocoUser user , UserPasskeyInfo passkey , CancellationToken cancellationToken )
1858+ {
1859+ throw new NotImplementedException ( ) ;
1860+ }
1861+
1862+ public Task < IList < UserPasskeyInfo > > GetPasskeysAsync ( PocoUser user , CancellationToken cancellationToken )
1863+ {
1864+ throw new NotImplementedException ( ) ;
1865+ }
1866+
1867+ public Task < PocoUser > FindByPasskeyIdAsync ( byte [ ] credentialId , CancellationToken cancellationToken )
1868+ {
1869+ throw new NotImplementedException ( ) ;
1870+ }
1871+
1872+ public Task < UserPasskeyInfo > FindPasskeyAsync ( PocoUser user , byte [ ] credentialId , CancellationToken cancellationToken )
1873+ {
1874+ throw new NotImplementedException ( ) ;
1875+ }
1876+
1877+ public Task RemovePasskeyAsync ( PocoUser user , byte [ ] credentialId , CancellationToken cancellationToken )
1878+ {
1879+ throw new NotImplementedException ( ) ;
1880+ }
17371881 }
17381882
17391883 [ Fact ]
0 commit comments