1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
//! Provides functions for automated database testing.
//!
//! This module contains asynchronous functions to test the basic CRUD (Create, Read, Update, Delete)
//! operations on database entities. It ensures that these operations are executed correctly and that
//! the data integrity is maintained throughout the process.

use crate::Entity;
use std::fmt::Debug;

/// Tests entity creation in the database.
///
/// Verifies that an entity can be created and retrieved correctly. It asserts the non-existence of
/// the entity before creation and checks for equality between the created and retrieved instances.
pub async fn create<E>(mut instance: E, pool: &crate::Pool)
where
    E: Entity + Clone + Debug + Eq + Send,
{
    assert!(
        E::find(instance.pk(), pool).await.is_err(),
        "instance was found (find) before it was created"
    );

    assert!(
        E::find_optional(instance.pk(), pool)
            .await
            .unwrap()
            .is_none(),
        "instance was found (find_optional) before it was created"
    );

    instance.create(pool).await.expect("insertion did not work");

    let retrieved = E::find(instance.pk(), pool)
        .await
        .expect("instance not found after insertion");

    assert_eq!(instance, retrieved);
}

/// Tests reading of an entity from the database.
///
/// Validates that an entity, once created, can be correctly read from the database. It ensures
/// that the entity does not exist prior to creation and that the retrieved instance matches the
/// created one.
pub async fn read<E>(mut instance: E, pool: &crate::Pool)
where
    E: Entity + Clone + Debug + Eq + Send,
{
    assert!(
        E::find(instance.pk(), pool).await.is_err(),
        "instance was found (find) after deletion"
    );

    assert!(
        E::find_optional(instance.pk(), pool)
            .await
            .unwrap()
            .is_none(),
        "instance was found (find_optional) after deletion"
    );

    instance.create(pool).await.expect("insertion did not work");

    let retrieved = E::find(instance.pk(), pool)
        .await
        .expect("instance not found after insertion");

    assert_eq!(instance, retrieved);
}

/// Tests updating of an entity in the database.
///
/// Checks that an entity can be updated and the changes are correctly reflected. Each update is
/// verified by reloading and comparing it with the original instance.
pub async fn update<E>(mut instance: E, updates: Vec<E>, pool: &crate::Pool)
where
    E: Entity + Clone + Debug + Eq + Send,
{
    instance.save(pool).await.expect("insertion did not work");

    for mut update in updates {
        update
            .update(pool)
            .await
            .expect("updating the instance did not work");

        instance
            .reload(pool)
            .await
            .expect("reloading the instance did not work");

        assert_eq!(instance, update);

        let retrieved = E::find(instance.pk(), pool)
            .await
            .expect("instance not found after update");

        assert_eq!(instance, retrieved);

        let retrieved = E::find_optional(instance.pk(), pool)
            .await
            .unwrap()
            .expect("instance not found (find_optional) after update");

        assert_eq!(instance, retrieved);
    }
}

/// Tests deletion of an entity from the database.
///
/// Ensures that an entity can be deleted and is no longer retrievable post-deletion. It also
/// confirms the non-existence of the entity after a delete operation.
pub async fn delete<E>(mut instance: E, pool: &crate::Pool)
where
    E: Entity + Clone + Debug + Eq + Send,
{
    instance.create(pool).await.expect("insertion did not work");

    instance.delete(pool).await.expect("deletion did not work");

    instance
        .reload(pool)
        .await
        .expect_err("instance could be reloaded from db after deletion");

    assert!(
        E::find(instance.pk(), pool).await.is_err(),
        "instance was found (find) after deletion"
    );

    assert!(
        E::find_optional(instance.pk(), pool)
            .await
            .unwrap()
            .is_none(),
        "instance was found (find_optional) after deletion"
    );

    instance.create(pool).await.expect("insertion did not work");

    E::delete_by(instance.pk(), pool)
        .await
        .expect("deletion did not work");

    instance
        .reload(pool)
        .await
        .expect_err("instance could be reloaded from db after deletion");
}

// TODO: provide helpers to autogenerate uuids, pks, strings, emails, etc – maybe reexport another
// crate?