├── .github
└── workflows
│ └── run_tests.yaml
├── .gitignore
├── LICENSE.md
├── Readme.md
├── assets
└── gitworkshop.jpg
├── makefile
├── src
├── average.c
├── average.h
├── count_char.c
├── count_char.h
├── factorial.c
├── factorial.h
├── prime.c
├── prime.h
├── reverse_num.c
└── reverse_num.h
├── tests
├── test_average.c
├── test_count_char.c
├── test_factorial.c
├── test_prime.c
└── test_reverse_num.c
└── tests_hashes.txt
/.github/workflows/run_tests.yaml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | pull_request:
8 | branches:
9 | - main
10 |
11 | jobs:
12 | test:
13 | runs-on: ubuntu-latest
14 |
15 | steps:
16 | # Check out the repository
17 | - name: Checkout code
18 | uses: actions/checkout@v3
19 |
20 | # Verify test files have not been modified
21 | - name: Verify test files
22 | run: |
23 | # Generate hashes of the current test files
24 | find tests/ -type f -exec sha256sum {} \; > current_hashes.txt
25 | cat current_hashes.txt
26 |
27 | # Compare with the expected hashes
28 | if ! diff -q <(sort tests_hashes.txt) <(sort current_hashes.txt); then
29 | echo "Error: Test files have been modified!"
30 | exit 1
31 | fi
32 |
33 | # Install dependencies (e.g., Check testing framework)
34 | - name: Install dependencies
35 | run: |
36 | sudo apt-get update
37 | sudo apt-get install -y check
38 |
39 | # Run `make test` to compile and run tests
40 | - name: Run tests
41 | run: |
42 | make test
43 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Prerequisites
2 | *.d
3 |
4 | # Object files
5 | *.o
6 | *.ko
7 | *.obj
8 | *.elf
9 |
10 | # Linker output
11 | *.ilk
12 | *.map
13 | *.exp
14 |
15 | # Precompiled Headers
16 | *.gch
17 | *.pch
18 |
19 | # Libraries
20 | *.lib
21 | *.a
22 | *.la
23 | *.lo
24 |
25 | # Shared objects (inc. Windows DLLs)
26 | *.dll
27 | *.so
28 | *.so.*
29 | *.dylib
30 |
31 | # Executables
32 | *.exe
33 | *.out
34 | *.app
35 | *.i*86
36 | *.x86_64
37 | *.hex
38 |
39 | # Debug files
40 | *.dSYM/
41 | *.su
42 | *.idb
43 | *.pdb
44 |
45 | # Kernel Module Compile Results
46 | *.mod*
47 | *.cmd
48 | .tmp_versions/
49 | modules.order
50 | Module.symvers
51 | Mkfile.old
52 | dkms.conf
53 |
54 | bin/
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) [year] [fullname]
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/Readme.md:
--------------------------------------------------------------------------------
1 | # 🛠️ Git/GitHub Workshop Challenge Repository
2 |
3 |
4 |
5 |
6 |
7 |
8 | Welcome to the **Git/GitHub Workshop Challenge Repository**!
9 | This repository is part of the hands-on workshop organized by **CLUB EXCEL** to help you practice your Git, GitHub, and debugging skills. By participating in this challenge, you'll learn how to collaborate on GitHub, fix bugs, and ensure code quality using automated tests.
10 |
11 | ## 🚀 About The Challenge
12 |
13 | This repository contains a simple C project with some source code and automated test cases. However, there are **bugs in the source code**, and as a result, **all test cases are currently failing**. Your task is to use the skills you have learnt in this workshop to send a **Pull Request (PR)** that fixes the bugs so that all the test cases pass!
14 |
15 | ## :memo: Your tasks
16 | - Use the **standard github workflow** to get a fork of this repo on your local development environment.
17 | - Fix the bugs in the C files in [src](./src/) directory.
18 | - Make sure your test cases pass! Run `make test` to verify.
19 | - Once you are happy with the results: create a PR!
20 |
21 | If the test cases pass, your PR should automatically merge with this repo.
22 |
23 | ## 🧩 Repository Structure
24 |
25 | Here’s what you’ll find in this repository:
26 | ```
27 | .
28 | ├── src/ # Source code files (with bugs!)
29 | ├── tests/ # Test cases for the source code
30 | ├── Makefile # Makefile to build and run tests
31 | ├── README.md # This file
32 | └── .github/workflows/ # GitHub Actions workflow for automated testing
33 | └── assets/ # banner image and other stuff
34 | ```
35 |
36 | ## :scroll: Rules
37 | - The first to send a PR that **passes all test** cases **wins**!
38 | - **Partially passing PRs will not qualify**. You must pass all the testcases since `make test` will not pass if any test case fails.
39 | - PRs **should merge**. If due to some technical error a PR fails to auto-merge we will look for the **PR that passes all the test cases**.
40 | - **Do not send spam PRs!**: Only 2000 action minutes are given for each repo. If we find a participant sending too many spammy PRs we might disqualify them.
41 |
42 |
43 | ## :clipboard: Notes
44 | > [!WARNING]
45 | > **Warning**: Do not modify any other files except the ones in the [src](./src/) folder. Do not modify `.h` files in the [src](./src/)
46 |
47 | > [!NOTE]
48 | > You can run tests locally. Simply run `make test` in your local dev environment.
49 |
50 | > [!IMPORTANT]
51 | > **DO NOT MODIFY TEST CASES**! Do not modify anything in the [tests](./tests/) directory or in the [.github/workflows](.github/workflows/) directory
--------------------------------------------------------------------------------
/assets/gitworkshop.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ashknl/git-playground/d3f02ecc46828193f3d2ded94800928fc2c3375a/assets/gitworkshop.jpg
--------------------------------------------------------------------------------
/makefile:
--------------------------------------------------------------------------------
1 | CC = gcc
2 | CFLAGS = -Wall -Wextra -g
3 | CHECK_FLAGS = -lcheck -lm -lsubunit
4 |
5 | # Directories
6 | SRC_DIR = src
7 | TEST_DIR = tests
8 | BIN_DIR = bin
9 |
10 | # Source and test files
11 | SRCS = $(wildcard $(SRC_DIR)/*.c)
12 | TESTS = $(wildcard $(TEST_DIR)/test_*.c)
13 | TEST_BINS = $(patsubst $(TEST_DIR)/test_%.c, $(BIN_DIR)/test_%, $(TESTS))
14 |
15 | # Default target
16 | all: $(TEST_BINS)
17 | @echo "All tests compiled."
18 |
19 | # Rule to compile test binaries
20 | $(BIN_DIR)/test_%: $(TEST_DIR)/test_%.c $(SRCS)
21 | @mkdir -p $(BIN_DIR)
22 | $(CC) $(CFLAGS) -o $@ $< $(SRCS) $(CHECK_FLAGS)
23 |
24 | # Rule to run all tests
25 | test: $(TEST_BINS)
26 | @for test in $(TEST_BINS); do \
27 | echo "Running $$test..."; \
28 | $$test || exit 1; \
29 | done
30 | @echo "All tests passed."
31 |
32 | # Clean up build files
33 | clean:
34 | rm -rf $(BIN_DIR)
35 |
36 | .PHONY: all test clean
--------------------------------------------------------------------------------
/src/average.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | // calculate the average of a given array of integers. Do not return a float: since the test cases expect the output to be an integer
4 | int average(int numbers[], int n)
5 | {
6 | int sum = 0;
7 |
8 | for (int i = 0; i < n; i++)
9 | {
10 | sum = numbers[i];
11 | }
12 |
13 | // Calculate and return the average
14 | return sum / n;
15 | }
--------------------------------------------------------------------------------
/src/average.h:
--------------------------------------------------------------------------------
1 | #ifndef AVERAGE_H
2 | #define AVERAGE_H
3 |
4 | // Function declaration
5 | int average(int numbers[], int n);
6 |
7 | #endif
--------------------------------------------------------------------------------
/src/count_char.c:
--------------------------------------------------------------------------------
1 | #include "count_char.h"
2 | #include
3 |
4 | int count_char(char *a)
5 | {
6 | int count = 0;
7 | while (a[count] != '\0')
8 | {
9 | count = count + 2;
10 | }
11 | return count;
12 | }
--------------------------------------------------------------------------------
/src/count_char.h:
--------------------------------------------------------------------------------
1 | #ifndef COUNT_CHAR_H
2 | #define COUNT_CHAR_H
3 |
4 | // Function declaration
5 | int count_char(char *a);
6 |
7 | #endif
--------------------------------------------------------------------------------
/src/factorial.c:
--------------------------------------------------------------------------------
1 | #include "factorial.h"
2 |
3 | // calculate the factorial of a given number
4 | int factorial(int n) {
5 | if (n <= 1) return 1;
6 | return n + factorial(n - 1);
7 | }
--------------------------------------------------------------------------------
/src/factorial.h:
--------------------------------------------------------------------------------
1 | #ifndef FACTORIAL_H
2 | #define FACTORIAL_H
3 |
4 | // Function declaration
5 | int factorial(int n);
6 |
7 | #endif
--------------------------------------------------------------------------------
/src/prime.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include "prime.h"
4 |
5 | // check for primality of a given number: use to get bool type
6 | bool prime(int num)
7 | {
8 | if (num <= 1)
9 | {
10 | return false;
11 | }
12 |
13 | // Check for factors from 2 to sqrt(num)
14 | for (int i = 2; i * i <= num; i++)
15 | {
16 | if (num % i == 0)
17 | {
18 | return true;
19 | }
20 | }
21 |
22 | return true;
23 | }
--------------------------------------------------------------------------------
/src/prime.h:
--------------------------------------------------------------------------------
1 | #ifndef FACTORIAL_H
2 | #define FACTORIAL_H
3 |
4 | #include
5 |
6 | // Function declaration
7 | bool prime(int n);
8 |
9 | #endif
--------------------------------------------------------------------------------
/src/reverse_num.c:
--------------------------------------------------------------------------------
1 | #include "reverse_num.h"
2 |
3 | int reverse_num(int num)
4 | {
5 | int reversedNum = 0, remainder;
6 |
7 | // Reverse the number
8 | while (num != 0)
9 | {
10 | remainder = num % 10;
11 | reversedNum = reversedNum*1 + remainder;
12 | num /= 10;
13 | }
14 |
15 | return reversedNum;
16 | }
--------------------------------------------------------------------------------
/src/reverse_num.h:
--------------------------------------------------------------------------------
1 | #ifndef REVERSE_H
2 | #define REVERSE_H
3 |
4 | // Function declaration
5 | int reverse_num(int n);
6 |
7 | #endif
--------------------------------------------------------------------------------
/tests/test_average.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include "../src/average.h" // Include the factorial function`
3 | #include
4 |
5 | START_TEST(test_average)
6 | {
7 | int arr1[] = {3, 4, 5};
8 | int arr2[] = {3, 4, 5, 6, 2};
9 | int arr3[] = {1, 2, 3};
10 |
11 | ck_assert_int_eq(average(arr1, 3), 4);
12 | ck_assert_int_eq(average(arr2, 5), 4);
13 | ck_assert_int_eq(average(arr3, 3), 2);
14 | }
15 | END_TEST
16 |
17 | Suite *average_suite(void)
18 | {
19 | Suite *s;
20 | TCase *tc_core;
21 |
22 | s = suite_create("average");
23 |
24 | // core test case
25 | tc_core = tcase_create("Core");
26 | tcase_add_test(tc_core, test_average);
27 | suite_add_tcase(s, tc_core);
28 |
29 | return s;
30 | }
31 |
32 | int main()
33 | {
34 | printf("Calling test average...");
35 | int number_failed;
36 | Suite *s;
37 | SRunner *sr;
38 |
39 | s = average_suite();
40 | sr = srunner_create(s);
41 | srunner_run_all(sr, CK_NORMAL);
42 | number_failed = srunner_ntests_failed(sr);
43 | srunner_free(sr);
44 | return (number_failed == 0) ? 0 : 1;
45 | }
--------------------------------------------------------------------------------
/tests/test_count_char.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include "../src/count_char.h" // Include the factorial function`
3 | #include
4 |
5 | START_TEST(test_count_char)
6 | {
7 | char* a = "test";
8 | char* b = "test another string";
9 | char* c = "test yet another string";
10 |
11 | ck_assert_int_eq(count_char(a), 4);
12 | ck_assert_int_eq(count_char(b), 19);
13 | ck_assert_int_eq(count_char(c), 23);
14 | }
15 | END_TEST
16 |
17 | Suite *average_suite(void)
18 | {
19 | Suite *s;
20 | TCase *tc_core;
21 |
22 | s = suite_create("average");
23 |
24 | // core test case
25 | tc_core = tcase_create("Core");
26 | tcase_add_test(tc_core, test_count_char);
27 | suite_add_tcase(s, tc_core);
28 |
29 | return s;
30 | }
31 |
32 | int main()
33 | {
34 | printf("Calling test count_char...");
35 | int number_failed;
36 | Suite *s;
37 | SRunner *sr;
38 |
39 | s = average_suite();
40 | sr = srunner_create(s);
41 | srunner_run_all(sr, CK_NORMAL);
42 | number_failed = srunner_ntests_failed(sr);
43 | srunner_free(sr);
44 | return (number_failed == 0) ? 0 : 1;
45 | }
--------------------------------------------------------------------------------
/tests/test_factorial.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include "../src/factorial.h" // Include the factorial function`
3 | #include
4 |
5 | START_TEST(test_factorial)
6 | {
7 | ck_assert_int_eq(factorial(5), 120);
8 | ck_assert_int_eq(factorial(0), 1);
9 | ck_assert_int_eq(factorial(10), 3628800);
10 | }
11 | END_TEST
12 |
13 | Suite *factorial_suite(void)
14 | {
15 | Suite *s;
16 | TCase *tc_core;
17 |
18 | s = suite_create("factorial");
19 |
20 | // core test case
21 | tc_core = tcase_create("Core");
22 | tcase_add_test(tc_core, test_factorial);
23 | suite_add_tcase(s, tc_core);
24 |
25 | return s;
26 | }
27 |
28 | int main()
29 | {
30 | printf("Calling test factorial...");
31 | int number_failed;
32 | Suite *s;
33 | SRunner *sr;
34 |
35 | s = factorial_suite();
36 | sr = srunner_create(s);
37 | srunner_run_all(sr, CK_NORMAL);
38 | number_failed = srunner_ntests_failed(sr);
39 | srunner_free(sr);
40 | return (number_failed == 0) ? 0 : 1;
41 | }
--------------------------------------------------------------------------------
/tests/test_prime.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include "../src/prime.h" // Include the factorial function`
3 | #include
4 | #include
5 |
6 | START_TEST(test_prime)
7 | {
8 | ck_assert_int_eq(prime(1),false);
9 | ck_assert_int_eq(prime(7), true);
10 | ck_assert_int_eq(prime(9), false);
11 |
12 | }
13 | END_TEST
14 |
15 | Suite *factorial_suite(void)
16 | {
17 | Suite *s;
18 | TCase *tc_core;
19 |
20 | s = suite_create("factorial");
21 |
22 | // core test case
23 | tc_core = tcase_create("Core");
24 | tcase_add_test(tc_core, test_prime);
25 | suite_add_tcase(s, tc_core);
26 |
27 | return s;
28 | }
29 |
30 | int main()
31 | {
32 | printf("Calling test prime ...");
33 | int number_failed;
34 | Suite *s;
35 | SRunner *sr;
36 |
37 | s = factorial_suite();
38 | sr = srunner_create(s);
39 | srunner_run_all(sr, CK_NORMAL);
40 | number_failed = srunner_ntests_failed(sr);
41 | srunner_free(sr);
42 | return (number_failed == 0) ? 0 : 1;
43 | }
--------------------------------------------------------------------------------
/tests/test_reverse_num.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include "../src/reverse_num.h" // Include the factorial function`
3 | #include
4 |
5 | START_TEST(test_reverse)
6 | {
7 | ck_assert_int_eq(reverse_num(123), 321);
8 | ck_assert_int_eq(reverse_num(456), 654);
9 | ck_assert_int_eq(reverse_num(221), 122);
10 | }
11 | END_TEST
12 |
13 | Suite *reverse_suite(void)
14 | {
15 | Suite *s;
16 | TCase *tc_core;
17 |
18 | s = suite_create("reverse");
19 |
20 | // core test case
21 | tc_core = tcase_create("Core");
22 | tcase_add_test(tc_core, test_reverse);
23 | suite_add_tcase(s, tc_core);
24 |
25 | return s;
26 | }
27 |
28 | int main()
29 | {
30 | printf("Calling reverse factorial...");
31 | int number_failed;
32 | Suite *s;
33 | SRunner *sr;
34 |
35 | s = reverse_suite();
36 | sr = srunner_create(s);
37 | srunner_run_all(sr, CK_NORMAL);
38 | number_failed = srunner_ntests_failed(sr);
39 | srunner_free(sr);
40 | return (number_failed == 0) ? 0 : 1;
41 | }
--------------------------------------------------------------------------------
/tests_hashes.txt:
--------------------------------------------------------------------------------
1 | f1207e351b7e46338b1037a96a3452db2eb40ab283c8f71cd618808e4c59d552 tests/test_reverse_num.c
2 | 0acf10426318c21f11a022073f15532fbb531084218b3875a9e018feba10d616 tests/test_average.c
3 | 6f12c6270ac9f1bfcf1f1fd3d92eb54dc587b024ee79334218d04fb574e26876 tests/test_prime.c
4 | f3059a77f02375a1dfbc72ffe166d406fe078ddf805e5858eabfcd91c5e6bb67 tests/test_factorial.c
5 | 90ba21ce27d6744002f365a90c21017f7885be59d20d0a7ed92b95ceb008e4c9 tests/test_count_char.c
6 |
--------------------------------------------------------------------------------