1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 2000,2008 Oracle. All rights reserved. 5 * 6 * $Id: TestConstruct01.cpp,v 12.7 2008/01/08 20:58:54 bostic Exp $ 7 */ 8 9/* 10 * Do some regression tests for constructors. 11 * Run normally (without arguments) it is a simple regression test. 12 * Run with a numeric argument, it repeats the regression a number 13 * of times, to try to determine if there are memory leaks. 14 */ 15#include <sys/types.h> 16 17#include <iostream.h> 18#include <errno.h> 19#include <stdlib.h> 20#include <string.h> 21#ifndef _MSC_VER 22#include <unistd.h> 23#endif 24 25#include <iomanip.h> 26#include <db_cxx.h> 27 28#define ERR(a) \ 29 do { \ 30 cout << "FAIL: " << (a) << "\n"; sysexit(1); \ 31 } while (0) 32 33#define ERR2(a1,a2) \ 34 do { \ 35 cout << "FAIL: " << (a1) << ": " << (a2) << "\n"; sysexit(1); \ 36 } while (0) 37 38#define ERR3(a1,a2,a3) \ 39 do { \ 40 cout << "FAIL: " << (a1) << ": " << (a2) << ": " << (a3) << "\n"; sysexit(1); \ 41 } while (0) 42 43#define CHK(a) \ 44 do { \ 45 int _ret; \ 46 if ((_ret = (a)) != 0) { \ 47 ERR3("DB function " #a " has bad return", _ret, DbEnv::strerror(_ret)); \ 48 } \ 49 } while (0) 50 51#ifdef VERBOSE 52#define DEBUGOUT(a) cout << a << "\n" 53#else 54#define DEBUGOUT(a) 55#endif 56 57#define CONSTRUCT01_DBNAME "construct01.db" 58#define CONSTRUCT01_DBDIR "." 59#define CONSTRUCT01_DBFULLPATH (CONSTRUCT01_DBDIR "/" CONSTRUCT01_DBNAME) 60 61int itemcount; // count the number of items in the database 62 63// A good place to put a breakpoint... 64// 65void sysexit(int status) 66{ 67 exit(status); 68} 69 70void check_file_removed(const char *name, int fatal) 71{ 72 unlink(name); 73#if 0 74 if (access(name, 0) == 0) { 75 if (fatal) 76 cout << "FAIL: "; 77 cout << "File \"" << name << "\" still exists after run\n"; 78 if (fatal) 79 sysexit(1); 80 } 81#endif 82} 83 84// Check that key/data for 0 - count-1 are already present, 85// and write a key/data for count. The key and data are 86// both "0123...N" where N == count-1. 87// 88// For some reason on Windows, we need to open using the full pathname 89// of the file when there is no environment, thus the 'has_env' 90// variable. 91// 92void rundb(Db *db, int count, int has_env) 93{ 94 const char *name; 95 96 if (has_env) 97 name = CONSTRUCT01_DBNAME; 98 else 99 name = CONSTRUCT01_DBFULLPATH; 100 101 db->set_error_stream(&cerr); 102 103 // We don't really care about the pagesize, but we do want 104 // to make sure adjusting Db specific variables works before 105 // opening the db. 106 // 107 CHK(db->set_pagesize(1024)); 108 CHK(db->open(NULL, name, NULL, DB_BTREE, count ? 0 : DB_CREATE, 0664)); 109 110 // The bit map of keys we've seen 111 long bitmap = 0; 112 113 // The bit map of keys we expect to see 114 long expected = (1 << (count+1)) - 1; 115 116 char outbuf[10]; 117 int i; 118 for (i=0; i<count; i++) { 119 outbuf[i] = '0' + i; 120 } 121 outbuf[i++] = '\0'; 122 Dbt key(outbuf, i); 123 Dbt data(outbuf, i); 124 125 DEBUGOUT("Put: " << outbuf); 126 CHK(db->put(0, &key, &data, DB_NOOVERWRITE)); 127 128 // Acquire a cursor for the table. 129 Dbc *dbcp; 130 CHK(db->cursor(NULL, &dbcp, 0)); 131 132 // Walk through the table, checking 133 Dbt readkey; 134 Dbt readdata; 135 while (dbcp->get(&readkey, &readdata, DB_NEXT) == 0) { 136 char *key_string = (char *)readkey.get_data(); 137 char *data_string = (char *)readdata.get_data(); 138 DEBUGOUT("Got: " << key_string << ": " << data_string); 139 int len = strlen(key_string); 140 long bit = (1 << len); 141 if (len > count) { 142 ERR("reread length is bad"); 143 } 144 else if (strcmp(data_string, key_string) != 0) { 145 ERR("key/data don't match"); 146 } 147 else if ((bitmap & bit) != 0) { 148 ERR("key already seen"); 149 } 150 else if ((expected & bit) == 0) { 151 ERR("key was not expected"); 152 } 153 else { 154 bitmap |= bit; 155 expected &= ~(bit); 156 for (i=0; i<len; i++) { 157 if (key_string[i] != ('0' + i)) { 158 cout << " got " << key_string 159 << " (" << (int)key_string[i] << ")" 160 << ", wanted " << i 161 << " (" << (int)('0' + i) << ")" 162 << " at position " << i << "\n"; 163 ERR("key is corrupt"); 164 } 165 } 166 } 167 } 168 if (expected != 0) { 169 cout << " expected more keys, bitmap is: " << expected << "\n"; 170 ERR("missing keys in database"); 171 } 172 CHK(dbcp->close()); 173 CHK(db->close(0)); 174} 175 176void t1(int except_flag) 177{ 178 cout << " Running test 1:\n"; 179 Db db(0, except_flag); 180 rundb(&db, itemcount++, 0); 181 cout << " finished.\n"; 182} 183 184void t2(int except_flag) 185{ 186 cout << " Running test 2:\n"; 187 Db db(0, except_flag); 188 rundb(&db, itemcount++, 0); 189 cout << " finished.\n"; 190} 191 192void t3(int except_flag) 193{ 194 cout << " Running test 3:\n"; 195 Db db(0, except_flag); 196 rundb(&db, itemcount++, 0); 197 cout << " finished.\n"; 198} 199 200void t4(int except_flag) 201{ 202 cout << " Running test 4:\n"; 203 DbEnv env(except_flag); 204 CHK(env.open(CONSTRUCT01_DBDIR, DB_CREATE | DB_INIT_MPOOL, 0)); 205 Db db(&env, 0); 206 CHK(db.close(0)); 207 CHK(env.close(0)); 208 cout << " finished.\n"; 209} 210 211void t5(int except_flag) 212{ 213 cout << " Running test 5:\n"; 214 DbEnv env(except_flag); 215 CHK(env.open(CONSTRUCT01_DBDIR, DB_CREATE | DB_INIT_MPOOL, 0)); 216 Db db(&env, 0); 217 rundb(&db, itemcount++, 1); 218 // Note we cannot reuse the old Db! 219 Db anotherdb(&env, 0); 220 221 anotherdb.set_errpfx("test5"); 222 rundb(&anotherdb, itemcount++, 1); 223 CHK(env.close(0)); 224 cout << " finished.\n"; 225} 226 227void t6(int except_flag) 228{ 229 cout << " Running test 6:\n"; 230 231 /* From user [#2939] */ 232 int err; 233 234 DbEnv* penv = new DbEnv(DB_CXX_NO_EXCEPTIONS); 235 penv->set_cachesize(0, 32 * 1024, 0); 236 penv->open(CONSTRUCT01_DBDIR, DB_CREATE | DB_PRIVATE | DB_INIT_MPOOL, 0); 237 238 //LEAK: remove this block and leak disappears 239 Db* pdb = new Db(penv,0); 240 if ((err = pdb->close(0)) != 0) { 241 fprintf(stderr, "Error closing Db: %s\n", db_strerror(err)); 242 } 243 delete pdb; 244 //LEAK: remove this block and leak disappears 245 246 if ((err = penv->close(0)) != 0) { 247 fprintf(stderr, "Error closing DbEnv: %s\n", db_strerror(err)); 248 } 249 delete penv; 250 251 cout << " finished.\n"; 252} 253 254// remove any existing environment or database 255void removeall() 256{ 257 { 258 DbEnv tmpenv(DB_CXX_NO_EXCEPTIONS); 259 (void)tmpenv.remove(CONSTRUCT01_DBDIR, DB_FORCE); 260 } 261 262 check_file_removed(CONSTRUCT01_DBFULLPATH, 1); 263 for (int i=0; i<8; i++) { 264 char buf[20]; 265 sprintf(buf, "__db.00%d", i); 266 check_file_removed(buf, 1); 267 } 268} 269 270int doall(int except_flag) 271{ 272 itemcount = 0; 273 try { 274 // before and after the run, removing any 275 // old environment/database. 276 // 277 removeall(); 278 t1(except_flag); 279 t2(except_flag); 280 t3(except_flag); 281 t4(except_flag); 282 t5(except_flag); 283 t6(except_flag); 284 285 removeall(); 286 return 0; 287 } 288 catch (DbException &dbe) { 289 ERR2("EXCEPTION RECEIVED", dbe.what()); 290 } 291 return 1; 292} 293 294int main(int argc, char *argv[]) 295{ 296 int iterations = 1; 297 if (argc > 1) { 298 iterations = atoi(argv[1]); 299 if (iterations < 0) { 300 ERR("Usage: construct01 count"); 301 } 302 } 303 for (int i=0; i<iterations; i++) { 304 if (iterations != 0) { 305 cout << "(" << i << "/" << iterations << ") "; 306 } 307 cout << "construct01 running:\n"; 308 if (doall(DB_CXX_NO_EXCEPTIONS) != 0) { 309 ERR("SOME TEST FAILED FOR NO-EXCEPTION TEST"); 310 } 311 else if (doall(0) != 0) { 312 ERR("SOME TEST FAILED FOR EXCEPTION TEST"); 313 } 314 else { 315 cout << "\nALL TESTS SUCCESSFUL\n"; 316 } 317 } 318 return 0; 319} 320