Skip to content

Commit

Permalink
Merge pull request #3 from edilson258/dev
Browse files Browse the repository at this point in the history
Merge with dev
  • Loading branch information
edilson258 authored Jun 23, 2024
2 parents 7452063 + 356ced8 commit 35e9536
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 40 deletions.
19 changes: 6 additions & 13 deletions examples/Testlib.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,37 +22,30 @@ Person *create_person(char *name, int age) {
}

/// Test function: function's name will be used as test's name
TEST test_create_person() {
TEST(test_create_person) {
Person p1 = {.name = "Low", .age = 30};
Person *p2 = create_person("Low", 30);
ASSERT_EQ_STRUCT(&p1, p2, sizeof(Person));
ASSERT_EQ_STRUCT(&p1, p2);
}

/// Test function: function's name will be used as test's name
TEST test_sum_two_ints() {
TEST(test_sum_two_ints) {
int a = 34;
int b = 35;
ASSERT_EQ_INT(69, sum_two_ints(a, b));
}

/// Test function: function's name will be used as test's name
TEST test_mul_two_ints() {
TEST(test_mul_two_ints) {
int a = 12;
int b = 12;
ASSERT_EQ_INT(144, mul_two_ints(a, b));
}

/// Test function: function's name will be used as test's name
TEST test_expect_true() {
TEST(test_expect_true) {
// will fail
ASSERT_TRUE(False);
}

int main() {
TestSuite_t ts = TestSuite_new(Str("Testing Demo!!"));
TestSuite_add(ts, test_sum_two_ints);
TestSuite_add(ts, test_mul_two_ints);
TestSuite_add(ts, test_create_person);
TestSuite_add(ts, test_expect_true);
return TestSuite_run(ts);
}
int main() { return RUN_ALL_TESTS(); }
12 changes: 8 additions & 4 deletions include/Queue.h
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
#ifndef QUEUE_H
#define QUEUE_H

#include "Common.h"
#include <pthread.h>
#include <stddef.h>

#include "Common.h"

/*
* Structure: Queue
*
* Represents a queue data structure.
* Represents a thread-safe queue data structure.
*
* Members:
* - Node_t head: Pointer to the head of the queue.
*/
typedef struct {
Node_t head;
size_t size;
Node_t tail;
pthread_mutex_t mutx;
} Queue;

typedef Queue *Queue_t;
Expand All @@ -38,9 +42,9 @@ Queue_t Queue_new();
* - Queue_t queue: Pointer to the queue to check.
*
* Returns:
* - int: 1 if the queue is empty, 0 otherwise.
* - `True`: if the queue is empty otherwise `False`
*/
int Queue_is_empty(Queue_t queue);
Boolean Queue_is_empty(Queue_t queue);

/*
* Function: Queue_dequeue(Queue_t queue) -> void*
Expand Down
2 changes: 1 addition & 1 deletion include/Testlib.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ Boolean __assert_eq_struct__(Any_t expected, Any_t provided, int line_number);
}

#define ASSERT_EQ_STRUCT(expected, provided) \
if (!(__assert_struct_eq__((expected), (provided), __LINE__))) { \
if (!(__assert_eq_struct__((expected), (provided), __LINE__))) { \
return; \
}

Expand Down
45 changes: 28 additions & 17 deletions src/Queue.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>

Expand All @@ -13,42 +14,52 @@ Queue_t Queue_new() {
}
queue->head = NULL;
queue->size = 0;
pthread_mutex_init(&queue->mutx, NULL);
return queue;
}

int Queue_is_empty(Queue_t queue) { return queue->head == NULL; }
Boolean Queue_is_empty(Queue_t queue) {
pthread_mutex_lock(&queue->mutx);
Boolean is_empty = queue->head == NULL;
pthread_mutex_unlock(&queue->mutx);
return is_empty;
}

void *Queue_dequeue(Queue_t queue) {
Any_t Queue_dequeue(Queue_t queue) {
if (Queue_is_empty(queue)) {
return NULL;
}
Node_t node = queue->head;
queue->head = node->next;
void *message = node->data;
free(node);
pthread_mutex_lock(&queue->mutx);
Node_t tmp = queue->head;
queue->head = tmp->next;
Any_t data = tmp->data;
free(tmp);
queue->size--;
return message;
pthread_mutex_unlock(&queue->mutx);
return data;
}

int Queue_enqueue(Queue_t queue, void *data) {
int Queue_enqueue(Queue_t queue, Any_t data) {
Node_t node = Node_new(data);
if (node == NULL) {
return -1;
}

pthread_mutex_lock(&queue->mutx);
if (!queue->head) {
queue->head = node;
queue->tail = node;
} else {
/*
* O(n)
*/
Node_t tmp = queue->head;
while (tmp->next)
tmp = tmp->next;
tmp->next = node;
queue->tail->next = node;
queue->tail = node;
}
queue->size++;
pthread_mutex_unlock(&queue->mutx);
return 0;
}

size_t Queue_size(Queue_t queue) { return queue->size; }
size_t Queue_size(Queue_t queue) {
pthread_mutex_lock(&queue->mutx);
size_t queue_size = queue->size;
pthread_mutex_unlock(&queue->mutx);
return queue_size;
}
16 changes: 11 additions & 5 deletions src/Testlib.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,23 @@

#include "../include/Testlib.h"

#define MAX_TESTS_PER_SUITE 50
#define INITIAL_TEST_SUITE_CAP 50

/// The instance of TestSuite that represents a suite of test
/// every file that contains `TEST()` cases is considered a test suite
///
/// yha! it's SINGLETON
struct TestSuite *global_test_suite_object = NULL;

void setup_global_test_suite_object(Str_t filename) {
global_test_suite_object = malloc(sizeof(struct TestSuite));
global_test_suite_object->name = filename;
global_test_suite_object->curr_test = NULL;
global_test_suite_object->cap = MAX_TESTS_PER_SUITE;
global_test_suite_object->cap = INITIAL_TEST_SUITE_CAP;
global_test_suite_object->count = 0;
global_test_suite_object->fails_count = 0;
global_test_suite_object->tests =
malloc(sizeof(struct Test *) * MAX_TESTS_PER_SUITE);
malloc(sizeof(struct Test *) * INITIAL_TEST_SUITE_CAP);
}

struct Test *Test_new(Str_t name, TestBody body) {
Expand All @@ -31,10 +33,14 @@ struct Test *Test_new(Str_t name, TestBody body) {
}

void register_test(Str_t name, TestBody body, Str_t filename) {
// @TODO: check bounds of global_test_suite_object

if (!global_test_suite_object) {
setup_global_test_suite_object(filename);
} else if (global_test_suite_object->count >= global_test_suite_object->cap) {
global_test_suite_object->tests =
realloc(global_test_suite_object->tests,
sizeof(struct Test *) *
(global_test_suite_object->cap + INITIAL_TEST_SUITE_CAP));
global_test_suite_object->cap += INITIAL_TEST_SUITE_CAP;
}
global_test_suite_object->tests[global_test_suite_object->count++] =
Test_new(name, body);
Expand Down
81 changes: 81 additions & 0 deletions tests/test_queue.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#include <pthread.h>

#include "../include/Queue.h"
#include "../include/Testlib.h"

TEST(ensureQueueIsEmpty) {
Queue_t q = Queue_new();
ASSERT_TRUE(Queue_is_empty(q));
Queue_enqueue(q, Int(69));
Queue_dequeue(q);
ASSERT_TRUE(Queue_is_empty(q));
}

TEST(stressTesting) {
Queue_t q = Queue_new();
for (int i = 1; i <= 50000; ++i) {
Queue_enqueue(q, Int(i));
}

ASSERT_EQ_INT(50000, (int)Queue_size(q));

for (int i = 1; i <= 50000; ++i) {
ASSERT_EQ_INT(i, *(int *)Queue_dequeue(q));
}

ASSERT_TRUE(Queue_is_empty(q));

for (int i = 1; i <= 100000; i += 10) {
Queue_enqueue(q, Int(i));
ASSERT_EQ_INT(i, *(int *)Queue_dequeue(q));
}
}

/*
* Multi-Thread testing
*/

Any_t process_1(Any_t arg) {
Queue_t q = arg;
Queue_enqueue(q, Str("From process_1"));
return NULL;
}

Any_t process_2(Any_t arg) {
Queue_t q = arg;
Queue_enqueue(q, Str("From process_2"));
return NULL;
}

Any_t process_3(Any_t arg) {
Queue_t q = arg;
Queue_enqueue(q, Str("From process_3"));
return NULL;
}

TEST(behaviorOnMultiThreadedScenario) {
Queue_t q = Queue_new();

pthread_t p1;
pthread_create(&p1, NULL, process_1, q);
pthread_join(p1, NULL);

ASSERT_EQ_INT(1, (int)Queue_size(q));
ASSERT_EQ_STR("From process_1", (Str_t)Queue_dequeue(q));

pthread_t p2;
pthread_create(&p2, NULL, process_2, q);
pthread_join(p2, NULL);

pthread_t p3;
pthread_create(&p3, NULL, process_3, q);
pthread_join(p3, NULL);

ASSERT_EQ_INT(2, (int)Queue_size(q));

Queue_dequeue(q); // From process_2

ASSERT_EQ_STR("From process_3", (Str_t)Queue_dequeue(q));
}

int main(void) { return RUN_ALL_TESTS(); }

0 comments on commit 35e9536

Please sign in to comment.