1 /*
2  * Copyright (C) 2014 - Julien Voisin <julien.voisin@dustri.org>
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License, version 2 only, as
6  * published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful, but WITHOUT
9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11  * more details.
12  *
13  * You should have received a copy of the GNU General Public License along with
14  * this program; if not, write to the Free Software Foundation, Inc., 51
15  * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16  */
17 
18 #include <gcrypt.h>
19 #include <limits.h>
20 #include <pthread.h>
21 #include <unistd.h>
22 
23 #include <proto.h>
24 #include <auth.h>
25 #include <context.h>
26 
27 #include <tap/tap.h>
28 #include <utils.h>
29 
30 GCRY_THREAD_OPTION_PTHREAD_IMPL;
31 
32 #define NUM_TESTS 13
33 
34 /* Current directory of this executable. */
35 static char curdir[PATH_MAX];
36 static char instag_filepath[PATH_MAX];
37 
test_otrl_instag_forget(void)38 static void test_otrl_instag_forget(void)
39 {
40 	OtrlInsTag *instag1 = calloc(1, sizeof(OtrlInsTag));
41 	OtrlInsTag *instag2 = calloc(1, sizeof(OtrlInsTag));
42 
43 	instag1->tous = &instag1;
44 	instag1->accountname = strdup("name one");
45 	instag1->protocol = strdup("protocol one");
46 	instag1->next = instag2;
47 	instag1->next->tous = &(instag1->next);
48 	instag2->accountname = strdup("name two");
49 	instag2->protocol = strdup("protocol two");
50 
51 	otrl_instag_forget(NULL);
52 	ok(1, "Forget on NULL didn't segfault");
53 
54 	otrl_instag_forget(instag2);
55 	ok(instag1->next == NULL, "Instag forgotten without segfault");
56 }
57 
test_otrl_instag_forget_all(void)58 static void test_otrl_instag_forget_all(void)
59 {
60 	OtrlUserState us = otrl_userstate_create();
61 	OtrlInsTag *p = malloc(sizeof(OtrlInsTag));
62 	p->accountname = strdup("account name");
63 	p->protocol = strdup("protocol name");
64 	p->instag = otrl_instag_get_new();
65 
66 	otrl_instag_forget_all(us);
67 	ok(1, "Forget all on empty user state");
68 
69 	p->next = us->instag_root;
70 	p->tous = &(us->instag_root);
71 	us->instag_root = p;
72 
73 	otrl_instag_forget_all(us);
74 	ok(1, "Forget all on a non-empty user state");
75 }
76 
test_otrl_instag_find(void)77 static void test_otrl_instag_find(void)
78 {
79 	OtrlUserState us = otrl_userstate_create();
80 	OtrlInsTag *p1 = malloc(sizeof(OtrlInsTag));
81 	OtrlInsTag *p2 = malloc(sizeof(OtrlInsTag));
82 
83 	p1->accountname = strdup("account one");
84 	p1->protocol = strdup("protocol one");
85 	p1->instag = otrl_instag_get_new();
86 	p1->next = us->instag_root;
87 	p1->tous = &(us->instag_root);
88 	us->instag_root = p1;
89 
90 	p2->accountname = strdup("account two");
91 	p2->protocol = strdup("protocol two");
92 	p2->instag = otrl_instag_get_new();
93 	p2->next = us->instag_root;
94 	p2->next->tous = &(p2->next);
95 	p2->tous = &(us->instag_root);
96 	us->instag_root = p2;
97 
98 	ok(otrl_instag_find(us, "account two", "protocol two") == p2,
99 			"Found instag");
100 	ok(otrl_instag_find(us, "account one", "protocol two") == NULL,
101 			"Instag not found");
102 	ok(otrl_instag_find(us, "account three", "protocol three") == NULL,
103 			"Instag not found");
104 }
105 
test_otrl_instag_read(void)106 static void test_otrl_instag_read(void)
107 {
108 	OtrlUserState us = otrl_userstate_create();
109 	OtrlInsTag *one, *two, *three, *four;
110 	char sone[9] = {0}, stwo[9] = {0}, sfour[9] = {0};
111 	one = two = three = four = NULL;
112 	ok(otrl_instag_read(us, "/non_existent_file") ==
113 			gcry_error_from_errno(ENOENT),
114 			"Non-existent file detected");
115 
116 	ok(otrl_instag_read(us, instag_filepath) == GPG_ERR_NO_ERROR,
117 			"Instag called with success");
118 
119 	one = otrl_instag_find(us, "alice_xmpp", "XMPP");
120 	snprintf(sone, sizeof(sone), "%08x", one->instag);
121 
122 	two = otrl_instag_find(us, "alice_irc", "IRC");
123 	snprintf(stwo, sizeof(stwo), "%08x", two->instag);
124 
125 	three = otrl_instag_find(us, "alice_inv", "IRC");
126 
127 	four = otrl_instag_find(us, "alice_icq", "ICQ");
128 	snprintf(sfour, sizeof(sfour), "%08x", four->instag);
129 
130 	ok(one && two && !three && four &&
131 			strcmp(sone, "01234567") == 0 &&
132 			strcmp(stwo, "9abcdef0") == 0 &&
133 			strcmp(sfour, "98765432") == 0,
134 			"Instag succesfully read");
135 }
136 
test_otrl_instag_read_FILEp(void)137 static void test_otrl_instag_read_FILEp(void)
138 {
139 	FILE* instf = fopen(instag_filepath, "rb");
140 	OtrlUserState us = otrl_userstate_create();
141 	OtrlInsTag* one, *two, *three, *four;
142 	char sone[9] = {0}, stwo[9] = {0}, sfour[9] = {0};
143 	one = two = three = four = NULL;
144 
145 	ok(otrl_instag_read_FILEp(us, instf) == gcry_error(GPG_ERR_NO_ERROR),
146 			"Instead read from FILEp");
147 	fclose(instf);
148 
149 	one = otrl_instag_find(us, "alice_xmpp", "XMPP");
150 	snprintf(sone, sizeof(sone), "%08x", one->instag);
151 
152 	two = otrl_instag_find(us, "alice_irc", "IRC");
153 	snprintf(stwo, sizeof(stwo), "%08x", two->instag);
154 
155 	three = otrl_instag_find(us, "alice_inv", "IRC");
156 
157 	four = otrl_instag_find(us, "alice_icq", "ICQ");
158 	snprintf(sfour, sizeof(sfour), "%08x", four->instag);
159 
160 	ok(one && two && !three && four &&
161 			strcmp(sone, "01234567") == 0 &&
162 			strcmp(stwo, "9abcdef0") == 0 &&
163 			strcmp(sfour, "98765432") == 0,
164 			"Instag succesfully read");
165 }
166 
test_otrl_instag_get_new(void)167 static void test_otrl_instag_get_new(void)
168 {
169 	ok(otrl_instag_get_new() != 0, "New instag generated");
170 }
171 
get_exe_path(char * buf,size_t len)172 static ssize_t get_exe_path(char *buf, size_t len)
173 {
174 	char *path_end;
175 
176 	if (readlink("/proc/self/exe", buf, len) < 0) {
177 		return -ENOMEM;
178 	}
179 
180 	/*
181 	 * Workaround to handle libtool path of the binary that is actually in the
182 	 * $(buildir)/.libs. This is to make sure unit test works outside of tree.
183 	 */
184 	path_end = strstr(buf, ".libs/");
185 	if (!path_end) {
186 		path_end = strrchr(buf, '/');
187 		if (!path_end) {
188 			return -errno;
189 		}
190 		*(++path_end) = '\0';
191 	} else {
192 		*path_end = '\0';
193 	}
194 
195 	return path_end - buf;
196 }
197 
main(int argc,char ** argv)198 int main(int argc, char **argv)
199 {
200 	/* Libtap call for the number of tests planned. */
201 	plan_tests(NUM_TESTS);
202 
203 	gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
204 	OTRL_INIT;
205 
206 	if (get_exe_path(curdir, sizeof(curdir)) < 0) {
207 		return -ENOMEM;
208 	}
209 
210 	/* Build the full path of the instag.txt file. */
211 	(void) snprintf(instag_filepath, sizeof(instag_filepath), "%s%s", curdir,
212 			"instag.txt");
213 
214 	test_otrl_instag_forget();
215 	test_otrl_instag_forget_all();
216 	test_otrl_instag_find();
217 	test_otrl_instag_read();
218 	test_otrl_instag_read_FILEp();
219 	test_otrl_instag_get_new();
220 
221 	return 0;
222 }
223