File: test_loop_misc.c

package info (click to toggle)
cif-api 0.4.2-6
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 3,472 kB
  • sloc: ansic: 19,411; lex: 246; makefile: 201; sql: 164; yacc: 115; sh: 37
file content (259 lines) | stat: -rw-r--r-- 10,916 bytes parent folder | download | duplicates (3)
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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
/*
 * test_loop_misc.c
 *
 * Tests CIF API packet iterator and loop behaviors that are not covered by other tests.  Specifically, behavior
 * of a packet iterator with with the scalar loop is excercised, and the rollback facility provided by
 * cif_pktitr_abort() is verified.  Also, cif_loop_add_packet() is tested as it applies to the scalar loop.
 *
 * Copyright 2014, 2015 John C. Bollinger
 *
 *
 * This file is part of the CIF API.
 *
 * The CIF API is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * The CIF API is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with the CIF API.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdlib.h>
#include <stdio.h>
#include <unicode/ustring.h>
#include <unicode/ustdio.h>
#include "../cif.h"
#include "assert_value.h"
#include "test.h"

static int assert_packets_equal(cif_packet_tp *packet1, cif_packet_tp *packet2);

int main(void) {
    char test_name[80] = "test_loop_misc";
    cif_tp *cif = NULL;
    cif_block_tp *block = NULL;
    cif_loop_tp *loop;
    cif_pktitr_tp *iterator;
    cif_packet_tp *packet = NULL;
    cif_packet_tp *packet2 = NULL;
    cif_value_tp *value = NULL;
    cif_value_tp *value1 = NULL;
    cif_value_tp *value2 = NULL;
    cif_value_tp *value3 = NULL;
    U_STRING_DECL(block_code, "block", 6);
    U_STRING_DECL(item1l, "_item1", 7);
    U_STRING_DECL(item2l, "_item2", 7);
    U_STRING_DECL(item3l, "_item3", 7);
    U_STRING_DECL(char_value1, "simple_Value", 13);

    /* Initialize data and prepare the test fixture */
    TESTHEADER(test_name);

    U_STRING_INIT(block_code, "block", 6);
    U_STRING_INIT(item1l, "_item1", 7);
    U_STRING_INIT(item2l, "_item2", 7);
    U_STRING_INIT(item3l, "_item3", 7);
    U_STRING_INIT(char_value1, "simple_Value", 13);

    /* set up the test fixture */

    CREATE_CIF(test_name, cif);
    CREATE_BLOCK(test_name, cif, block_code, block);

    /* Add some scalar values to the block */
    TEST(cif_value_create(CIF_UNK_KIND, &value1), CIF_OK, test_name, 1);
    TEST(cif_value_autoinit_numb(value1, 2.5, 0.25, 19), CIF_OK, test_name, 2);
    TEST(cif_value_create(CIF_UNK_KIND, &value2), CIF_OK, test_name, 3);
    TEST(cif_value_copy_char(value2, char_value1), CIF_OK, test_name, 4);
    TEST(cif_value_create(CIF_TABLE_KIND, &value3), CIF_OK, test_name, 5);
    TEST(cif_container_set_value(block, item1l, value1), CIF_OK, test_name, 6);
    TEST(cif_container_set_value(block, item2l, value2), CIF_OK, test_name, 7);
    TEST(cif_container_set_value(block, item3l, value3), CIF_OK, test_name, 9);

    /* Obtain a handle on the block's scalar loop */
    TEST(cif_container_get_category_loop(block, CIF_SCALARS, &loop), CIF_OK, test_name, 10);

    /* Test modifying the scalar loop via a packet iterator */

    /* obtain an iterator and advance it across the first (only) packet */
    TEST(cif_loop_get_packets(loop, &iterator), CIF_OK, test_name, 11);
    TEST(cif_pktitr_next_packet(iterator, &packet), CIF_OK, test_name, 12);

    /* verify values, and modify some of them */
    TEST(cif_packet_get_item(packet, item1l, &value), CIF_OK, test_name, 13);
    TEST(!assert_values_equal(value, value1), 0, test_name, 14);
    TEST(cif_packet_get_item(packet, item2l, &value), CIF_OK, test_name, 15);
    TEST(!assert_values_equal(value, value2), 0, test_name, 16);
    TEST(cif_value_init(value, CIF_NA_KIND), CIF_OK, test_name, 17);
    TEST(cif_value_clone(value, &value2), CIF_OK, test_name, 18);
    TEST(cif_packet_get_item(packet, item3l, &value), CIF_OK, test_name, 19);
    TEST(!assert_values_equal(value, value3), 0, test_name, 20);
    TEST(cif_value_copy_char(value, block_code), CIF_OK, test_name, 21);
    TEST(cif_value_clone(value, &value3), CIF_OK, test_name, 22);

    /* Apply the update */
    TEST(cif_pktitr_update_packet(iterator, packet), CIF_OK, test_name, 23);
    /* Verify that the update was applied (iterator still open) */
    TEST(cif_container_get_value(block, item2l, &value), CIF_OK, test_name, 24);
    TEST(!assert_values_equal(value, value2), 0, test_name, 25);
    /* Close the iterator, then reload the packet and test again */
    TEST(cif_pktitr_close(iterator), CIF_OK, test_name, 26);
    cif_packet_free(packet);
    packet = NULL;
    TEST(cif_loop_get_packets(loop, &iterator), CIF_OK, test_name, 27);
    TEST(cif_pktitr_next_packet(iterator, &packet), CIF_OK, test_name, 28);
    /* verify the revised values */
    TEST(cif_packet_get_item(packet, item1l, &value), CIF_OK, test_name, 29);
    TEST(!assert_values_equal(value, value1), 0, test_name, 30);
    TEST(cif_packet_get_item(packet, item2l, &value), CIF_OK, test_name, 31);
    TEST(!assert_values_equal(value, value2), 0, test_name, 32);
    TEST(cif_packet_get_item(packet, item3l, &value), CIF_OK, test_name, 33);
    TEST(!assert_values_equal(value, value3), 0, test_name, 34);
    /* iterator is still open */

    /* test aborting a modification */
    TEST(cif_value_init(value, CIF_LIST_KIND), CIF_OK, test_name, 35);
    TEST(cif_pktitr_update_packet(iterator, packet), CIF_OK, test_name, 36);
        /* 'value' currently belongs to the packet */
    value = NULL;
    TEST(cif_container_get_value(block, item3l, &value), CIF_OK, test_name, 37);
    TEST(cif_value_kind(value), CIF_LIST_KIND, test_name, 38);
    TEST(cif_pktitr_abort(iterator), CIF_OK, test_name, 39);
    cif_value_free(value);
    value = NULL;
    TEST(cif_container_get_value(block, item3l, &value), CIF_OK, test_name, 40);
    TEST(!assert_values_equal(value, value3), 0, test_name, 41);
    cif_value_free(value);
    value = NULL;
    
    /* test aborting a deletion */
    TEST(cif_loop_get_packets(loop, &iterator), CIF_OK, test_name, 42);
    TEST(cif_pktitr_next_packet(iterator, &packet), CIF_OK, test_name, 43);
    TEST(cif_pktitr_remove_packet(iterator), CIF_OK, test_name, 44);
        /* verify the deletion */
    TEST(cif_container_get_value(block, item1l, NULL), CIF_NOSUCH_ITEM, test_name, 45);
        /* abort */
    TEST(cif_pktitr_abort(iterator), CIF_OK, test_name, 46);
    TEST(cif_container_get_value(block, item1l, NULL), CIF_OK, test_name, 47);

    /* test finalizing a deletion */
    TEST(cif_loop_get_packets(loop, &iterator), CIF_OK, test_name, 48);
    TEST(cif_pktitr_next_packet(iterator, &packet), CIF_OK, test_name, 49);
    TEST(cif_pktitr_remove_packet(iterator), CIF_OK, test_name, 50);
        /* commit */
    TEST(cif_pktitr_close(iterator), CIF_OK, test_name, 51);
        /* verify */
    TEST(cif_container_get_value(block, item1l, NULL), CIF_NOSUCH_ITEM, test_name, 52);
    TEST(cif_loop_get_packets(loop, &iterator), CIF_EMPTY_LOOP, test_name, 53);

    /* test adding a packet */
    TEST(cif_loop_add_packet(loop, packet), CIF_OK, test_name, 55);
        /* verify */
    TEST(cif_loop_get_packets(loop, &iterator), CIF_OK, test_name, 56);
    TEST(cif_pktitr_next_packet(iterator, &packet2), CIF_OK, test_name, 57);
    TEST(!assert_packets_equal(packet2, packet), 0, test_name, 58);
    TEST(cif_pktitr_abort(iterator), CIF_OK, test_name, 59);
    cif_packet_free(packet2);

    /* test adding another packet */
    TEST(cif_loop_add_packet(loop, packet), CIF_RESERVED_LOOP, test_name, 60);

    cif_packet_free(packet);

    cif_value_free(value3);
    cif_value_free(value2);
    cif_value_free(value1);
    cif_loop_free(loop);
    cif_block_free(block);
    DESTROY_CIF(test_name, cif);

    return 0;
}

/*
 * Clones a packet and returns a pointer to the clone.  Returns NULL on failure.
 */
static cif_packet_tp *clone_packet(cif_packet_tp *packet) {
    cif_packet_tp *clone = NULL;
    const UChar **names;

    if (cif_packet_get_names(packet, &names) == CIF_OK) {
        if (cif_packet_create(&clone, NULL) == CIF_OK) {
            const UChar **name_p;

            for (name_p = names; *name_p != NULL; name_p += 1) {
                cif_value_tp *value;

                /* 'value' does not need to be released because it belongs to 'packet' */
                /* 'value' is automatically cloned into 'clone'; no need to clone it explicitly */
                if ((cif_packet_get_item(packet, *name_p, &value) != CIF_OK)
                        || (cif_packet_set_item(clone, *name_p, value) != CIF_OK)) {
                    /* something went wrong -- clean up and exit */
                    cif_packet_free(clone);
                    clone = NULL;
                    break;
                }
            }
        }

        free(names);
    }

    return clone;
}

/*
 * Tests the assertion that the specified packets contain values for identical
 * sets of item names, with all pairs of values associated with the same name
 * being equal.  Returns a nonzero value if the assertion is true, or 0 if it
 * is false.
 */
static int assert_packets_equal(cif_packet_tp *packet1, cif_packet_tp *packet2) {
    const UChar **item_names;
    int rval = 0;

    if (cif_packet_get_names(packet1, &item_names) == CIF_OK) {
        /*
         * packet2 is cloned to create a scratch value that can be destroyed.
         * That's convenient, but we really need only a name set, so cloning
         * the whole thing is overkill.
         */
        cif_packet_tp *clone = clone_packet(packet2);

        if (clone != NULL) {
            const UChar **name_p;

            /* check each item in packet1 to see whether it matches an item in the clone of packet2 */
            for (name_p = item_names; *name_p != NULL; name_p += 1) {
                cif_value_tp *value1;
                cif_value_tp *value2;

                if ((cif_packet_get_item(packet1, *name_p, &value1) != CIF_OK)
                        || (cif_packet_get_item(clone, *name_p, &value2) != CIF_OK)
                        || (!assert_values_equal(value1, value2))
                           /* match successful.  remove the matching item from the clone: */
                        || (cif_packet_remove_item(clone, *name_p, NULL) != CIF_OK)) {
                    goto done;
                }
            }

            /* check whether there are any unmatched items left in the erstwhile clone of packet2 */
            free(item_names);
            item_names = NULL;  /* in case the following fails, to avoid doubly freeing 'item_names' */
            rval = ((cif_packet_get_names(clone, &item_names) == CIF_OK) && (*item_names == NULL));

            done:
            cif_packet_free(clone);
        }

        free(item_names);
    }

    return rval;
}