1
1
//! Utilities to help writing tests.
2
2
//!
3
3
//! This private module is only compiled for test runs.
4
- use std:: collections:: { BTreeMap , HashSet } ;
4
+ use std:: collections:: { BTreeMap , BTreeSet , HashSet } ;
5
5
use std:: env:: current_dir;
6
6
use std:: fmt:: Write ;
7
7
use std:: ops:: { Deref , DerefMut } ;
@@ -70,67 +70,70 @@ static CONTEXT_NAMES: LazyLock<std::sync::RwLock<BTreeMap<u32, String>>> =
70
70
/// [`TestContext`]s without managing your own [`LogSink`].
71
71
pub struct TestContextManager {
72
72
log_sink : LogSink ,
73
+ used_names : BTreeSet < String > ,
73
74
}
74
75
75
76
impl TestContextManager {
76
77
pub fn new ( ) -> Self {
77
- let log_sink = LogSink :: new ( ) ;
78
- Self { log_sink }
78
+ Self {
79
+ log_sink : LogSink :: new ( ) ,
80
+ used_names : BTreeSet :: new ( ) ,
81
+ }
79
82
}
80
83
81
84
pub async fn alice ( & mut self ) -> TestContext {
82
85
TestContext :: builder ( )
83
86
. configure_alice ( )
84
87
. with_log_sink ( self . log_sink . clone ( ) )
85
- . build ( )
88
+ . build ( Some ( & mut self . used_names ) )
86
89
. await
87
90
}
88
91
89
92
pub async fn bob ( & mut self ) -> TestContext {
90
93
TestContext :: builder ( )
91
94
. configure_bob ( )
92
95
. with_log_sink ( self . log_sink . clone ( ) )
93
- . build ( )
96
+ . build ( Some ( & mut self . used_names ) )
94
97
. await
95
98
}
96
99
97
100
pub async fn charlie ( & mut self ) -> TestContext {
98
101
TestContext :: builder ( )
99
102
. configure_charlie ( )
100
103
. with_log_sink ( self . log_sink . clone ( ) )
101
- . build ( )
104
+ . build ( Some ( & mut self . used_names ) )
102
105
. await
103
106
}
104
107
105
108
pub async fn dom ( & mut self ) -> TestContext {
106
109
TestContext :: builder ( )
107
110
. configure_dom ( )
108
111
. with_log_sink ( self . log_sink . clone ( ) )
109
- . build ( )
112
+ . build ( Some ( & mut self . used_names ) )
110
113
. await
111
114
}
112
115
113
116
pub async fn elena ( & mut self ) -> TestContext {
114
117
TestContext :: builder ( )
115
118
. configure_elena ( )
116
119
. with_log_sink ( self . log_sink . clone ( ) )
117
- . build ( )
120
+ . build ( Some ( & mut self . used_names ) )
118
121
. await
119
122
}
120
123
121
124
pub async fn fiona ( & mut self ) -> TestContext {
122
125
TestContext :: builder ( )
123
126
. configure_fiona ( )
124
127
. with_log_sink ( self . log_sink . clone ( ) )
125
- . build ( )
128
+ . build ( Some ( & mut self . used_names ) )
126
129
. await
127
130
}
128
131
129
132
/// Creates a new unconfigured test account.
130
133
pub async fn unconfigured ( & mut self ) -> TestContext {
131
134
TestContext :: builder ( )
132
135
. with_log_sink ( self . log_sink . clone ( ) )
133
- . build ( )
136
+ . build ( Some ( & mut self . used_names ) )
134
137
. await
135
138
}
136
139
@@ -326,7 +329,7 @@ impl TestContextBuilder {
326
329
}
327
330
328
331
/// Builds the [`TestContext`].
329
- pub async fn build ( self ) -> TestContext {
332
+ pub async fn build ( self , used_names : Option < & mut BTreeSet < String > > ) -> TestContext {
330
333
if let Some ( key_pair) = self . key_pair {
331
334
let userid = {
332
335
let public_key = & key_pair. public ;
@@ -340,7 +343,19 @@ impl TestContextBuilder {
340
343
. addr ;
341
344
let name = EmailAddress :: new ( & addr) . unwrap ( ) . local ;
342
345
343
- let test_context = TestContext :: new_internal ( Some ( name) , self . log_sink ) . await ;
346
+ let mut unused_name = name. clone ( ) ;
347
+ if let Some ( used_names) = used_names {
348
+ assert ! ( used_names. len( ) < 100 ) ;
349
+ // If there are multiple Alices, call them 'alice', 'alice2', 'alice3', ...
350
+ let mut i = 1 ;
351
+ while used_names. contains ( & unused_name) {
352
+ i += 1 ;
353
+ unused_name = format ! ( "{name}{i}" ) ;
354
+ }
355
+ used_names. insert ( unused_name. clone ( ) ) ;
356
+ }
357
+
358
+ let test_context = TestContext :: new_internal ( Some ( unused_name) , self . log_sink ) . await ;
344
359
test_context. configure_addr ( & addr) . await ;
345
360
key:: store_self_keypair ( & test_context, & key_pair)
346
361
. await
@@ -394,21 +409,21 @@ impl TestContext {
394
409
///
395
410
/// This is a shortcut which configures [email protected] with a fixed key.
396
411
pub async fn new_alice ( ) -> Self {
397
- Self :: builder ( ) . configure_alice ( ) . build ( ) . await
412
+ Self :: builder ( ) . configure_alice ( ) . build ( None ) . await
398
413
}
399
414
400
415
/// Creates a new configured [`TestContext`].
401
416
///
402
417
/// This is a shortcut which configures [email protected] with a fixed key.
403
418
pub async fn new_bob ( ) -> Self {
404
- Self :: builder ( ) . configure_bob ( ) . build ( ) . await
419
+ Self :: builder ( ) . configure_bob ( ) . build ( None ) . await
405
420
}
406
421
407
422
/// Creates a new configured [`TestContext`].
408
423
///
409
424
/// This is a shortcut which configures [email protected] with a fixed key.
410
425
pub async fn new_fiona ( ) -> Self {
411
- Self :: builder ( ) . configure_fiona ( ) . build ( ) . await
426
+ Self :: builder ( ) . configure_fiona ( ) . build ( None ) . await
412
427
}
413
428
414
429
/// Print current chat state.
@@ -1585,14 +1600,14 @@ mod tests {
1585
1600
1586
1601
#[ tokio:: test( flavor = "multi_thread" , worker_threads = 2 ) ]
1587
1602
async fn test_with_alice ( ) {
1588
- let alice = TestContext :: builder ( ) . configure_alice ( ) . build ( ) . await ;
1603
+ let alice = TestContext :: builder ( ) . configure_alice ( ) . build ( None ) . await ;
1589
1604
alice. ctx . emit_event ( EventType :: Info ( "hello" . into ( ) ) ) ;
1590
1605
// panic!("Alice fails");
1591
1606
}
1592
1607
1593
1608
#[ tokio:: test( flavor = "multi_thread" , worker_threads = 2 ) ]
1594
1609
async fn test_with_bob ( ) {
1595
- let bob = TestContext :: builder ( ) . configure_bob ( ) . build ( ) . await ;
1610
+ let bob = TestContext :: builder ( ) . configure_bob ( ) . build ( None ) . await ;
1596
1611
bob. ctx . emit_event ( EventType :: Info ( "there" . into ( ) ) ) ;
1597
1612
// panic!("Bob fails");
1598
1613
}
0 commit comments