Skip to content

Commit c82a2ff

Browse files
Revise myshell test cases for better functionality
Refactor myshell test cases to improve coverage and clarity.
1 parent 5999188 commit c82a2ff

File tree

1 file changed

+243
-68
lines changed

1 file changed

+243
-68
lines changed

code/tests/cases/test_myshell.cpp

Lines changed: 243 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -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
*/
5454
FOSSIL_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

Comments
 (0)