Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add 'allergies' exercise #83

Merged
merged 7 commits into from
Oct 29, 2016
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"checklist_issue": 8,
"active": false,
"problems": [
"allergies",
"hello-world",
"anagram",
"leap",
Expand All @@ -23,6 +24,15 @@
"binary-search"
],
"exercises": [{
"slug": "allergies",
"difficulty": 4,
"topics": [
"control-flow (if-statements)",
"control-flow (loops)",
"structs",
"memory management"
]
}, {
"slug": "hello-world",
"difficulty": 1,
"topics": [
Expand Down
15 changes: 15 additions & 0 deletions exercises/allergies/makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
CFLAGS = -std=c99
CFLAGS += -Wall
CFLAGS += -Wextra
CFLAGS += -pedantic
CFLAGS += -Werror

test: tests.out
@./tests.out

clean:
rm -f *.o *.out

tests.out: test/test_allergies.c src/allergies.c src/allergies.h
@echo Compiling $@
@cc $(CFLAGS) src/allergies.c test/vendor/unity.c test/test_allergies.c -o tests.out
21 changes: 21 additions & 0 deletions exercises/allergies/src/allergies.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#ifndef _ALLERGIES_H
#define _ALLERGIES_H

typedef enum {
Allergen_Eggs = 0,
Allergen_Peanuts,
Allergen_Shellfish,
Allergen_Strawberries,
Allergen_Tomatoes,
Allergen_Chocolate,
Allergen_Pollen,
Allergen_Cats,
Allergen_Count
} Allergen_t;

typedef struct {
int count;
Allergen_t *allergens;
} Allergen_List_t;

#endif
32 changes: 32 additions & 0 deletions exercises/allergies/src/example.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#include "allergies.h"
#include <stdlib.h>

static const unsigned int scores[] = {
1,
2,
4,
8,
16,
32,
64,
128
};

bool is_allergic_to(Allergen_t allergen, unsigned int score)
{
return ((score & scores[allergen]) == scores[allergen]);
}

void get_allergens(int score, Allergen_List_t * list)
{
list->allergens = calloc(Allergen_Count, sizeof(Allergen_t));
list->count = 0;

for (Allergen_t allergen = 0; allergen < Allergen_Count; allergen++) {
if (is_allergic_to(allergen, score)) {
score -= scores[allergen];
list->allergens[list->count] = allergen;
list->count++;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this guy is never initialized to 0

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep. I originally had get_allergens() mallocing the entire Allergen_List_t and then switched to having it passed in. Will fix.

}
}
}
26 changes: 26 additions & 0 deletions exercises/allergies/src/example.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#ifndef _ALLERGIES_H
#define _ALLERGIES_H

#include <stdbool.h>

typedef enum {
Allergen_Eggs = 0,
Allergen_Peanuts,
Allergen_Shellfish,
Allergen_Strawberries,
Allergen_Tomatoes,
Allergen_Chocolate,
Allergen_Pollen,
Allergen_Cats,
Allergen_Count
} Allergen_t;

typedef struct {
int count;
Allergen_t *allergens;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that we know exactly how many allergens there are prior to declaring this type, why wouldn't we simply create a properly sized array for allergens instead of requiring a memory allocation?

Copy link
Member

@ryanplusplus ryanplusplus Oct 15, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess leaving this as an allocation means that the implementation could potentially allocate only as many as are actually necessary for the given score.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could go either way. I do like having the option allocate only as many as necessary.

} Allergen_List_t;

bool is_allergic_to(Allergen_t allergen, unsigned int score);
void get_allergens(int score, Allergen_List_t * list);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you update this score to be unsigned as well?


#endif
203 changes: 203 additions & 0 deletions exercises/allergies/test/test_allergies.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
#include "vendor/unity.h"
#include "../src/allergies.h"
#include <stdlib.h>

void test_list_count_is(int count, Allergen_List_t * list)
{
TEST_ASSERT_EQUAL(count, list->count);
}

void test_list_contains(Allergen_t allergen, Allergen_List_t * list)
{
bool allergen_found = false;

for (int i = 0; i < list->count; i++) {
if (list->allergens[i] == allergen) {
allergen_found = true;
break;
}
}

TEST_ASSERT_TRUE(allergen_found);
}

void test_no_allergies_means_not_allergic(void)
{
int score = 0;

TEST_ASSERT_FALSE(is_allergic_to(Allergen_Peanuts, score));
TEST_ASSERT_FALSE(is_allergic_to(Allergen_Cats, score));
TEST_ASSERT_FALSE(is_allergic_to(Allergen_Strawberries, score));
}

void test_is_allergic_to_eggs(void)
{
int score = 1;

TEST_ASSERT_TRUE(is_allergic_to(Allergen_Eggs, score));
}

void test_is_allergic_to_eggs_in_addition_to_other_stuff(void)
{
int score = 5;

TEST_ASSERT_TRUE(is_allergic_to(Allergen_Eggs, score));
TEST_ASSERT_TRUE(is_allergic_to(Allergen_Shellfish, score));
TEST_ASSERT_FALSE(is_allergic_to(Allergen_Strawberries, score));
}

void test_no_allergies_at_all(void)
{
int score = 0;
Allergen_List_t list;

get_allergens(score, &list);

test_list_count_is(0, &list);

free(list.allergens);
}

void test_allergic_to_just_eggs(void)
{
int score = 1;
Allergen_List_t list;

get_allergens(score, &list);

test_list_count_is(1, &list);
test_list_contains(Allergen_Eggs, &list);

free(list.allergens);
}

void test_allergic_to_just_peanuts(void)
{
int score = 2;
Allergen_List_t list;

get_allergens(score, &list);

test_list_count_is(1, &list);
test_list_contains(Allergen_Peanuts, &list);

free(list.allergens);
}

void test_allergic_to_just_strawberries(void)
{
int score = 8;
Allergen_List_t list;

get_allergens(score, &list);

test_list_count_is(1, &list);
test_list_contains(Allergen_Strawberries, &list);

free(list.allergens);
}

void test_allergic_to_eggs_and_peanuts(void)
{
int score = 3;
Allergen_List_t list;

get_allergens(score, &list);

test_list_count_is(2, &list);
test_list_contains(Allergen_Eggs, &list);
test_list_contains(Allergen_Peanuts, &list);

free(list.allergens);
}

void test_allergic_to_more_than_eggs_but_not_peanuts(void)
{
int score = 5;
Allergen_List_t list;

get_allergens(score, &list);

test_list_count_is(2, &list);
test_list_contains(Allergen_Eggs, &list);
test_list_contains(Allergen_Shellfish, &list);

free(list.allergens);
}

void test_allergic_to_lots_of_stuff(void)
{
int score = 248;
Allergen_List_t list;

get_allergens(score, &list);

test_list_count_is(5, &list);
test_list_contains(Allergen_Strawberries, &list);
test_list_contains(Allergen_Tomatoes, &list);
test_list_contains(Allergen_Chocolate, &list);
test_list_contains(Allergen_Pollen, &list);
test_list_contains(Allergen_Cats, &list);

free(list.allergens);
}

void test_allergic_to_everything(void)
{
int score = 255;
Allergen_List_t list;

get_allergens(score, &list);

test_list_count_is(8, &list);
test_list_contains(Allergen_Eggs, &list);
test_list_contains(Allergen_Peanuts, &list);
test_list_contains(Allergen_Shellfish, &list);
test_list_contains(Allergen_Strawberries, &list);
test_list_contains(Allergen_Tomatoes, &list);
test_list_contains(Allergen_Chocolate, &list);
test_list_contains(Allergen_Pollen, &list);
test_list_contains(Allergen_Cats, &list);

free(list.allergens);
}

void test_ignore_non_allergen_score_parts(void)
{
int score = 509;
Allergen_List_t list;

get_allergens(score, &list);

test_list_count_is(7, &list);
test_list_contains(Allergen_Eggs, &list);
test_list_contains(Allergen_Shellfish, &list);
test_list_contains(Allergen_Strawberries, &list);
test_list_contains(Allergen_Tomatoes, &list);
test_list_contains(Allergen_Chocolate, &list);
test_list_contains(Allergen_Pollen, &list);
test_list_contains(Allergen_Cats, &list);

free(list.allergens);
}

int main(void)
{
UnityBegin("test/test_allergies.c");

RUN_TEST(test_no_allergies_means_not_allergic);
RUN_TEST(test_is_allergic_to_eggs);
RUN_TEST(test_is_allergic_to_eggs_in_addition_to_other_stuff);
RUN_TEST(test_no_allergies_at_all);
RUN_TEST(test_allergic_to_just_eggs);
RUN_TEST(test_allergic_to_just_peanuts);
RUN_TEST(test_allergic_to_just_strawberries);
RUN_TEST(test_allergic_to_eggs_and_peanuts);
RUN_TEST(test_allergic_to_more_than_eggs_but_not_peanuts);
RUN_TEST(test_allergic_to_lots_of_stuff);
RUN_TEST(test_allergic_to_everything);
RUN_TEST(test_ignore_non_allergen_score_parts);

UnityEnd();
return 0;
}
Loading