├── .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 | --------------------------------------------------------------------------------