/work/auto_tests/scenarios/scenario_avatar_test.c
Line | Count | Source (jump to first uncovered line) |
1 | | #include "framework/framework.h" |
2 | | #include <stdio.h> |
3 | | #include <stdlib.h> |
4 | | #include <string.h> |
5 | | |
6 | 7 | #define AVATAR_SIZE 100 |
7 | | static const uint8_t avatar_data[AVATAR_SIZE] = "This is a fake avatar image data. It should be longer but for testing this is enough."; |
8 | | |
9 | | typedef struct { |
10 | | uint8_t avatar_hash[TOX_HASH_LENGTH]; |
11 | | bool transfer_finished; |
12 | | } AvatarState; |
13 | | |
14 | | static void on_file_chunk_request(const Tox_Event_File_Chunk_Request *event, void *user_data) |
15 | 2 | { |
16 | 2 | ToxNode *self = (ToxNode *)user_data; |
17 | 2 | AvatarState *state = (AvatarState *)tox_node_get_script_ctx(self); |
18 | | |
19 | 2 | uint32_t friend_number = tox_event_file_chunk_request_get_friend_number(event); |
20 | 2 | uint32_t file_number = tox_event_file_chunk_request_get_file_number(event); |
21 | 2 | uint64_t position = tox_event_file_chunk_request_get_position(event); |
22 | 2 | size_t length = tox_event_file_chunk_request_get_length(event); |
23 | | |
24 | 2 | if (length == 0) { |
25 | 1 | state->transfer_finished = true; |
26 | 1 | return; |
27 | 1 | } |
28 | | |
29 | 1 | if (position >= AVATAR_SIZE) { |
30 | 0 | tox_file_send_chunk(tox_node_get_tox(self), friend_number, file_number, position, nullptr, 0, nullptr); |
31 | 0 | state->transfer_finished = true; |
32 | 0 | return; |
33 | 0 | } |
34 | | |
35 | 1 | size_t to_send = AVATAR_SIZE - (size_t)position; |
36 | 1 | if (to_send > length) { |
37 | 0 | to_send = length; |
38 | 0 | } |
39 | | |
40 | 1 | tox_file_send_chunk(tox_node_get_tox(self), friend_number, file_number, position, avatar_data + position, to_send, nullptr); |
41 | 1 | } |
42 | | |
43 | | static void alice_script(ToxNode *self, void *ctx) |
44 | 2 | { |
45 | 2 | AvatarState *state = (AvatarState *)ctx; |
46 | 2 | tox_events_callback_file_chunk_request(tox_node_get_dispatch(self), on_file_chunk_request); |
47 | | |
48 | 2 | tox_node_wait_for_self_connected(self); |
49 | 2 | tox_node_wait_for_friend_connected(self, 0); |
50 | | |
51 | 2 | Tox *tox = tox_node_get_tox(self); |
52 | 2 | tox_hash(state->avatar_hash, avatar_data, AVATAR_SIZE); |
53 | | |
54 | 2 | tox_node_log(self, "Sending avatar request to Bob..."); |
55 | 2 | Tox_Err_File_Send err_send; |
56 | 2 | tox_file_send(tox, 0, TOX_FILE_KIND_AVATAR, AVATAR_SIZE, state->avatar_hash, (const uint8_t *)"avatar.png", 10, &err_send); |
57 | 2 | ck_assert(err_send == TOX_ERR_FILE_SEND_OK); |
58 | | |
59 | 2 | WAIT_UNTIL(state->transfer_finished); |
60 | 2 | tox_node_log(self, "Avatar transfer finished from Alice side."); |
61 | 2 | } |
62 | | |
63 | | typedef struct { |
64 | | bool avatar_received; |
65 | | uint8_t received_data[AVATAR_SIZE]; |
66 | | size_t received_len; |
67 | | } BobState; |
68 | | |
69 | | static void on_file_recv(const Tox_Event_File_Recv *event, void *user_data) |
70 | 1 | { |
71 | 1 | ToxNode *self = (ToxNode *)user_data; |
72 | 1 | uint32_t kind = tox_event_file_recv_get_kind(event); |
73 | 1 | uint32_t friend_number = tox_event_file_recv_get_friend_number(event); |
74 | 1 | uint32_t file_number = tox_event_file_recv_get_file_number(event); |
75 | | |
76 | 1 | if (kind == TOX_FILE_KIND_AVATAR) { |
77 | 1 | tox_node_log(self, "Receiving avatar from Alice, resuming..."); |
78 | 1 | tox_file_control(tox_node_get_tox(self), friend_number, file_number, TOX_FILE_CONTROL_RESUME, nullptr); |
79 | 1 | } |
80 | 1 | } |
81 | | |
82 | | static void on_file_recv_chunk(const Tox_Event_File_Recv_Chunk *event, void *user_data) |
83 | 2 | { |
84 | 2 | ToxNode *self = (ToxNode *)user_data; |
85 | 2 | BobState *state = (BobState *)tox_node_get_script_ctx(self); |
86 | 2 | size_t length = tox_event_file_recv_chunk_get_data_length(event); |
87 | 2 | uint64_t position = tox_event_file_recv_chunk_get_position(event); |
88 | | |
89 | 2 | if (length == 0) { |
90 | 1 | state->avatar_received = true; |
91 | 1 | return; |
92 | 1 | } |
93 | | |
94 | 1 | if (position + length <= AVATAR_SIZE) { |
95 | 1 | memcpy(state->received_data + position, tox_event_file_recv_chunk_get_data(event), length); |
96 | 1 | state->received_len += length; |
97 | 1 | } |
98 | 1 | } |
99 | | |
100 | | static void bob_script(ToxNode *self, void *ctx) |
101 | 1 | { |
102 | 1 | const BobState *state = (const BobState *)ctx; |
103 | 1 | tox_events_callback_file_recv(tox_node_get_dispatch(self), on_file_recv); |
104 | 1 | tox_events_callback_file_recv_chunk(tox_node_get_dispatch(self), on_file_recv_chunk); |
105 | | |
106 | 1 | tox_node_wait_for_self_connected(self); |
107 | 1 | tox_node_wait_for_friend_connected(self, 0); |
108 | | |
109 | 1 | WAIT_UNTIL(state->avatar_received); |
110 | 1 | tox_node_log(self, "Avatar received. Verifying data..."); |
111 | | |
112 | 1 | ck_assert(state->received_len == AVATAR_SIZE); |
113 | 1 | ck_assert(memcmp(state->received_data, avatar_data, AVATAR_SIZE) == 0); |
114 | | |
115 | 1 | tox_node_log(self, "Avatar verification successful!"); |
116 | 1 | } |
117 | | |
118 | | int main(int argc, char *argv[]) |
119 | 31 | { |
120 | 31 | ToxScenario *s = tox_scenario_new(argc, argv, 60000); |
121 | | |
122 | 31 | AvatarState alice_state = {{0}, false}; |
123 | 31 | BobState bob_state = {false, {0}, 0}; |
124 | | |
125 | 31 | tox_scenario_add_node(s, "Alice", alice_script, &alice_state, sizeof(AvatarState)); |
126 | 31 | tox_scenario_add_node(s, "Bob", bob_script, &bob_state, sizeof(BobState)); |
127 | | |
128 | 31 | ToxNode *alice = tox_scenario_get_node(s, 0); |
129 | 31 | ToxNode *bob = tox_scenario_get_node(s, 1); |
130 | | |
131 | 31 | tox_node_bootstrap(alice, bob); |
132 | 31 | tox_node_friend_add(alice, bob); |
133 | 31 | tox_node_friend_add(bob, alice); |
134 | | |
135 | 31 | ToxScenarioStatus res = tox_scenario_run(s); |
136 | 31 | if (res != TOX_SCENARIO_DONE) { |
137 | 0 | fprintf(stderr, "Scenario failed with status %u\n", res); |
138 | 0 | return 1; |
139 | 0 | } |
140 | | |
141 | 31 | tox_scenario_free(s); |
142 | 31 | return 0; |
143 | 31 | } |
144 | | |