Coverage Report

Created: 2026-10-24 08:16

/work/auto_tests/scenarios/scenario_group_invite_test.c
Line
Count
Source (jump to first uncovered line)
1
#include "framework/framework.h"
2
#include <stdio.h>
3
#include <string.h>
4
#include <stdlib.h>
5
6
4
#define PASSWORD "dadada"
7
2
#define PASS_LEN (sizeof(PASSWORD) - 1)
8
2
#define WRONG_PASS "dadadada"
9
1
#define WRONG_PASS_LEN (sizeof(WRONG_PASS) - 1)
10
1
#define PEER_LIMIT 1
11
12
typedef struct {
13
    uint32_t group_number;
14
    uint8_t chat_id[TOX_GROUP_CHAT_ID_SIZE];
15
    bool peer_limit_fail;
16
    bool password_fail;
17
    bool connected;
18
    uint32_t peer_count;
19
} State;
20
21
static void on_group_join_fail(const Tox_Event_Group_Join_Fail *event, void *user_data)
22
3
{
23
3
    ToxNode *self = (ToxNode *)user_data;
24
3
    State *state = (State *)tox_node_get_script_ctx(self);
25
3
    Tox_Group_Join_Fail fail_type = tox_event_group_join_fail_get_fail_type(event);
26
27
3
    if (fail_type == TOX_GROUP_JOIN_FAIL_PEER_LIMIT) {
28
1
        state->peer_limit_fail = true;
29
2
    } else if (fail_type == TOX_GROUP_JOIN_FAIL_INVALID_PASSWORD) {
30
2
        state->password_fail = true;
31
2
    }
32
3
}
33
34
static void on_group_self_join(const Tox_Event_Group_Self_Join *event, void *user_data)
35
13
{
36
13
    ToxNode *self = (ToxNode *)user_data;
37
13
    State *state = (State *)tox_node_get_script_ctx(self);
38
13
    state->connected = true;
39
13
}
40
41
static void on_group_peer_join(const Tox_Event_Group_Peer_Join *event, void *user_data)
42
25
{
43
25
    ToxNode *self = (ToxNode *)user_data;
44
25
    State *state = (State *)tox_node_get_script_ctx(self);
45
25
    state->peer_count++;
46
25
}
47
48
static void founder_script(ToxNode *self, void *ctx)
49
1
{
50
1
    State *state = (State *)ctx;
51
1
    Tox *tox = tox_node_get_tox(self);
52
1
    Tox_Dispatch *dispatch = tox_node_get_dispatch(self);
53
54
1
    tox_events_callback_group_peer_join(dispatch, on_group_peer_join);
55
1
    tox_events_callback_group_self_join(dispatch, on_group_self_join);
56
57
1
    tox_node_wait_for_self_connected(self);
58
59
1
    Tox_Err_Group_New err_new;
60
1
    state->group_number = tox_group_new(tox, TOX_GROUP_PRIVACY_STATE_PUBLIC, (const uint8_t *)"test", 4, (const uint8_t *)"test", 4, &err_new);
61
1
    ck_assert(err_new == TOX_ERR_GROUP_NEW_OK);
62
63
1
    tox_group_get_chat_id(tox, state->group_number, state->chat_id, nullptr);
64
65
    // Phase 1: Peer 1 joins with no password
66
1
    tox_scenario_barrier_wait(self); // Barrier 1: Founder created group
67
1
    WAIT_UNTIL(state->peer_count == 1);
68
1
    tox_node_log(self, "Peer 1 joined.");
69
70
    // Phase 2: Set password
71
1
    tox_group_set_password(tox, state->group_number, (const uint8_t *)PASSWORD, PASS_LEN, nullptr);
72
1
    tox_scenario_barrier_wait(self); // Barrier 2: Founder set password
73
74
    // Phase 3: Peer 2 attempts with no password (and fails)
75
    // Phase 4: Peer 3 attempts with wrong password (and fails)
76
1
    tox_scenario_barrier_wait(self); // Barrier 3: Peers 2 and 3 finished attempts
77
78
    // Phase 5: Set peer limit
79
1
    tox_group_set_peer_limit(tox, state->group_number, PEER_LIMIT, nullptr);
80
1
    tox_scenario_barrier_wait(self); // Barrier 4: Founder set peer limit
81
82
    // Phase 6: Peer 4 attempts with correct password (and fails due to limit)
83
1
    tox_scenario_barrier_wait(self); // Barrier 5: Peer 4 finished attempt
84
85
    // Phase 7: Remove password and increase limit
86
1
    tox_group_set_password(tox, state->group_number, nullptr, 0, nullptr);
87
1
    tox_group_set_peer_limit(tox, state->group_number, 100, nullptr);
88
1
    tox_scenario_barrier_wait(self); // Barrier 6: Founder relaxed restrictions
89
90
    // Phase 8: Peer 5 joins
91
1
    WAIT_UNTIL(state->peer_count >= 2);
92
93
    // Phase 9: Set private state
94
1
    tox_group_set_privacy_state(tox, state->group_number, TOX_GROUP_PRIVACY_STATE_PRIVATE, nullptr);
95
1
    tox_scenario_barrier_wait(self); // Barrier 7: Founder made group private
96
97
    // Phase 10: Peer 6 attempts join (and fails because it's private)
98
1
    tox_scenario_barrier_wait(self); // Barrier 8: Peer 6 finished wait
99
100
    // Phase 11: Make group public again
101
1
    tox_group_set_privacy_state(tox, state->group_number, TOX_GROUP_PRIVACY_STATE_PUBLIC, nullptr);
102
1
    tox_scenario_barrier_wait(self); // Barrier 9: Founder made group public again
103
104
    // Final phase: Everyone leaves
105
1
    WAIT_UNTIL(state->peer_count >= 2); // At least Peer 1 and 5 are here
106
1
    tox_scenario_barrier_wait(self); // Barrier 10: Ready to leave
107
1
    tox_group_leave(tox, state->group_number, nullptr, 0, nullptr);
108
1
}
109
110
static void peer1_script(ToxNode *self, void *ctx)
111
1
{
112
1
    Tox *tox = tox_node_get_tox(self);
113
1
    tox_node_wait_for_self_connected(self);
114
115
1
    const ToxNode *founder = tox_scenario_get_node(tox_node_get_scenario(self), 0);
116
1
    const State *founder_view = (const State *)tox_node_get_peer_ctx(founder);
117
1
    tox_scenario_barrier_wait(self); // Barrier 1: Founder created group
118
119
1
    tox_group_join(tox, founder_view->chat_id, (const uint8_t *)"Peer1", 5, nullptr, 0, nullptr);
120
121
1
    tox_scenario_barrier_wait(self); // Barrier 2
122
1
    tox_scenario_barrier_wait(self); // Barrier 3
123
1
    tox_scenario_barrier_wait(self); // Barrier 4
124
1
    tox_scenario_barrier_wait(self); // Barrier 5
125
1
    tox_scenario_barrier_wait(self); // Barrier 6
126
1
    tox_scenario_barrier_wait(self); // Barrier 7
127
1
    tox_scenario_barrier_wait(self); // Barrier 8
128
1
    tox_scenario_barrier_wait(self); // Barrier 9
129
1
    tox_scenario_barrier_wait(self); // Barrier 10
130
1
    tox_group_leave(tox, 0, nullptr, 0, nullptr);
131
1
}
132
133
static void peer2_script(ToxNode *self, void *ctx)
134
1
{
135
1
    const State *state = (const State *)ctx;
136
1
    Tox *tox = tox_node_get_tox(self);
137
1
    tox_events_callback_group_join_fail(tox_node_get_dispatch(self), on_group_join_fail);
138
1
    tox_node_wait_for_self_connected(self);
139
140
1
    const ToxNode *founder = tox_scenario_get_node(tox_node_get_scenario(self), 0);
141
1
    const State *founder_view = (const State *)tox_node_get_peer_ctx(founder);
142
1
    tox_scenario_barrier_wait(self); // 1
143
1
    tox_scenario_barrier_wait(self); // 2: Password set
144
145
1
    tox_group_join(tox, founder_view->chat_id, (const uint8_t *)"Peer2", 5, nullptr, 0, nullptr);
146
147
1
    WAIT_UNTIL(state->password_fail);
148
1
    tox_node_log(self, "Blocked by password as expected.");
149
150
1
    tox_scenario_barrier_wait(self); // 3
151
1
    tox_scenario_barrier_wait(self); // 4
152
1
    tox_scenario_barrier_wait(self); // 5
153
1
    tox_scenario_barrier_wait(self); // 6
154
1
    tox_scenario_barrier_wait(self); // 7
155
1
    tox_scenario_barrier_wait(self); // 8
156
1
    tox_scenario_barrier_wait(self); // 9
157
1
    tox_scenario_barrier_wait(self); // 10
158
1
}
159
160
static void peer3_script(ToxNode *self, void *ctx)
161
1
{
162
1
    const State *state = (const State *)ctx;
163
1
    Tox *tox = tox_node_get_tox(self);
164
1
    tox_events_callback_group_join_fail(tox_node_get_dispatch(self), on_group_join_fail);
165
1
    tox_node_wait_for_self_connected(self);
166
167
1
    const ToxNode *founder = tox_scenario_get_node(tox_node_get_scenario(self), 0);
168
1
    const State *founder_view = (const State *)tox_node_get_peer_ctx(founder);
169
1
    tox_scenario_barrier_wait(self); // 1
170
1
    tox_scenario_barrier_wait(self); // 2
171
172
1
    tox_group_join(tox, founder_view->chat_id, (const uint8_t *)"Peer3", 5, (const uint8_t *)WRONG_PASS, WRONG_PASS_LEN, nullptr);
173
174
1
    WAIT_UNTIL(state->password_fail);
175
1
    tox_node_log(self, "Blocked by wrong password as expected.");
176
177
1
    tox_scenario_barrier_wait(self); // 3
178
1
    tox_scenario_barrier_wait(self); // 4
179
1
    tox_scenario_barrier_wait(self); // 5
180
1
    tox_scenario_barrier_wait(self); // 6
181
1
    tox_scenario_barrier_wait(self); // 7
182
1
    tox_scenario_barrier_wait(self); // 8
183
1
    tox_scenario_barrier_wait(self); // 9
184
1
    tox_scenario_barrier_wait(self); // 10
185
1
}
186
187
static void peer4_script(ToxNode *self, void *ctx)
188
1
{
189
1
    const State *state = (const State *)ctx;
190
1
    Tox *tox = tox_node_get_tox(self);
191
1
    tox_events_callback_group_join_fail(tox_node_get_dispatch(self), on_group_join_fail);
192
1
    tox_node_wait_for_self_connected(self);
193
194
1
    const ToxNode *founder = tox_scenario_get_node(tox_node_get_scenario(self), 0);
195
1
    const State *founder_view = (const State *)tox_node_get_peer_ctx(founder);
196
1
    tox_scenario_barrier_wait(self); // 1
197
1
    tox_scenario_barrier_wait(self); // 2
198
1
    tox_scenario_barrier_wait(self); // 3
199
1
    tox_scenario_barrier_wait(self); // 4: Peer limit set
200
201
1
    tox_group_join(tox, founder_view->chat_id, (const uint8_t *)"Peer4", 5, (const uint8_t *)PASSWORD, PASS_LEN, nullptr);
202
203
1
    WAIT_UNTIL(state->peer_limit_fail);
204
1
    tox_node_log(self, "Blocked by peer limit as expected.");
205
206
1
    tox_scenario_barrier_wait(self); // 5
207
1
    tox_scenario_barrier_wait(self); // 6
208
1
    tox_scenario_barrier_wait(self); // 7
209
1
    tox_scenario_barrier_wait(self); // 8
210
1
    tox_scenario_barrier_wait(self); // 9
211
1
    tox_scenario_barrier_wait(self); // 10
212
1
}
213
214
static void peer5_script(ToxNode *self, void *ctx)
215
1
{
216
1
    const State *state = (const State *)ctx;
217
1
    Tox *tox = tox_node_get_tox(self);
218
1
    tox_events_callback_group_self_join(tox_node_get_dispatch(self), on_group_self_join);
219
1
    tox_node_wait_for_self_connected(self);
220
221
1
    const ToxNode *founder = tox_scenario_get_node(tox_node_get_scenario(self), 0);
222
1
    const State *founder_view = (const State *)tox_node_get_peer_ctx(founder);
223
1
    tox_scenario_barrier_wait(self); // 1
224
1
    tox_scenario_barrier_wait(self); // 2
225
1
    tox_scenario_barrier_wait(self); // 3
226
1
    tox_scenario_barrier_wait(self); // 4
227
1
    tox_scenario_barrier_wait(self); // 5
228
1
    tox_scenario_barrier_wait(self); // 6: Restrictions relaxed
229
230
1
    tox_group_join(tox, founder_view->chat_id, (const uint8_t *)"Peer5", 5, nullptr, 0, nullptr);
231
232
1
    WAIT_UNTIL(state->connected);
233
1
    tox_node_log(self, "Joined group.");
234
235
1
    tox_scenario_barrier_wait(self); // 7
236
1
    tox_scenario_barrier_wait(self); // 8
237
1
    tox_scenario_barrier_wait(self); // 9
238
1
    tox_scenario_barrier_wait(self); // 10
239
1
    tox_group_leave(tox, 0, nullptr, 0, nullptr);
240
1
}
241
242
static void peer6_script(ToxNode *self, void *ctx)
243
1
{
244
1
    const State *state = (const State *)ctx;
245
1
    Tox *tox = tox_node_get_tox(self);
246
1
    tox_events_callback_group_self_join(tox_node_get_dispatch(self), on_group_self_join);
247
1
    tox_node_wait_for_self_connected(self);
248
249
1
    const ToxNode *founder = tox_scenario_get_node(tox_node_get_scenario(self), 0);
250
1
    const State *founder_view = (const State *)tox_node_get_peer_ctx(founder);
251
1
    tox_scenario_barrier_wait(self); // 1
252
1
    tox_scenario_barrier_wait(self); // 2
253
1
    tox_scenario_barrier_wait(self); // 3
254
1
    tox_scenario_barrier_wait(self); // 4
255
1
    tox_scenario_barrier_wait(self); // 5
256
1
    tox_scenario_barrier_wait(self); // 6
257
1
    tox_scenario_barrier_wait(self); // 7: Private group
258
259
1
    tox_group_join(tox, founder_view->chat_id, (const uint8_t *)"Peer6", 5, nullptr, 0, nullptr);
260
261
    // Wait some time to be sure we are NOT connected
262
41
    for (int i = 0; i < 2000 / TOX_SCENARIO_TICK_MS; ++i) {
263
40
        ck_assert(!state->connected);
264
40
        tox_scenario_yield(self);
265
40
    }
266
1
    tox_node_log(self, "Could not join private group via chat ID as expected.");
267
268
1
    tox_scenario_barrier_wait(self); // 8
269
1
    tox_scenario_barrier_wait(self); // 9
270
1
    tox_scenario_barrier_wait(self); // 10
271
1
}
272
273
int main(int argc, char *argv[])
274
2
{
275
2
    ToxScenario *s = tox_scenario_new(argc, argv, 300000);
276
2
    State states[7] = {0};
277
278
2
    ToxNode *nodes[7];
279
2
    nodes[0] = tox_scenario_add_node(s, "Founder", founder_script, &states[0], sizeof(State));
280
2
    nodes[1] = tox_scenario_add_node(s, "Peer1",   peer1_script,   &states[1], sizeof(State));
281
2
    nodes[2] = tox_scenario_add_node(s, "Peer2",   peer2_script,   &states[2], sizeof(State));
282
2
    nodes[3] = tox_scenario_add_node(s, "Peer3",   peer3_script,   &states[3], sizeof(State));
283
2
    nodes[4] = tox_scenario_add_node(s, "Peer4",   peer4_script,   &states[4], sizeof(State));
284
2
    nodes[5] = tox_scenario_add_node(s, "Peer5",   peer5_script,   &states[5], sizeof(State));
285
2
    nodes[6] = tox_scenario_add_node(s, "Peer6",   peer6_script,   &states[6], sizeof(State));
286
287
40
    for (int i = 1; i < 7; ++i) {
288
38
        tox_node_bootstrap(nodes[i], nodes[0]);
289
38
    }
290
291
2
    ToxScenarioStatus res = tox_scenario_run(s);
292
2
    if (res != TOX_SCENARIO_DONE) {
293
0
        tox_scenario_log(s, "Test failed with status %u", res);
294
0
        return 1;
295
0
    }
296
297
2
    tox_scenario_free(s);
298
2
    return 0;
299
2
}
300
301
#undef PASSWORD
302
#undef PASS_LEN
303
#undef PEER_LIMIT