xref: /netbsd-src/external/bsd/atf/dist/atf-c/tp.c (revision b62fc9e20372b08e1785ff6d769312d209fa2005)
1 /*
2  * Automated Testing Framework (atf)
3  *
4  * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
17  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include <stdio.h>
31 #include <string.h>
32 #include <unistd.h>
33 
34 #include "atf-c/error.h"
35 #include "atf-c/fs.h"
36 #include "atf-c/io.h"
37 #include "atf-c/sanity.h"
38 #include "atf-c/tc.h"
39 #include "atf-c/tcr.h"
40 #include "atf-c/tp.h"
41 
42 /* ---------------------------------------------------------------------
43  * Auxiliary functions.
44  * --------------------------------------------------------------------- */
45 
46 static
47 const atf_tc_t *
48 find_tc(const atf_tp_t *tp, const char *ident)
49 {
50     const atf_tc_t *tc;
51     atf_list_citer_t iter;
52 
53     tc = NULL;
54     atf_list_for_each_c(iter, &tp->m_tcs) {
55         const atf_tc_t *tc2;
56         tc2 = atf_list_citer_data(iter);
57         if (strcmp(tc2->m_ident, ident) == 0) {
58             tc = tc2;
59             break;
60         }
61     }
62     return tc;
63 }
64 
65 /* ---------------------------------------------------------------------
66  * The "atf_tp" type.
67  * --------------------------------------------------------------------- */
68 
69 /*
70  * Constructors/destructors.
71  */
72 
73 atf_error_t
74 atf_tp_init(atf_tp_t *tp, struct atf_map *config)
75 {
76     atf_error_t err;
77 
78     PRE(config != NULL);
79 
80     atf_object_init(&tp->m_object);
81 
82     err = atf_list_init(&tp->m_tcs);
83     if (atf_is_error(err))
84         goto err_object;
85 
86     tp->m_config = config;
87 
88     INV(!atf_is_error(err));
89     return err;
90 
91 err_object:
92     atf_object_fini(&tp->m_object);
93     return err;
94 }
95 
96 void
97 atf_tp_fini(atf_tp_t *tp)
98 {
99     atf_list_iter_t iter;
100 
101     atf_list_for_each(iter, &tp->m_tcs) {
102         atf_tc_t *tc = atf_list_iter_data(iter);
103         atf_tc_fini(tc);
104     }
105     atf_list_fini(&tp->m_tcs);
106 
107     atf_object_fini(&tp->m_object);
108 }
109 
110 /*
111  * Getters.
112  */
113 
114 const struct atf_map *
115 atf_tp_get_config(const atf_tp_t *tp)
116 {
117     return tp->m_config;
118 }
119 
120 const atf_tc_t *
121 atf_tp_get_tc(const atf_tp_t *tp, const char *id)
122 {
123     const atf_tc_t *tc = find_tc(tp, id);
124     PRE(tc != NULL);
125     return tc;
126 }
127 
128 const atf_list_t *
129 atf_tp_get_tcs(const atf_tp_t *tp)
130 {
131     return &tp->m_tcs;
132 }
133 
134 /*
135  * Modifiers.
136  */
137 
138 atf_error_t
139 atf_tp_add_tc(atf_tp_t *tp, atf_tc_t *tc)
140 {
141     atf_error_t err;
142 
143     PRE(find_tc(tp, tc->m_ident) == NULL);
144 
145     err = atf_list_append(&tp->m_tcs, tc, false);
146 
147     POST(find_tc(tp, tc->m_ident) != NULL);
148 
149     return err;
150 }
151 
152 /* ---------------------------------------------------------------------
153  * Free functions.
154  * --------------------------------------------------------------------- */
155 
156 atf_error_t
157 atf_tp_run(const atf_tp_t *tp, const atf_list_t *ids, int fd,
158            const atf_fs_path_t *workdir, size_t *failcount)
159 {
160     atf_error_t err;
161     atf_list_citer_t iter;
162     size_t count;
163 
164     err = atf_io_write_fmt(fd, "Content-Type: application/X-atf-tcs; "
165                            "version=\"1\"\n\n");
166     if (atf_is_error(err))
167         goto out;
168     err = atf_io_write_fmt(fd, "tcs-count: %d\n", atf_list_size(ids));
169     if (atf_is_error(err))
170         goto out;
171 
172     *failcount = count = 0;
173     atf_list_for_each_c(iter, ids) {
174         const char *ident = atf_list_citer_data(iter);
175         const atf_tc_t *tc;
176         atf_tcr_t tcr;
177         int state;
178 
179         err = atf_io_write_fmt(fd, "tc-start: %s\n", ident);
180         if (atf_is_error(err))
181             goto out;
182 
183         tc = find_tc(tp, ident);
184         PRE(tc != NULL);
185 
186         err = atf_tc_run(tc, &tcr, STDOUT_FILENO, STDERR_FILENO, workdir);
187         if (atf_is_error(err))
188             goto out;
189 
190         count++;
191         if (count < atf_list_size(ids)) {
192             fprintf(stdout, "__atf_tc_separator__\n");
193             fprintf(stderr, "__atf_tc_separator__\n");
194         }
195         fflush(stdout);
196         fflush(stderr);
197 
198         state = atf_tcr_get_state(&tcr);
199         if (state == atf_tcr_passed_state) {
200             err = atf_io_write_fmt(fd, "tc-end: %s, passed\n", ident);
201         } else if (state == atf_tcr_failed_state) {
202             const atf_dynstr_t *reason = atf_tcr_get_reason(&tcr);
203             err = atf_io_write_fmt(fd, "tc-end: %s, failed, %s\n", ident,
204                                    atf_dynstr_cstring(reason));
205             (*failcount)++;
206         } else if (state == atf_tcr_skipped_state) {
207             const atf_dynstr_t *reason = atf_tcr_get_reason(&tcr);
208             err = atf_io_write_fmt(fd, "tc-end: %s, skipped, %s\n", ident,
209                                    atf_dynstr_cstring(reason));
210         } else
211             UNREACHABLE;
212         atf_tcr_fini(&tcr);
213         if (atf_is_error(err))
214             goto out;
215     }
216 
217 out:
218     return err;
219 }
220