@@ -49,7 +49,7 @@ FOSSIL_TEARDOWN(cpp_myshell_fixture) {
4949
5050/*
5151 * Test case for creating a new record in the database file (FSON encoding)
52- * Uses C++ RAII wrapper
52+ * Now uses fossil::bluecrab::MyShell C++ RAII wrapper.
5353 */
5454FOSSIL_TEST (cpp_test_myshell_open_create_close) {
5555 fossil_bluecrab_myshell_error_t err;
@@ -96,110 +96,274 @@ FOSSIL_TEST(cpp_test_myshell_errstr) {
9696 ASSUME_ITS_EQUAL_CSTR (fossil::bluecrab::MyShell::errstr (FOSSIL_MYSHELL_ERROR_SUCCESS), " Success" );
9797 ASSUME_ITS_EQUAL_CSTR (fossil::bluecrab::MyShell::errstr (FOSSIL_MYSHELL_ERROR_NOT_FOUND), " Not found" );
9898 ASSUME_ITS_EQUAL_CSTR (fossil::bluecrab::MyShell::errstr (FOSSIL_MYSHELL_ERROR_INVALID_FILE), " Invalid file" );
99+ ASSUME_ITS_EQUAL_CSTR (fossil::bluecrab::MyShell::errstr (static_cast <fossil_bluecrab_myshell_error_t >(9999 )), " Unknown error" );
99100}
100101
101- // Edge case tests for myshell
102-
103- FOSSIL_TEST (cpp_test_myshell_corrupted_key_hash) {
102+ FOSSIL_TEST (cpp_test_myshell_put_get_del) {
104103 fossil_bluecrab_myshell_error_t err;
105- const std::string file_name = " corrupt_key .myshell" ;
104+ const std::string file_name = " test_put_get_del .myshell" ;
106105 auto db = fossil::bluecrab::MyShell::create (file_name, err);
107106 ASSUME_ITS_TRUE (db.is_open ());
108107
109- db.put (" corruptkey" , " cstr" , " corruptval" );
110- db.commit (" commit" );
108+ // Put key-value pairs
109+ err = db.put (" username" , " cstr" , " alice" );
110+ ASSUME_ITS_TRUE (err == FOSSIL_MYSHELL_ERROR_SUCCESS);
111+
112+ err = db.put (" password" , " cstr" , " secret" );
113+ ASSUME_ITS_TRUE (err == FOSSIL_MYSHELL_ERROR_SUCCESS);
114+
115+ // Get key-value pairs
116+ std::string value;
117+ err = db.get (" username" , value);
118+ ASSUME_ITS_TRUE (err == FOSSIL_MYSHELL_ERROR_SUCCESS);
119+ ASSUME_ITS_EQUAL_CSTR (value.c_str (), " alice" );
120+
121+ err = db.get (" password" , value);
122+ ASSUME_ITS_TRUE (err == FOSSIL_MYSHELL_ERROR_SUCCESS);
123+ ASSUME_ITS_EQUAL_CSTR (value.c_str (), " secret" );
124+
125+ // Delete key
126+ err = db.del (" username" );
127+ ASSUME_ITS_TRUE (err == FOSSIL_MYSHELL_ERROR_SUCCESS);
128+
129+ err = db.get (" username" , value);
130+ ASSUME_ITS_TRUE (err == FOSSIL_MYSHELL_ERROR_NOT_FOUND);
111131
112132 db.close ();
133+ remove (file_name.c_str ());
134+ }
113135
114- // Corrupt the key hash in the file
115- FILE *file = fopen (file_name.c_str (), " rb+" );
116- ASSUME_ITS_TRUE (file != NULL );
117- char line[1024 ];
118- long pos = 0 ;
119- while (fgets (line, sizeof (line), file)) {
120- char *hash_comment = strstr (line, " #hash=" );
121- if (hash_comment) {
122- pos = ftell (file) - strlen (line) + (hash_comment - line) + 6 ;
123- break ;
124- }
136+ FOSSIL_TEST (cpp_test_myshell_put_all_types) {
137+ fossil_bluecrab_myshell_error_t err;
138+ const std::string file_name = " test_put_all_types.myshell" ;
139+ auto db = fossil::bluecrab::MyShell::create (file_name, err);
140+ ASSUME_ITS_TRUE (db.is_open ());
141+
142+ const char *types[] = {
143+ " null" , " bool" , " i8" , " i16" , " i32" , " i64" , " u8" , " u16" , " u32" , " u64" ,
144+ " f32" , " f64" , " oct" , " hex" , " bin" , " char" , " cstr" , " array" , " object" ,
145+ " enum" , " datetime" , " duration"
146+ };
147+ const char *values[] = {
148+ " " , " true" , " 127" , " 32767" , " 2147483647" , " 9223372036854775807" ,
149+ " 255" , " 65535" , " 4294967295" , " 18446744073709551615" ,
150+ " 3.14" , " 2.71828" , " 0755" , " 0xFF" , " 0b1010" , " A" , " hello" , " [1,2]" , " {\" k\" :1}" , " VAL" , " 2024-06-01T12:00:00Z" , " 1h30m"
151+ };
152+
153+ for (size_t i = 0 ; i < sizeof (types)/sizeof (types[0 ]); ++i) {
154+ std::string key = std::string (" key_" ) + types[i];
155+ err = db.put (key, types[i], values[i]);
156+ ASSUME_ITS_TRUE (err == FOSSIL_MYSHELL_ERROR_SUCCESS);
157+
158+ std::string value;
159+ err = db.get (key, value);
160+ ASSUME_ITS_TRUE (err == FOSSIL_MYSHELL_ERROR_SUCCESS);
161+ ASSUME_ITS_EQUAL_CSTR (value.c_str (), values[i]);
125162 }
126- fseek (file, pos, SEEK_SET);
127- fputs (" deadbeefdeadbeef" , file); // overwrite hash with invalid value
128- fclose (file);
129163
130- fossil::bluecrab::MyShell db2 (file_name, err);
131- ASSUME_ITS_TRUE (db2.is_open ());
164+ db.close ();
165+ remove (file_name.c_str ());
166+ }
132167
133- err = db2.check_integrity ();
134- ASSUME_ITS_TRUE (err == FOSSIL_MYSHELL_ERROR_INTEGRITY);
168+ FOSSIL_TEST (cpp_test_myshell_put_invalid_type) {
169+ fossil_bluecrab_myshell_error_t err;
170+ const std::string file_name = " test_put_invalid_type.myshell" ;
171+ auto db = fossil::bluecrab::MyShell::create (file_name, err);
172+ ASSUME_ITS_TRUE (db.is_open ());
135173
136- db2.close ();
174+ err = db.put (" badkey" , " notatype" , " value" );
175+ ASSUME_ITS_TRUE (err == FOSSIL_MYSHELL_ERROR_INVALID_TYPE);
176+
177+ db.close ();
137178 remove (file_name.c_str ());
138179}
139180
140- FOSSIL_TEST (cpp_test_myshell_corrupted_file_size ) {
181+ FOSSIL_TEST (cpp_test_myshell_get_not_found ) {
141182 fossil_bluecrab_myshell_error_t err;
142- const std::string file_name = " corrupt_size .myshell" ;
183+ const std::string file_name = " test_get_not_found .myshell" ;
143184 auto db = fossil::bluecrab::MyShell::create (file_name, err);
144185 ASSUME_ITS_TRUE (db.is_open ());
145186
146- db.put (" sizekey" , " cstr" , " sizeval" );
147- db.commit (" commit" );
187+ std::string value;
188+ err = db.get (" nonexistent" , value);
189+ ASSUME_ITS_TRUE (err == FOSSIL_MYSHELL_ERROR_NOT_FOUND);
148190
149- // Artificially change db->file_size to simulate corruption
150- db.handle ()->file_size += 10 ;
191+ db.close ();
192+ remove (file_name.c_str ());
193+ }
194+
195+ FOSSIL_TEST (cpp_test_myshell_get_buffer_too_small) {
196+ fossil_bluecrab_myshell_error_t err;
197+ const std::string file_name = " test_get_buffer_small.myshell" ;
198+ auto db = fossil::bluecrab::MyShell::create (file_name, err);
199+ ASSUME_ITS_TRUE (db.is_open ());
200+
201+ err = db.put (" shortkey" , " cstr" , " longvalue" );
202+ ASSUME_ITS_TRUE (err == FOSSIL_MYSHELL_ERROR_SUCCESS);
151203
152- err = db.check_integrity ();
153- ASSUME_ITS_TRUE (err == FOSSIL_MYSHELL_ERROR_CORRUPTED);
204+ // Direct C API call for buffer-too-small test
205+ char value[4 ]; // too small for "longvalue"
206+ err = fossil_myshell_get (db.handle (), " shortkey" , value, sizeof (value));
207+ ASSUME_ITS_TRUE (err == FOSSIL_MYSHELL_ERROR_BUFFER_TOO_SMALL);
154208
155209 db.close ();
156210 remove (file_name.c_str ());
157211}
158212
159- FOSSIL_TEST (cpp_test_myshell_parse_failed_commit ) {
213+ FOSSIL_TEST (cpp_test_myshell_del_not_found ) {
160214 fossil_bluecrab_myshell_error_t err;
161- const std::string file_name = " parsefail .myshell" ;
215+ const std::string file_name = " test_del_not_found .myshell" ;
162216 auto db = fossil::bluecrab::MyShell::create (file_name, err);
163217 ASSUME_ITS_TRUE (db.is_open ());
164218
165- db.put (" parsekey" , " cstr" , " parseval" );
166- db.commit (" parse commit" );
219+ // Try to delete a key that does not exist
220+ err = db.del (" nonexistent_key" );
221+ ASSUME_ITS_TRUE (err == FOSSIL_MYSHELL_ERROR_NOT_FOUND);
167222
168223 db.close ();
224+ remove (file_name.c_str ());
225+ }
169226
170- // Remove timestamp from commit line to cause parse failure
171- FILE *file = fopen (file_name.c_str (), " rb+" );
172- ASSUME_ITS_TRUE (file != NULL );
173- char lines[10 ][1024 ];
174- int count = 0 ;
175- while (fgets (lines[count], sizeof (lines[count]), file)) {
176- count++;
177- }
178- fclose (file);
179-
180- file = fopen (file_name.c_str (), " wb" );
181- ASSUME_ITS_TRUE (file != NULL );
182- for (int i = 0 ; i < count; ++i) {
183- if (strncmp (lines[i], " #commit " , 8 ) == 0 ) {
184- char hash_str[17 ], msg[512 ];
185- int n = sscanf (lines[i], " #commit %16s %511[^\n ]" , hash_str, msg);
186- if (n == 2 ) {
187- fprintf (file, " #commit %s %s\n " , hash_str, msg); // omit timestamp
188- }
189- } else {
190- fputs (lines[i], file);
191- }
192- }
193- fclose (file);
227+ FOSSIL_TEST (cpp_test_myshell_del_twice) {
228+ fossil_bluecrab_myshell_error_t err;
229+ const std::string file_name = " test_del_twice.myshell" ;
230+ auto db = fossil::bluecrab::MyShell::create (file_name, err);
231+ ASSUME_ITS_TRUE (db.is_open ());
194232
195- fossil::bluecrab::MyShell db2 (file_name, err);
233+ // Put a key and delete it
234+ err = db.put (" key" , " cstr" , " value" );
235+ ASSUME_ITS_TRUE (err == FOSSIL_MYSHELL_ERROR_SUCCESS);
236+
237+ err = db.del (" key" );
238+ ASSUME_ITS_TRUE (err == FOSSIL_MYSHELL_ERROR_SUCCESS);
239+
240+ // Try to delete again
241+ err = db.del (" key" );
242+ ASSUME_ITS_TRUE (err == FOSSIL_MYSHELL_ERROR_NOT_FOUND);
243+
244+ db.close ();
245+ remove (file_name.c_str ());
246+ }
247+
248+ FOSSIL_TEST (cpp_test_myshell_stage_unstage) {
249+ fossil_bluecrab_myshell_error_t err;
250+ const std::string file_name = " test_stage_unstage.myshell" ;
251+ auto db = fossil::bluecrab::MyShell::create (file_name, err);
252+ ASSUME_ITS_TRUE (db.is_open ());
253+
254+ err = db.stage (" foo" , " cstr" , " bar" );
255+ ASSUME_ITS_TRUE (err == FOSSIL_MYSHELL_ERROR_SUCCESS);
256+
257+ err = db.unstage (" foo" );
258+ ASSUME_ITS_TRUE (err == FOSSIL_MYSHELL_ERROR_SUCCESS);
259+
260+ // Unstage again should return NOT_FOUND
261+ err = db.unstage (" foo" );
262+ ASSUME_ITS_TRUE (err == FOSSIL_MYSHELL_ERROR_NOT_FOUND);
263+
264+ db.close ();
265+ remove (file_name.c_str ());
266+ }
267+
268+ FOSSIL_TEST (cpp_test_myshell_backup_restore) {
269+ fossil_bluecrab_myshell_error_t err;
270+ const std::string file_name = " test_backup_restore.myshell" ;
271+ const std::string backup_file = " test_backup_restore.bak" ;
272+ const std::string restore_file = " test_backup_restore_restored.myshell" ;
273+ auto db = fossil::bluecrab::MyShell::create (file_name, err);
274+ ASSUME_ITS_TRUE (db.is_open ());
275+
276+ err = db.put (" alpha" , " cstr" , " beta" );
277+ ASSUME_ITS_TRUE (err == FOSSIL_MYSHELL_ERROR_SUCCESS);
278+
279+ err = db.backup (backup_file);
280+ ASSUME_ITS_TRUE (err == FOSSIL_MYSHELL_ERROR_SUCCESS);
281+
282+ db.close ();
283+
284+ err = fossil::bluecrab::MyShell::restore (backup_file, restore_file);
285+ ASSUME_ITS_TRUE (err == FOSSIL_MYSHELL_ERROR_SUCCESS);
286+
287+ fossil::bluecrab::MyShell db2 (restore_file, err);
196288 ASSUME_ITS_TRUE (db2.is_open ());
197289
198- err = db2.check_integrity ();
199- ASSUME_ITS_TRUE (err == FOSSIL_MYSHELL_ERROR_PARSE_FAILED);
290+ std::string value;
291+ err = db2.get (" alpha" , value);
292+ ASSUME_ITS_TRUE (err == FOSSIL_MYSHELL_ERROR_SUCCESS);
293+ ASSUME_ITS_EQUAL_CSTR (value.c_str (), " beta" );
200294
201295 db2.close ();
202296 remove (file_name.c_str ());
297+ remove (backup_file.c_str ());
298+ remove (restore_file.c_str ());
299+ }
300+
301+ FOSSIL_TEST (cpp_test_myshell_open_invalid_path) {
302+ fossil_bluecrab_myshell_error_t err;
303+ fossil::bluecrab::MyShell db1 (" " , err);
304+ ASSUME_ITS_TRUE (!db1.is_open ());
305+ ASSUME_ITS_TRUE (err == FOSSIL_MYSHELL_ERROR_INVALID_FILE);
306+
307+ fossil::bluecrab::MyShell db2 (" not_a_myshell.txt" , err);
308+ ASSUME_ITS_TRUE (!db2.is_open ());
309+ ASSUME_ITS_TRUE (err == FOSSIL_MYSHELL_ERROR_INVALID_FILE);
310+ }
311+
312+ FOSSIL_TEST (cpp_test_myshell_create_existing_file) {
313+ fossil_bluecrab_myshell_error_t err;
314+ const std::string file_name = " test_existing.myshell" ;
315+ auto db = fossil::bluecrab::MyShell::create (file_name, err);
316+ ASSUME_ITS_TRUE (db.is_open ());
317+ db.close ();
318+
319+ auto db2 = fossil::bluecrab::MyShell::create (file_name, err);
320+ ASSUME_ITS_TRUE (!db2.is_open ());
321+ ASSUME_ITS_TRUE (err == FOSSIL_MYSHELL_ERROR_ALREADY_EXISTS);
322+
323+ remove (file_name.c_str ());
324+ }
325+
326+ FOSSIL_TEST (cpp_test_myshell_backup_restore_null_args) {
327+ fossil_bluecrab_myshell_error_t err;
328+ const std::string file_name = " test_backup_restore_null.myshell" ;
329+ auto db = fossil::bluecrab::MyShell::create (file_name, err);
330+ ASSUME_ITS_TRUE (db.is_open ());
331+
332+ err = fossil_myshell_backup (nullptr , " backup.bak" );
333+ ASSUME_ITS_TRUE (err == FOSSIL_MYSHELL_ERROR_INVALID_FILE);
334+
335+ err = fossil_myshell_backup (db.handle (), nullptr );
336+ ASSUME_ITS_TRUE (err == FOSSIL_MYSHELL_ERROR_CONFIG_INVALID);
337+
338+ err = fossil_myshell_backup (db.handle (), " " );
339+ ASSUME_ITS_TRUE (err == FOSSIL_MYSHELL_ERROR_CONFIG_INVALID);
340+
341+ err = fossil_myshell_restore (nullptr , " target.myshell" );
342+ ASSUME_ITS_TRUE (err == FOSSIL_MYSHELL_ERROR_INVALID_FILE);
343+
344+ err = fossil_myshell_restore (" backup.bak" , nullptr );
345+ ASSUME_ITS_TRUE (err == FOSSIL_MYSHELL_ERROR_INVALID_FILE);
346+
347+ db.close ();
348+ remove (file_name.c_str ());
349+ }
350+
351+ FOSSIL_TEST (cpp_test_myshell_diff_null_args) {
352+ fossil_bluecrab_myshell_error_t err;
353+ char diff[128 ];
354+ err = fossil_myshell_diff (nullptr , nullptr , diff, sizeof (diff));
355+ ASSUME_ITS_TRUE (err == FOSSIL_MYSHELL_ERROR_INVALID_FILE);
356+
357+ err = fossil_myshell_diff (nullptr , nullptr , nullptr , sizeof (diff));
358+ ASSUME_ITS_TRUE (err == FOSSIL_MYSHELL_ERROR_INVALID_FILE);
359+
360+ err = fossil_myshell_diff (nullptr , nullptr , diff, 0 );
361+ ASSUME_ITS_TRUE (err == FOSSIL_MYSHELL_ERROR_INVALID_FILE);
362+ }
363+
364+ FOSSIL_TEST (cpp_test_myshell_check_integrity_null) {
365+ fossil_bluecrab_myshell_error_t err = fossil_myshell_check_integrity (nullptr );
366+ ASSUME_ITS_TRUE (err == FOSSIL_MYSHELL_ERROR_INVALID_FILE);
203367}
204368
205369// * * * * * * * * * * * * * * * * * * * * * * * *
@@ -209,9 +373,20 @@ FOSSIL_TEST_GROUP(cpp_myshell_database_tests) {
209373 FOSSIL_TEST_ADD (cpp_myshell_fixture, cpp_test_myshell_open_create_close);
210374 FOSSIL_TEST_ADD (cpp_myshell_fixture, cpp_test_myshell_commit_branch_checkout);
211375 FOSSIL_TEST_ADD (cpp_myshell_fixture, cpp_test_myshell_errstr);
212- FOSSIL_TEST_ADD (cpp_myshell_fixture, cpp_test_myshell_corrupted_key_hash);
213- FOSSIL_TEST_ADD (cpp_myshell_fixture, cpp_test_myshell_corrupted_file_size);
214- FOSSIL_TEST_ADD (cpp_myshell_fixture, cpp_test_myshell_parse_failed_commit);
376+ FOSSIL_TEST_ADD (cpp_myshell_fixture, cpp_test_myshell_put_get_del);
377+ FOSSIL_TEST_ADD (cpp_myshell_fixture, cpp_test_myshell_put_all_types);
378+ FOSSIL_TEST_ADD (cpp_myshell_fixture, cpp_test_myshell_put_invalid_type);
379+ FOSSIL_TEST_ADD (cpp_myshell_fixture, cpp_test_myshell_get_not_found);
380+ FOSSIL_TEST_ADD (cpp_myshell_fixture, cpp_test_myshell_get_buffer_too_small);
381+ FOSSIL_TEST_ADD (cpp_myshell_fixture, cpp_test_myshell_del_not_found);
382+ FOSSIL_TEST_ADD (cpp_myshell_fixture, cpp_test_myshell_del_twice);
383+ FOSSIL_TEST_ADD (cpp_myshell_fixture, cpp_test_myshell_stage_unstage);
384+ FOSSIL_TEST_ADD (cpp_myshell_fixture, cpp_test_myshell_backup_restore);
385+ FOSSIL_TEST_ADD (cpp_myshell_fixture, cpp_test_myshell_open_invalid_path);
386+ FOSSIL_TEST_ADD (cpp_myshell_fixture, cpp_test_myshell_create_existing_file);
387+ FOSSIL_TEST_ADD (cpp_myshell_fixture, cpp_test_myshell_backup_restore_null_args);
388+ FOSSIL_TEST_ADD (cpp_myshell_fixture, cpp_test_myshell_diff_null_args);
389+ FOSSIL_TEST_ADD (cpp_myshell_fixture, cpp_test_myshell_check_integrity_null);
215390
216391 FOSSIL_TEST_REGISTER (cpp_myshell_fixture);
217392} // end of tests
0 commit comments