text: /*********************************************************************
   *        _       _         _
   *  _ __ | |_  _ | |  __ _ | |__   ___
   * | '__|| __|(_)| | / _` || '_ \ / __|
   * | |   | |_  _ | || (_| || |_) |\__ \
   * |_|    \__|(_)|_| \__,_||_.__/ |___/
   *
   * www.rt-labs.com
   * Copyright 2017 rt-labs AB, Sweden.
   *
   * This software is licensed under the terms of the BSD 3-clause
   * license. See the file LICENSE distributed with this software for
   * full license information.
   ********************************************************************/
  
  #include "osal.h"
  #include <gtest/gtest.h>
  
  static int expired_calls;
  static void * expired_arg;
  static void expired (os_timer_t * timer, void * arg)
  {
     expired_calls++;
     expired_arg = arg;
  }
  
  class Osal : public ::testing::Test
  {
   protected:
     virtual void SetUp()
     {
        expired_calls = 0;
     }
  };
  
  TEST_F (Osal, SemShouldTimeoutWhenCountIsZero)
  {
     os_sem_t * sem = os_sem_create (2);
     bool tmo;
  
     // Count 2
     tmo = os_sem_wait (sem, 100);
     EXPECT_FALSE (tmo);
  
     // Count 1
     tmo = os_sem_wait (sem, 100);
     EXPECT_FALSE (tmo);
  
     // Count 0 - timeout
     tmo = os_sem_wait (sem, 100);
     EXPECT_TRUE (tmo);
  
     // Count 0 - timeout
     tmo = os_sem_wait (sem, 100);
     EXPECT_TRUE (tmo);
  
     // Increase count
     os_sem_signal (sem);
  
     // Count 1
     tmo = os_sem_wait (sem, 100);
     EXPECT_FALSE (tmo);
  
     // Count 0 - timeout
     tmo = os_sem_wait (sem, 100);
     EXPECT_TRUE (tmo);
  
     os_sem_destroy (sem);
  }
  
  TEST_F (Osal, EventShouldNotTimeout)
  {
     os_event_t * event = os_event_create();
     uint32_t value     = 99;
     bool tmo;
  
     os_event_set (event, 1);
     tmo = os_event_wait (event, 1, &value, OS_WAIT_FOREVER);
     EXPECT_FALSE (tmo);
     EXPECT_EQ (1u, value);
  
     os_event_destroy (event);
  }
  
  TEST_F (Osal, EventShouldTimeout)
  {
     os_event_t * event = os_event_create();
     uint32_t value     = 99;
     bool tmo;
  
     os_event_set (event, 2);
     tmo = os_event_wait (event, 1, &value, 100);
     EXPECT_TRUE (tmo);
     EXPECT_EQ (0u, value);
  
     os_event_destroy (event);
  }
  
  TEST_F (Osal, MboxShouldNotTimeout)
  {
     os_mbox_t * mbox = os_mbox_create (2);
     void * msg;
     bool tmo;
  
     os_mbox_post (mbox, (void *)1, OS_WAIT_FOREVER);
     tmo = os_mbox_fetch (mbox, &msg, OS_WAIT_FOREVER);
  
     EXPECT_FALSE (tmo);
     EXPECT_EQ (1, (intptr_t)msg);
  
     os_mbox_destroy (mbox);
  }
  
  TEST_F (Osal, FetchFromEmptyMboxShouldTimeout)
  {
     os_mbox_t * mbox = os_mbox_create (2);
     void * msg;
     bool tmo;
  
     tmo = os_mbox_fetch (mbox, &msg, 100);
     EXPECT_TRUE (tmo);
  
     os_mbox_destroy (mbox);
  }
  
  TEST_F (Osal, PostToFullMBoxShouldTimeout)
  {
     os_mbox_t * mbox = os_mbox_create (2);
     bool tmo;
  
     os_mbox_post (mbox, (void *)1, 100);
     os_mbox_post (mbox, (void *)2, 100);
     tmo = os_mbox_post (mbox, (void *)3, 100);
     EXPECT_TRUE (tmo);
  
     os_mbox_destroy (mbox);
  }
  
  #define TEN_MS (10 * 1000)
  #define CALLS   39
  
  TEST_F (Osal, CyclicTimer)
  {
     int t0, t1;
     os_timer_t * timer;
  
     timer = os_timer_create (TEN_MS, expired, (void *)0x42, false);
     os_timer_start (timer);
  
     t0 = os_get_current_time_us();
     os_usleep (CALLS * TEN_MS);
     t1 = os_get_current_time_us();
     os_timer_stop (timer);
  
     EXPECT_NEAR (CALLS * TEN_MS, t1 - t0, 1000);
     EXPECT_NEAR (CALLS, expired_calls, 2);
  
     EXPECT_EQ ((void *)0x42, expired_arg);
  
     // Check that timer is stopped
     expired_calls = 0;
     os_usleep (10 * TEN_MS);
     EXPECT_NEAR (0, expired_calls, 1);
  
     os_timer_destroy (timer);
  }
  
  TEST_F (Osal, OneshotTimer)
  {
     os_timer_t * timer;
  
     timer = os_timer_create (TEN_MS, expired, (void *)0x42, true);
  
     os_timer_start (timer);
     os_usleep (10 * TEN_MS);
  
     EXPECT_EQ (1, expired_calls);
     EXPECT_EQ ((void *)0x42, expired_arg);
  
     os_timer_destroy (timer);
  }
  
  TEST_F (Osal, MultipleTimers)
  {
     os_timer_t * timer1;
     os_timer_t * timer2;
  
     timer1 = os_timer_create (10 * 1000, expired, (void *)1, true);
     timer2 = os_timer_create (20 * 1000, expired, (void *)2, true);
  
     os_timer_start (timer1);
     os_timer_start (timer2);
     os_usleep (100 * 1000);
  
     EXPECT_EQ (2, expired_calls);
     EXPECT_EQ ((void *)2, expired_arg);
  
     os_timer_destroy (timer1);
     os_timer_destroy (timer2);
  }
  