Test shutdown without closing handles

Add some test cases that shut down and restart without explicitly
closing handles, and check that the handles are properly invalidated.
diff --git a/tests/psa_helpers.function b/tests/psa_helpers.function
index 2205500..edaea80 100644
--- a/tests/psa_helpers.function
+++ b/tests/psa_helpers.function
@@ -32,7 +32,7 @@
  */
 #define PSA_ASSERT( expr ) TEST_EQUAL( ( expr ), PSA_SUCCESS )
 
-static void test_helper_psa_done( int line, const char *file )
+static int test_helper_is_psa_pristine( int line, const char *file )
 {
     mbedtls_psa_stats_t stats;
     const char *msg = NULL;
@@ -48,12 +48,28 @@
     else if( stats.half_filled_slots != 0 )
         msg = "A half-filled slot has not been cleared properly.";
 
-    /* If the test failed, don't overwrite the failure information.
-     * Do keep the stats lookup above, because it can be convenient to
-     * break on it when debugging a failure. */
+    /* If the test has already failed, don't overwrite the failure
+     * information. Do keep the stats lookup above, because it can be
+     * convenient to break on it when debugging a failure. */
     if( msg != NULL && test_info.failed == 0 )
         test_fail( msg, line, file );
 
+    return( msg == NULL );
+}
+
+/** Check that no PSA slots are in use.
+ */
+#define ASSERT_PSA_PRISTINE( )                                    \
+    do                                                            \
+    {                                                             \
+        if( ! test_helper_is_psa_pristine( __LINE__, __FILE__ ) ) \
+            goto exit;                                            \
+    }                                                             \
+    while( 0 )
+
+static void test_helper_psa_done( int line, const char *file )
+{
+    (void) test_helper_is_psa_pristine( line, file );
     mbedtls_psa_crypto_free( );
 }
 
diff --git a/tests/suites/test_suite_psa_crypto_slot_management.data b/tests/suites/test_suite_psa_crypto_slot_management.data
index e65befe..233b166 100644
--- a/tests/suites/test_suite_psa_crypto_slot_management.data
+++ b/tests/suites/test_suite_psa_crypto_slot_management.data
@@ -1,19 +1,31 @@
 Transient slot, check after closing
 transient_slot_lifecycle:0:0:PSA_KEY_TYPE_RAW_DATA:"0123456789abcdef0123456789abcdef":CLOSE_BY_CLOSE
 
+Transient slot, check after closing and restarting
+transient_slot_lifecycle:0:0:PSA_KEY_TYPE_RAW_DATA:"0123456789abcdef0123456789abcdef":CLOSE_BY_CLOSE_WITH_SHUTDOWN
+
 Transient slot, check after destroying
 transient_slot_lifecycle:0:0:PSA_KEY_TYPE_RAW_DATA:"0123456789abcdef0123456789abcdef":CLOSE_BY_DESTROY
 
-Transient slot, check after restart
+Transient slot, check after destroying and restarting
+transient_slot_lifecycle:0:0:PSA_KEY_TYPE_RAW_DATA:"0123456789abcdef0123456789abcdef":CLOSE_BY_DESTROY_WITH_SHUTDOWN
+
+Transient slot, check after restart with live handles
 transient_slot_lifecycle:0:0:PSA_KEY_TYPE_RAW_DATA:"0123456789abcdef0123456789abcdef":CLOSE_BY_SHUTDOWN
 
 Persistent slot, check after closing, id=min
 persistent_slot_lifecycle:PSA_KEY_LIFETIME_PERSISTENT:PSA_KEY_ID_USER_MIN:0:0:0:PSA_KEY_TYPE_RAW_DATA:"0123456789abcdef0123456789abcdef":CLOSE_BY_CLOSE
 
+Persistent slot, check after closing and restarting, id=min
+persistent_slot_lifecycle:PSA_KEY_LIFETIME_PERSISTENT:PSA_KEY_ID_USER_MIN:0:0:0:PSA_KEY_TYPE_RAW_DATA:"0123456789abcdef0123456789abcdef":CLOSE_BY_CLOSE
+
 Persistent slot, check after destroying, id=min
 persistent_slot_lifecycle:PSA_KEY_LIFETIME_PERSISTENT:PSA_KEY_ID_USER_MIN:0:0:0:PSA_KEY_TYPE_RAW_DATA:"0123456789abcdef0123456789abcdef":CLOSE_BY_DESTROY
 
-Persistent slot, check after restart, id=min
+Persistent slot, check after destroying and restarting, id=min
+persistent_slot_lifecycle:PSA_KEY_LIFETIME_PERSISTENT:PSA_KEY_ID_USER_MIN:0:0:0:PSA_KEY_TYPE_RAW_DATA:"0123456789abcdef0123456789abcdef":CLOSE_BY_DESTROY
+
+Persistent slot, check after restart with live handle, id=min
 persistent_slot_lifecycle:PSA_KEY_LIFETIME_PERSISTENT:PSA_KEY_ID_USER_MIN:0:0:0:PSA_KEY_TYPE_RAW_DATA:"0123456789abcdef0123456789abcdef":CLOSE_BY_SHUTDOWN
 
 Persistent slot, check after closing, id=max
@@ -29,6 +41,10 @@
 depends_on:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED
 persistent_slot_lifecycle:PSA_KEY_LIFETIME_PERSISTENT:1:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN | PSA_KEY_USAGE_VERIFY:PSA_ALG_ECDSA_ANY:0:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_CURVE_SECP256R1):"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":CLOSE_BY_CLOSE
 
+Persistent slot: ECP keypair (ECDSA, exportable); close+restart
+depends_on:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED
+persistent_slot_lifecycle:PSA_KEY_LIFETIME_PERSISTENT:1:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN | PSA_KEY_USAGE_VERIFY:PSA_ALG_ECDSA_ANY:0:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_CURVE_SECP256R1):"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":CLOSE_BY_CLOSE_WITH_SHUTDOWN
+
 Persistent slot: ECP keypair (ECDSA, exportable); restart
 depends_on:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED
 persistent_slot_lifecycle:PSA_KEY_LIFETIME_PERSISTENT:1:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN | PSA_KEY_USAGE_VERIFY:PSA_ALG_ECDSA_ANY:0:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_CURVE_SECP256R1):"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":CLOSE_BY_SHUTDOWN
@@ -37,6 +53,10 @@
 depends_on:MBEDTLS_ECDH_C:MBEDTLS_SHA256_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED
 persistent_slot_lifecycle:PSA_KEY_LIFETIME_PERSISTENT:1:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN | PSA_KEY_USAGE_VERIFY:PSA_ALG_KEY_AGREEMENT(PSA_ALG_ECDH, PSA_ALG_HKDF(PSA_ALG_SHA_256)):PSA_ALG_ECDSA_ANY:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_CURVE_SECP256R1):"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":CLOSE_BY_CLOSE
 
+Persistent slot: ECP keypair (ECDH+ECDSA, exportable); close+restart
+depends_on:MBEDTLS_ECDH_C:MBEDTLS_SHA256_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED
+persistent_slot_lifecycle:PSA_KEY_LIFETIME_PERSISTENT:1:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN | PSA_KEY_USAGE_VERIFY:PSA_ALG_KEY_AGREEMENT(PSA_ALG_ECDH, PSA_ALG_HKDF(PSA_ALG_SHA_256)):PSA_ALG_ECDSA_ANY:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_CURVE_SECP256R1):"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":CLOSE_BY_CLOSE_WITH_SHUTDOWN
+
 Persistent slot: ECP keypair (ECDH+ECDSA, exportable); restart
 depends_on:MBEDTLS_ECDH_C:MBEDTLS_SHA256_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED
 persistent_slot_lifecycle:PSA_KEY_LIFETIME_PERSISTENT:1:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN | PSA_KEY_USAGE_VERIFY:PSA_ALG_KEY_AGREEMENT(PSA_ALG_ECDH, PSA_ALG_HKDF(PSA_ALG_SHA_256)):PSA_ALG_ECDSA_ANY:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_CURVE_SECP256R1):"49c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eee":CLOSE_BY_SHUTDOWN
diff --git a/tests/suites/test_suite_psa_crypto_slot_management.function b/tests/suites/test_suite_psa_crypto_slot_management.function
index 589d1ec..da93bc8 100644
--- a/tests/suites/test_suite_psa_crypto_slot_management.function
+++ b/tests/suites/test_suite_psa_crypto_slot_management.function
@@ -6,9 +6,11 @@
 
 typedef enum
 {
-    CLOSE_BY_CLOSE,
-    CLOSE_BY_DESTROY,
-    CLOSE_BY_SHUTDOWN,
+    CLOSE_BY_CLOSE, /**< Close the handle(s). */
+    CLOSE_BY_DESTROY, /**< Destroy the handle(s). */
+    CLOSE_BY_SHUTDOWN, /**< Deinit and reinit without closing handles. */
+    CLOSE_BY_CLOSE_WITH_SHUTDOWN, /**< Close handle(s) then deinit/reinit. */
+    CLOSE_BY_DESTROY_WITH_SHUTDOWN, /**< Destroy handle(s) then deinit/reinit. */
 } close_method_t;
 
 typedef enum
@@ -62,6 +64,58 @@
 #define TEST_USES_KEY_ID( key_id ) ( (void) ( key_id ) )
 #endif /* MBEDTLS_PSA_CRYPTO_STORAGE_C */
 
+/** Apply \p close_method to invalidate the specified handles:
+ * close it, destroy it, or do nothing;
+ */
+static int invalidate_handle( close_method_t close_method,
+                              psa_key_handle_t handle )
+{
+    switch( close_method )
+    {
+        case CLOSE_BY_CLOSE:
+        case CLOSE_BY_CLOSE_WITH_SHUTDOWN:
+            PSA_ASSERT( psa_close_key( handle ) );
+            break;
+        case CLOSE_BY_DESTROY:
+        case CLOSE_BY_DESTROY_WITH_SHUTDOWN:
+            PSA_ASSERT( psa_destroy_key( handle ) );
+            break;
+        case CLOSE_BY_SHUTDOWN:
+            break;
+    }
+    return( 1 );
+exit:
+    return( 0 );
+}
+
+/** Restart the PSA subsystem if \p close_method says so. */
+static int invalidate_psa( close_method_t close_method )
+{
+    switch( close_method )
+    {
+        case CLOSE_BY_CLOSE:
+        case CLOSE_BY_DESTROY:
+            return( 1 );
+        case CLOSE_BY_CLOSE_WITH_SHUTDOWN:
+        case CLOSE_BY_DESTROY_WITH_SHUTDOWN:
+            /* All keys must have been closed. */
+            PSA_DONE( );
+            break;
+        case CLOSE_BY_SHUTDOWN:
+            /* Some keys may remain behind, and we're testing that this
+             * properly closes them. */
+            mbedtls_psa_crypto_free( );
+            break;
+    }
+
+    PSA_ASSERT( psa_crypto_init( ) );
+    ASSERT_PSA_PRISTINE( );
+    return( 1 );
+
+exit:
+    return( 0 );
+}
+
 /* END_HEADER */
 
 /* BEGIN_DEPENDENCIES
@@ -94,19 +148,10 @@
     TEST_EQUAL( psa_get_key_type( &attributes ), type );
 
     /* Do something that invalidates the handle. */
-    switch( close_method )
-    {
-        case CLOSE_BY_CLOSE:
-            PSA_ASSERT( psa_close_key( handle ) );
-            break;
-        case CLOSE_BY_DESTROY:
-            PSA_ASSERT( psa_destroy_key( handle ) );
-            break;
-        case CLOSE_BY_SHUTDOWN:
-            PSA_DONE( );
-            PSA_ASSERT( psa_crypto_init( ) );
-            break;
-    }
+    if( ! invalidate_handle( close_method, handle ) )
+        goto exit;
+    if( ! invalidate_psa( close_method ) )
+        goto exit;
 
     /* Test that the handle is now invalid. */
     TEST_EQUAL( psa_get_key_attributes( handle, &attributes ),
@@ -171,19 +216,11 @@
     TEST_EQUAL( psa_get_key_type( &attributes ), type );
 
     /* Do something that invalidates the handle. */
-    switch( close_method )
-    {
-        case CLOSE_BY_CLOSE:
-            PSA_ASSERT( psa_close_key( handle ) );
-            break;
-        case CLOSE_BY_DESTROY:
-            PSA_ASSERT( psa_destroy_key( handle ) );
-            break;
-        case CLOSE_BY_SHUTDOWN:
-            PSA_DONE( );
-            PSA_ASSERT( psa_crypto_init( ) );
-            break;
-    }
+    if( ! invalidate_handle( close_method, handle ) )
+        goto exit;
+    if( ! invalidate_psa( close_method ) )
+        goto exit;
+
     /* Test that the handle is now invalid. */
     TEST_EQUAL( psa_get_key_attributes( handle, &read_attributes ),
                 PSA_ERROR_INVALID_HANDLE );
@@ -196,6 +233,7 @@
     switch( close_method )
     {
         case CLOSE_BY_CLOSE:
+        case CLOSE_BY_CLOSE_WITH_SHUTDOWN:
         case CLOSE_BY_SHUTDOWN:
             PSA_ASSERT( psa_open_key( id, &handle ) );
             PSA_ASSERT( psa_get_key_attributes( handle, &read_attributes ) );
@@ -230,7 +268,9 @@
             }
             PSA_ASSERT( psa_close_key( handle ) );
             break;
+
         case CLOSE_BY_DESTROY:
+        case CLOSE_BY_DESTROY_WITH_SHUTDOWN:
             TEST_EQUAL( psa_open_key( id, &handle ),
                         PSA_ERROR_DOES_NOT_EXIST );
             break;