1<?php 2 3function check_skip_any() { 4 if (dba_handlers() === []) { 5 die('skip no handlers installed'); 6 } 7 if (dba_handlers() === ['cdb']) { 8 die('skip only cdb installed which is not suitable'); 9 } 10 if (dba_handlers() === ['cdb_make']) { 11 die('skip only cdb_make installed which is not suitable'); 12 } 13} 14 15function check_skip(string $handler) { 16 $handlers = dba_handlers(); 17 if ($handlers === []) { 18 die('skip no handlers installed'); 19 } 20 if (!in_array($handler, $handlers)) { 21 $HND = strtoupper($handler); 22 die("skip $HND handler not available"); 23 } 24} 25 26function get_any_handler(): string { 27 foreach (dba_handlers() as $handler) { 28 // Those are weird 29 if ($handler !== 'cdb' && $handler !== 'cdb_make' && $handler !== 'inifile') { 30 echo 'Using handler: "', $handler, '"', \PHP_EOL; 31 return $handler; 32 } 33 } 34 return 'should_not_happen'; 35} 36function get_any_db(string $name) { 37 return dba_open($name, 'c', get_any_handler()); 38} 39 40enum LockFlag: string { 41 case FileLock = 'l'; 42 case DbLock = 'd'; 43 case NoLock = '-'; 44} 45 46function set_up_db_ex(string $handler, string $name, LockFlag $lock, bool $persistent = false) { 47 $lock_flag = $lock->value; 48 // Open file in creation/truncation mode 49 $func = $persistent ? 'dba_popen' : 'dba_open'; 50 51 $db_file = $func($name, 'n'.$lock_flag, $handler); 52 53 if ($db_file === false) { 54 die("Failed to create DB"); 55 } 56 57 // Insert some data 58 dba_insert("key1", "Content String 1", $db_file); 59 dba_insert("key2", "Content String 2", $db_file); 60 dba_insert("key3", "Third Content String", $db_file); 61 dba_insert("key4", "Another Content String", $db_file); 62 dba_insert("key5", "The last content string", $db_file); 63 64 // Insert date with array keys 65 dba_insert(["", "name9"], "Content String 9", $db_file); 66 dba_insert(["key10", "name10"] , "Content String 10", $db_file); 67 dba_insert("[key30]name30", "Content String 30", $db_file); 68 69 return $db_file; 70} 71 72function set_up_db(string $handler, string $name, LockFlag $lock = LockFlag::FileLock): void { 73 $db_file = set_up_db_ex($handler, $name, $lock); 74 // Close creation/truncation handler 75 dba_close($db_file); 76} 77 78function run_common_read_only_test($dbHandle): void { 79 $key = dba_firstkey($dbHandle); 80 $result = []; 81 while ($key) { 82 $result[$key] = dba_fetch($key, $dbHandle); 83 $key = dba_nextkey($dbHandle); 84 } 85 ksort($result); 86 var_dump($result); 87} 88 89function run_standard_tests_ex(string $handler, string $name, LockFlag $lock, bool $persistent = false): void 90{ 91 $lock_flag = $lock->value; 92 set_up_db($handler, $name, $lock); 93 $db_writer = dba_open($name, 'w'.$lock_flag, $handler); 94 if ($db_writer === false) { 95 die("Failed to open DB for write"); 96 } 97 98 echo 'Remove key 1 and 3', \PHP_EOL; 99 var_dump(dba_delete("key3", $db_writer)); 100 var_dump(dba_delete("key1", $db_writer)); 101 102 echo 'Try to remove key 1 again', \PHP_EOL; 103 var_dump(dba_delete("key1", $db_writer)); 104 105 // Fetch data 106 $key = dba_firstkey($db_writer); 107 $total_keys = 0; 108 while ($key) { 109 echo $key, ': ', dba_fetch($key, $db_writer), \PHP_EOL; 110 $key = dba_nextkey($db_writer); 111 $total_keys++; 112 } 113 echo 'Total keys: ', $total_keys, \PHP_EOL; 114 for ($i = 1; $i < 6; $i++) { 115 echo "Key $i exists? ", dba_exists("key$i", $db_writer) ? 'Y' : 'N', \PHP_EOL; 116 } 117 118 echo 'Replace second key data', \PHP_EOL; 119 var_dump(dba_replace('key2', 'Content 2 replaced', $db_writer)); 120 echo dba_fetch('key2', $db_writer), \PHP_EOL; 121 122 // Check that read is possible when a lock is used 123 $test_flag = 't'; 124 if ($lock === LockFlag::NoLock) { 125 // No point testing when we don't use locks 126 $test_flag = ''; 127 } 128 $db_reader = @dba_open($name, 'r'.$lock_flag.$test_flag, $handler); 129 if ($db_reader === false) { 130 echo 'Read during write: not allowed', \PHP_EOL; 131 } else { 132 echo 'Read during write: allowed', \PHP_EOL; 133 dba_close($db_reader); 134 } 135 136 if (dba_insert('key number 6', 'The 6th value', $db_writer)) { 137 echo 'Expected: Added a new data entry', \PHP_EOL; 138 } else { 139 echo 'Unexpected: Failed to add a new data entry', \PHP_EOL; 140 } 141 142 if (dba_insert('key number 6', 'The 6th value inserted again would be an error', $db_writer)) { 143 echo 'Unexpected: Wrote data to already used key', \PHP_EOL; 144 } else { 145 echo 'Expected: Failed to insert data for already used key', \PHP_EOL; 146 } 147 148 echo 'Replace second key data', \PHP_EOL; 149 var_dump(dba_replace('key2', 'Content 2 replaced 2nd time', $db_writer)); 150 echo 'Delete "key4"', \PHP_EOL; 151 var_dump(dba_delete('key4', $db_writer)); 152 echo 'Fetch "key2": ', dba_fetch('key2', $db_writer), \PHP_EOL; 153 echo 'Fetch "key number 6": ', dba_fetch('key number 6', $db_writer), \PHP_EOL; 154 dba_close($db_writer); // when the writer is open at least db3 would fail because of buffered io. 155 156 $db_reader = dba_open($name, 'r'.$lock_flag, $handler); 157 run_common_read_only_test($db_reader); 158 dba_close($db_reader); 159 160 /* TODO popen test? Old code copied from the previous general test 161 if (($db_file = dba_popen($db_filename, 'r'.($lock_flag==''?'':'-'), $handler))!==FALSE) { 162 if ($handler == 'dbm' || $handler == "tcadb") { 163 dba_close($db_file); 164 } 165 } 166 */ 167} 168 169const MODES = ['r', 'w', 'c', 'n']; 170const LOCKS = ['l', 'd', '-', '' /* No lock flag is like 'd' */]; 171function run_creation_tests_ex(string $handler, string $file_suffix, string $pre_req): void 172{ 173 $db_name = $handler . $file_suffix; 174 foreach (MODES as $mode) { 175 foreach (LOCKS as $lock) { 176 eval($pre_req); 177 $arg = $mode.$lock; 178 echo 'Mode parameter is "', $arg, '":', \PHP_EOL; 179 $db = dba_open($db_name, $arg, $handler); 180 if ($db !== false) { 181 assert(file_exists($db_name)); 182 $status = dba_insert("key1", "This is a test insert", $db); 183 if ($status) { 184 $fetch = dba_fetch("key1", $db); 185 if ($fetch === false) { 186 echo 'Cannot fetch insertion', \PHP_EOL; 187 } else { 188 echo $fetch, \PHP_EOL; 189 } 190 } else { 191 echo 'Insertion failed', \PHP_EOL; 192 } 193 dba_close($db); 194 } else { 195 echo 'Opening DB failed', \PHP_EOL; 196 } 197 cleanup_standard_db($db_name); 198 } 199 } 200} 201 202function run_creation_tests(string $handler): void 203{ 204 $extension = $handler === 'tcadb' ? 'tch' : 'db'; 205 /* Trying to open a non-existing file */ 206 echo '=== OPENING NON-EXISTING FILE ===', \PHP_EOL; 207 run_creation_tests_ex($handler, '_not_existing.'.$extension, ''); 208 209 /* Trying to open an existing db file */ 210 echo '=== OPENING EXISTING DB FILE ===', \PHP_EOL; 211 run_creation_tests_ex($handler, '_existing.'.$extension, 'dba_open($db_name, "n", $handler);'); 212 213 /* Trying to open an existing random file */ 214 echo '=== OPENING EXISTING RANDOM FILE ===', \PHP_EOL; 215 run_creation_tests_ex($handler, '_random.txt', 'file_put_contents($db_name, "Dummy contents");'); 216} 217 218function clean_creation_tests(string $handler): void { 219 $db_name = $handler . '_not_existing.db'; 220 cleanup_standard_db($db_name); 221 $db_name = $handler . '_existing.db'; 222 cleanup_standard_db($db_name); 223 $db_name = $handler . '_random.txt'; 224 cleanup_standard_db($db_name); 225} 226 227function run_standard_tests(string $handler, string $name): void { 228 echo '=== RUNNING WITH FILE LOCK ===', \PHP_EOL; 229 ob_start(); 230 set_up_db($handler, $name, LockFlag::FileLock); 231 run_standard_tests_ex($handler, $name, LockFlag::FileLock); 232 cleanup_standard_db($name); 233 $run1_output = ob_get_flush(); 234 echo '=== RUNNING WITH DB LOCK (default) ===', \PHP_EOL; 235 ob_start(); 236 set_up_db($handler, $name, LockFlag::DbLock); 237 run_standard_tests_ex($handler, $name, LockFlag::DbLock); 238 cleanup_standard_db($name); 239 $run2_output = ob_get_clean(); 240 if ($run1_output === $run2_output) { 241 echo 'SAME OUTPUT AS PREVIOUS RUN', \PHP_EOL; 242 } else { 243 echo $run2_output; 244 } 245 246 echo '=== RUNNING WITH NO LOCK ===', \PHP_EOL; 247 ob_start(); 248 set_up_db($handler, $name, LockFlag::NoLock); 249 run_standard_tests_ex($handler, $name, LockFlag::NoLock); 250 $run3_output = ob_get_clean(); 251 if ($run2_output === $run3_output) { 252 echo 'SAME OUTPUT AS PREVIOUS RUN', \PHP_EOL; 253 } else if ($run2_output === str_replace( // If only the fact that the lock prevented reads 254 'Read during write: allowed', 255 'Read during write: not allowed', 256 $run3_output 257 ) 258 ) { 259 echo 'SAME OUTPUT AS PREVIOUS RUN (modulo read during write due to no lock)', \PHP_EOL; 260 } else { 261 echo $run3_output; 262 } 263} 264 265// TODO Array keys insertion 266// TODO Run all lock flags 267function set_up_cdb_db_and_run(string $name): void { 268 set_up_db('cdb', $name); 269 270 $db_file = dba_open($name, 'rl', 'cdb'); 271 if ($db_file === false) { 272 die("Failed to reopen DB"); 273 } 274 for ($i = 1; $i < 6; $i++) { 275 echo "Key $i exists? ", dba_exists("key$i", $db_file) ? 'Y' : 'N', \PHP_EOL; 276 } 277 run_common_read_only_test($db_file); 278 dba_close($db_file); 279 280 echo '--NO-LOCK--', \PHP_EOL; 281 cleanup_standard_db($name); 282 set_up_db('cdb', $name, LockFlag::NoLock); 283 $db_file = dba_open($name, 'r-', 'cdb'); 284 if ($db_file === false) { 285 die("Failed to reopen DB"); 286 } 287 for ($i = 1; $i < 6; $i++) { 288 echo "Key $i exists? ", dba_exists("key$i", $db_file) ? 'Y' : 'N', \PHP_EOL; 289 } 290 run_common_read_only_test($db_file); 291} 292 293function cleanup_standard_db(string $name): void { 294 @unlink($name); 295 @unlink($name.'.lck'); 296 @unlink($name.'-lock'); 297} 298