summaryrefslogtreecommitdiff
path: root/example/chef_wrap/waiter_test_wrap.c
blob: 1b8ed94385a2c5908d2d7894318255aa4d112228 (plain)
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
/*
 * Copyright 2013 (c) Andreas Schneider <asn@cynapses.org>
 *                    Jakub Hrozek <jakub.hrozek@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>

#include "waiter_test_wrap.h"
#include "chef.h"

/*
 * This is a mocked Chef object. A real Chef would look if he knows
 * the dish in some kind of internal database and check his storage for
 * ingredients. This chef simply retrieves this information from the test
 * that is calling him.
 *
 * This object is also wrapped - if any code links with this file and is
 * compiled with linker option --wrap chef_cook, any calls of that code to
 * chef_cook will end up calling __wrap_chef_cook.
 *
 * If for any reason the wrapped function wanted to call the real chef_cook()
 * function, it could do so by calling the special symbol __real_chef_cook().
 *
 * Please note that when setting return codes for the chef_cook function, we
 * use this wrapper as a parameter for the will_return() macro, not the
 * real function.
 *
 * A chef object would return:
 * 0 - cooking dish went fine
 * -1 - unknown dish
 * -2 - ran out of ingredients for the dish
 * any other error code -- unexpected error while cooking
 *
 * The return codes should be consistent between the real and mocked objects.
 */
int __wrap_chef_cook(const char *order, char **dish_out)
{
    bool has_ingredients;
    bool knows_dish;
    char *dish;

    check_expected(order);

    knows_dish = mock_type(bool);
    if (knows_dish == false) {
        return -1;
    }

    has_ingredients = mock_type(bool);
    if (has_ingredients == false) {
        return -2;
    }

    dish = mock_ptr_type(char *);
    *dish_out = strdup(dish);
    if (*dish_out == NULL) return ENOMEM;

    return mock_type(int);
}

/* Waiter return codes:
 *  0  - success
 * -1  - kitchen failed
 * -2  - kitchen succeeded, but cooked a different food
 */
static int waiter_process(const char *order, char **dish)
{
    int rv;

    rv = chef_cook(order, dish);
    if (rv != 0) {
        fprintf(stderr, "Chef couldn't cook %s: %s\n",
                order, chef_strerror(rv));
        return -1;
    }

    /* Check if we received the dish we wanted from the kitchen */
    if (strcmp(order, *dish) != 0) {
        free(*dish);
        *dish = NULL;
        return -2;
    }

    return 0;
}

static void test_order_hotdog(void **state)
{
    int rv;
    char *dish;

    (void) state; /* unused */

    /* We expect the chef to receive an order for a hotdog */
    expect_string(__wrap_chef_cook, order, "hotdog");
    /* And we tell the test chef that ke knows how to cook a hotdog
     * and has the ingredients
     */
    will_return(__wrap_chef_cook, true);
    will_return(__wrap_chef_cook, true);
    /* The result will be a hotdog and the cooking process will succeed */
    will_return(__wrap_chef_cook, "hotdog");
    will_return(__wrap_chef_cook, 0);

    /* Test the waiter */
    rv = waiter_process("hotdog", &dish);

    /* We expect the cook to succeed cooking the hotdog */
    assert_int_equal(rv, 0);
    /* And actually receive one */
    assert_string_equal(dish, "hotdog");
    if (dish != NULL) {
        free(dish);
    }
}

static void test_bad_dish(void **state)
{
    int rv;
    char *dish;

    (void) state; /* unused */

    /* We expect the chef to receive an order for a hotdog */
    expect_string(__wrap_chef_cook, order, "hotdog");
    /* And we tell the test chef that ke knows how to cook a hotdog
     * and has the ingredients
     */
    will_return(__wrap_chef_cook, true);
    will_return(__wrap_chef_cook, true);
    /* The result will be a burger and the cooking process will succeed.
     * We expect the waiter to handle the bad dish and return an error
     * code
     */
    will_return(__wrap_chef_cook, "burger");
    will_return(__wrap_chef_cook, 0);

    /* Test the waiter */
    rv = waiter_process("hotdog", &dish);

    /* According to the documentation the waiter should return -2 now */
    assert_int_equal(rv, -2);
    /* And do not give the bad dish to the customer */
    assert_null(dish);
}

int main(void)
{
    const UnitTest tests[] = {
        unit_test(test_order_hotdog),
        unit_test(test_bad_dish),
    };

    return run_tests(tests);
}