2
2
// Use of this source code is governed by a BSD-style license that can be
3
3
// found in the LICENSE file.
4
4
5
- import Flutter
6
5
import XCTest
7
6
8
7
@testable import local_auth_darwin
9
8
9
+ #if os(iOS)
10
+ import Flutter
11
+ #else
12
+ import FlutterMacOS
13
+ #endif
14
+
10
15
// Set a long timeout to avoid flake due to slow CI.
11
16
private let timeout : TimeInterval = 30.0
12
17
13
18
/// A context factory that returns preset contexts.
14
19
final class StubAuthContextFactory : NSObject , FLADAuthContextFactory {
20
+
15
21
var contexts : [ FLADAuthContext ]
16
22
init ( contexts: [ FLADAuthContext ] ) {
17
23
self . contexts = contexts
@@ -23,6 +29,74 @@ final class StubAuthContextFactory: NSObject, FLADAuthContextFactory {
23
29
}
24
30
}
25
31
32
+ final class StubViewProvider : NSObject , FLAViewProvider {
33
+ #if os(macOS)
34
+ var view : NSView
35
+ var window : NSWindow
36
+ override init ( ) {
37
+ self . window = NSWindow ( )
38
+ self . view = NSView ( )
39
+ self . window. contentView = self . view
40
+ }
41
+ #endif
42
+ }
43
+
44
+ #if os(macOS)
45
+ final class TestAlert : NSObject , FLANSAlert {
46
+ var messageText : String = " "
47
+ var buttons : [ String ] = [ ]
48
+ var presentingWindow : NSWindow ?
49
+
50
+ func addButton( withTitle title: String ) -> NSButton {
51
+ buttons. append ( title)
52
+ return NSButton ( ) // The return value is not used by the plugin.
53
+ }
54
+
55
+ func beginSheetModal( for sheetWindow: NSWindow ) async -> NSApplication . ModalResponse {
56
+ presentingWindow = sheetWindow
57
+ return NSApplication . ModalResponse. OK
58
+ }
59
+ }
60
+ #else
61
+ final class TestAlertController : NSObject , FLAUIAlertController {
62
+ var actions : [ UIAlertAction ] = [ ]
63
+ var presented = false
64
+ var presentingViewController : UIViewController ?
65
+
66
+ func add( _ action: UIAlertAction ) {
67
+ actions. append ( action)
68
+ }
69
+
70
+ func present(
71
+ on presentingViewController: UIViewController , animated flag: Bool ,
72
+ completion: ( ( ) -> Void ) ? = nil
73
+ ) {
74
+ presented = true
75
+ self . presentingViewController = presentingViewController
76
+ }
77
+ }
78
+ #endif
79
+
80
+ final class StubAlertFactory : NSObject , FLADAlertFactory {
81
+ #if os(macOS)
82
+ var alert : TestAlert = TestAlert ( )
83
+ #else
84
+ var alertController : TestAlertController = TestAlertController ( )
85
+ #endif
86
+
87
+ #if os(macOS)
88
+ func createAlert( ) -> FLANSAlert {
89
+ return self . alert
90
+ }
91
+ #else
92
+ func createAlertController(
93
+ withTitle title: String ? , message: String ? , preferredStyle: UIAlertController . Style
94
+ ) -> FLAUIAlertController {
95
+ return self . alertController
96
+ }
97
+ #endif
98
+ }
99
+
26
100
final class StubAuthContext : NSObject , FLADAuthContext {
27
101
/// Whether calls to this stub are expected to be for biometric authentication.
28
102
///
@@ -75,8 +149,12 @@ class FLALocalAuthPluginTests: XCTestCase {
75
149
76
150
func testSuccessfullAuthWithBiometrics( ) throws {
77
151
let stubAuthContext = StubAuthContext ( )
152
+ let alertFactory = StubAlertFactory ( )
153
+ let viewProvider = StubViewProvider ( )
78
154
let plugin = FLALocalAuthPlugin (
79
- contextFactory: StubAuthContextFactory ( contexts: [ stubAuthContext] ) )
155
+ contextFactory: StubAuthContextFactory ( contexts: [ stubAuthContext] ) ,
156
+ alertFactory: alertFactory, viewProvider: viewProvider
157
+ )
80
158
81
159
let strings = createAuthStrings ( )
82
160
stubAuthContext. expectBiometrics = true
@@ -99,8 +177,12 @@ class FLALocalAuthPluginTests: XCTestCase {
99
177
100
178
func testSuccessfullAuthWithoutBiometrics( ) {
101
179
let stubAuthContext = StubAuthContext ( )
180
+ let alertFactory = StubAlertFactory ( )
181
+ let viewProvider = StubViewProvider ( )
182
+
102
183
let plugin = FLALocalAuthPlugin (
103
- contextFactory: StubAuthContextFactory ( contexts: [ stubAuthContext] ) )
184
+ contextFactory: StubAuthContextFactory ( contexts: [ stubAuthContext] ) ,
185
+ alertFactory: alertFactory, viewProvider: viewProvider)
104
186
105
187
let strings = createAuthStrings ( )
106
188
stubAuthContext. evaluateResponse = true
@@ -123,8 +205,11 @@ class FLALocalAuthPluginTests: XCTestCase {
123
205
124
206
func testFailedAuthWithBiometrics( ) {
125
207
let stubAuthContext = StubAuthContext ( )
208
+ let alertFactory = StubAlertFactory ( )
209
+ let viewProvider = StubViewProvider ( )
126
210
let plugin = FLALocalAuthPlugin (
127
- contextFactory: StubAuthContextFactory ( contexts: [ stubAuthContext] ) )
211
+ contextFactory: StubAuthContextFactory ( contexts: [ stubAuthContext] ) ,
212
+ alertFactory: alertFactory, viewProvider: viewProvider)
128
213
129
214
let strings = createAuthStrings ( )
130
215
stubAuthContext. expectBiometrics = true
@@ -153,8 +238,11 @@ class FLALocalAuthPluginTests: XCTestCase {
153
238
154
239
func testFailedWithUnknownErrorCode( ) {
155
240
let stubAuthContext = StubAuthContext ( )
241
+ let alertFactory = StubAlertFactory ( )
242
+ let viewProvider = StubViewProvider ( )
156
243
let plugin = FLALocalAuthPlugin (
157
- contextFactory: StubAuthContextFactory ( contexts: [ stubAuthContext] ) )
244
+ contextFactory: StubAuthContextFactory ( contexts: [ stubAuthContext] ) ,
245
+ alertFactory: alertFactory, viewProvider: viewProvider)
158
246
159
247
let strings = createAuthStrings ( )
160
248
stubAuthContext. evaluateError = NSError ( domain: " error " , code: 99 )
@@ -177,8 +265,11 @@ class FLALocalAuthPluginTests: XCTestCase {
177
265
178
266
func testSystemCancelledWithoutStickyAuth( ) {
179
267
let stubAuthContext = StubAuthContext ( )
268
+ let alertFactory = StubAlertFactory ( )
269
+ let viewProvider = StubViewProvider ( )
180
270
let plugin = FLALocalAuthPlugin (
181
- contextFactory: StubAuthContextFactory ( contexts: [ stubAuthContext] ) )
271
+ contextFactory: StubAuthContextFactory ( contexts: [ stubAuthContext] ) ,
272
+ alertFactory: alertFactory, viewProvider: viewProvider)
182
273
183
274
let strings = createAuthStrings ( )
184
275
stubAuthContext. evaluateError = NSError ( domain: " error " , code: LAError . systemCancel. rawValue)
@@ -201,8 +292,11 @@ class FLALocalAuthPluginTests: XCTestCase {
201
292
202
293
func testFailedAuthWithoutBiometrics( ) {
203
294
let stubAuthContext = StubAuthContext ( )
295
+ let alertFactory = StubAlertFactory ( )
296
+ let viewProvider = StubViewProvider ( )
204
297
let plugin = FLALocalAuthPlugin (
205
- contextFactory: StubAuthContextFactory ( contexts: [ stubAuthContext] ) )
298
+ contextFactory: StubAuthContextFactory ( contexts: [ stubAuthContext] ) ,
299
+ alertFactory: alertFactory, viewProvider: viewProvider)
206
300
207
301
let strings = createAuthStrings ( )
208
302
stubAuthContext. evaluateError = NSError (
@@ -228,10 +322,50 @@ class FLALocalAuthPluginTests: XCTestCase {
228
322
self . waitForExpectations ( timeout: timeout)
229
323
}
230
324
325
+ func testFailedAuthShowsAlert( ) {
326
+ let stubAuthContext = StubAuthContext ( )
327
+ let alertFactory = StubAlertFactory ( )
328
+ let viewProvider = StubViewProvider ( )
329
+ let plugin = FLALocalAuthPlugin (
330
+ contextFactory: StubAuthContextFactory ( contexts: [ stubAuthContext] ) ,
331
+ alertFactory: alertFactory, viewProvider: viewProvider)
332
+
333
+ let strings = createAuthStrings ( )
334
+ stubAuthContext. canEvaluateError = NSError (
335
+ domain: " error " , code: LAError . biometryNotEnrolled. rawValue)
336
+
337
+ #if os(macOS)
338
+ let expectation = expectation ( description: " Result is called " )
339
+ #endif
340
+ plugin. authenticate (
341
+ with: FLADAuthOptions . make (
342
+ withBiometricOnly: false ,
343
+ sticky: false ,
344
+ useErrorDialogs: true ) ,
345
+ strings: strings
346
+ ) { resultDetails, error in
347
+ // TODO(stuartmorgan): Add a wrapper around UIAction to allow accessing the handler, so
348
+ // that the test can trigger the callback on iOS as well, and then unfork this.
349
+ #if os(macOS)
350
+ expectation. fulfill ( )
351
+ #endif
352
+ }
353
+ #if os(macOS)
354
+ self . waitForExpectations ( timeout: timeout)
355
+ XCTAssertEqual ( alertFactory. alert. presentingWindow, viewProvider. view. window)
356
+ #else
357
+ XCTAssertTrue ( alertFactory. alertController. presented)
358
+ XCTAssertEqual ( alertFactory. alertController. actions. count, 2 )
359
+ #endif
360
+ }
361
+
231
362
func testLocalizedFallbackTitle( ) {
232
363
let stubAuthContext = StubAuthContext ( )
364
+ let alertFactory = StubAlertFactory ( )
365
+ let viewProvider = StubViewProvider ( )
233
366
let plugin = FLALocalAuthPlugin (
234
- contextFactory: StubAuthContextFactory ( contexts: [ stubAuthContext] ) )
367
+ contextFactory: StubAuthContextFactory ( contexts: [ stubAuthContext] ) ,
368
+ alertFactory: alertFactory, viewProvider: viewProvider)
235
369
236
370
let strings = createAuthStrings ( )
237
371
strings. localizedFallbackTitle = " a title "
@@ -255,8 +389,11 @@ class FLALocalAuthPluginTests: XCTestCase {
255
389
256
390
func testSkippedLocalizedFallbackTitle( ) {
257
391
let stubAuthContext = StubAuthContext ( )
392
+ let alertFactory = StubAlertFactory ( )
393
+ let viewProvider = StubViewProvider ( )
258
394
let plugin = FLALocalAuthPlugin (
259
- contextFactory: StubAuthContextFactory ( contexts: [ stubAuthContext] ) )
395
+ contextFactory: StubAuthContextFactory ( contexts: [ stubAuthContext] ) ,
396
+ alertFactory: alertFactory, viewProvider: viewProvider)
260
397
261
398
let strings = createAuthStrings ( )
262
399
strings. localizedFallbackTitle = nil
@@ -278,8 +415,11 @@ class FLALocalAuthPluginTests: XCTestCase {
278
415
279
416
func testDeviceSupportsBiometrics_withEnrolledHardware( ) {
280
417
let stubAuthContext = StubAuthContext ( )
418
+ let alertFactory = StubAlertFactory ( )
419
+ let viewProvider = StubViewProvider ( )
281
420
let plugin = FLALocalAuthPlugin (
282
- contextFactory: StubAuthContextFactory ( contexts: [ stubAuthContext] ) )
421
+ contextFactory: StubAuthContextFactory ( contexts: [ stubAuthContext] ) ,
422
+ alertFactory: alertFactory, viewProvider: viewProvider)
283
423
284
424
stubAuthContext. expectBiometrics = true
285
425
@@ -291,8 +431,11 @@ class FLALocalAuthPluginTests: XCTestCase {
291
431
292
432
func testDeviceSupportsBiometrics_withNonEnrolledHardware( ) {
293
433
let stubAuthContext = StubAuthContext ( )
434
+ let alertFactory = StubAlertFactory ( )
435
+ let viewProvider = StubViewProvider ( )
294
436
let plugin = FLALocalAuthPlugin (
295
- contextFactory: StubAuthContextFactory ( contexts: [ stubAuthContext] ) )
437
+ contextFactory: StubAuthContextFactory ( contexts: [ stubAuthContext] ) ,
438
+ alertFactory: alertFactory, viewProvider: viewProvider)
296
439
297
440
stubAuthContext. expectBiometrics = true
298
441
stubAuthContext. canEvaluateError = NSError (
@@ -306,8 +449,11 @@ class FLALocalAuthPluginTests: XCTestCase {
306
449
307
450
func testDeviceSupportsBiometrics_withNoBiometricHardware( ) {
308
451
let stubAuthContext = StubAuthContext ( )
452
+ let alertFactory = StubAlertFactory ( )
453
+ let viewProvider = StubViewProvider ( )
309
454
let plugin = FLALocalAuthPlugin (
310
- contextFactory: StubAuthContextFactory ( contexts: [ stubAuthContext] ) )
455
+ contextFactory: StubAuthContextFactory ( contexts: [ stubAuthContext] ) ,
456
+ alertFactory: alertFactory, viewProvider: viewProvider)
311
457
312
458
stubAuthContext. expectBiometrics = true
313
459
stubAuthContext. canEvaluateError = NSError ( domain: " error " , code: 0 )
@@ -320,11 +466,17 @@ class FLALocalAuthPluginTests: XCTestCase {
320
466
321
467
func testGetEnrolledBiometricsWithFaceID( ) {
322
468
let stubAuthContext = StubAuthContext ( )
469
+ let alertFactory = StubAlertFactory ( )
470
+ let viewProvider = StubViewProvider ( )
323
471
let plugin = FLALocalAuthPlugin (
324
- contextFactory: StubAuthContextFactory ( contexts: [ stubAuthContext] ) )
472
+ contextFactory: StubAuthContextFactory ( contexts: [ stubAuthContext] ) ,
473
+ alertFactory: alertFactory, viewProvider: viewProvider)
325
474
326
475
stubAuthContext. expectBiometrics = true
327
- stubAuthContext. biometryType = . faceID
476
+ if #available( iOS 11 , macOS 10 . 15 , * ) {
477
+ stubAuthContext. biometryType = . faceID
478
+
479
+ }
328
480
329
481
var error : FlutterError ?
330
482
let result = plugin. getEnrolledBiometricsWithError ( & error)
@@ -335,8 +487,11 @@ class FLALocalAuthPluginTests: XCTestCase {
335
487
336
488
func testGetEnrolledBiometricsWithTouchID( ) {
337
489
let stubAuthContext = StubAuthContext ( )
490
+ let alertFactory = StubAlertFactory ( )
491
+ let viewProvider = StubViewProvider ( )
338
492
let plugin = FLALocalAuthPlugin (
339
- contextFactory: StubAuthContextFactory ( contexts: [ stubAuthContext] ) )
493
+ contextFactory: StubAuthContextFactory ( contexts: [ stubAuthContext] ) ,
494
+ alertFactory: alertFactory, viewProvider: viewProvider)
340
495
341
496
stubAuthContext. expectBiometrics = true
342
497
stubAuthContext. biometryType = . touchID
@@ -350,8 +505,11 @@ class FLALocalAuthPluginTests: XCTestCase {
350
505
351
506
func testGetEnrolledBiometricsWithoutEnrolledHardware( ) {
352
507
let stubAuthContext = StubAuthContext ( )
508
+ let alertFactory = StubAlertFactory ( )
509
+ let viewProvider = StubViewProvider ( )
353
510
let plugin = FLALocalAuthPlugin (
354
- contextFactory: StubAuthContextFactory ( contexts: [ stubAuthContext] ) )
511
+ contextFactory: StubAuthContextFactory ( contexts: [ stubAuthContext] ) ,
512
+ alertFactory: alertFactory, viewProvider: viewProvider)
355
513
356
514
stubAuthContext. expectBiometrics = true
357
515
stubAuthContext. canEvaluateError = NSError (
@@ -365,8 +523,11 @@ class FLALocalAuthPluginTests: XCTestCase {
365
523
366
524
func testIsDeviceSupportedHandlesSupported( ) {
367
525
let stubAuthContext = StubAuthContext ( )
526
+ let alertFactory = StubAlertFactory ( )
527
+ let viewProvider = StubViewProvider ( )
368
528
let plugin = FLALocalAuthPlugin (
369
- contextFactory: StubAuthContextFactory ( contexts: [ stubAuthContext] ) )
529
+ contextFactory: StubAuthContextFactory ( contexts: [ stubAuthContext] ) ,
530
+ alertFactory: alertFactory, viewProvider: viewProvider)
370
531
371
532
var error : FlutterError ?
372
533
let result = plugin. isDeviceSupportedWithError ( & error)
@@ -378,8 +539,11 @@ class FLALocalAuthPluginTests: XCTestCase {
378
539
let stubAuthContext = StubAuthContext ( )
379
540
// An arbitrary error to cause canEvaluatePolicy to return false.
380
541
stubAuthContext. canEvaluateError = NSError ( domain: " error " , code: 1 )
542
+ let alertFactory = StubAlertFactory ( )
543
+ let viewProvider = StubViewProvider ( )
381
544
let plugin = FLALocalAuthPlugin (
382
- contextFactory: StubAuthContextFactory ( contexts: [ stubAuthContext] ) )
545
+ contextFactory: StubAuthContextFactory ( contexts: [ stubAuthContext] ) ,
546
+ alertFactory: alertFactory, viewProvider: viewProvider)
383
547
384
548
var error : FlutterError ?
385
549
let result = plugin. isDeviceSupportedWithError ( & error)
0 commit comments