/**
 * Copyright (c) 2021 Dominic Masters
 * 
 * This software is released under the MIT License.
 * https://opensource.org/licenses/MIT
 */

#include "card.h"

//cardGetSuit
void test_cardGetSuit_should_ReturnCardsSuit(void) {
  TEST_ASSERT_EQUAL_UINT8(CARD_SUIT_CLUBS, cardGetSuit(CARD_CLUBS_ACE));
  TEST_ASSERT_EQUAL_UINT8(CARD_SUIT_CLUBS, cardGetSuit(CARD_CLUBS_TWO));
  TEST_ASSERT_EQUAL_UINT8(CARD_SUIT_CLUBS, cardGetSuit(CARD_CLUBS_KING));
  
  TEST_ASSERT_EQUAL_UINT8(CARD_SUIT_HEARTS, cardGetSuit(CARD_HEARTS_QUEEN));
  TEST_ASSERT_EQUAL_UINT8(CARD_SUIT_HEARTS, cardGetSuit(CARD_HEARTS_TWO));
  TEST_ASSERT_EQUAL_UINT8(CARD_SUIT_HEARTS, cardGetSuit(CARD_HEARTS_SEVEN));

  TEST_ASSERT_EQUAL_UINT8(CARD_SUIT_SPADES, cardGetSuit(CARD_SPADES_TWO));
  TEST_ASSERT_EQUAL_UINT8(CARD_SUIT_SPADES, cardGetSuit(CARD_SPADES_ACE));

  TEST_ASSERT_EQUAL_UINT8(CARD_SUIT_DIAMONDS, cardGetSuit(CARD_DIAMONDS_ACE));
}

//cardGetNumber
void test_cardGetNumber_should_ReturnCardsNumber(void) {
  TEST_ASSERT_EQUAL_UINT8(CARD_ACE, cardGetNumber(CARD_CLUBS_ACE));
  TEST_ASSERT_EQUAL_UINT8(CARD_TWO, cardGetNumber(CARD_CLUBS_TWO));
  TEST_ASSERT_EQUAL_UINT8(CARD_KING, cardGetNumber(CARD_CLUBS_KING));
  
  TEST_ASSERT_EQUAL_UINT8(CARD_QUEEN, cardGetNumber(CARD_HEARTS_QUEEN));
  TEST_ASSERT_EQUAL_UINT8(CARD_TWO, cardGetNumber(CARD_HEARTS_TWO));
  TEST_ASSERT_EQUAL_UINT8(CARD_SEVEN, cardGetNumber(CARD_HEARTS_SEVEN));

  TEST_ASSERT_EQUAL_UINT8(CARD_TWO, cardGetNumber(CARD_SPADES_TWO));
  TEST_ASSERT_EQUAL_UINT8(CARD_ACE, cardGetNumber(CARD_SPADES_ACE));

  TEST_ASSERT_EQUAL_UINT8(CARD_ACE, cardGetNumber(CARD_DIAMONDS_ACE));
}

//cardGet
void test_cardGet_should_ReturnTheCard(void) {
  TEST_ASSERT_EQUAL_UINT8(CARD_CLUBS_ACE, cardGet(CARD_ACE, CARD_SUIT_CLUBS));
  TEST_ASSERT_EQUAL_UINT8(CARD_CLUBS_TWO, cardGet(CARD_TWO, CARD_SUIT_CLUBS));
  TEST_ASSERT_EQUAL_UINT8(CARD_CLUBS_KING, cardGet(CARD_KING, CARD_SUIT_CLUBS));

  TEST_ASSERT_EQUAL_UINT8(
    CARD_HEARTS_QUEEN, cardGet(CARD_QUEEN, CARD_SUIT_HEARTS)
  );
  TEST_ASSERT_EQUAL_UINT8(
    CARD_HEARTS_TWO, cardGet(CARD_TWO, CARD_SUIT_HEARTS)
  );
  TEST_ASSERT_EQUAL_UINT8(
    CARD_HEARTS_SEVEN, cardGet(CARD_SEVEN, CARD_SUIT_HEARTS)
  );

  TEST_ASSERT_EQUAL_UINT8(CARD_SPADES_TWO, cardGet(CARD_TWO, CARD_SUIT_SPADES));
  TEST_ASSERT_EQUAL_UINT8(CARD_SPADES_ACE, cardGet(CARD_ACE, CARD_SUIT_SPADES));
  
  TEST_ASSERT_EQUAL_UINT8(
    CARD_DIAMONDS_ACE, cardGet(CARD_ACE, CARD_SUIT_DIAMONDS)
  );
}

//cardDeal
void test_cardDeal_should_DealCards(void) {
  card_t deck[CARD_DECK_SIZE];
  uint8_t deckSize = cardWriteDeck(deck);
  card_t hand[CARD_DECK_SIZE];
  uint8_t handSize = 0;

  cardDeal(deck, &deckSize, hand, &handSize);
  TEST_ASSERT_EQUAL_INT32(deckSize, 51);
  TEST_ASSERT_EQUAL_INT32(1, handSize);
  TEST_ASSERT_EQUAL_INT8(hand[0], CARD_SPADES_ACE);

  cardDeal(deck, &deckSize, hand, &handSize);
  TEST_ASSERT_EQUAL_INT32(deckSize, 50);
  TEST_ASSERT_EQUAL_INT32(2, handSize);
  TEST_ASSERT_EQUAL_INT8(hand[1], CARD_SPADES_KING);

  cardDeal(deck, &deckSize, hand, &handSize);
  TEST_ASSERT_EQUAL_INT32(deckSize, 49);
  TEST_ASSERT_EQUAL_INT32(3, handSize);
  TEST_ASSERT_EQUAL_INT8(hand[2], CARD_SPADES_QUEEN);
}

//cardHandSort
void test_cardHandSort_should_SortTheCards(void) {
  card_t cards[7];
  uint8_t l = 7;
  cards[0] = CARD_HEARTS_QUEEN;
  cards[1] = CARD_CLUBS_FOUR;
  cards[2] = CARD_HEARTS_FOUR;
  cards[3] = CARD_CLUBS_KING;
  cards[4] = CARD_DIAMONDS_SIX;
  cards[5] = CARD_SPADES_THREE;
  cards[6] = CARD_DIAMONDS_ACE;

  cardHandSort(cards, l);
  TEST_ASSERT_EQUAL(CARD_CLUBS_KING, cards[0]);
  TEST_ASSERT_EQUAL(CARD_CLUBS_FOUR, cards[1]);

  TEST_ASSERT_EQUAL(CARD_DIAMONDS_ACE, cards[2]);
  TEST_ASSERT_EQUAL(CARD_DIAMONDS_SIX, cards[3]);
  
  TEST_ASSERT_EQUAL(CARD_HEARTS_QUEEN, cards[4]);
  TEST_ASSERT_EQUAL(CARD_HEARTS_FOUR, cards[5]);

  TEST_ASSERT_EQUAL(CARD_SPADES_THREE, cards[6]);
}

//cardContains
void test_cardContains_should_ReturnTheIndex(void) {
  card_t deck[CARD_DECK_SIZE];
  uint8_t l = cardWriteDeck(deck);

  TEST_ASSERT_EQUAL_INT32(0, cardContains(deck, l, CARD_CLUBS_TWO));
  TEST_ASSERT_EQUAL_INT32(1, cardContains(deck, l, CARD_CLUBS_THREE));
  TEST_ASSERT_EQUAL_INT32(12, cardContains(deck, l, CARD_CLUBS_ACE));
  TEST_ASSERT_EQUAL_INT32(21, cardContains(deck, l, CARD_DIAMONDS_TEN));
  TEST_ASSERT_EQUAL_INT32(26, cardContains(deck, l, CARD_HEARTS_TWO));
  TEST_ASSERT_EQUAL_INT32(36, cardContains(deck, l, CARD_HEARTS_QUEEN));
  TEST_ASSERT_EQUAL_INT32(51, cardContains(deck, l, CARD_SPADES_ACE));
}

void test_cardContains_should_BeNegativeOne(void) {
  card_t cards[6];
  uint8_t l = 6;
  cards[0] = CARD_SPADES_THREE;
  cards[1] = CARD_HEARTS_QUEEN;
  cards[2] = CARD_CLUBS_THREE;
  cards[3] = CARD_CLUBS_FOUR;
  cards[4] = CARD_CLUBS_QUEEN;
  cards[5] = CARD_DIAMONDS_FOUR;

  TEST_ASSERT_EQUAL_INT32(-1, cardContains(cards, l, CARD_CLUBS_TWO));
  TEST_ASSERT_EQUAL_INT32(-1, cardContains(cards, l, CARD_DIAMONDS_QUEEN));
  TEST_ASSERT_EQUAL_INT32(-1, cardContains(cards, l, CARD_SPADES_FIVE));
  TEST_ASSERT_EQUAL_INT32(-1, cardContains(cards, l, CARD_HEARTS_FIVE));
  TEST_ASSERT_EQUAL_INT32(-1, cardContains(cards, l, CARD_CLUBS_EIGHT));
}

//cardContainsNumber
void test_cardContainsNumber_should_ReturnTheIndex(void) {
  card_t cards[6];
  uint8_t l = 6;
  cards[0] = CARD_SPADES_THREE;
  cards[1] = CARD_HEARTS_QUEEN;
  cards[2] = CARD_CLUBS_FIVE;
  cards[3] = CARD_CLUBS_FOUR;
  cards[4] = CARD_CLUBS_KING;
  cards[5] = CARD_DIAMONDS_SIX;

  TEST_ASSERT_EQUAL_INT32(0, cardContainsNumber(cards,l,CARD_THREE));
  TEST_ASSERT_EQUAL_INT32(1, cardContainsNumber(cards,l,CARD_QUEEN));
  TEST_ASSERT_EQUAL_INT32(4, cardContainsNumber(cards,l,CARD_KING));
  TEST_ASSERT_EQUAL_INT32(5, cardContainsNumber(cards,l,CARD_SIX));
}

void test_cardContainsNumber_should_ReturnNegativeOne(void) {
  card_t cards[6];
  uint8_t l = 6;
  cards[0] = CARD_SPADES_THREE;
  cards[1] = CARD_HEARTS_QUEEN;
  cards[2] = CARD_CLUBS_FIVE;
  cards[3] = CARD_CLUBS_FOUR;
  cards[4] = CARD_CLUBS_KING;
  cards[5] = CARD_DIAMONDS_SIX;

  TEST_ASSERT_EQUAL_INT32(-1, cardContainsNumber(cards, l, CARD_ACE));
  TEST_ASSERT_EQUAL_INT32(-1, cardContainsNumber(cards, l, CARD_SEVEN));
  TEST_ASSERT_EQUAL_INT32(-1, cardContainsNumber(cards, l, CARD_TEN));
  TEST_ASSERT_EQUAL_INT32(-1, cardContainsNumber(cards, l, CARD_NINE));
}

// cardCountPairs
void test_cardCountPairs_should_CountPairs(void) {
  card_t cards[8];
  int32_t pairs[CARD_SUIT_COUNT];

  cards[0] = CARD_CLUBS_TWO;
  cards[1] = CARD_SPADES_TWO;

  TEST_ASSERT_EQUAL_UINT8(2, cardCountPairs(cards, 2, CARD_TWO, pairs));
  TEST_ASSERT_EQUAL_INT32(0, pairs[0]);
  TEST_ASSERT_EQUAL_INT32(1, pairs[1]);

  TEST_ASSERT_EQUAL_UINT8(0, cardCountPairs(cards, 2, CARD_THREE, pairs));

  cards[0] = CARD_SPADES_THREE;
  cards[1] = CARD_HEARTS_QUEEN;
  cards[2] = CARD_CLUBS_THREE;
  cards[3] = CARD_CLUBS_FOUR;
  cards[4] = CARD_CLUBS_QUEEN;
  cards[5] = CARD_DIAMONDS_FOUR;

  TEST_ASSERT_EQUAL_UINT8(2, cardCountPairs(cards, 6, CARD_THREE, pairs));
  TEST_ASSERT_EQUAL_INT32(0, pairs[0]);
  TEST_ASSERT_EQUAL_INT32(2, pairs[1]);

  TEST_ASSERT_EQUAL_UINT8(2, cardCountPairs(cards, 6, CARD_QUEEN, pairs));
  TEST_ASSERT_EQUAL_INT32(1, pairs[0]);
  TEST_ASSERT_EQUAL_INT32(4, pairs[1]);

  TEST_ASSERT_EQUAL_UINT8(2, cardCountPairs(cards, 6, CARD_FOUR, pairs));
  TEST_ASSERT_EQUAL_INT32(3, pairs[0]);
  TEST_ASSERT_EQUAL_INT32(5, pairs[1]);
}

//cardWriteDeck
void test_cardWriteDeck_should_WriteCardsToArray(void) {
  card_t cards[CARD_DECK_SIZE];
  cardWriteDeck(cards);
  
  TEST_ASSERT_EQUAL_UINT8(CARD_CLUBS_TWO, cards[0]);
  TEST_ASSERT_EQUAL_UINT8(CARD_CLUBS_THREE, cards[1]);
  TEST_ASSERT_EQUAL_UINT8(CARD_CLUBS_FOUR, cards[2]);
  TEST_ASSERT_EQUAL_UINT8(CARD_CLUBS_ACE, cards[12]);

  TEST_ASSERT_EQUAL_UINT8(CARD_DIAMONDS_NINE, cards[20]);

  TEST_ASSERT_EQUAL_UINT8(CARD_HEARTS_ACE, cards[38]);

  TEST_ASSERT_EQUAL_UINT8(CARD_SPADES_ACE, cards[51]);
}

void test_cardWriteDeck_should_ReturnCardsWritten(void) {
  card_t cards[CARD_DECK_SIZE];
  TEST_ASSERT_EQUAL_UINT8(CARD_DECK_SIZE, cardWriteDeck(cards));
}

void test_cardGetHighest_should_ReturnTheHighestCard(void) {
  card_t cards[CARD_DECK_SIZE];
  uint8_t l = cardWriteDeck(cards);
  
  TEST_ASSERT_EQUAL(CARD_CLUBS_ACE, cardGetHighest(cards, l));
  TEST_ASSERT_EQUAL(CARD_CLUBS_ACE, cardGetHighest(cards, l));

  l = 3;
  TEST_ASSERT_EQUAL(CARD_CLUBS_FOUR, cardGetHighest(cards, l));

  cards[0] = CARD_CLUBS_SIX;
  cards[1] = CARD_HEARTS_SEVEN;
  cards[2] = CARD_DIAMONDS_EIGHT;
  cards[3] = CARD_SPADES_NINE;
  l = 4;
  TEST_ASSERT_EQUAL(CARD_SPADES_NINE, cardGetHighest(cards, l));
  
  cards[2] = CARD_DIAMONDS_TEN;
  TEST_ASSERT_EQUAL(CARD_DIAMONDS_TEN, cardGetHighest(cards, l));

  cards[2] = CARD_DIAMONDS_TEN;
  TEST_ASSERT_EQUAL(CARD_DIAMONDS_TEN, cardGetHighest(cards, l));

  cards[4] = CARD_CLUBS_TEN;
  l = 5;
  TEST_ASSERT_EQUAL(CARD_DIAMONDS_TEN, cardGetHighest(cards, l));

  cards[1] = CARD_HEARTS_TEN;
  TEST_ASSERT_EQUAL(CARD_HEARTS_TEN, cardGetHighest(cards, l));
}

int test_card_h() {
  UNITY_BEGIN();
  
  RUN_TEST(test_cardGetSuit_should_ReturnCardsSuit);
  RUN_TEST(test_cardGetNumber_should_ReturnCardsNumber);
  RUN_TEST(test_cardGet_should_ReturnTheCard);
  RUN_TEST(test_cardDeal_should_DealCards);
  RUN_TEST(test_cardHandSort_should_SortTheCards);
  RUN_TEST(test_cardContains_should_ReturnTheIndex);
  RUN_TEST(test_cardContains_should_BeNegativeOne);
  RUN_TEST(test_cardContainsNumber_should_ReturnTheIndex);
  RUN_TEST(test_cardContainsNumber_should_ReturnNegativeOne);
  RUN_TEST(test_cardCountPairs_should_CountPairs);
  RUN_TEST(test_cardWriteDeck_should_WriteCardsToArray);
  RUN_TEST(test_cardWriteDeck_should_ReturnCardsWritten);
  RUN_TEST(test_cardGetHighest_should_ReturnTheHighestCard);

  return UNITY_END();
}