You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: tests.rs
    path of file: ./repos/p2panda/p2panda-rs/src/secret_group
    
    the code of the file until where you have to start completion: // SPDX-License-Identifier: AGPL-3.0-or-later

use crate::hash::Hash;
use crate::identity::KeyPair;
use crate::secret_group::lts::LongTermSecretEpoch;
use crate::secret_group::mls::MlsProvider;
use crate::secret_group::{SecretGroup, SecretGroupMember};

#[test]
fn long_term_secret_evolution() {
    // ~~~~~~~~~~~~~~
    // Group creation
    // ~~~~~~~~~~~~~~

    // Billie generates a new `KeyPair` and uses it to create a `SecretGroupMember`
    let billie_key_pair = KeyPair::new();
    let billie_provider = MlsProvider::new();
    let billie_member = SecretGroupMember::new(&billie_provider, &billie_key_pair).unwrap();

    // Billie creates a new `SecretGroup`
    let secret_group_id = Hash::new_from_bytes(&[1, 2, 3]);
    let mut billie_group =
        SecretGroup::new(&billie_provider, &secret_group_id, &billie_member).unwrap();
    assert!(billie_group.is_active());

    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
    // Add members & share secrets
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~

    // Ada generates a new `KeyPair` to also create a new `SecretGroupMember`
    let ada_key_pair = KeyPair::new();
    let ada_provider = MlsProvider::new();
    let ada_member = SecretGroupMember::new(&ada_provider, &ada_key_pair).unwrap();

    // Ada publishes their `KeyPackage` for future group invitations
    let ada_key_package = ada_member.key_package(&ada_provider).unwrap();

    // Billie invites Ada into their group, the return value is a `SecretGroupCommit` which
    // contains the MLS `Commit` and MLS `Welcome` message for this epoch, also the already generated
    // symmetrical long-term secret will be encoded, encrypted and included in the same commit
    let group_commit = billie_group
        .add_members(&billie_provider, &[ada_key_package])
        .unwrap();
    assert!(group_commit.welcome().is_some());

    // Ada joins the group and decrypts the long-term secret
    let mut ada_group = SecretGroup::new_from_welcome(&ada_provider, &group_commit).unwrap();
    assert!(ada_group.is_active());

    // ~~~~~~~~~~~~~~~~
    // En- & Decryption
    // ~~~~~~~~~~~~~~~~

    // Billie sends a message which was encrypted with the first `LongTermSecret` to Ada, the
    // group will automatically use the latest secret for encryption
    let me
    
fn sender_ratchet_evolution() {
    // ~~~~~~~~~~~~~~
    // Group creation
    // ~~~~~~~~~~~~~~

    // Billie generates a new `KeyPair` and uses it to create a `SecretGroupMember`
    let billie_key_pair = KeyPair::new();
    let billie_provider = MlsProvider::new();
    let billie_member = SecretGroupMember::new(&billie_provider, &billie_key_pair).unwrap();

    // Billie creates a new `SecretGroup`
    let secret_group_id = Hash::new_from_bytes(&[1, 2, 3]);
    let mut billie_group =
        SecretGroup::new(&billie_provider, &secret_group_id, &billie_member).unwrap();
    assert!(billie_group.is_active());

    // ~~~~~~~~~~~
    // Add members
    // ~~~~~~~~~~-

    // Ada generates a new `KeyPair` to also create a new `SecretGroupMember`
    let ada_key_pair = KeyPair::new();
    let ada_provider = MlsProvider::new();
    let ada_member = SecretGroupMember::new(&ada_provider, &ada_key_pair).unwrap();

    // Ada publishes their `KeyPackage` for future group invitations
    let ada_key_package = ada_member.key_package(&ada_provider).unwrap();

    // Billie invites Ada into their group
    let group_commit = billie_group
        .add_members(&billie_provider, &[ada_key_package])
        .unwrap();

    // Ada joins the group
    let mut ada_group = SecretGroup::new_from_welcome(&ada_provider, &group_commit).unwrap();
    assert!(ada_group.is_active());

    // ~~~~~~~~~~~~~~~~
    // En- & Decryption
    // ~~~~~~~~~~~~~~~~

    // Billie sends an encrypted message to Ada. This message was encrypted using Billie's Sender
    // Ratchet Secret.
    let message_ciphertext = billie_group
        .encrypt(&billie_provider, b"This is a secret message")
        .unwrap();

    // Ada decrypts the message with the known secret
    let message_plaintext = ada_group
        .decrypt(&ada_provider, &message_ciphertext)
        .unwrap();
    assert_eq!(b"This is a secret message".to_vec(), message_plaintext);

    // ~~~~~~~~~~~~
    // Late members
    // ~~~~~~~~~~~~

    // Calvin generates a new `KeyPair` and uses it to create a `SecretGroupMember`
    let calvin_key_pair = KeyPair::new();
    let calvin_provider = MlsProvider::new();
    let calvin_member = SecretGroupMember::new(&calvin_provider, &calvin_key_pair).unwrap();

    // Calvin publishes their `KeyPackage` for future group invitations
    let calvin_key_package = calvin_member.key_package(&calvin_provider).unwrap();

    // Billie invites Calvin into the group
    let group_commit = billie_group
        .add_members(&billie_provider, &[calvin_key_package])
        .unwrap();

    // Calvin joins the group
    let mut calvin_group = SecretGroup::new_from_welcome(&calvin_provider, &group_commit).unwrap();
    assert!(calvin_group.is_active());

    // Ada processes the commit as well to sync up with the others
    ada_group
        .process_commit(&ada_provider, &group_commit)
        .unwrap();

    // Calvin can not decrypt the former message as they were not participating in that epoch
    assert!(calvin_group
        .decrypt(&calvin_provider, &message_ciphertext)
        .is_err());
}