Added tests for the stack and made them pass.
* Make 'empty(stack)' more robust * Only try to 'push(stack, card)' if card != NULL * Added message explaining why 'pop(stack)' needs to create a new stack object when popping a stack's last element * 'move_card(stack, stack)' now checks if the origin pops something before trying to 'push(stack)' to destination. This prevents dereferencing a possible NULL pointer.
This commit is contained in:
		
							parent
							
								
									02e9e0a04f
								
							
						
					
					
						commit
						777434177f
					
				
							
								
								
									
										37
									
								
								lib/stack.c
									
									
									
									
									
								
							
							
						
						
									
										37
									
								
								lib/stack.c
									
									
									
									
									
								
							| @ -38,7 +38,10 @@ void delete_stack(struct stack *stack) { | ||||
| } | ||||
| 
 | ||||
| bool empty(struct stack *stack) { | ||||
|   return(stack->card->value == NO_VALUE); | ||||
|   return(stack->card->value == NO_VALUE && | ||||
|          stack->card->suit == NO_SUIT && | ||||
|          stack->card->face == NO_FACE && | ||||
|          !stack->next); | ||||
| } | ||||
| 
 | ||||
| int length(struct stack *stack) { | ||||
| @ -59,29 +62,32 @@ int length(struct stack *stack) { | ||||
| void push(struct stack **stack, struct card *card) { | ||||
|   struct stack *new_stack = NULL; | ||||
| 
 | ||||
|   if (empty(*stack)) { | ||||
|     (*stack)->card = card; | ||||
|   } else { | ||||
|     allocate_stack(&new_stack); | ||||
|     new_stack->card = card; | ||||
|     new_stack->next = (*stack); | ||||
|     *stack = new_stack; | ||||
|   if (card) { | ||||
|     if (empty(*stack)) { | ||||
|       (*stack)->card = card; | ||||
|     } else { | ||||
|       allocate_stack(&new_stack); | ||||
|       new_stack->card = card; | ||||
|       new_stack->next = (*stack); | ||||
|       *stack = new_stack; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| /* FIXME: hack hack hack to get the old coordinates after clearing the structure */ | ||||
| struct stack *pop(struct stack **stack) { | ||||
|   struct stack *popped_entry = NULL; | ||||
| 
 | ||||
|   if(!empty(*stack)) { | ||||
|     popped_entry = *stack; | ||||
|     /* As what's considered an empty stack is an allocated and initialized
 | ||||
|      * stack structure, we make sure pop doesn't make '*stack' point to NULL | ||||
|      * when popping a stack with only 1 element. */ | ||||
|     if (length(*stack) == 1) { | ||||
|       int start_y, start_x; | ||||
|       start_y = (*stack)->card->frame->start_y; | ||||
|       start_x = (*stack)->card->frame->start_x; | ||||
|       allocate_stack(stack); | ||||
|       initialize_stack(*stack); | ||||
|       set_frame((*stack)->card->frame, start_y, start_x); | ||||
|       set_frame((*stack)->card->frame, | ||||
|                 (*stack)->card->frame->start_y, | ||||
|                 (*stack)->card->frame->start_x); | ||||
|     } else { | ||||
|       *stack = (*stack)->next; | ||||
|     } | ||||
| @ -99,8 +105,9 @@ void move_card(struct stack **origin, struct stack **destination) { | ||||
|   if (!empty(*destination) && maneuvre_stack(*destination)) { | ||||
|     (*origin)->card->frame->start_y++; | ||||
|   } | ||||
|   stack = pop(origin); | ||||
|   push(destination, stack->card); | ||||
|   if ((stack = pop(origin))) { | ||||
|     push(destination, stack->card); | ||||
|   } | ||||
| 
 | ||||
|   return; | ||||
| } | ||||
|  | ||||
| @ -1,8 +1,330 @@ | ||||
| #include <assert.h> | ||||
| #include "../lib/stack.h" | ||||
| #include "test_helper.h" | ||||
| 
 | ||||
| void test_stack() { | ||||
|   assert(true); | ||||
| void test_initialize_stack() { | ||||
|   struct stack *stack; | ||||
| 
 | ||||
|   allocate_stack(&stack); | ||||
|   initialize_stack(stack); | ||||
| 
 | ||||
|   assert(stack->card->value == NO_VALUE); | ||||
|   assert(!stack->next); | ||||
| 
 | ||||
|   delete_stack(stack); | ||||
| 
 | ||||
|   return; | ||||
| } | ||||
| 
 | ||||
| void test_empty_on_empty_stack() { | ||||
|   struct stack *stack; | ||||
| 
 | ||||
|   allocate_stack(&stack); | ||||
|   initialize_stack(stack); | ||||
| 
 | ||||
|   assert(empty(stack)); | ||||
| 
 | ||||
|   delete_stack(stack); | ||||
| 
 | ||||
|   return; | ||||
| } | ||||
| 
 | ||||
| void test_empty_on_non_empty_stack() { | ||||
|   struct stack *stack; | ||||
|   struct card *card; | ||||
| 
 | ||||
|   allocate_card(&card); | ||||
|   initialize_card(card); | ||||
|   set_card(card, ACE, SPADES, EXPOSED, 0, 0); | ||||
| 
 | ||||
|   allocate_stack(&stack); | ||||
|   initialize_stack(stack); | ||||
|   push(&stack, card); | ||||
| 
 | ||||
|   assert(!empty(stack)); | ||||
| 
 | ||||
|   delete_stack(stack); | ||||
| 
 | ||||
|   return; | ||||
| } | ||||
| 
 | ||||
| void test_push_on_empty_stack() { | ||||
|   struct stack *stack; | ||||
|   struct card *card; | ||||
| 
 | ||||
|   allocate_card(&card); | ||||
|   initialize_card(card); | ||||
|   set_card(card, ACE, SPADES, EXPOSED, 0, 0); | ||||
| 
 | ||||
|   allocate_stack(&stack); | ||||
|   initialize_stack(stack); | ||||
|   push(&stack, card); | ||||
| 
 | ||||
|   assert(stack->card == card); | ||||
|   assert(!stack->next); | ||||
| 
 | ||||
|   delete_stack(stack); | ||||
| 
 | ||||
|   return; | ||||
| } | ||||
| 
 | ||||
| void test_push_on_non_empty_stack() { | ||||
|   struct stack *stack; | ||||
|   struct card *card_0, *card_1; | ||||
| 
 | ||||
|   allocate_card(&card_0); | ||||
|   allocate_card(&card_1); | ||||
|   initialize_card(card_0); | ||||
|   initialize_card(card_1); | ||||
|   set_card(card_0, ACE, SPADES, EXPOSED, 0, 0); | ||||
|   set_card(card_1, ACE, HEARTS, EXPOSED, 0, 0); | ||||
| 
 | ||||
|   allocate_stack(&stack); | ||||
|   initialize_stack(stack); | ||||
|   push(&stack, card_0); | ||||
|   push(&stack, card_1); | ||||
| 
 | ||||
|   assert(stack->card == card_1); | ||||
|   assert(stack->next->card == card_0); | ||||
|   assert(!stack->next->next); | ||||
| 
 | ||||
|   delete_stack(stack); | ||||
| 
 | ||||
|   return; | ||||
| } | ||||
| 
 | ||||
| void test_push_null_on_empty_stack() { | ||||
|   struct stack *stack, *old_stack; | ||||
| 
 | ||||
|   allocate_stack(&stack); | ||||
|   initialize_stack(stack); | ||||
|   old_stack = stack; | ||||
|   push(&stack, NULL); | ||||
| 
 | ||||
|   assert(stack->card == old_stack->card); | ||||
|   assert(stack->next == NULL); | ||||
| 
 | ||||
|   delete_stack(stack); | ||||
| 
 | ||||
|   return; | ||||
| } | ||||
| 
 | ||||
| void test_push_null_on_non_empty_stack() { | ||||
|   struct stack *stack, *old_stack; | ||||
|   struct card *card; | ||||
| 
 | ||||
|   allocate_card(&card); | ||||
|   initialize_card(card); | ||||
|   set_card(card, ACE, SPADES, EXPOSED, 0, 0); | ||||
| 
 | ||||
|   allocate_stack(&stack); | ||||
|   initialize_stack(stack); | ||||
|   old_stack = stack; | ||||
|   push(&stack, NULL); | ||||
| 
 | ||||
|   assert(stack->card == old_stack->card); | ||||
|   assert(stack->next == old_stack->next); | ||||
| 
 | ||||
|   delete_stack(stack); | ||||
| 
 | ||||
|   return; | ||||
| } | ||||
| 
 | ||||
| void test_pop_on_empty_stack() { | ||||
|   struct stack *stack; | ||||
|   struct stack *popped_entry; | ||||
| 
 | ||||
|   allocate_stack(&stack); | ||||
|   allocate_stack(&popped_entry); | ||||
|   initialize_stack(stack); | ||||
|   popped_entry = pop(&stack); | ||||
| 
 | ||||
|   assert(empty(stack)); | ||||
|   assert(!popped_entry); | ||||
| 
 | ||||
|   delete_stack(stack); | ||||
| 
 | ||||
|   return; | ||||
| } | ||||
| 
 | ||||
| void test_pop_on_stack_with_one_element() { | ||||
|   struct stack *stack, *popped_entry; | ||||
|   struct card *card; | ||||
| 
 | ||||
|   allocate_card(&card); | ||||
|   initialize_card(card); | ||||
|   set_card(card, ACE, SPADES, EXPOSED, 0, 0); | ||||
| 
 | ||||
|   allocate_stack(&stack); | ||||
|   initialize_stack(stack); | ||||
|   push(&stack, card); | ||||
|   popped_entry = pop(&stack); | ||||
| 
 | ||||
|   assert(empty(stack)); | ||||
|   assert(popped_entry->card == card); | ||||
|   assert(!popped_entry->next); | ||||
| 
 | ||||
|   delete_stack(stack); | ||||
| 
 | ||||
|   return; | ||||
| } | ||||
| 
 | ||||
| void test_pop_on_stack_with_more_than_one_element() { | ||||
|   struct stack *stack, *old_stack_next, *popped_entry; | ||||
|   struct card *card[3]; | ||||
| 
 | ||||
|   allocate_stack(&stack); | ||||
|   initialize_stack(stack); | ||||
|   for (int i = 0; i < 3; i++) { | ||||
|     allocate_card(&card[i]); | ||||
|     initialize_card(card[i]); | ||||
|     set_card(card[i], ACE, SPADES, EXPOSED, 0, 0); | ||||
|     push(&stack, card[i]); | ||||
|   } | ||||
|   old_stack_next = stack->next; | ||||
|   popped_entry = pop(&stack); | ||||
| 
 | ||||
|   assert(length(stack) == 2); | ||||
|   assert(stack == old_stack_next); | ||||
|   assert(popped_entry->card == card[2]); | ||||
|   assert(!popped_entry->next); | ||||
| 
 | ||||
|   delete_stack(stack); | ||||
| 
 | ||||
|   return; | ||||
| } | ||||
| 
 | ||||
| void test_move_card_from_empty_stack_to_empty_stack() { | ||||
|   struct stack *origin, *destination, | ||||
|                *new_origin, *new_destination, | ||||
|                *origin_duplicate, *destination_duplicate; | ||||
| 
 | ||||
|   allocate_stack(&origin); | ||||
|   allocate_stack(&destination); | ||||
|   initialize_stack(origin); | ||||
|   initialize_stack(destination); | ||||
|   new_origin = origin; | ||||
|   new_destination = destination; | ||||
|   origin_duplicate = duplicate_stack(origin); | ||||
|   destination_duplicate = duplicate_stack(destination); | ||||
|   move_card(&new_origin, &new_destination); | ||||
| 
 | ||||
|   assert(origin == new_origin); | ||||
|   assert(stacks_equal(origin, origin_duplicate)); | ||||
|   assert(destination == new_destination); | ||||
|   assert(stacks_equal(destination, destination_duplicate)); | ||||
| 
 | ||||
|   delete_stack(origin); | ||||
|   delete_stack(destination); | ||||
| 
 | ||||
|   return; | ||||
| } | ||||
| 
 | ||||
| void test_move_card_from_empty_stack_to_non_empty_stack() { | ||||
|   struct stack *origin, *destination, | ||||
|                *new_origin, *new_destination, | ||||
|                *origin_duplicate, *destination_duplicate; | ||||
|   struct card *card; | ||||
| 
 | ||||
|   allocate_card(&card); | ||||
|   initialize_card(card); | ||||
|   set_card(card, ACE, SPADES, EXPOSED, 0, 0); | ||||
| 
 | ||||
|   allocate_stack(&origin); | ||||
|   allocate_stack(&destination); | ||||
|   initialize_stack(origin); | ||||
|   initialize_stack(destination); | ||||
|   new_origin = origin; | ||||
|   new_destination = destination; | ||||
|   push(&new_destination, card); | ||||
|   origin_duplicate = duplicate_stack(origin); | ||||
|   destination_duplicate = duplicate_stack(destination); | ||||
|   move_card(&new_origin, &new_destination); | ||||
| 
 | ||||
|   assert(origin == new_origin); | ||||
|   assert(stacks_equal(origin, origin_duplicate)); | ||||
|   assert(destination == new_destination); | ||||
|   assert(stacks_equal(destination, destination_duplicate)); | ||||
| 
 | ||||
|   delete_stack(origin); | ||||
|   delete_stack(destination); | ||||
| 
 | ||||
|   return; | ||||
| } | ||||
| 
 | ||||
| void test_move_card_from_non_empty_stack_to_empty_stack() { | ||||
|   struct stack *origin, *destination; | ||||
|   struct card *card; | ||||
| 
 | ||||
|   allocate_card(&card); | ||||
|   initialize_card(card); | ||||
|   set_card(card, ACE, SPADES, EXPOSED, 0, 0); | ||||
| 
 | ||||
|   allocate_stack(&origin); | ||||
|   allocate_stack(&destination); | ||||
|   initialize_stack(origin); | ||||
|   initialize_stack(destination); | ||||
|   push(&origin, card); | ||||
|   move_card(&origin, &destination); | ||||
| 
 | ||||
|   assert(empty(origin)); | ||||
|   assert(length(destination) == 1); | ||||
|   assert(cards_equal(destination->card, card)); | ||||
| 
 | ||||
|   delete_stack(origin); | ||||
|   delete_stack(destination); | ||||
| 
 | ||||
|   return; | ||||
| } | ||||
| 
 | ||||
| void test_move_card_from_non_empty_stack_to_non_empty_stack() { | ||||
|   struct stack *origin, *destination; | ||||
|   struct card *card[2]; | ||||
| 
 | ||||
|   allocate_card(&card[0]); | ||||
|   allocate_card(&card[1]); | ||||
|   initialize_card(card[0]); | ||||
|   initialize_card(card[1]); | ||||
|   set_card(card[0], ACE, SPADES, EXPOSED, 1, 1); | ||||
|   set_card(card[1], KING, HEARTS, EXPOSED, 1, 1); | ||||
| 
 | ||||
|   allocate_stack(&origin); | ||||
|   allocate_stack(&destination); | ||||
|   initialize_stack(origin); | ||||
|   initialize_stack(destination); | ||||
|   push(&origin, card[0]); | ||||
|   push(&destination, card[1]); | ||||
|   move_card(&origin, &destination); | ||||
| 
 | ||||
|   assert(empty(origin)); | ||||
|   assert(length(destination) == 2); | ||||
|   assert(cards_equal(destination->card, card[0])); | ||||
|   assert(cards_equal(destination->next->card, card[1])); | ||||
| 
 | ||||
|   delete_stack(origin); | ||||
|   delete_stack(destination); | ||||
| 
 | ||||
|   return; | ||||
| } | ||||
| 
 | ||||
| void test_stack() { | ||||
|   test_initialize_stack(); | ||||
| 
 | ||||
|   test_empty_on_empty_stack(); | ||||
|   test_empty_on_non_empty_stack(); | ||||
| 
 | ||||
|   test_push_on_empty_stack(); | ||||
|   test_push_on_non_empty_stack(); | ||||
|   test_push_null_on_empty_stack(); | ||||
| 
 | ||||
|   test_pop_on_empty_stack(); | ||||
|   test_pop_on_stack_with_one_element(); | ||||
|   test_pop_on_stack_with_more_than_one_element(); | ||||
| 
 | ||||
|   test_move_card_from_empty_stack_to_empty_stack(); | ||||
|   test_move_card_from_empty_stack_to_non_empty_stack(); | ||||
|   test_move_card_from_non_empty_stack_to_empty_stack(); | ||||
|   test_move_card_from_non_empty_stack_to_non_empty_stack(); | ||||
| 
 | ||||
|   return; | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user