From dfcdfd6fe418f85f77d4ee259d997074dcceb75f Mon Sep 17 00:00:00 2001 From: Mateusz Masiarz Date: Mon, 3 Jul 2023 19:21:25 +0200 Subject: [PATCH] Compilation improvements (#38) * Print gcc output with colors * Add option to compile with weaker flags * Fix tests * Remove hasattr check * Bump version * Small refactor * Add test for --weak-compilation-flags * Fix fixtures * tmp fix, will be fixed in pr with checker/inwer --- src/sinol_make/__init__.py | 2 +- src/sinol_make/commands/run/__init__.py | 6 +++++- src/sinol_make/helpers/compile.py | 10 +++++++--- tests/commands/run/test_integration.py | 26 ++++++++++++++++++++++--- tests/commands/run/test_unit.py | 4 ++-- tests/commands/run/util.py | 8 ++++++++ tests/fixtures.py | 14 ++++++++++--- tests/packages/wcf/config.yml | 6 ++++++ tests/packages/wcf/in/.gitkeep | 0 tests/packages/wcf/prog/wcf.cpp | 11 +++++++++++ tests/util.py | 7 +++++++ 11 files changed, 81 insertions(+), 13 deletions(-) create mode 100644 tests/packages/wcf/config.yml create mode 100644 tests/packages/wcf/in/.gitkeep create mode 100644 tests/packages/wcf/prog/wcf.cpp diff --git a/src/sinol_make/__init__.py b/src/sinol_make/__init__.py index fa680185..24df7a8e 100644 --- a/src/sinol_make/__init__.py +++ b/src/sinol_make/__init__.py @@ -3,7 +3,7 @@ from sinol_make import util -__version__ = "1.1.1" +__version__ = "1.1.2" def configure_parsers(): parser = argparse.ArgumentParser( diff --git a/src/sinol_make/commands/run/__init__.py b/src/sinol_make/commands/run/__init__.py index bb24a8da..7c2557a1 100644 --- a/src/sinol_make/commands/run/__init__.py +++ b/src/sinol_make/commands/run/__init__.py @@ -57,6 +57,8 @@ def configure_subparser(self, subparser): help='Python interpreter to use (default: python3)') parser.add_argument('--java_compiler_path', type=str, default=compiler.get_java_compiler_path(), help='Java compiler to use (default: javac)') + parser.add_argument('--weak_compilation_flags', dest='weak_compilation_flags', action='store_true', + help='use weaker compilation flags') parser.add_argument('--apply_suggestions', dest='apply_suggestions', action='store_true', help='apply suggestions from expected scores report') @@ -191,8 +193,10 @@ def compile(self, solution): self.COMPILATION_DIR, "%s.compile_log" % self.extract_file_name(solution)) source_file = os.path.join(os.getcwd(), "prog", self.get_solution_from_exe(solution)) output = os.path.join(self.EXECUTABLES_DIR, self.get_executable(solution)) + try: - compile.compile(source_file, output, self.compilers, open(compile_log_file, "w")) + compile.compile(source_file, output, self.compilers, + open(compile_log_file, "w"), self.args.weak_compilation_flags) print(util.info("Compilation of file %s was successful." % self.extract_file_name(solution))) return True diff --git a/src/sinol_make/helpers/compile.py b/src/sinol_make/helpers/compile.py index f744926f..84c523f1 100644 --- a/src/sinol_make/helpers/compile.py +++ b/src/sinol_make/helpers/compile.py @@ -2,19 +2,23 @@ from sinol_make.interfaces.Errors import CompilationError import os, subprocess, sys -def compile(program, output, compilers = None, compile_log = None): +def compile(program, output, compilers = None, compile_log = None, weak_compilation_flags = False): """ Compile a program compilers - A dictionary of compilers to use. If not set, the default compilers will be used """ + gcc_compilation_flags = '-Werror -Wall -Wextra -Wshadow -Wconversion -Wno-unused-result -Wfloat-equal' + if weak_compilation_flags: + gcc_compilation_flags = '-w' # Disable all warnings + ext = os.path.splitext(program)[1] arguments = [] if ext == '.cpp': arguments = [compilers['cpp_compiler_path'] or compiler.get_cpp_compiler_path(), program, '-o', output] + \ - '--std=c++17 -O3 -lm -Werror -Wall -Wextra -Wshadow -Wconversion -Wno-unused-result -Wfloat-equal'.split(' ') + f'--std=c++17 -O3 -lm {gcc_compilation_flags} -fdiagnostics-color'.split(' ') elif ext == '.c': arguments = [compilers['c_compiler_path'] or compiler.get_c_compiler_path(), program, '-o', output] + \ - '--std=c17 -O3 -lm -Werror -Wall -Wextra -Wshadow -Wconversion -Wno-unused-result -Wfloat-equal'.split(' ') + f'--std=c17 -O3 -lm {gcc_compilation_flags} -fdiagnostics-color'.split(' ') elif ext == '.py': if sys.platform == 'win32' or sys.platform == 'cygwin': # TODO: Make this work on Windows diff --git a/tests/commands/run/test_integration.py b/tests/commands/run/test_integration.py index fac6aea2..4946f99c 100644 --- a/tests/commands/run/test_integration.py +++ b/tests/commands/run/test_integration.py @@ -5,7 +5,7 @@ from sinol_make import configure_parsers -@pytest.mark.parametrize("create_package", [get_simple_package_path(), get_verify_status_package_path()], indirect=True) +@pytest.mark.parametrize("create_package", [get_simple_package_path()], indirect=True) def test_simple(create_package, time_tool): """ Test a simple run. @@ -21,7 +21,7 @@ def test_simple(create_package, time_tool): command.run(args) -@pytest.mark.parametrize("create_package", [get_simple_package_path(), get_verify_status_package_path()], indirect=True) +@pytest.mark.parametrize("create_package", [get_simple_package_path()], indirect=True) def test_no_expected_scores(capsys, create_package, time_tool): """ Test with no sinol_expected_scores in config.yml. @@ -51,7 +51,7 @@ def test_no_expected_scores(capsys, create_package, time_tool): assert "abc.cpp" in out -@pytest.mark.parametrize("create_package", [get_simple_package_path(), get_verify_status_package_path()], indirect=True) +@pytest.mark.parametrize("create_package", [get_simple_package_path()], indirect=True) def test_apply_suggestions(create_package, time_tool): """ Test with no sinol_expected_scores in config.yml. @@ -143,3 +143,23 @@ def test_flag_solutions(capsys, create_package, time_tool): assert "abc1.cpp" in out assert "abc2.cpp" in out assert "abc3.cpp" not in out + + +@pytest.mark.parametrize("create_package", [get_weak_compilation_flags_package_path()], indirect=True) +def test_weak_compilation_flags(create_package): + """ + Test flag --weak-compilation-flags. + """ + parser = configure_parsers() + args = parser.parse_args(["run", "--time_tool", "time"]) + command = Command() + + with pytest.raises(SystemExit) as e: + command.run(args) + + assert e.type == SystemExit + assert e.value.code == 1 + + args = parser.parse_args(["run", "--weak_compilation_flags", "--time_tool", "time"]) + command = Command() + command.run(args) diff --git a/tests/commands/run/test_unit.py b/tests/commands/run/test_unit.py index 29c38ccb..3e11847b 100644 --- a/tests/commands/run/test_unit.py +++ b/tests/commands/run/test_unit.py @@ -72,7 +72,7 @@ def test_get_tests(create_package): def test_execution(create_package, time_tool): package_path = create_package command = get_command(package_path) - command.args = argparse.Namespace(time_tool = time_tool) + command.args = argparse.Namespace(time_tool=time_tool, weak_compilation_flags=False) solution = "abc.cpp" executable = command.get_executable(solution) result = command.compile_solutions([solution]) @@ -105,7 +105,7 @@ def test_calculate_points(): def test_run_solutions(create_package, time_tool): package_path = create_package command = get_command(package_path) - command.args = argparse.Namespace(solutions_report=False, time_tool=time_tool) + command.args = argparse.Namespace(solutions_report=False, time_tool=time_tool, weak_compilation_flags=False) create_ins_outs(package_path, command) command.tests = command.get_tests(None) command.groups = list(sorted(set([command.get_group(test) for test in command.tests]))) diff --git a/tests/commands/run/util.py b/tests/commands/run/util.py index c02dfa70..2d19f870 100644 --- a/tests/commands/run/util.py +++ b/tests/commands/run/util.py @@ -1,6 +1,7 @@ import multiprocessing as mp import os, glob +import argparse import yaml from ...util import * from sinol_make.commands.run import Command @@ -23,6 +24,7 @@ def get_command(path = None): 'java_compiler_path': compiler.get_java_compiler_path() } command.config = yaml.load(open(os.path.join(path, "config.yml"), "r"), Loader=yaml.FullLoader) + set_default_args(command) return command def create_ins(package_path, command): @@ -47,3 +49,9 @@ def create_outs(package_path, command): def create_ins_outs(package_path, command): create_ins(package_path, command) create_outs(package_path, command) + + +def set_default_args(command): + command.args = argparse.Namespace( + weak_compilation_flags=False + ) diff --git a/tests/fixtures.py b/tests/fixtures.py index caac1417..9e2bce5b 100644 --- a/tests/fixtures.py +++ b/tests/fixtures.py @@ -3,11 +3,19 @@ @pytest.fixture -def create_package(path=None): - if path is None: +def create_package(request): + """ + Fixture to create a temporary directory with specified package (by default simple package). + Changes the current working directory to the package directory. + """ + if hasattr(request, 'param') and request.param is not None: + path = request.param + else: path = get_simple_package_path() + task_id = os.path.basename(path) + tmpdir = tempfile.TemporaryDirectory() - package_path = os.path.join(tmpdir.name, "abc") + package_path = os.path.join(tmpdir.name, task_id) shutil.copytree(path, package_path) os.chdir(package_path) diff --git a/tests/packages/wcf/config.yml b/tests/packages/wcf/config.yml new file mode 100644 index 00000000..b94ecced --- /dev/null +++ b/tests/packages/wcf/config.yml @@ -0,0 +1,6 @@ +title: Package for testing --weak-compilation-flags +memory_limit: 16000 +time_limit: 1000 + +scores: + 1: 100 diff --git a/tests/packages/wcf/in/.gitkeep b/tests/packages/wcf/in/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/tests/packages/wcf/prog/wcf.cpp b/tests/packages/wcf/prog/wcf.cpp new file mode 100644 index 00000000..a7bad9e7 --- /dev/null +++ b/tests/packages/wcf/prog/wcf.cpp @@ -0,0 +1,11 @@ +#include + +using namespace std; + +int main() { + int a, b; + int c; // Unused variable + + cin >> a >> b; + cout << a + b << endl; +} diff --git a/tests/util.py b/tests/util.py index d403f737..1db06193 100644 --- a/tests/util.py +++ b/tests/util.py @@ -9,3 +9,10 @@ def get_verify_status_package_path(): Get path to package for veryfing status order (/test/packages/vso) """ return os.path.join(os.path.dirname(__file__), "packages", "vso") + + +def get_weak_compilation_flags_package_path(): + """ + Get path to package for testing weak compilation flags (/test/packages/wcf) + """ + return os.path.join(os.path.dirname(__file__), "packages", "wcf")