Setting up a Holberton School project

Setting up a Holberton School project

#C #Unity #testframework #Makefile #automation #conventionalcommits


Let's work through Sorting algorithms & Big O. It is a project in Holberton School Australia's C curriculum.

If you are thinking of studying at Holberton School Australia, this article series will give you a taste of its project-based learning.

Learning Goals

Each Holberton project has a set of learning goals associated with it. Having goals is important. I try to set a few personal goals in addition to the provided goals.

Provided goals

For the Sorting algorithms & Big O project, Holberton provides a family of related goals. By the end of the project, I am expected to be able to explain to anyone without the help of Google:

  • At least four different sorting algorithms

  • What is the Big O notation, and how to evaluate the time complexity of an algorithm

  • How to select the best sorting algorithm for a given input

  • What is a stable sorting algorithm

Personal goals

In addition to these knowledge goals, I have also set myself a few process goals:

  • Set up test automation

  • Do Test-Driven Development

  • Use conventional commits


Setting up the repository

I define a project path for where I want my project files stored. I use that path to create a directory and then I initialise it is a git repository.

$ path_project='/root/holbertonschool-sorting_algorithms'
$ mkdir $path_project
$ cd $path_project
$ git init

chore(docs): add README

I add the project readme.

$ echo "Repository for 'Sorting algorithms & Big O' project" > README.md
$ git add README.md
$ git commit -m 'chore(docs): add README'
💡
Although I use git commit -m in this blog post for brevity, I actually prefer the flagless git commit . When used without any flags, git commit opens an editor session. In the editor session, Git shows what files have been staged. In my Vim editor, it also shows how many characters have been typed. Consequently, I make fewer mistakes and it is easier to create well-formatted commit bodies and satisfy line-length commit conventions (see this and this).

Setting up a testing framework

chore(tests): add Unity framework

Unity is a lightweight unit test framework for C written in C. The core dependencies are a source file (unity.c) and two header files (unity.h and unity_internals.h). A C source file can act as a Unity test runner if it includes unity.h and defines a main function that executes Unity's test suite management macros.

I install the Unity dependencies and locate the files.

$ git submodule add https://github.com/ThrowTheSwitch/Unity.git Unity
..
$ find -name unity.c -o -name unity.h -o -name unity_internals.h
./Unity/src/unity.c
./Unity/src/unity.h
./Unity/src/unity_internals.h

I define the path to the dependencies and explicitly add them to version control.

💡
By explicitly adding the core Unity files, I no longer depend on the submodule repository. This means that a) in the future I can clone without the recurse-submodules flag but that b) my version of Unity is frozen and I won't pull in any updates.
$ path_unity=$path_project/Unity/src
$ git add "$path_project"/unity{.c, .h, _internals.h}
$ git commit -m 'chore(tests): add Unity framework'
chore(tests): add Unity framework
👀
Observe the brace expansion in the second line: unity{.c, .h, _internals.h}. I learned about this feature of Bash during Holberton's Unix curriculum. I am a big fan of learning simple tools that I can then apply to multiple contexts.

feat(tests): add test runner template

Let's use a modified version of the file from my Unity series as our test runner template.

In Part 1 of my series that explores how to do TDD in C, I step through TDD cycles until a near-minimal Unity test runner compiles. The result of that process, test_that_unity_works.c, can be found in the Replit supplied at the end of the article.

To keep the project organised, I create a directory for my tests. This is where I add the test_runner_template.c file.

$ path_tests=$path_project/tests
$ mkdir $path_tests

I confirm that the test runner template compiles.

$ gcc -I$path_unity $path_unity/unity.c $path_tests/test_runner_template.c -o unity_test_runner.out

I confirm that the test runner executable runs as expected.

$ ./unity_test_runner.out

-----------------------
0 Tests 0 Failures 0 Ignored
OK

I add the test runner template to version control.

$ git add $path_tests/test_runner_template.c
$ git commit -m 'feat(tests): add test runner template'

Setting up test automation

Instead of building and executing the tests manually as above, let's use the GNU make utility to define rules that automatically build and run the test runner.

make can be used to 1) execute shell commands and 2) describe and then execute the steps for any task where some files must be updated automatically from other files whenever those file changes.

build(tests): automate test runner

To use GNU Make as an automated test runner, I define a Makefile with targets that contain build, run and clean recipes.

I confirm that the run target works.

$ make run
/root/holbertonschool-sorting_algorithms/tests/unity_test_runner.out

-----------------------
0 Tests 0 Failures 0 Ignored
OK

I confirm that the clean target works.

$ make clean
rm -f /root/holbertonschool-sorting_algorithms/tests/unity_test_runner.out
$ make run
...
make: *** [Makefile:17: run] Error 127

I confirm that the build target works.

$ make build
gcc -I/root/holbertonschool-sorting_algorithms/Unity/src /root/holbertonschool-sorting_algorithms/Unity/src/unity.c /root/holbertonschool-sorting_algorithms/tests/test_runner_template.c -o /root/holbertonschool-sorting_algorithms/tests/unity_test_runner.out
$ make run
/root/holbertonschool-sorting_algorithms/tests/unity_test_runner.out

-----------------------
0 Tests 0 Failures 0 Ignored
OK

Finally, I run GNU Make to confirm that the default target works as intended.

I use the -s flag to silence GNU Make - now it won't print the commands it executes.
$ make -s 

-----------------------
0 Tests 0 Failures 0 Ignored
OK

Everything works. I add the automation tool to version control.

$ git add Makefile
$ git commit -m 'build(tests): automate test runner'

Setting up supplied dependencies

A Holberton project often provides algorithms or data structures to use. Sorting Algorithms & Big O is one such project. It provides the following dependencies:

  • a print array algorithm

  • a print linked list algorithm

  • a linked list data structure

feat(Holberton): define linked list

I create an include guarded header file, sort.h, and add the linked list definition supplied by Holberton to it. Then I add the file to version control.

$ git add sort.h
$ git commit -m 'feat(Holbertone): define Linked List'

After the next two commits, sort.h will contain the following:

feat(Holberton): print arrays

I add the supplied Holberton file, print_array.c, to version control. It contains the print_array function. I also add the function's prototype to sort.h.

$ git add print_array.c sort.h
$ git commit -m 'feat(Holberton): print arrays'

feat(Holberton): print linked lists

I do the same for the Holberton file, print_list.c, which contains the print_list function.

$ git add print_list.c sort.h
$ git commit -m 'feat(Holberton): print lists'


Adding to documentation

To finish, I add this blog post to the project README.

docs: add setup blog post to README

$ url='https://warrenmarkham.hashnode.dev/setting-up-a-holberton-school-project'
$ echo -e "\nRead about [the project setup]($url)." >> README.md 
$ git add README.md
$ git commit -m 'docs: add setup blog post to README'

Next: Bubble Sort


👋
Hello, I'm Warren. I've worked in an AWS Data Engineer role at Infosys, Australia. Previously, I was a Disability Support Worker. I'm interested in collaborative workflows and going deeper into TDD, automation and distributed systems.
📆
I am currently studying C at Holberton School Australia.
🐴
"Holberton School Australia is a tech school that trains software engineers through a collaborative, project-based curriculum. Over the course of 9 months, our students learn how to walk, talk, and code like software engineers."