about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--prof_history.c105
-rw-r--r--test_prof_history.c37
2 files changed, 106 insertions, 36 deletions
diff --git a/prof_history.c b/prof_history.c
index 24213140..e896ac15 100644
--- a/prof_history.c
+++ b/prof_history.c
@@ -32,17 +32,26 @@ PHistory p_history_new(unsigned int size)
 
 void p_history_append(PHistory history, char *item)
 {
-    char *copied = strdup(item);
+    char *copied = "";
+    if (item != NULL) {
+        copied = strdup(item);
+    }
 
-    // if not editing history (no session)
+    // if no history yet, just add the item
+    if (history->items == NULL) {
+        history->items = g_list_append(history->items, copied);
+        return;
+    }
+        
+    // if not editing history (no session started)
     if (history->session == NULL) {
         
-        // if already at max size
+        // lose first element if hit max size
         if (g_list_length(history->items) == history->max_size) {
 
             // remove first element
             GList *first = g_list_first(history->items);
-            const char *first_item = (char *) first->data;
+            char *first_item = first->data;
             history->items = g_list_remove(history->items, first_item);
         }
     
@@ -51,19 +60,23 @@ void p_history_append(PHistory history, char *item)
 
     // if editing history (session exists with possible changes)
     } else {
-        
-        // if adding a new element, copy the session over the history
-        if (history->sess_curr == history->sess_new) {
+
+        // if adding a new item, copy the session over the history
+        if ((history->sess_new != NULL) && 
+                (history->sess_curr == history->sess_new)) {
             _replace_history_with_session(history);
 
         // otherwise, adding edited history item
         } else {
-            // remove the new item, from the session
-            history->session = g_list_reverse(history->session);
-            GList *first = g_list_first(history->session);
-            const char *first_item = (char *) first->data;
-            history->session = g_list_remove(history->session, first_item);
-            history->session = g_list_reverse(history->session);
+            
+            // discard the new item if there was one
+            if (history->sess_new != NULL) {
+                history->session = g_list_reverse(history->session);
+                GList *first = g_list_first(history->session);
+                char *first_item = first->data;
+                history->session = g_list_remove(history->session, first_item);
+                history->session = g_list_reverse(history->session);
+            }
 
             // copy sess_curr to the end of the session
             char *new_data = strdup(history->sess_curr->data);
@@ -99,45 +112,77 @@ static void _replace_history_with_session(PHistory history)
 
 char * p_history_previous(PHistory history, char *item)
 {
+    // no history
     if (history->items == NULL) {
         return item;
     }
 
+    char *copied = "";
+    if (item != NULL) {
+        copied = strdup(item);
+    }
+    
+    // no session, create one
     if (history->session == NULL) {
         history->session = g_list_copy(history->items);
         history->sess_curr = g_list_last(history->session);
+        history->items_curr = g_list_last(history->items);
+        
+        // add the new item including empty string
+        g_list_append(history->session, copied);
+        history->sess_new = g_list_last(history->session);
+
+        char *result = strdup(history->sess_curr->data);
+        return result;
+
+    // session exists
     } else {
+        // update the currently pointed to item with passed data
+        history->sess_curr->data = copied;
+        
+        // move to previous
         history->sess_curr = g_list_previous(history->sess_curr);
-    }
+        history->items_curr = g_list_previous(history->items_curr);
 
-    // set to first if rolled over beginning
-    if (history->sess_curr == NULL) {
-        history->sess_curr = g_list_first(history->session);
+        // set to first if rolled over beginning
+        if (history->sess_curr == NULL) {
+            history->sess_curr = g_list_first(history->session);
+            history->items_curr = g_list_first(history->items);
+        }
     }
 
-    char *curr = history->sess_curr->data;
-    char *result = malloc((strlen(curr) + 1) * sizeof(char));
-    strcpy(result, curr);
-
+    char *result = strdup(history->sess_curr->data);
     return result;
 }
 
 char * p_history_next(PHistory history, char *item)
 {
-    if (history->session == NULL) {
-        return NULL;
-    } else {
-        history->sess_curr = g_list_next(history->sess_curr);
+
+    // no history, or no session, return item
+    if ((history->items == NULL) || (history->session == NULL)) {
+        return item;
+    }
+
+    char *copied = "";
+    if (item != NULL) {
+        copied = strdup(item);
     }
 
-    // set to last if rolled over end
+    // session exists
+    
+    // update the currently pointed to item with passed data
+    history->sess_curr->data = copied;
+    
+    // move to next
+    history->sess_curr = g_list_next(history->sess_curr);
+    history->items_curr = g_list_next(history->items_curr);
+
+    // set to last if rolled over beginning
     if (history->sess_curr == NULL) {
         history->sess_curr = g_list_last(history->session);
+        history->items_curr = NULL;
     }
 
-    char *curr = history->sess_curr->data;
-    char *result = malloc((strlen(curr) + 1) * sizeof(char));
-    strcpy(result, curr);
-
+    char *result = strdup(history->sess_curr->data);
     return result;
 }
diff --git a/test_prof_history.c b/test_prof_history.c
index db4ef24b..6b42a160 100644
--- a/test_prof_history.c
+++ b/test_prof_history.c
@@ -10,12 +10,12 @@ void previous_on_empty_returns_current(void)
     assert_string_equals("inp", item);
 }
 
-void next_on_empty_returns_null(void)
+void next_on_empty_returns_current(void)
 {
     PHistory history = p_history_new(10);
     char *item = p_history_next(history, "inp");
 
-    assert_is_null(item);
+    assert_string_equals("inp", item);
 }
 
 void previous_once_returns_last(void)
@@ -71,7 +71,7 @@ void previous_goes_to_correct_element(void)
     assert_string_equals("going", item3); 
 }
 
-void prev_then_next_returns_null(void)
+void prev_then_next_returns_empty(void)
 {
     PHistory history = p_history_new(10);
     p_history_append(history, "Hello");
@@ -79,17 +79,42 @@ void prev_then_next_returns_null(void)
     char *item1 = p_history_previous(history, NULL);
     char *item2 = p_history_next(history, item1);
 
-    assert_is_null(item2);
+    assert_string_equals("", item2);
+}
+
+void prev_with_val_then_next_returns_val(void)
+{
+    PHistory history = p_history_new(10);
+    p_history_append(history, "Hello");
+
+    char *item1 = p_history_previous(history, "Oioi");
+    char *item2 = p_history_next(history, item1);
+
+    assert_string_equals("Oioi", item2);
+}
+
+void prev_with_val_then_next_twice_returns_val(void)
+{
+    PHistory history = p_history_new(10);
+    p_history_append(history, "Hello");
+
+    char *item1 = p_history_previous(history, "Oioi");
+    char *item2 = p_history_next(history, item1);
+    char *item3 = p_history_next(history, item2);
+
+    assert_string_equals("Oioi", item3);
 }
 
 void register_prof_history_tests(void)
 {
     TEST_MODULE("prof_history tests");
     TEST(previous_on_empty_returns_current);
-    TEST(next_on_empty_returns_null);
+    TEST(next_on_empty_returns_current);
     TEST(previous_once_returns_last);
     TEST(previous_twice_when_one_returns_first);
     TEST(previous_always_stops_at_first);
     TEST(previous_goes_to_correct_element);
-    TEST(prev_then_next_returns_null);
+    TEST(prev_then_next_returns_empty);
+    TEST(prev_with_val_then_next_returns_val);
+    TEST(prev_with_val_then_next_twice_returns_val);
 }