diff --git a/Makefile b/Makefile index 6c468b6..e3ad8c6 100644 --- a/Makefile +++ b/Makefile @@ -1,18 +1,26 @@ -# executable files / archive files +# executable files NAME = push_swap CHECKER = checker TEST_NAME = unit_tester + +# libraries LIBFT = $(LIBFT_DIR)/libft.a # compilar options CFLAGS = -Werror -Wextra -Wall CXXFLAGS = -std=c++17 -Wall -Wextra -Werror PROD_FLAGS = -O3 -DEV_FLAGS = -g -fsanitize=address,integer,undefined -O0 -D DEV -LEAK_FLAGS = -O0 -D DEV -D LEAK +DEV_FLAGS = -O0 -g -fsanitize=address,integer,undefined -D DEV +LEAK_FLAGS = -D LEAK DEPFLAGS = -MMD -MP INCLUDE = -I $(INC_DIR) +# flag options +# 1. PROD_FLAGS: flags for production +# 2. DEV_FLAGS: flags for development +# 3. LEAK_FLAGS: flags for checking leaks +FLAGS_OPTION = $(PROD_FLAGS) + # directories SRC_DIR = src BUILD_DIR = build @@ -55,6 +63,7 @@ OBJ_FILTER_MAIN = $(filter-out $(BUILD_DIR)/main.o, $(patsubst $(SRC_DIR)/%.c, $ # bonus source files BONUS_SRC = $(SRC_DIR)/checker/checker_main.c \ + $(SRC_DIR)/checker/sort_based_on_operation.c \ $(SRC_DIR)/initialization/check_args.c \ $(SRC_DIR)/initialization/exit_with_error.c \ $(SRC_DIR)/initialization/generate_stack.c \ @@ -64,10 +73,14 @@ BONUS_SRC = $(SRC_DIR)/checker/checker_main.c \ $(SRC_DIR)/stack_operations/rotate.c \ $(SRC_DIR)/stack_operations/reverse_rotate.c \ $(SRC_DIR)/utils/get_content.c \ - $(SRC_DIR)/utils/stack_size.c + $(SRC_DIR)/utils/stack_size.c \ + $(SRC_DIR)/utils/clear_stack.c BONUS_OBJ = $(patsubst $(SRC_DIR)/%.c, $(BUILD_DIR)/%.o, $(BONUS_SRC)) BONUS_DEP = $(patsubst $(SRC_DIR)/%.c, $(BUILD_DIR)/%.d, $(BONUS_SRC)) +# header files +HEADER = $(wildcard $(INC_DIR)/*.h) + # test files TEST_SRC = $(TEST_DIR)/test_check_args.cpp \ $(TEST_DIR)/test_push_stack.cpp \ @@ -85,11 +98,11 @@ TEST_OBJ = $(patsubst $(TEST_DIR)/%.cpp, $(TEST_BUILD_DIR)/%.o, $(TEST_SRC)) GTEST_SRC = $(GTEST_DIR)/gtest_main.cc $(GTEST_DIR)/gtest-all.cc GTEST_OBJ = $(patsubst $(GTEST_DIR)/%.cc, $(TEST_BUILD_DIR)/%.o, $(GTEST_SRC)) -GTEST_VERSION = 1.14.0 -GTEST_ARCHIVE = v$(GTEST_VERSION).tar.gz -GTEST_REPO_URL = https://github.com/google/googletest/archive/refs/tags/$(GTEST_ARCHIVE) -GTEST_SRC_DIR = googletest-$(GTEST_VERSION) -GTEST_FUSE_URL = https://raw.githubusercontent.com/google/googletest/ec44c6c1675c25b9827aacd08c02433cccde7780/googletest/scripts/$(GTEST_FUSE) +# google test version: 1.14.0 +GTEST_ARCHIVE = v1.14.0.tar.gz +GTEST_REPO_URL = https://github.com/google/googletest/archive/refs/tags/v1.14.0.tar.gz +GTEST_SRC_DIR = googletest-1.14.0 +GTEST_FUSE_URL = https://raw.githubusercontent.com/google/googletest/ec44c6c1675c25b9827aacd08c02433cccde7780/googletest/scripts/fuse_gtest_files.py GTEST_FUSE = fuse_gtest_files.py # colors @@ -104,37 +117,38 @@ MAGENTA = \033[0;95m CYAN = \033[0;96m WHITE = \033[0;97m -# flags options -# 1. PROD_FLAGS: flags for production -# 2. DEV_FLAGS: flags for development -# 3. LEAK_FLAGS: flangs for checking leaks - # rules for mandatory -all: CFLAGS += $(PROD_FLAGS) +.PHONY: all +all: CFLAGS += $(FLAGS_OPTION) all: $(NAME) -$(NAME): $(LIBFT) $(SRC) - @make _main +$(NAME): $(LIBFT) $(SRC) $(HEADER) + @make _main CFLAGS="$(CFLAGS)" +.PHONY: _main _main: @echo "$(BLUE)[$(NAME)]\t./$(NAME)$(RESET)\t$(WHITE)compling...$(RESET)" - @make _build + @make _build CFLAGS="$(CFLAGS)" +.PHONY: _build _build: $(OBJ) @$(CC) $(CFLAGS) $^ -L $(LIBFT_DIR) -lft -o $(NAME) @echo "\n$(BLUE)[$(NAME)]\t./$(NAME)$(RESET)\t$(GREEN)compiled ✔$(RESET)" # rules for bonus -bonus: CFLAGS += $(PROD_FLAGS) +.PHONY: bonus +bonus: CFLAGS += $(FLAGS_OPTION) bonus: $(CHECKER) -$(CHECKER): $(LIBFT) $(BONUS_SRC) - @make _checker_main +$(CHECKER): $(LIBFT) $(BONUS_SRC) $(HEADER) + @make _checker_main CFLAGS="$(CFLAGS)" +.PHONY: _checker_main _checker_main: @echo "$(BLUE)[$(CHECKER)]\t./$(CHECKER)$(RESET)\t$(WHITE)compling...$(RESET)" - @make _checker_build + @make _checker_build CFLAGS="$(CFLAGS)" +.PHONY: _checker_build _checker_build: $(BONUS_OBJ) @$(CC) $(CFLAGS) $^ -L $(LIBFT_DIR) -lft -o $(CHECKER) @echo "\n$(BLUE)[$(CHECKER)]\t./$(CHECKER)$(RESET)\t$(GREEN)compiled ✔$(RESET)" @@ -145,9 +159,13 @@ $(BUILD_DIR)/%.o: $(SRC_DIR)/%.c @$(CC) $(CFLAGS) $(INCLUDE) $(DEPFLAGS) -c $< -o $@ @printf "$(GREEN)─$(RESET)" -$(LIBFT): +$(LIBFT): $(LIBFT_DIR) @make -C $(@D) +$(LIBFT_DIR): + @git submodule update --init + +.PHONY: clean clean: @make clean -C $(LIBFT_DIR) @$(RM) $(OBJ) $(DEP) @@ -155,6 +173,7 @@ clean: @$(RM) $(BONUS_OBJ) $(BONUS_DEP) @echo "$(BLUE)[$(CHECKER)]\tobject files$(RESET)\t$(GREEN)deleted ✔$(RESET)" +.PHONY: fclean fclean: clean @make fclean -C $(LIBFT_DIR) @$(RM) $(NAME) @@ -162,32 +181,36 @@ fclean: clean @$(RM) $(CHECKER) @echo "$(BLUE)[$(CHECKER)]\t./$(NAME)$(RESET)\t$(GREEN)deleted ✔$(RESET)" +.PHONY: re re: fclean all # rules for test +.PHONY: test test: all $(GTEST_OBJ) $(TEST_OBJ) - @echo "$(BLUE)\ntest linking$(RESET)" @$(CXX) -L $(LIBFT_DIR) -lft -lpthread $(OBJ_FILTER_MAIN) $(TEST_OBJ) $(GTEST_OBJ) -o $(TEST_NAME) + @echo "\n$(BLUE)[gtest]\t\t./$(TEST_NAME)$(RESET)\t$(GREEN)compiled ✔$(RESET)" ./$(TEST_NAME) +.PHONY: test_clean test_clean: - @echo "$(BLUE)test cleaning$(RESET)" @$(RM) -r $(TEST_BUILD_DIR) + @echo "$(BLUE)[gtest]\t\t./$(TEST_NAME)$(RESET)\t$(GREEN)deleted ✔$(RESET)" +.PHONY: retest retest: test_clean test $(TEST_BUILD_DIR)/%.o: $(TEST_DIR)/%.cpp @mkdir -p $(@D) @$(CXX) $(CXXFLAGS) -I $(TEST_DIR) $(INCLUDE) -c $< -o $@ - @printf "$(GREEN).$(RESET)" + @printf "$(GREEN)─$(RESET)" $(GTEST_OBJ): $(GTEST_DIR) - @echo "$(BLUE)test compiling$(RESET)" + @echo "$(BLUE)[gtest]\t\t./$(TEST_NAME)$(RESET)\t$(WHITE)compling...$(RESET)" @mkdir -p $(@D) @$(CXX) $(CXXFLAGS) -I $(TEST_DIR) $(INCLUDE) -c $(GTEST_DIR)/gtest-all.cc -o $(TEST_BUILD_DIR)/gtest-all.o - @printf "$(GREEN).$(RESET)" + @printf "$(GREEN)─$(RESET)" @$(CXX) $(CXXFLAGS) -I $(TEST_DIR) $(INCLUDE) -c $(GTEST_DIR)/gtest_main.cc -o $(TEST_BUILD_DIR)/gtest_main.o - @printf "$(GREEN).$(RESET)" + @printf "$(GREEN)─$(RESET)" $(GTEST_DIR): @echo "fetching google test" @@ -200,9 +223,8 @@ $(GTEST_DIR): @mv $(GTEST_DIR)/gtest/* $(GTEST_DIR) @$(RM) -r $(GTEST_SRC_DIR) $(GTEST_DIR)/gtest $(GTEST_ARCHIVE) $(GTEST_FUSE) +.PHONY: norm norm: norminette $(INC_DIR) $(SRC_DIR) $(LIBFT_DIR) -.PHONY: all clean fclean re dev redev leak releak test norm title - -include $(DEP) diff --git a/include/checker.h b/include/checker.h index 710cc51..a284326 100644 --- a/include/checker.h +++ b/include/checker.h @@ -6,7 +6,7 @@ /* By: reasuke +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/02/14 10:26:54 by reasuke #+# #+# */ -/* Updated: 2024/02/14 10:29:44 by reasuke ### ########.fr */ +/* Updated: 2024/02/19 12:11:08 by reasuke ### ########.fr */ /* */ /* ************************************************************************** */ @@ -16,4 +16,6 @@ # include "../libft/libft.h" # include "types.h" +void sort_based_on_operation(t_stack **p_a, t_stack **p_b); + #endif diff --git a/src/checker/checker_main.c b/src/checker/checker_main.c index dab9669..9235b5f 100644 --- a/src/checker/checker_main.c +++ b/src/checker/checker_main.c @@ -6,73 +6,34 @@ /* By: reasuke +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/02/14 10:25:27 by reasuke #+# #+# */ -/* Updated: 2024/02/14 13:50:38 by reasuke ### ########.fr */ +/* Updated: 2024/02/19 12:49:49 by reasuke ### ########.fr */ /* */ /* ************************************************************************** */ #include "checker.h" #include "initialization.h" #include "sort.h" -#include "stack_operations.h" -static bool _is_operation_present(const char *op) -{ - bool present; +#ifdef LEAK +# ifdef __APPLE__ - present = false; - present |= !ft_strcmp(op, "sa\n"); - present |= !ft_strcmp(op, "sb\n"); - present |= !ft_strcmp(op, "ss\n"); - present |= !ft_strcmp(op, "pa\n"); - present |= !ft_strcmp(op, "pb\n"); - present |= !ft_strcmp(op, "ra\n"); - present |= !ft_strcmp(op, "rb\n"); - present |= !ft_strcmp(op, "rr\n"); - present |= !ft_strcmp(op, "rra\n"); - present |= !ft_strcmp(op, "rrb\n"); - present |= !ft_strcmp(op, "rrr\n"); - return (present); -} +void leak_check(void) __attribute__((destructor)); -static void _stack_operation(t_stack **p_a, t_stack **p_b, const char *op) +void leak_check(void) { - if (!ft_strcmp(op, "sa\n") || !ft_strcmp(op, "ss\n")) - swap_stack(p_a); - if (!ft_strcmp(op, "sb\n") || !ft_strcmp(op, "ss\n")) - swap_stack(p_b); - if (!ft_strcmp(op, "pa\n")) - push_stack(p_b, p_a); - if (!ft_strcmp(op, "pb\n")) - push_stack(p_a, p_b); - if (!ft_strcmp(op, "ra\n") || !ft_strcmp(op, "rr\n")) - rotate_stack(p_a); - if (!ft_strcmp(op, "rb\n") || !ft_strcmp(op, "rr\n")) - rotate_stack(p_b); - if (!ft_strcmp(op, "rra\n") || !ft_strcmp(op, "rrr\n")) - reverse_rotate_stack(p_a); - if (!ft_strcmp(op, "rrb\n") || !ft_strcmp(op, "rrr\n")) - reverse_rotate_stack(p_b); + system("leaks -q checker"); } -static void _sort_based_on_operation(t_stack **p_a, t_stack **p_b) -{ - char *op; - - while (true) - { - op = get_next_line(STDIN_FILENO); - if (!op) - break ; - if (!_is_operation_present(op)) - exit_with_error(); - _stack_operation(p_a, p_b, op); - } -} +# endif +#endif static void _check_sorted(t_stack *st_a, int size_a) { if (stack_size(st_a) != size_a) + { ft_putendl_fd("KO", STDOUT_FILENO); + return ; + } if (is_sorted_stack(st_a)) ft_putendl_fd("OK", STDOUT_FILENO); else @@ -89,7 +50,9 @@ int main(int argc, char **argv) check_args(argc, argv); st_a = generate_stack(argc, argv); st_b = NULL; - _sort_based_on_operation(&st_a, &st_b); + sort_based_on_operation(&st_a, &st_b); _check_sorted(st_a, argc - 1); + clear_stack(&st_a, free); + clear_stack(&st_b, free); return (0); } diff --git a/src/checker/sort_based_on_operation.c b/src/checker/sort_based_on_operation.c new file mode 100644 index 0000000..eaab9b2 --- /dev/null +++ b/src/checker/sort_based_on_operation.c @@ -0,0 +1,70 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* sort_based_on_operation.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: reasuke +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2024/02/19 12:10:41 by reasuke #+# #+# */ +/* Updated: 2024/02/19 12:48:45 by reasuke ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "checker.h" +#include "initialization.h" +#include "stack_operations.h" + +static bool _is_operation_present(const char *op) +{ + bool present; + + present = false; + present |= !ft_strcmp(op, "sa\n"); + present |= !ft_strcmp(op, "sb\n"); + present |= !ft_strcmp(op, "ss\n"); + present |= !ft_strcmp(op, "pa\n"); + present |= !ft_strcmp(op, "pb\n"); + present |= !ft_strcmp(op, "ra\n"); + present |= !ft_strcmp(op, "rb\n"); + present |= !ft_strcmp(op, "rr\n"); + present |= !ft_strcmp(op, "rra\n"); + present |= !ft_strcmp(op, "rrb\n"); + present |= !ft_strcmp(op, "rrr\n"); + return (present); +} + +static void _stack_operation(t_stack **p_a, t_stack **p_b, const char *op) +{ + if (!ft_strcmp(op, "sa\n") || !ft_strcmp(op, "ss\n")) + swap_stack(p_a); + if (!ft_strcmp(op, "sb\n") || !ft_strcmp(op, "ss\n")) + swap_stack(p_b); + if (!ft_strcmp(op, "pa\n")) + push_stack(p_b, p_a); + if (!ft_strcmp(op, "pb\n")) + push_stack(p_a, p_b); + if (!ft_strcmp(op, "ra\n") || !ft_strcmp(op, "rr\n")) + rotate_stack(p_a); + if (!ft_strcmp(op, "rb\n") || !ft_strcmp(op, "rr\n")) + rotate_stack(p_b); + if (!ft_strcmp(op, "rra\n") || !ft_strcmp(op, "rrr\n")) + reverse_rotate_stack(p_a); + if (!ft_strcmp(op, "rrb\n") || !ft_strcmp(op, "rrr\n")) + reverse_rotate_stack(p_b); +} + +void sort_based_on_operation(t_stack **p_a, t_stack **p_b) +{ + char *op; + + while (true) + { + op = get_next_line(STDIN_FILENO); + if (!op) + break ; + if (!_is_operation_present(op)) + exit_with_error(); + _stack_operation(p_a, p_b, op); + free(op); + } +} diff --git a/src/initialization/check_args.c b/src/initialization/check_args.c index 544e5a3..6d5ca31 100644 --- a/src/initialization/check_args.c +++ b/src/initialization/check_args.c @@ -6,7 +6,7 @@ /* By: reasuke +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/01/11 14:44:55 by reasuke #+# #+# */ -/* Updated: 2024/02/13 11:45:54 by reasuke ### ########.fr */ +/* Updated: 2024/02/19 12:56:30 by reasuke ### ########.fr */ /* */ /* ************************************************************************** */ @@ -67,6 +67,8 @@ static bool _has_duplicate(int argc, char **argv) int check_args(int argc, char **argv) { + if (argc == 1) + exit(0); if (_has_not_digit(argc, argv) || _has_overflow(argc, argv) || _has_duplicate(argc, argv)) exit_with_error(); diff --git a/src/main.c b/src/main.c index f11c1b7..2894ed0 100644 --- a/src/main.c +++ b/src/main.c @@ -6,7 +6,7 @@ /* By: reasuke +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/01/10 12:37:36 by reasuke #+# #+# */ -/* Updated: 2024/02/13 22:58:00 by reasuke ### ########.fr */ +/* Updated: 2024/02/19 12:06:15 by reasuke ### ########.fr */ /* */ /* ************************************************************************** */ @@ -15,22 +15,14 @@ #ifdef LEAK # ifdef __APPLE__ -void leak_chek(void) __attribute__((destructor)); +void leak_check(void) __attribute__((destructor)); -void leak_chek(void) +void leak_check(void) { system("leaks -q push_swap"); } # endif -#endif -#ifdef DEV - -void put_void(void *content) -{ - ft_printf("%d\n", *(int *)content); -} - #endif int main(int argc, char **argv) diff --git a/test/e2e/spec/checker_spec.rb b/test/e2e/spec/checker_spec.rb index b9f6945..4ba8c5e 100644 --- a/test/e2e/spec/checker_spec.rb +++ b/test/e2e/spec/checker_spec.rb @@ -3,13 +3,11 @@ require_relative "../helper/command_helper" describe("Performance test for push_swap") do - [5, 10, 50, 100, 200, 500, 1000].each do |size| + [1, 2, 3, 4, 5, 10, 50, 100, 200, 500, 1000].each do |size| it "measures operations for random input of size #{size}" do - results = [] - input = (0...size).to_a.shuffle.map(&:to_s) - stdout, _stderr, status = execute_push_swap(*input) + input = (-10000..10000).to_a.sample(size).map(&:to_s) + _stdout, _stderr, status = execute_push_swap(*input) expect(status.exitstatus).to(eq(0)) - results << stdout.split("\n").count stdout, _stderr, status = execute_checker(*input) expect(status.exitstatus).to(eq(0)) diff --git a/test/e2e/spec/corner_cases_spec.rb b/test/e2e/spec/corner_cases_spec.rb index f1111da..71eda60 100644 --- a/test/e2e/spec/corner_cases_spec.rb +++ b/test/e2e/spec/corner_cases_spec.rb @@ -3,6 +3,13 @@ require_relative "../helper/command_helper" describe "Corner cases for push_swap" do + it "does not output anything for not inputs" do + stdout, _stderr, status = execute_push_swap + + expect(stdout).to(eq("")) + expect(status.exitstatus).to(eq(0)) + end + it "does not output operations for already sorted input" do stdout, _stderr, status = execute_push_swap("0", "1", "2", "3") expect(stdout).to(eq("")) diff --git a/test/e2e/spec/error_cases_spec.rb b/test/e2e/spec/error_cases_spec.rb index e63d4bd..363ccbf 100644 --- a/test/e2e/spec/error_cases_spec.rb +++ b/test/e2e/spec/error_cases_spec.rb @@ -3,21 +3,39 @@ require_relative "../helper/command_helper" describe "Error cases for push_swap" do - it "returns error for non integer inputs" do - _stdout, stderr, status = execute_push_swap("a", "b", "c") + describe "when inputs are not integers" do + it "reports an error if all arguments are non-integer" do + _stdout, stderr, status = execute_push_swap("a", "b", "c") - expect(stderr).to(eq("Error\n")) - expect(status.exitstatus).to(eq(1)) + expect(stderr).to(eq("Error\n")) + expect(status.exitstatus).to(eq(1)) + end + + it "reports an error if any argument is non-integer" do + _stdout, stderr, status = execute_push_swap("3", "push_swap", "5", "4", "1", "0", "2") + + expect(stderr).to(eq("Error\n")) + expect(status.exitstatus).to(eq(1)) + end end - it "returns error for duplicates" do - _stdout, stderr, status = execute_push_swap("3", "2", "5", "4", "1", "0", "2") + describe "when there are duplicate inputs" do + it "reports an error if all arguments are the same" do + _stdout, stderr, status = execute_push_swap("3", "3", "3", "3", "3", "3", "3") - expect(stderr).to(eq("Error\n")) - expect(status.exitstatus).to(eq(1)) + expect(stderr).to(eq("Error\n")) + expect(status.exitstatus).to(eq(1)) + end + + it "reports an error if there are any duplicate arguments" do + _stdout, stderr, status = execute_push_swap("3", "2", "5", "4", "1", "0", "2") + + expect(stderr).to(eq("Error\n")) + expect(status.exitstatus).to(eq(1)) + end end - it "returns error for overflow" do + it "reports an error for integer overflow" do _stdout, stderr, status = execute_push_swap("0", "3", "2", "34578347984", "1") expect(stderr).to(eq("Error\n")) diff --git a/test/unit/test_is_sorted_stack.cpp b/test/unit/test_is_sorted_stack.cpp index f77a9df..1f1c63e 100644 --- a/test/unit/test_is_sorted_stack.cpp +++ b/test/unit/test_is_sorted_stack.cpp @@ -10,6 +10,14 @@ extern "C" { #include "sort.h" } +TEST(is_sorted_stack, oneElement) { + t_stack *st; + t_content *c = new t_content({0, -1, 0, 0, 0, 0, 0, INIT, false}); + + st = ft_lstnew(c); + EXPECT_TRUE(is_sorted_stack(st)); +} + // st: sorted // 0 // 1