Crossfire Server, Trunk  R20513
check_account.c
Go to the documentation of this file.
1 /*
2  * static char *rcsid_check_account_c =
3  * "$Id: check_account.c 11817 2009-06-12 15:46:56Z akirschbaum $";
4  */
5 
6 /*
7  * CrossFire, A Multiplayer game for X-windows
8  *
9  * Copyright (C) 2010 Mark Wedel & Crossfire Development Team
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24  *
25  * The authors can be reached via e-mail at crossfire-devel@real-time.com
26  */
27 
28 /*
29  * This is the unit tests file for server/account.c
30  */
31 
32 #include <global.h>
33 #include <stdlib.h>
34 #include <check.h>
35 #include <loader.h>
36 #include <toolkit_common.h>
37 #include <sproto.h>
38 #include <unistd.h>
39 #include <toolkit_server.h>
40 
41 static void setup(void) {
42 }
43 
44 static void teardown(void) {
45  /* put any cleanup steps here, they will be run after each testcase */
46 }
47 
48 
49 /* This test makes sure account_check_string() behaves as expected -
50  * rejects strings with bad characters in them, etc.
51  */
52 START_TEST(test_account_check_string) {
53  char longname[MAX_NAME+3];
54  int i;
55 
56  i=account_check_string(" abcd");
57  fail_unless(i != 0, "string started with spaces should not be considered valid");
58  /* We test one string with colon at end, other starting with semicolon -
59  * in that way, we also do some basic testing to make sure entire string is being checked.
60  */
61  i=account_check_string("abcd:");
62  fail_unless(i != 0, "string with colons should not be considered valid");
63  i=account_check_string("a;bcd");
64  fail_unless(i != 0, "string with semicolons should not be considered valid");
65  i=account_check_string("a/bcd");
66  fail_unless(i != 0, "string with slash should not be considered valid");
67  i=account_check_string("a'bcd");
68  fail_unless(i != 0, "string with quote should not be considered valid");
69 
70  i=account_check_string("abc\n\nefg");
71  fail_unless(i != 0, "string with non printable characters should not be considered valid");
72 
73  i=account_check_string("$abc");
74  fail_unless(i != 0, "string starting with non alphanumeric should not be considered valid");
75 
76  i=account_check_string("abc ");
77  fail_unless(i != 0, "string ending in space should not be considered valid");
78 
79  for (i=0; i<=MAX_NAME; i++) {
80  longname[i]='a';
81  }
82  longname[i]='\0';
83  i=account_check_string(longname);
84 
85  fail_unless(i != 0, "Too long string should not be considered valid");
86 
87  i=account_check_string("Some Body");
88  fail_unless(i == 0, "Valid string not considered valid");
89 
90 }
91 END_TEST
92 
93 /* This test tries to add some accounts. As a final action, we try
94  * to save the account file out.
95  */
96 START_TEST(test_account_add_account) {
97  int i,j;
98  char names[50];
99  char **char_names;
100 
101  /* Note that we run explicit checks for valid account names/passwords.
102  * As such, the focus here is not checking valid strings again, but checking
103  * duplicate account names, saving them out, etc.
104  */
105  i=account_new("Some Body", "mypassword");
106  fail_unless(i == 0, "Could not add valid account, got code %d", i);
107 
108  i=account_new("Some Body", "mypassword");
109  fail_unless(i != 0, "Duplicate account successfully added");
110 
111  /* This is mainly here to have 2 valid accounts */
112  i=account_new("No Body", "mypassword");
113  fail_unless(i == 0, "Could not add valid account, got code %d", i);
114 
115  /* This third account is to have one with no players associated to it */
116  i=account_new("Every Body", "hispassword");
117  fail_unless(i == 0, "Could not add valid account");
118 
119  i=account_link("foobar", "foobar");
120  fail_unless(i != 0, "Added player to non existent character name");
121 
122  i=account_link("Some Body", "foobar");
123  fail_unless(i == 0, "Failed to add player to valid account");
124 
125  /* The precise number of players per account is not exposed,
126  * but at least as of now, it should be less than 30. So we try to add
127  * 30 players. We use |= so that we can just try to add them all.
128  */
129  for (j=0; j<30; j++) {
130  sprintf(names,"char-%02d", j);
131  i |= account_link("No Body", names);
132  }
133  fail_unless(i != 0, "Too many players added to account");
134 
135  char_names = account_get_players_for_account("foobar");
136  fail_unless(char_names == NULL, "Got non null value for players on account with non existant accoun");
137 
138  char_names = account_get_players_for_account("No Body");
139  fail_unless(char_names != NULL, "Got null value for players on account");
140 
141  /* No return value here */
142  accounts_save();
143 }
144 END_TEST
145 
146 /* This tests the load logic. Since the only data were are loading is the data from above,
147  * we use that knowledge to check for proper existence accounts, etc.
148  */
149 START_TEST(test_account_load_entries) {
150  int i,j;
151  char **char_names;
152  const char *ae;
153 
154  accounts_clear();
155  accounts_load();
156 
157  ae = account_exists("Every Body");
158  fail_unless(ae != NULL, "Could not find valid account");
159  ae = account_exists("Some Body");
160  fail_unless(ae != NULL, "Could not find valid account");
161 
162  char_names = account_get_players_for_account("No Body");
163  fail_unless(char_names != NULL, "Got null value for players on account");
164 
165  /* This is sort of data integrity testing - if char_names is not properly
166  * null terminated, with will fail. if char_names[] is corrupt, it should also
167  * core.
168  */
169  i=0;
170  while (char_names[i] != NULL) {
171  j=strlen(char_names[i]);
172  i++;
173  }
174  char_names = account_get_players_for_account("Some Body");
175  fail_unless(char_names != NULL, "Got null value for players on account");
176  fail_unless(strcmp(char_names[0],"foobar") == 0, "Can not match on name we put in");
177 
178  /* while we do this same check in test_account_add_account, doing it
179  * again here makes sure the code is properly detecting the end of the accounts
180  * list after loading it up.
181  */
182  char_names = account_get_players_for_account("foobar");
183  fail_unless(char_names == NULL, "Got non null value for players on account with non existant account");
184 
185  i = account_remove_player("foobar", "1foobar");
186  fail_unless(i!=0, "Got successsful return code on account_remove_player_from_account with non existent account");
187 
188  i = account_remove_player("No Body", "1foobar");
189  fail_unless(i!=0, "Got successsful return code on account_remove_player_from_account with non existent player");
190 
191  char_names = account_get_players_for_account("No Body");
192  j=0;
193  while (char_names[j] != NULL) {
194  j++;
195  }
196 
197  i = account_remove_player("No Body", "char-01");
198  fail_unless(i==0, "Got error removing player when it should have worked");
199 
200  char_names = account_get_players_for_account("No Body");
201 
202  i=0;
203  while (char_names[i] != NULL) {
204  i++;
205  }
206  fail_unless((i+1) == j, "Player removal get unexpected result - %d != %d", i+1, j);
207 }
208 END_TEST
209 
210 static Suite *account_suite(void) {
211  Suite *s = suite_create("account");
212  TCase *tc_core = tcase_create("Core");
213 
214  /*setup and teardown will be called before each test in testcase 'tc_core' */
215  tcase_add_checked_fixture(tc_core, setup, teardown);
216 
217  suite_add_tcase(s, tc_core);
218  tcase_add_test(tc_core, test_account_check_string);
219  tcase_add_test(tc_core, test_account_add_account);
220  tcase_add_test(tc_core, test_account_load_entries);
221 
222  return s;
223 }
224 
225 int main(void) {
226  int nf;
227  Suite *s = account_suite();
228  SRunner *sr = srunner_create(s);
229 
230  /* If you wish to debug the program, uncomment this line. */
231  /*srunner_set_fork_status (sr, CK_NOFORK);*/
232 
233  settings.debug = 0;
234  /* Not sure if there is a better place to put this file - basically,
235  * the account code usings the localdir to determine where to read/write
236  * the accounts file from - we don't want to be altering the real version of
237  * that file.
238  */
239  settings.localdir = strdup_local("/tmp/");
241  init(0, NULL);
242 
243  srunner_set_xml(sr, LOGDIR "/unit/server/account.xml");
244  srunner_set_log(sr, LOGDIR "/unit/server/account.out");
245  srunner_run_all(sr, CK_ENV); /*verbosity from env variable*/
246  nf = srunner_ntests_failed(sr);
247  srunner_free(sr);
249  return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
250 }
static void setup(void)
Definition: check_account.c:41
int account_remove_player(const char *account_name, const char *player_name)
Removes a player name from an account.
Definition: account.c:496
#define strdup_local
Definition: compat.h:25
int account_new(const char *account_name, const char *account_password)
Adds an account.
Definition: account.c:407
const char * account_exists(const char *account_name)
Checks the existing accounts, and see if this account exists.
Definition: account.c:308
void accounts_load(void)
This loads all the account entries into memory.
Definition: account.c:121
static END_TEST Suite * account_suite(void)
LogLevel debug
Default debugging level.
Definition: global.h:240
Global type definitions and header inclusions.
void clean_test_account_data(void)
Clean temporary account-related files, put into /tmp.
Definition: toolkit_server.c:5
void accounts_save(void)
Save all the account information.
Definition: account.c:267
Defines for loader.l / loader.c.
void init(int argc, char **argv)
This is the main server initialization function.
Definition: init.c:978
int account_check_string(const char *str)
Checks a string to make sure it does not have any invalid characters.
Definition: account.c:368
static void teardown(void)
Definition: check_account.c:44
int account_link(const char *account_name, const char *player_name)
Adds a player name to an account.
Definition: account.c:460
const char * localdir
Read/write data files.
Definition: global.h:245
struct Settings settings
Server settings.
Definition: init.c:40
START_TEST(test_account_check_string)
Definition: check_account.c:52
void accounts_clear(void)
This is used purely by the test harness - by clearing the accounts, it can then verify that the data ...
Definition: account.c:112
int main(void)
#define MAX_NAME
Definition: define.h:41
char ** account_get_players_for_account(const char *account_name)
Returns an array of strings for the characters on this account - the array is null terminated...
Definition: account.c:542