aboutsummaryrefslogtreecommitdiffhomepage
path: root/fish_tests.cpp
diff options
context:
space:
mode:
authorGravatar ridiculousfish <corydoras@ridiculousfish.com>2012-12-02 23:38:38 -0800
committerGravatar ridiculousfish <corydoras@ridiculousfish.com>2012-12-02 23:38:38 -0800
commit984a4980635c637057ada3efc9a213c0a1d037a9 (patch)
treed3843cf87733aa259be1aa9bb237e7c1a63eec03 /fish_tests.cpp
parentc1b51c65302f2d2a8008d9d02c40b9bd594cc3e8 (diff)
More work towards incremental history. Added some tests.
Diffstat (limited to 'fish_tests.cpp')
-rw-r--r--fish_tests.cpp122
1 files changed, 122 insertions, 0 deletions
diff --git a/fish_tests.cpp b/fish_tests.cpp
index ccf45337..0f7358b2 100644
--- a/fish_tests.cpp
+++ b/fish_tests.cpp
@@ -978,6 +978,9 @@ public:
static void test_history(void);
static void test_history_merge(void);
static void test_history_formats(void);
+
+ static void test_history_races(void);
+ static void test_history_races_pound_on_history();
};
static wcstring random_string(void)
@@ -1077,6 +1080,121 @@ static void time_barrier(void)
while (time(NULL) == start);
}
+static wcstring_list_t generate_history_lines(int pid)
+{
+ wcstring_list_t result;
+ long max = 256;
+ result.reserve(max);
+ for (long i=0; i < max; i++)
+ {
+ result.push_back(format_string(L"%ld %ld", (long)pid, i));
+ }
+ return result;
+}
+
+void history_tests_t::test_history_races_pound_on_history()
+{
+ /* Called in child process to modify history */
+ history_t *hist = new history_t(L"race_test");
+ hist->chaos_mode = true;
+ const wcstring_list_t lines = generate_history_lines(getpid());
+ for (size_t idx = 0; idx < lines.size(); idx++)
+ {
+ const wcstring &line = lines.at(idx);
+ hist->add(line);
+ hist->save();
+ }
+ delete hist;
+}
+
+void history_tests_t::test_history_races(void)
+{
+ say(L"Testing history race conditions");
+
+ // Ensure history is clear
+ history_t *hist = new history_t(L"race_test");
+ hist->clear();
+ delete hist;
+
+ // Test concurrent history writing
+#define RACE_COUNT 20
+ pid_t children[RACE_COUNT];
+
+ for (size_t i=0; i < RACE_COUNT; i++)
+ {
+ pid_t pid = fork();
+ if (! pid)
+ {
+ // Child process
+ setup_fork_guards();
+ test_history_races_pound_on_history();
+ exit_without_destructors(0);
+ }
+ else
+ {
+ // Parent process
+ children[i] = pid;
+ }
+ }
+
+ // Wait for all children
+ for (size_t i=0; i < RACE_COUNT; i++)
+ {
+ int stat;
+ waitpid(children[i], &stat, WUNTRACED);
+ }
+
+ // Compute the expected lines
+ wcstring_list_t lines[RACE_COUNT];
+ for (size_t i=0; i < RACE_COUNT; i++)
+ {
+ lines[i] = generate_history_lines(children[i]);
+ }
+
+ // Count total lines
+ size_t line_count = 0;
+ for (size_t i=0; i < RACE_COUNT; i++)
+ {
+ line_count += lines[i].size();
+ }
+
+ // Ensure we consider the lines that have been outputted as part of our history
+ time_barrier();
+
+ /* Ensure that we got sane, sorted results */
+ hist = new history_t(L"race_test");
+ hist->chaos_mode = true;
+ size_t hist_idx;
+ for (hist_idx = 1; ; hist_idx ++)
+ {
+ history_item_t item = hist->item_at_index(hist_idx);
+ if (item.empty())
+ break;
+
+ // The item must be present in one of our 'lines' arrays
+ // If it is present, then every item after it is assumed to be missed
+ size_t i;
+ for (i=0; i < RACE_COUNT; i++)
+ {
+ wcstring_list_t::iterator where = std::find(lines[i].begin(), lines[i].end(), item.str());
+ if (where != lines[i].end())
+ {
+ // Delete everything from the found location onwards
+ lines[i].resize(where - lines[i].begin());
+
+ // Break because we found it
+ break;
+ }
+ }
+ assert(i < RACE_COUNT && "Line expected to be at end of some array");
+ }
+ // every write should add at least one item
+ assert(hist_idx >= RACE_COUNT);
+
+ //hist->clear();
+ delete hist;
+}
+
void history_tests_t::test_history_merge(void)
{
// In a single fish process, only one history is allowed to exist with the given name
@@ -1310,6 +1428,7 @@ int main(int argc, char **argv)
reader_init();
env_init();
+#if 0
test_format();
test_escape();
test_convert();
@@ -1323,8 +1442,11 @@ int main(int argc, char **argv)
test_is_potential_path();
test_colors();
test_autosuggest_suggest_special();
+#endif
history_tests_t::test_history();
history_tests_t::test_history_merge();
+ history_tests_t::test_history_races();
+ return 0;
history_tests_t::test_history_formats();
say(L"Encountered %d errors in low-level tests", err_count);