├── tests ├── __init__.py ├── commands │ ├── __init__.py │ ├── chkwer │ │ ├── __init__.py │ │ └── test_integration.py │ ├── export │ │ ├── __init__.py │ │ ├── util.py │ │ └── test_unit.py │ ├── gen │ │ └── __init__.py │ ├── init │ │ ├── __init__.py │ │ ├── test_unit.py │ │ └── test_integration.py │ ├── inwer │ │ ├── __init__.py │ │ └── test_unit.py │ ├── run │ │ ├── __init__.py │ │ └── util.py │ ├── verify │ │ └── __init__.py │ └── doc │ │ └── test_unit.py ├── helpers │ ├── __init__.py │ ├── test_oicompare.py │ └── test_compile.py ├── packages │ ├── abc │ │ ├── doc │ │ │ └── .gitkeep │ │ ├── in │ │ │ └── .gitkeep │ │ ├── out │ │ │ └── .gitkeep │ │ ├── prog │ │ │ ├── abc.cpp │ │ │ ├── abc1.cpp │ │ │ ├── abc4.cpp │ │ │ ├── abcingen.cpp │ │ │ ├── abc2.cpp │ │ │ └── abc3.cpp │ │ └── config.yml │ ├── chk │ │ ├── in │ │ │ └── .gitkeep │ │ ├── out │ │ │ ├── .gitkeep │ │ │ ├── chk1a.out │ │ │ ├── chk1c.out │ │ │ ├── chk2a.out │ │ │ ├── chk2b.out │ │ │ ├── chk1b.out │ │ │ └── chk2c.out │ │ ├── prog │ │ │ ├── chk1.cpp │ │ │ ├── chk.cpp │ │ │ ├── chk2.cpp │ │ │ ├── chk3.cpp │ │ │ ├── chkingen.cpp │ │ │ └── chkchk.cpp │ │ └── config.yml │ ├── dlazaw │ │ ├── in │ │ │ └── .gitkeep │ │ ├── out │ │ │ └── .gitkeep │ │ ├── dlazaw │ │ │ └── epic_file │ │ ├── prog │ │ │ ├── dla.cpp │ │ │ └── dlaingen.cpp │ │ └── config.yml │ ├── doc │ │ ├── in │ │ │ └── .gitkeep │ │ ├── out │ │ │ └── .gitkeep │ │ ├── prog │ │ │ └── .gitkeep │ │ ├── config.yml │ │ └── doc │ │ │ ├── doczad.tex │ │ │ ├── test_image.png │ │ │ └── doctest.tex │ ├── gen │ │ ├── in │ │ │ └── .gitkeep │ │ ├── no-precompile │ │ ├── out │ │ │ └── .gitkeep │ │ ├── prog │ │ │ ├── tests │ │ │ ├── gen.cpp │ │ │ ├── geningen6.cpp │ │ │ ├── geningen7.cpp │ │ │ ├── geningen2.cpp │ │ │ ├── geningen3.cpp │ │ │ ├── gen_helper.cpp │ │ │ ├── geningen5.cpp │ │ │ └── geningen.sh │ │ └── config.yml │ ├── hwr │ │ ├── out │ │ │ ├── hwr0.out │ │ │ └── hwr0a.out │ │ ├── in │ │ │ ├── hwr0.in │ │ │ └── hwr0a.in │ │ ├── prog │ │ │ ├── hwr.cpp │ │ │ └── hwringen.cpp │ │ └── config.yml │ ├── icpc │ │ ├── in │ │ │ └── .gitkeep │ │ ├── out │ │ │ └── .gitkeep │ │ ├── prog │ │ │ ├── acm.cpp │ │ │ ├── acm1.cpp │ │ │ ├── abc4.cpp │ │ │ ├── acm2.cpp │ │ │ ├── acmingen.cpp │ │ │ └── acm3.cpp │ │ └── config.yml │ ├── lib │ │ ├── in │ │ │ └── .gitkeep │ │ ├── no-precompile │ │ ├── out │ │ │ └── .gitkeep │ │ ├── dlazaw │ │ │ └── testfile │ │ ├── prog │ │ │ ├── liblib.h │ │ │ ├── libingen.cpp │ │ │ ├── libs1.cpp │ │ │ ├── lib.py │ │ │ ├── libchk.cpp │ │ │ ├── lib.cpp │ │ │ ├── liblib.py │ │ │ └── liblib.cpp │ │ └── config.yml │ ├── lim │ │ ├── in │ │ │ └── .gitkeep │ │ ├── out │ │ │ └── .gitkeep │ │ ├── prog │ │ │ ├── lim.cpp │ │ │ ├── lim3.cpp │ │ │ ├── lim4.cpp │ │ │ ├── limingen.cpp │ │ │ └── lim2.cpp │ │ └── config.yml │ ├── lsa │ │ ├── in │ │ │ └── .gitkeep │ │ ├── no-precompile │ │ ├── out │ │ │ └── .gitkeep │ │ ├── prog │ │ │ ├── lsalib.h │ │ │ ├── lsaingen.cpp │ │ │ ├── lsas1.cpp │ │ │ ├── lsa.py │ │ │ ├── lsachk.cpp │ │ │ ├── lsa.cpp │ │ │ ├── lsalib.py │ │ │ └── lsalib.cpp │ │ └── config.yml │ ├── luadoc │ │ ├── in │ │ │ └── .gitkeep │ │ ├── out │ │ │ └── .gitkeep │ │ ├── doc │ │ │ └── doczad.tex │ │ └── config.yml │ ├── ovl │ │ ├── in │ │ │ └── .gitkeep │ │ ├── out │ │ │ └── .gitkeep │ │ ├── prog │ │ │ ├── ovlingen.cpp │ │ │ └── ovl.cpp │ │ └── config.yml │ ├── ps_doc │ │ ├── in │ │ │ └── .gitkeep │ │ ├── out │ │ │ └── .gitkeep │ │ ├── doc │ │ │ ├── doczad.tex │ │ │ └── doctest.tex │ │ └── config.yml │ ├── score │ │ ├── doc │ │ │ └── .gitkeep │ │ ├── in │ │ │ └── .gitkeep │ │ ├── out │ │ │ └── .gitkeep │ │ ├── prog │ │ │ ├── score.cpp │ │ │ └── scoreingen.cpp │ │ └── config.yml │ ├── stc │ │ ├── in │ │ │ └── .gitkeep │ │ ├── out │ │ │ └── .gitkeep │ │ ├── prog │ │ │ ├── stcingen.cpp │ │ │ └── stc.cpp │ │ └── config.yml │ ├── vso │ │ ├── doc │ │ │ └── .gitkeep │ │ ├── in │ │ │ └── .gitkeep │ │ ├── out │ │ │ └── .gitkeep │ │ ├── prog │ │ │ ├── vso.cpp │ │ │ ├── vsoingen.cpp │ │ │ ├── vso1.cpp │ │ │ ├── vso2.cpp │ │ │ ├── vso5.cpp │ │ │ ├── vso3.cpp │ │ │ ├── vso6.cpp │ │ │ ├── vso4.cpp │ │ │ └── vso7.cpp │ │ └── config.yml │ ├── wcf │ │ ├── in │ │ │ ├── .gitkeep │ │ │ └── wcf1a.in │ │ ├── no-precompile │ │ ├── out │ │ │ ├── .gitkeep │ │ │ └── wcf1a.out │ │ ├── prog │ │ │ └── wcf.cpp │ │ └── config.yml │ ├── wer │ │ ├── in │ │ │ └── .gitkeep │ │ ├── no-precompile │ │ ├── out │ │ │ └── .gitkeep │ │ ├── prog │ │ │ ├── werinwer5.cpp │ │ │ ├── werinwer6.cpp │ │ │ ├── wer.cpp │ │ │ ├── weringen.cpp │ │ │ ├── werinwer4.cpp │ │ │ ├── werinwer3.cpp │ │ │ ├── werinwer.cpp │ │ │ ├── werinwer2.cpp │ │ │ └── werinwer7.cpp │ │ └── config.yml │ ├── bad_tests │ │ ├── in │ │ │ └── .gitkeep │ │ ├── out │ │ │ └── .gitkeep │ │ ├── config.yml │ │ └── prog │ │ │ ├── bad4.cpp │ │ │ ├── bad.cpp │ │ │ ├── bad1.cpp │ │ │ ├── bad5.cpp │ │ │ ├── bad2.cpp │ │ │ ├── bad3.cpp │ │ │ └── badingen.cpp │ ├── stresstest │ │ ├── in │ │ │ └── .gitkeep │ │ ├── out │ │ │ └── .gitkeep │ │ ├── prog │ │ │ ├── strstresstest.sh │ │ │ ├── str.cpp │ │ │ └── stringen.cpp │ │ └── config.yml │ ├── example_tests │ │ ├── in │ │ │ └── .gitkeep │ │ ├── out │ │ │ └── .gitkeep │ │ ├── prog │ │ │ ├── exa.cpp │ │ │ └── exaingen.cpp │ │ └── config.yml │ ├── large_output │ │ ├── out │ │ │ └── .gitkeep │ │ ├── in │ │ │ └── lou0.in │ │ ├── prog │ │ │ ├── lou.cpp │ │ │ └── lou1.cpp │ │ └── config.yml │ ├── ocen │ │ ├── in │ │ │ ├── ocen0.in │ │ │ ├── ocen0a.in │ │ │ ├── ocen1a.in │ │ │ └── ocen1ocen.in │ │ ├── out │ │ │ └── ocen0.out │ │ ├── config.yml │ │ └── prog │ │ │ ├── ocen.cpp │ │ │ └── oceningen.cpp │ ├── oioioi_flags │ │ ├── in │ │ │ ├── .gitkeep │ │ │ └── oif1a.in │ │ ├── no-precompile │ │ ├── out │ │ │ ├── .gitkeep │ │ │ └── oif1a.out │ │ ├── prog │ │ │ └── oif.cpp │ │ └── config.yml │ ├── two_interactive │ │ ├── in │ │ │ └── .gitkeep │ │ ├── out │ │ │ └── .gitkeep │ │ ├── prog │ │ │ ├── twoingen.cpp │ │ │ ├── two.cpp │ │ │ ├── two1.cpp │ │ │ ├── two2.cpp │ │ │ └── twosoc.cpp │ │ └── config.yml │ ├── long_solution_names │ │ ├── in │ │ │ └── .gitkeep │ │ ├── out │ │ │ └── .gitkeep │ │ ├── prog │ │ │ ├── lsn.cpp │ │ │ ├── lsn1_long_name.cpp │ │ │ ├── lsn_long_name.cpp │ │ │ ├── lsningen.cpp │ │ │ ├── lsns1_long_name.cpp │ │ │ └── lsnb10_long_name.cpp │ │ └── config.yml │ ├── simple_interactive │ │ ├── in │ │ │ └── .gitkeep │ │ ├── out │ │ │ └── .gitkeep │ │ ├── prog │ │ │ ├── int3.cpp │ │ │ ├── intingen.cpp │ │ │ ├── int.cpp │ │ │ ├── int2.cpp │ │ │ └── intsoc.cpp │ │ └── config.yml │ ├── undocumented_options │ │ ├── in │ │ │ └── .gitkeep │ │ ├── out │ │ │ └── .gitkeep │ │ ├── prog │ │ │ ├── und.cpp │ │ │ ├── undingen.cpp │ │ │ └── und1.cpp │ │ └── config.yml │ └── long_package_name │ │ └── config.yml ├── contest_types │ ├── test_icpc.py │ ├── test_oi.py │ └── test_default.py ├── fixtures.py ├── test_multiple_arguments.py └── test_sio2jail.py ├── example_package ├── in │ └── .gitkeep ├── out │ └── .gitkeep ├── prog │ ├── __ID__s.cpp │ ├── __ID__.cpp │ ├── __ID__ingen.cpp │ ├── __ID__inwer.cpp │ └── __ID__ingen.sh ├── .gitignore └── config.yml ├── src └── sinol_make │ ├── helpers │ ├── __init__.py │ ├── func_cache.py │ ├── paths.py │ ├── parsers.py │ ├── classinit.py │ └── oicompare.py │ ├── interfaces │ ├── __init__.py │ ├── Errors.py │ └── BaseCommand.py │ ├── structs │ ├── __init__.py │ ├── gen_structs.py │ ├── run_structs.py │ ├── compiler_structs.py │ ├── inwer_structs.py │ ├── chkwer_structs.py │ ├── cache_structs.py │ └── status_structs.py │ ├── sio2jail │ └── perf_test.py │ ├── contest_types │ ├── __init__.py │ ├── oij.py │ ├── icpc.py │ └── oi.py │ ├── task_type │ └── normal.py │ ├── commands │ ├── outgen │ │ └── outgen_util.py │ ├── gen │ │ └── __init__.py │ ├── chkwer │ │ └── chkwer_util.py │ └── ingen │ │ ├── ingen_util.py │ │ └── __init__.py │ └── executors │ ├── __init__.py │ ├── detailed.py │ └── sio2jail.py ├── pyproject.toml ├── tox.ini ├── .gitignore ├── .github ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md └── workflows │ ├── GithubRunner.yaml │ ├── release.yaml │ ├── Arch.yaml │ ├── Ubuntu.yaml │ └── macOS.yaml └── setup.cfg /tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example_package/in/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example_package/out/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/commands/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/helpers/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/commands/chkwer/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/commands/export/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/commands/gen/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/commands/init/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/commands/inwer/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/commands/run/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/commands/verify/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/abc/doc/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/abc/in/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/abc/out/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/chk/in/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/chk/out/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/dlazaw/in/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/doc/in/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/doc/out/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/doc/prog/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/gen/in/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/gen/no-precompile: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/gen/out/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/hwr/out/hwr0.out: -------------------------------------------------------------------------------- 1 | 3 -------------------------------------------------------------------------------- /tests/packages/hwr/out/hwr0a.out: -------------------------------------------------------------------------------- 1 | 9 -------------------------------------------------------------------------------- /tests/packages/icpc/in/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/icpc/out/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/lib/in/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/lib/no-precompile: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/lib/out/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/lim/in/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/lim/out/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/lsa/in/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/lsa/no-precompile: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/lsa/out/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/luadoc/in/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/ovl/in/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/ovl/out/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/ps_doc/in/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/score/doc/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/score/in/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/score/out/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/stc/in/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/stc/out/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/vso/doc/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/vso/in/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/vso/out/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/wcf/in/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/wcf/no-precompile: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/wcf/out/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/wer/in/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/wer/no-precompile: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/wer/out/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/sinol_make/helpers/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/sinol_make/interfaces/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/sinol_make/structs/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/bad_tests/in/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/bad_tests/out/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/chk/out/chk1a.out: -------------------------------------------------------------------------------- 1 | 6 2 | -------------------------------------------------------------------------------- /tests/packages/chk/out/chk1c.out: -------------------------------------------------------------------------------- 1 | 6 2 | -------------------------------------------------------------------------------- /tests/packages/chk/out/chk2a.out: -------------------------------------------------------------------------------- 1 | 5 2 | -------------------------------------------------------------------------------- /tests/packages/chk/out/chk2b.out: -------------------------------------------------------------------------------- 1 | 2 2 | -------------------------------------------------------------------------------- /tests/packages/dlazaw/out/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/hwr/in/hwr0.in: -------------------------------------------------------------------------------- 1 | 1 2 2 | -------------------------------------------------------------------------------- /tests/packages/hwr/in/hwr0a.in: -------------------------------------------------------------------------------- 1 | 3 6 2 | -------------------------------------------------------------------------------- /tests/packages/luadoc/out/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/ps_doc/out/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/stresstest/in/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/stresstest/out/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/wcf/in/wcf1a.in: -------------------------------------------------------------------------------- 1 | 1 1 2 | -------------------------------------------------------------------------------- /tests/packages/wcf/out/wcf1a.out: -------------------------------------------------------------------------------- 1 | 2 2 | -------------------------------------------------------------------------------- /tests/packages/chk/out/chk1b.out: -------------------------------------------------------------------------------- 1 | -1 2 | -------------------------------------------------------------------------------- /tests/packages/chk/out/chk2c.out: -------------------------------------------------------------------------------- 1 | -1 2 | -------------------------------------------------------------------------------- /tests/packages/example_tests/in/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/example_tests/out/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/large_output/out/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/ocen/in/ocen0.in: -------------------------------------------------------------------------------- 1 | 2 3 2 | -------------------------------------------------------------------------------- /tests/packages/ocen/in/ocen0a.in: -------------------------------------------------------------------------------- 1 | 3 4 2 | -------------------------------------------------------------------------------- /tests/packages/ocen/in/ocen1a.in: -------------------------------------------------------------------------------- 1 | 1 2 2 | -------------------------------------------------------------------------------- /tests/packages/ocen/in/ocen1ocen.in: -------------------------------------------------------------------------------- 1 | 3 5 2 | -------------------------------------------------------------------------------- /tests/packages/ocen/out/ocen0.out: -------------------------------------------------------------------------------- 1 | 5 2 | -------------------------------------------------------------------------------- /tests/packages/oioioi_flags/in/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/oioioi_flags/no-precompile: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/oioioi_flags/out/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/two_interactive/in/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/two_interactive/out/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/large_output/in/lou0.in: -------------------------------------------------------------------------------- 1 | 1 2 | -------------------------------------------------------------------------------- /tests/packages/long_solution_names/in/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/long_solution_names/out/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/oioioi_flags/in/oif1a.in: -------------------------------------------------------------------------------- 1 | 1 1 2 | -------------------------------------------------------------------------------- /tests/packages/oioioi_flags/out/oif1a.out: -------------------------------------------------------------------------------- 1 | 2 2 | -------------------------------------------------------------------------------- /tests/packages/simple_interactive/in/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/simple_interactive/out/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/undocumented_options/in/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/undocumented_options/out/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/packages/lib/dlazaw/testfile: -------------------------------------------------------------------------------- 1 | TeSt StRiNg 2 | -------------------------------------------------------------------------------- /tests/packages/dlazaw/dlazaw/epic_file: -------------------------------------------------------------------------------- 1 | this is a file 2 | -------------------------------------------------------------------------------- /tests/packages/gen/prog/tests: -------------------------------------------------------------------------------- 1 | gen1a.in gen1b.in gen1c.in 2 | -------------------------------------------------------------------------------- /src/sinol_make/sio2jail/perf_test.py: -------------------------------------------------------------------------------- 1 | print("Test Successful!") 2 | -------------------------------------------------------------------------------- /tests/packages/simple_interactive/prog/int3.cpp: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 0; 3 | } 4 | -------------------------------------------------------------------------------- /tests/packages/bad_tests/config.yml: -------------------------------------------------------------------------------- 1 | title: Package with bad tests 2 | sinol_task_id: bad 3 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools>=67.0"] 3 | build-backend = "setuptools.build_meta" 4 | -------------------------------------------------------------------------------- /tests/packages/gen/config.yml: -------------------------------------------------------------------------------- 1 | title: Package with shell ingen 2 | memory_limit: 16000 3 | time_limit: 1000 4 | -------------------------------------------------------------------------------- /tests/packages/stresstest/prog/strstresstest.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo Very hard stress test 4 | exit 0 5 | -------------------------------------------------------------------------------- /tests/packages/doc/config.yml: -------------------------------------------------------------------------------- 1 | title: Package for testing `doc` command 2 | time_limit: 1000 3 | memory_limit: 1024 4 | -------------------------------------------------------------------------------- /tests/packages/doc/doc/doczad.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | \begin{document} 3 | Hello World! 4 | \end{document} 5 | -------------------------------------------------------------------------------- /tests/packages/luadoc/doc/doczad.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | \begin{document} 3 | Hello World! 4 | \end{document} 5 | -------------------------------------------------------------------------------- /tests/packages/ps_doc/doc/doczad.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | \begin{document} 3 | Hello World! 4 | \end{document} 5 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py37,py312 3 | 4 | [testenv] 5 | extras = tests 6 | commands = pytest --cov=./ {posargs} 7 | -------------------------------------------------------------------------------- /tests/packages/doc/doc/test_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sio2project/sinol-make/HEAD/tests/packages/doc/doc/test_image.png -------------------------------------------------------------------------------- /tests/packages/lib/prog/liblib.h: -------------------------------------------------------------------------------- 1 | #ifndef _liblib_h 2 | #define _liblib_h 3 | 4 | void init(); 5 | int guess(int a); 6 | void quit(); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /tests/packages/long_package_name/config.yml: -------------------------------------------------------------------------------- 1 | title: Package with long name for testing `package_util.get_task_id()` function 2 | sinol_task_id: lpn 3 | -------------------------------------------------------------------------------- /tests/packages/lsa/prog/lsalib.h: -------------------------------------------------------------------------------- 1 | #ifndef _lsalib_h 2 | #define _lsalib_h 3 | 4 | void init(); 5 | int guess(int a); 6 | void quit(); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /tests/packages/doc/doc/doctest.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | \usepackage{graphicx} 3 | \begin{document} 4 | \includegraphics{test_image.png} 5 | \end{document} 6 | -------------------------------------------------------------------------------- /tests/packages/ps_doc/doc/doctest.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | \usepackage{graphicx} 3 | \begin{document} 4 | \includegraphics{test_image.ps} 5 | \end{document} 6 | -------------------------------------------------------------------------------- /tests/packages/ps_doc/config.yml: -------------------------------------------------------------------------------- 1 | title: Package for testing `doc` command (version with ps images) 2 | time_limit: 1000 3 | memory_limit: 1024 4 | sinol_task_id: doc2 5 | -------------------------------------------------------------------------------- /tests/packages/bad_tests/prog/bad4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | int main() { 4 | int a, b; 5 | cin >> a >> b; 6 | cout << a + b; 7 | } 8 | -------------------------------------------------------------------------------- /tests/packages/luadoc/config.yml: -------------------------------------------------------------------------------- 1 | title: Package for testing `doc` command 2 | time_limit: 1000 3 | memory_limit: 1024 4 | sinol_task_id: luadoc 5 | sinol_latex_compiler: lualatex 6 | -------------------------------------------------------------------------------- /tests/packages/ocen/config.yml: -------------------------------------------------------------------------------- 1 | title: Package for testing ocen archive creation 2 | sinol_task_id: ocen 3 | sinol_contest_type: oi 4 | time_limit: 1000 5 | memory_limit: 10240 6 | -------------------------------------------------------------------------------- /tests/packages/bad_tests/prog/bad.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | int main() { 4 | int a, b; 5 | cin >> a >> b; 6 | cout << a + b << endl; 7 | } 8 | -------------------------------------------------------------------------------- /tests/packages/bad_tests/prog/bad1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | int main() { 4 | int a, b; 5 | cin >> a >> b; 6 | cout << a + b << " \n"; 7 | } 8 | -------------------------------------------------------------------------------- /tests/packages/icpc/prog/acm.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | int a, b; 7 | cin >> a >> b; 8 | cout << a + b; 9 | } 10 | -------------------------------------------------------------------------------- /tests/packages/ocen/prog/ocen.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | int a, b; 7 | cin >> a >> b; 8 | cout << a + b; 9 | } 10 | -------------------------------------------------------------------------------- /tests/packages/bad_tests/prog/bad5.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | int main() { 4 | int a, b; 5 | cin >> a >> b; 6 | cout << a + b << "\n\n\n"; 7 | } 8 | -------------------------------------------------------------------------------- /tests/packages/hwr/prog/hwr.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | int a, b; 7 | cin >> a >> b; 8 | cout << a + b; 9 | } 10 | -------------------------------------------------------------------------------- /tests/packages/lim/prog/lim.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | int a, b; 7 | cin >> a >> b; 8 | cout << a + b; 9 | } 10 | -------------------------------------------------------------------------------- /tests/packages/vso/prog/vso.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | int a, b; 7 | cin >> a >> b; 8 | cout << a + b; 9 | } 10 | -------------------------------------------------------------------------------- /tests/packages/bad_tests/prog/bad2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | int main() { 4 | int a, b; 5 | cin >> a >> b; 6 | cout << " " << a + b << endl; 7 | } 8 | -------------------------------------------------------------------------------- /tests/packages/dlazaw/prog/dla.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | int a, b; 7 | cin >> a >> b; 8 | cout << a + b << "\n"; 9 | } 10 | -------------------------------------------------------------------------------- /tests/packages/stresstest/prog/str.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | int a, b; 7 | cin >> a >> b; 8 | cout << a + b << "\n"; 9 | } 10 | -------------------------------------------------------------------------------- /tests/packages/abc/prog/abc.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | int a, b; 7 | cin >> a >> b; 8 | cout << a + b << "\n"; 9 | } 10 | -------------------------------------------------------------------------------- /tests/packages/dlazaw/prog/dlaingen.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | ofstream f("dla1a.in"); 7 | f << "1 1\n"; 8 | f.close(); 9 | } 10 | -------------------------------------------------------------------------------- /tests/packages/gen/prog/gen.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | int a, b; 7 | cin >> a >> b; 8 | cout << a + b << "\n"; 9 | } 10 | -------------------------------------------------------------------------------- /tests/packages/long_solution_names/prog/lsn.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | int a, b; 7 | cin >> a >> b; 8 | cout << a + b; 9 | } 10 | -------------------------------------------------------------------------------- /tests/packages/bad_tests/prog/bad3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | int main() { 4 | int a, b; 5 | cin >> a >> b; 6 | cout << a + b << " " << a + b << endl; 7 | } 8 | -------------------------------------------------------------------------------- /tests/packages/gen/prog/geningen6.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | ofstream f("gen2.in"); 7 | f << "2 3\n"; 8 | f.close(); 9 | } 10 | -------------------------------------------------------------------------------- /tests/packages/gen/prog/geningen7.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | ofstream f("gen3.in"); 7 | f << "2 3\n"; 8 | f.close(); 9 | } 10 | -------------------------------------------------------------------------------- /tests/packages/score/prog/score.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | int a, b; 7 | cin >> a >> b; 8 | cout << a + b << "\n"; 9 | } 10 | -------------------------------------------------------------------------------- /tests/packages/stc/prog/stcingen.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | ofstream f("stc1a.in"); 7 | f << "1 2\n"; 8 | f.close(); 9 | } 10 | -------------------------------------------------------------------------------- /tests/packages/dlazaw/config.yml: -------------------------------------------------------------------------------- 1 | title: Package with no ocen files and dlazaw dir 2 | sinol_task_id: dla 3 | sinol_contest_type: oi 4 | time_limit: 1000 5 | memory_limit: 10240 6 | 7 | scores: 8 | 1: 100 9 | -------------------------------------------------------------------------------- /tests/packages/example_tests/prog/exa.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | int a, b; 7 | cin >> a >> b; 8 | cout << a + b << endl; 9 | } 10 | -------------------------------------------------------------------------------- /tests/packages/undocumented_options/prog/und.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | int a, b; 7 | cin >> a >> b; 8 | cout << a + b; 9 | } 10 | -------------------------------------------------------------------------------- /tests/packages/icpc/prog/acm1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | int a, b; 7 | cin >> a >> b; 8 | if (a == 4) 9 | cout << a + b + 1; 10 | else 11 | cout << a + b; 12 | } 13 | -------------------------------------------------------------------------------- /tests/packages/wcf/prog/wcf.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | int a, b; 7 | int c; // Unused variable 8 | 9 | cin >> a >> b; 10 | cout << a + b << endl; 11 | } 12 | -------------------------------------------------------------------------------- /tests/packages/abc/prog/abc1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | int a, b; 7 | cin >> a >> b; 8 | if (a == 4) 9 | cout << a + b + 1; 10 | else 11 | cout << a + b; 12 | } 13 | -------------------------------------------------------------------------------- /tests/packages/stc/config.yml: -------------------------------------------------------------------------------- 1 | title: Package for testing if changing stack size works 2 | memory_limit: 1000 3 | time_limit: 10000 4 | sinol_expected_scores: 5 | stc.cpp: 6 | expected: 7 | 1: {points: 100, status: OK} 8 | points: 100 9 | -------------------------------------------------------------------------------- /tests/packages/gen/prog/geningen2.cpp: -------------------------------------------------------------------------------- 1 | // Fails with -fsanitize=address 2 | #include 3 | 4 | using namespace std; 5 | 6 | int main() { 7 | int *a = (int*)malloc(1024); 8 | a[0] = 0; 9 | cout << a[0] << endl; 10 | } 11 | -------------------------------------------------------------------------------- /tests/packages/wer/prog/werinwer5.cpp: -------------------------------------------------------------------------------- 1 | // Fails with -fsanitize=address 2 | #include 3 | 4 | using namespace std; 5 | 6 | int main() { 7 | int *a = (int*)malloc(1024); 8 | a[0] = 0; 9 | cout << a[0] << endl; 10 | } 11 | -------------------------------------------------------------------------------- /tests/packages/lib/prog/libingen.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | ofstream t("lib1a.in"); 7 | t << "50 7\n"; 8 | t.close(); 9 | 10 | t.open("lib2a.in"); 11 | t << "1 7\n"; 12 | } 13 | -------------------------------------------------------------------------------- /tests/packages/long_solution_names/prog/lsn1_long_name.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | int a, b; 7 | cin >> a >> b; 8 | if (a == 4) 9 | cout << a + b + 1; 10 | else 11 | cout << a + b; 12 | } 13 | -------------------------------------------------------------------------------- /tests/packages/lsa/prog/lsaingen.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | ofstream t("lsa1a.in"); 7 | t << "50 7\n"; 8 | t.close(); 9 | 10 | t.open("lsa2a.in"); 11 | t << "1 7\n"; 12 | } 13 | -------------------------------------------------------------------------------- /tests/packages/stresstest/prog/stringen.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | ofstream f("str1a.in"); 7 | f << "1 3\n"; 8 | f.close(); 9 | f.open("str2a.in"); 10 | f << "2 5\n"; 11 | f.close(); 12 | } 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .venv 2 | .venv3.12 3 | dist 4 | *.egg-info 5 | build 6 | .vscode 7 | .idea 8 | __pycache__ 9 | /tests/packages/**/cache 10 | /tests/packages/**/.cache 11 | src/sinol_make/data 12 | 13 | # pytest-cov 14 | .coverage* 15 | coverage.xml 16 | 17 | /.tox/ 18 | -------------------------------------------------------------------------------- /example_package/prog/__ID__s.cpp: -------------------------------------------------------------------------------- 1 | // This is a "brute force" solution for testing model solution. 2 | 3 | #include 4 | 5 | using namespace std; 6 | 7 | int main() { 8 | int a, b; 9 | cin >> a >> b; 10 | cout << a + b << endl; 11 | } 12 | -------------------------------------------------------------------------------- /tests/packages/example_tests/config.yml: -------------------------------------------------------------------------------- 1 | title: Package with example tests 2 | sinol_task_id: exa 3 | memory_limit: 50240 4 | time_limit: 1000 5 | 6 | sinol_expected_scores: 7 | exa.cpp: 8 | expected: 9 | 0: {points: 0, status: OK} 10 | points: 0 11 | -------------------------------------------------------------------------------- /tests/packages/oioioi_flags/prog/oif.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | long long a, b; 7 | cin >> a >> b; 8 | int c = a + b; // conversion from ‘long long int’ to ‘int’ 9 | cout << c << endl; 10 | } 11 | -------------------------------------------------------------------------------- /tests/packages/wcf/config.yml: -------------------------------------------------------------------------------- 1 | title: Package for testing --compile-mode weak 2 | memory_limit: 16000 3 | time_limit: 1000 4 | scores: 5 | 1: 100 6 | sinol_expected_scores: 7 | wcf.cpp: 8 | expected: 9 | 1: {points: 100, status: OK} 10 | points: 100 11 | -------------------------------------------------------------------------------- /tests/packages/gen/prog/geningen3.cpp: -------------------------------------------------------------------------------- 1 | // Fails with -fsanitize=undefined 2 | #include 3 | 4 | using namespace std; 5 | 6 | int main(int argc, char** argv) { 7 | int k = 0x7fffffff; 8 | k += argc; 9 | cout << k << " " << argv[0] << endl; 10 | } 11 | -------------------------------------------------------------------------------- /tests/packages/large_output/prog/lou.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | int bytes_to_write = (1 << 16) + 1; 7 | for (int i = 0; i < bytes_to_write; i++) { 8 | cout << "x"; 9 | } 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /tests/packages/large_output/prog/lou1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | int bytes_to_write = (1 << 20); 7 | for (int i = 0; i < bytes_to_write; i++) { 8 | cout << "x"; 9 | } 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /tests/packages/wer/prog/werinwer6.cpp: -------------------------------------------------------------------------------- 1 | // Fails with -fsanitize=undefined 2 | #include 3 | 4 | using namespace std; 5 | 6 | int main(int argc, char** argv) { 7 | int k = 0x7fffffff; 8 | k += argc; 9 | cout << k << " " << argv[0] << endl; 10 | } 11 | -------------------------------------------------------------------------------- /tests/packages/two_interactive/prog/twoingen.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | ofstream f("two1.in"); 7 | f << "10\n"; 8 | f.close(); 9 | 10 | f.open("two2.in"); 11 | f << "20\n"; 12 | f.close(); 13 | } 14 | -------------------------------------------------------------------------------- /example_package/prog/__ID__.cpp: -------------------------------------------------------------------------------- 1 | // This is the main model solution. 2 | // It is used for generating output files. 3 | 4 | #include 5 | 6 | using namespace std; 7 | 8 | int main() { 9 | int a, b; 10 | cin >> a >> b; 11 | cout << a + b << endl; 12 | } 13 | -------------------------------------------------------------------------------- /tests/packages/simple_interactive/prog/intingen.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | ofstream f("int1.in"); 7 | f << "1\n"; 8 | f.close(); 9 | 10 | f.open("int2.in"); 11 | f << "42\n"; 12 | f.close(); 13 | } 14 | -------------------------------------------------------------------------------- /tests/packages/undocumented_options/prog/undingen.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | ofstream f("und1a.in"); 7 | f << "1 1\n"; 8 | f.close(); 9 | 10 | f.open("und1b.in"); 11 | f << "2 2\n"; 12 | f.close(); 13 | } 14 | -------------------------------------------------------------------------------- /tests/packages/ovl/prog/ovlingen.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | ofstream f; 7 | 8 | f.open("ovl1a.in"); 9 | f << "21 4\n"; 10 | f.close(); 11 | 12 | f.open("ovl2a.in"); 13 | f << "3 6\n"; 14 | f.close(); 15 | } 16 | -------------------------------------------------------------------------------- /tests/packages/hwr/prog/hwringen.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | ofstream f; 7 | 8 | f.open("hwr1a.in"); 9 | f << "20 2\n"; 10 | f.close(); 11 | 12 | f.open("hwr2a.in"); 13 | f << "53 6\n"; 14 | f.close(); 15 | } 16 | -------------------------------------------------------------------------------- /tests/packages/oioioi_flags/config.yml: -------------------------------------------------------------------------------- 1 | title: Package for testing --compile-mode oioioi flag 2 | memory_limit: 16000 3 | time_limit: 1000 4 | sinol_task_id: oif 5 | scores: 6 | 1: 100 7 | sinol_expected_scores: 8 | oif.cpp: 9 | expected: 10 | 1: {points: 100, status: OK} 11 | points: 100 12 | -------------------------------------------------------------------------------- /tests/packages/chk/prog/chk1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | int n, s = 0; 7 | cin >> n; 8 | 9 | for (int i = 0; i < n; i++) { 10 | int a; 11 | cin >> a; 12 | s += a; 13 | } 14 | 15 | cout << s + 1 << endl; 16 | } 17 | -------------------------------------------------------------------------------- /tests/packages/wer/prog/wer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | int n, s = 0; 7 | cin >> n; 8 | for (int i = 1; i <= n; i++) { 9 | int a; 10 | cin >> a; 11 | s += a; 12 | } 13 | s *= n; 14 | cout << s << "\n"; 15 | } 16 | -------------------------------------------------------------------------------- /tests/packages/lib/prog/libs1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "liblib.h" 3 | 4 | using namespace std; 5 | 6 | int main() { 7 | init(); 8 | for (int i = 1; i <= 100; i++) { 9 | if (guess(i) == 0) { 10 | break; 11 | } 12 | } 13 | quit(); 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /tests/packages/lsa/prog/lsas1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "lsalib.h" 3 | 4 | using namespace std; 5 | 6 | int main() { 7 | init(); 8 | for (int i = 1; i <= 100; i++) { 9 | if (guess(i) == 0) { 10 | break; 11 | } 12 | } 13 | quit(); 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /tests/packages/gen/prog/gen_helper.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main(int argc, char const *argv[]) { 6 | if (argc != 2) { 7 | return 1; 8 | } 9 | 10 | int c = argv[1][4] - 'a'; 11 | int g = argv[1][3] - '0'; 12 | cout << c << " " << g << endl; 13 | } 14 | -------------------------------------------------------------------------------- /tests/packages/stresstest/config.yml: -------------------------------------------------------------------------------- 1 | title: Package with stresstest.sh (for `verify` command) 2 | sinol_task_id: str 3 | time_limit: 1000 4 | memory_limit: 50240 5 | 6 | sinol_expected_scores: 7 | str.cpp: 8 | expected: 9 | 1: {points: 50, status: OK} 10 | 2: {points: 50, status: OK} 11 | points: 100 12 | -------------------------------------------------------------------------------- /tests/packages/ocen/prog/oceningen.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | ofstream f("ocen0b.in"); 7 | f << "0 0\n"; 8 | f.close(); 9 | f.open("ocen2ocen.in"); 10 | f << "1 2\n"; 11 | f.close(); 12 | f.open("ocen2a.in"); 13 | f << "1 1\n"; 14 | f.close(); 15 | } 16 | -------------------------------------------------------------------------------- /tests/packages/vso/prog/vsoingen.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | for (char c = 'a'; c <= 'e'; c++) { 7 | string letter(1, c); 8 | ofstream f("vso1" + letter + ".in"); 9 | f << "1 " << (c - 'a' + 1) << endl; 10 | f.close(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tests/packages/icpc/prog/abc4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | int a, b; 7 | cin >> a >> b; 8 | if (a == 1 || a == 2) 9 | cout << a + b; 10 | else if (a == 3) 11 | cout << a + b + 2; 12 | else if (a == 4) { 13 | int c = 0; 14 | cout << a + b / c; 15 | return 1; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/packages/large_output/config.yml: -------------------------------------------------------------------------------- 1 | title: Package with large outputs 2 | sinol_task_id: lou 3 | memory_limit: 16000 4 | time_limit: 2000 5 | sinol_expected_scores: 6 | lou.cpp: 7 | expected: 8 | 0: {points: 0, status: OK} 9 | points: 0 10 | lou1.cpp: 11 | expected: 12 | 0: {points: 0, status: WA} 13 | points: 0 14 | -------------------------------------------------------------------------------- /tests/packages/simple_interactive/prog/int.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | int main(int argc, char *argv[]) { 7 | assert(argc == 2); 8 | int proc_num = atoi(argv[1]); 9 | assert(proc_num == 0); 10 | 11 | int a; 12 | cin >> a; 13 | cout << a + 42 << endl; 14 | } 15 | -------------------------------------------------------------------------------- /tests/packages/lim/prog/lim3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | int a, b; 7 | cin >> a >> b; 8 | 9 | vector mem; 10 | if (a == 1) { 11 | for (int i = 1; i <= 1280000; i++) { 12 | mem.push_back(i); 13 | } 14 | } 15 | cout << a + b; 16 | } 17 | -------------------------------------------------------------------------------- /tests/packages/abc/prog/abc4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | int a, b; 7 | cin >> a >> b; 8 | if (a == 1 || a == 2) 9 | cout << a + b; 10 | else if (a == 3) 11 | cout << a + b + 2; 12 | else if (a == 4) { 13 | int c = 0; 14 | cout << a + b / c; 15 | return 1; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/packages/example_tests/prog/exaingen.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | ofstream f("exa0.in"); 7 | f << "1 1\n"; 8 | f.close(); 9 | 10 | f.open("exa0a.in"); 11 | f << "1 2\n"; 12 | f.close(); 13 | 14 | f.open("exa0b.in"); 15 | f << "1 3\n"; 16 | f.close(); 17 | } 18 | -------------------------------------------------------------------------------- /tests/packages/undocumented_options/prog/und1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | using namespace std::chrono_literals; 6 | 7 | int main() { 8 | int a, b; 9 | cin >> a >> b; 10 | if (a == 1 && b == 1) { 11 | this_thread::sleep_for(3s); 12 | } 13 | cout << a + b << endl; 14 | } 15 | -------------------------------------------------------------------------------- /tests/packages/gen/prog/geningen5.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | #ifdef _INGEN 7 | ofstream f("gen1.in"); 8 | f << "1 2\n"; 9 | f.close(); 10 | 11 | f.open("gen2.in"); 12 | f << "2 3\n"; 13 | f.close(); 14 | #else 15 | This should not compile 16 | #endif 17 | } 18 | -------------------------------------------------------------------------------- /tests/packages/ovl/config.yml: -------------------------------------------------------------------------------- 1 | title: Package with `override_limits` set 2 | memory_limit: 8192 3 | time_limit: 100 4 | override_limits: 5 | cpp: 6 | memory_limit: 16384 7 | time_limit: 10000 8 | sinol_expected_scores: 9 | ovl.cpp: 10 | expected: 11 | 1: {points: 50, status: OK} 12 | 2: {points: 50, status: OK} 13 | points: 100 14 | -------------------------------------------------------------------------------- /tests/packages/long_solution_names/prog/lsn_long_name.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | int a, b; 7 | cin >> a >> b; 8 | if (a == 1 || a == 2) 9 | cout << a + b; 10 | else if (a == 3) 11 | cout << a + b + 2; 12 | else if (a == 4) { 13 | int c = 0; 14 | cout << a + b / c; 15 | return 1; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/packages/hwr/config.yml: -------------------------------------------------------------------------------- 1 | title: Package with handwritten tests for testing `export` command 2 | memory_limit: 32000 3 | time_limit: 1 4 | scores: 5 | 1: 50 6 | 2: 50 7 | sinol_expected_scores: 8 | hwr.cpp: 9 | expected: 10 | 0: {points: 0, status: OK} 11 | 1: {points: 50, status: OK} 12 | 2: {points: 50, status: OK} 13 | points: 100 14 | -------------------------------------------------------------------------------- /tests/packages/vso/prog/vso1.cpp: -------------------------------------------------------------------------------- 1 | // First test WA, 2 | // other OK. 3 | // Group should have status WA. 4 | 5 | #include 6 | 7 | using namespace std; 8 | 9 | int main() { 10 | int a, b; 11 | cin >> a >> b; 12 | if (a == 1 && b == 1) { 13 | cout << 0; 14 | } 15 | else { 16 | cout << a + b; 17 | } 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /tests/packages/wer/prog/weringen.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | ofstream f; 7 | f.open("wer1a.in"); 8 | f << "2\n0 1\n"; 9 | f.close(); 10 | 11 | f.open("wer2a.in"); 12 | f << "3\n2 1 1\n"; 13 | f.close(); 14 | 15 | f.open("wer3a.in"); 16 | f << "4\n1 1 3 2\n"; 17 | f.close(); 18 | } 19 | -------------------------------------------------------------------------------- /tests/packages/lim/prog/lim4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | int a, b; 7 | cin >> a >> b; 8 | 9 | vector mem; 10 | int times = 2; 11 | if (a == 2) 12 | times = 1; 13 | 14 | for (int i = 1; i <= times * 1280000; i++) { 15 | mem.push_back(i); 16 | } 17 | cout << a + b; 18 | } 19 | -------------------------------------------------------------------------------- /tests/packages/long_solution_names/prog/lsningen.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | ofstream f("lsn1a.in"); 7 | f << "1 3\n"; 8 | f.close(); 9 | f.open("lsn2a.in"); 10 | f << "2 5\n"; 11 | f.close(); 12 | f.open("lsn3a.in"); 13 | f << "3 7\n"; 14 | f.close(); 15 | f.open("lsn4a.in"); 16 | f << "4 9\n"; 17 | f.close(); 18 | } 19 | -------------------------------------------------------------------------------- /tests/packages/chk/prog/chk.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | int n, s = 0; 7 | 8 | cin >> n; 9 | for (int i = 0; i < n; i++) { 10 | int a; 11 | cin >> a; 12 | s += a; 13 | } 14 | 15 | if (s % n != 0) 16 | cout << -1 << endl; 17 | else 18 | cout << s / 2 - 1 << endl; 19 | } 20 | -------------------------------------------------------------------------------- /tests/packages/lib/prog/lib.py: -------------------------------------------------------------------------------- 1 | from liblib import * 2 | 3 | 4 | def main(): 5 | a, b = 0, 100 6 | 7 | while a <= b: 8 | mid = (a + b) // 2 9 | g = guess(mid) 10 | if g == 0: 11 | quit() 12 | elif g == 1: 13 | b = mid + 1 14 | else: 15 | a = mid - 1 16 | guess(a) 17 | quit() 18 | 19 | 20 | main() 21 | -------------------------------------------------------------------------------- /tests/packages/lsa/prog/lsa.py: -------------------------------------------------------------------------------- 1 | from lsalib import * 2 | 3 | 4 | def main(): 5 | a, b = 0, 100 6 | 7 | while a <= b: 8 | mid = (a + b) // 2 9 | g = guess(mid) 10 | if g == 0: 11 | quit() 12 | elif g == 1: 13 | b = mid + 1 14 | else: 15 | a = mid - 1 16 | guess(a) 17 | quit() 18 | 19 | 20 | main() 21 | -------------------------------------------------------------------------------- /tests/packages/wer/prog/werinwer4.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | int n, a; 7 | cin >> n; 8 | for (int i = 0; i < n; i++) { 9 | cin >> a; 10 | 11 | if (a >= n) { 12 | cout << "ERROR: " << a << " >= " << n << "\n"; 13 | return 1; 14 | } 15 | } 16 | 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /tests/packages/lib/prog/libchk.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main(int argc, char const *argv[]) { 6 | assert(argc == 4); 7 | 8 | ifstream out(argv[2]); 9 | 10 | string s1, s2; 11 | out >> s1 >> s2; 12 | if (s2 == "") { 13 | cout << "WRONG\n"; 14 | return 0; 15 | } 16 | cout << s2; 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /tests/packages/lsa/prog/lsachk.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main(int argc, char const *argv[]) { 6 | assert(argc == 4); 7 | 8 | ifstream out(argv[2]); 9 | 10 | string s1, s2; 11 | out >> s1 >> s2; 12 | if (s2 == "") { 13 | cout << "WRONG\n"; 14 | return 0; 15 | } 16 | cout << s2; 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /tests/packages/chk/prog/chk2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | int n, s = 0; 7 | 8 | cin >> n; 9 | for (int i = 0; i < n; i++) { 10 | int a; 11 | cin >> a; 12 | s += a; 13 | } 14 | 15 | if (s % n != 0) { 16 | cout << "-1"; 17 | return 0; 18 | } 19 | 20 | cout << s / 2 + 1; 21 | } 22 | -------------------------------------------------------------------------------- /tests/packages/wer/config.yml: -------------------------------------------------------------------------------- 1 | title: Test package for veryfing inwer command 2 | memory_limit: 16000 3 | time_limit: 1000 4 | sinol_contest_type: oi 5 | 6 | scores: 7 | 1: 33 8 | 2: 33 9 | 3: 34 10 | 11 | sinol_expected_scores: 12 | wer.cpp: 13 | expected: 14 | 1: {points: 33, status: OK} 15 | 2: {points: 33, status: OK} 16 | 3: {points: 34, status: OK} 17 | points: 100 18 | -------------------------------------------------------------------------------- /src/sinol_make/structs/gen_structs.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | 3 | 4 | @dataclass 5 | class OutputGenerationArguments: 6 | """ 7 | Arguments used for function that generates output file. 8 | """ 9 | # Path to correct solution executable 10 | correct_solution_exe: str 11 | # Path to input file 12 | input_test: str 13 | # Path to output file 14 | output_test: str 15 | -------------------------------------------------------------------------------- /tests/packages/abc/prog/abcingen.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "oi.h" 3 | 4 | using namespace std; 5 | 6 | int main() { 7 | ofstream f("abc1a.in"); 8 | f << "1 3\n"; 9 | f.close(); 10 | f.open("abc2a.in"); 11 | f << "2 5\n"; 12 | f.close(); 13 | f.open("abc3a.in"); 14 | f << "3 7\n"; 15 | f.close(); 16 | f.open("abc4a.in"); 17 | f << "4 9\n"; 18 | f.close(); 19 | } 20 | -------------------------------------------------------------------------------- /tests/packages/icpc/prog/acm2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | int a, b; 7 | cin >> a >> b; 8 | if (a == 1) 9 | cout << a + b; 10 | else if (a == 2 || a == 3) 11 | cout << a + b - 1; 12 | else if (a == 4) { 13 | time_t start = time(0); 14 | int i = 0; 15 | while (time(0) - start < 5) { 16 | i++; 17 | } 18 | cout << a + b; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tests/packages/score/prog/scoreingen.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "oi.h" 3 | 4 | using namespace std; 5 | 6 | int main() { 7 | ofstream f("score1a.in"); 8 | f << "1 3\n"; 9 | f.close(); 10 | f.open("score2a.in"); 11 | f << "2 5\n"; 12 | f.close(); 13 | f.open("score3a.in"); 14 | f << "3 7\n"; 15 | f.close(); 16 | f.open("score4a.in"); 17 | f << "4 9\n"; 18 | f.close(); 19 | } 20 | -------------------------------------------------------------------------------- /tests/packages/simple_interactive/prog/int2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | int main(int argc, char *argv[]) { 7 | assert(argc == 2); 8 | int proc_num = atoi(argv[1]); 9 | assert(proc_num == 0); 10 | 11 | int a; 12 | cin >> a; 13 | if (a == 42) 14 | cout << a + 24 << endl; 15 | else 16 | cout << a + 41 << endl; 17 | } 18 | -------------------------------------------------------------------------------- /tests/packages/lim/prog/limingen.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | ofstream f("lim1a.in"); 7 | f << "1 1\n"; 8 | f.close(); 9 | 10 | f.open("lim1b.in"); 11 | f << "1 2\n"; 12 | f.close(); 13 | 14 | f.open("lim2a.in"); 15 | f << "2 1\n"; 16 | f.close(); 17 | 18 | f.open("lim2b.in"); 19 | f << "2 2\n"; 20 | f.close(); 21 | } 22 | -------------------------------------------------------------------------------- /tests/packages/abc/prog/abc2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | int a, b; 7 | cin >> a >> b; 8 | if (a == 1) 9 | cout << a + b; 10 | else if (a == 2 || a == 3) 11 | cout << a + b - 1; 12 | else if (a == 4) { 13 | time_t start = time(0); 14 | int i = 0; 15 | while (time(0) - start < 5) { 16 | i++; 17 | } 18 | cout << a + b; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tests/packages/wer/prog/werinwer3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | int n, a, s = 0; 7 | cin >> n; 8 | for (int i = 0; i < n; i++) { 9 | cin >> a; 10 | s += a; 11 | 12 | assert(a <= n); 13 | } 14 | 15 | if (n == 3) 16 | assert(s == 5); 17 | 18 | cout << "OK" << endl << "Group " << n - 1 << endl; 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /tests/packages/icpc/prog/acmingen.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | ofstream f("acm0.in"); 7 | f << "0 0\n"; 8 | f.close(); 9 | f.open("acm1a.in"); 10 | f << "1 3\n"; 11 | f.close(); 12 | f.open("acm2a.in"); 13 | f << "2 5\n"; 14 | f.close(); 15 | f.open("acm3a.in"); 16 | f << "3 7\n"; 17 | f.close(); 18 | f.open("acm4a.in"); 19 | f << "4 9\n"; 20 | f.close(); 21 | } 22 | -------------------------------------------------------------------------------- /tests/packages/long_solution_names/prog/lsns1_long_name.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | int a, b; 7 | cin >> a >> b; 8 | if (a == 1) 9 | cout << a + b; 10 | else if (a == 2 || a == 3) 11 | cout << a + b - 1; 12 | else if (a == 4) { 13 | time_t start = time(0); 14 | int i = 0; 15 | while (time(0) - start < 5) { 16 | i++; 17 | } 18 | cout << a + b; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tests/packages/stc/prog/stc.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | using namespace std::chrono_literals; 6 | 7 | 8 | int main() { 9 | char array[30000000]; // 30 MB 10 | for (int i = 0; i < 30000000; i++) { 11 | array[i] = 'a'; 12 | } 13 | this_thread::sleep_for(5s); 14 | int a, b; 15 | cin >> a >> b; 16 | array[a] = (char)b; 17 | cout << a + array[a]; 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /tests/packages/score/config.yml: -------------------------------------------------------------------------------- 1 | title: Package for testing sinol_total_score configuration 2 | sinol_task_id: score 3 | sinol_contest_type: oij 4 | memory_limit: 16000 5 | time_limit: 1000 6 | sinol_total_score: 40 7 | scores: 8 | 1: 10 9 | 2: 10 10 | 3: 10 11 | 4: 10 12 | sinol_expected_scores: 13 | score.cpp: 14 | expected: 15 | 1: {points: 10, status: OK} 16 | 2: {points: 10, status: OK} 17 | 3: {points: 10, status: OK} 18 | 4: {points: 10, status: OK} 19 | points: 40 20 | -------------------------------------------------------------------------------- /tests/packages/vso/prog/vso2.cpp: -------------------------------------------------------------------------------- 1 | // First test RE, 2 | // second WA, 3 | // other OK. 4 | // Group should have status RE. 5 | 6 | #include 7 | 8 | using namespace std; 9 | 10 | int main() { 11 | int a, b; 12 | cin >> a >> b; 13 | 14 | if (a == 1 && b == 1) { 15 | int c = 0; 16 | cout << a + b / c; 17 | return 1; 18 | } 19 | else if (a == 1 && b == 2) { 20 | cout << "0"; 21 | } 22 | else { 23 | cout << a + b; 24 | } 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /tests/packages/undocumented_options/config.yml: -------------------------------------------------------------------------------- 1 | title: Package with undocumented sinol-make options 2 | sinol_task_id: und 3 | sinol_undocumented_time_tool: time 4 | sinol_undocumented_test_limits: true 5 | sinol_contest_type: oi 6 | memory_limit: 20480 7 | time_limit: 1000 8 | time_limits: 9 | 1a: 5000 10 | sinol_expected_scores: 11 | und.cpp: 12 | expected: 13 | 1: {points: 100, status: OK} 14 | points: 100 15 | und1.cpp: 16 | expected: 17 | 1: {points: 100, status: OK} 18 | points: 100 19 | -------------------------------------------------------------------------------- /tests/packages/chk/prog/chk3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | int n, s = 0; 7 | 8 | cin >> n; 9 | for (int i = 0; i < n; i++) { 10 | int a; 11 | cin >> a; 12 | s += a; 13 | } 14 | 15 | if (n == 5) { 16 | if (s % n != 0) { 17 | cout << "-1"; 18 | return 0; 19 | } 20 | else { 21 | cout << s / 2 - 1; 22 | return 0; 23 | } 24 | } 25 | cout << s; 26 | } 27 | -------------------------------------------------------------------------------- /tests/packages/lib/prog/lib.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "liblib.h" 3 | 4 | using namespace std; 5 | 6 | int main() { 7 | init(); 8 | 9 | int a = 0, b = 100; 10 | while (a <= b) { 11 | int m = (a + b) / 2; 12 | int g = guess(m); 13 | if (g == 0) { 14 | quit(); 15 | return 0; 16 | } 17 | if (g == 1) { 18 | b = m + 1; 19 | } else { 20 | a = m - 1; 21 | } 22 | } 23 | guess(a); 24 | quit(); 25 | } 26 | -------------------------------------------------------------------------------- /tests/packages/lsa/prog/lsa.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "lsalib.h" 3 | 4 | using namespace std; 5 | 6 | int main() { 7 | init(); 8 | 9 | int a = 0, b = 100; 10 | while (a <= b) { 11 | int m = (a + b) / 2; 12 | int g = guess(m); 13 | if (g == 0) { 14 | quit(); 15 | return 0; 16 | } 17 | if (g == 1) { 18 | b = m + 1; 19 | } else { 20 | a = m - 1; 21 | } 22 | } 23 | guess(a); 24 | quit(); 25 | } 26 | -------------------------------------------------------------------------------- /tests/packages/wer/prog/werinwer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | #ifdef _INWER 7 | int n, a; 8 | cin >> n; 9 | for (int i = 0; i < n; i++) { 10 | cin >> a; 11 | 12 | if (a >= n) { 13 | cout << "ERROR: " << a << " >= " << n << "\n"; 14 | return 1; 15 | } 16 | } 17 | 18 | cout << "OK" << endl << "Group " << n - 1 << endl; 19 | return 0; 20 | #else 21 | This should not compile 22 | #endif 23 | } 24 | -------------------------------------------------------------------------------- /src/sinol_make/interfaces/Errors.py: -------------------------------------------------------------------------------- 1 | class SinolMakeException(Exception): 2 | pass 3 | 4 | 5 | class CompilationError(SinolMakeException): 6 | def __init__(self, message): 7 | self.message = message 8 | 9 | def __str__(self): 10 | return self.message 11 | 12 | 13 | class CheckerException(SinolMakeException): 14 | def __init__(self, message): 15 | self.message = message 16 | 17 | def __str__(self): 18 | return self.message 19 | 20 | 21 | class UnknownContestType(SinolMakeException): 22 | pass 23 | -------------------------------------------------------------------------------- /tests/packages/bad_tests/prog/badingen.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | ofstream f("bad0.in"); 7 | f << "1 1 \n"; 8 | f.close(); 9 | f.open("bad1.in"); 10 | f << " 1 1\n"; 11 | f.close(); 12 | f.open("bad2.in"); 13 | f << "1 1\n"; 14 | f.close(); 15 | f.open("bad3.in"); 16 | f << "1 1\n\n\n"; 17 | f.close(); 18 | f.open("bad4.in"); 19 | f << "1 1\n1 1 \n"; 20 | f.close(); 21 | f.open("bad5.in"); 22 | f << "1 1"; 23 | f.close(); 24 | } 25 | -------------------------------------------------------------------------------- /tests/packages/simple_interactive/config.yml: -------------------------------------------------------------------------------- 1 | title: Simple interactive 2 | sinol_task_id: int 3 | memory_limit: 102400 4 | time_limit: 1000 5 | 6 | sinol_expected_scores: 7 | int.cpp: 8 | expected: 9 | 1: {points: 50, status: OK} 10 | 2: {points: 50, status: OK} 11 | points: 100 12 | int2.cpp: 13 | expected: 14 | 1: {points: 0, status: WA} 15 | 2: {points: 25, status: OK} 16 | points: 25 17 | int3.cpp: 18 | expected: 19 | 1: {points: 0, status: WA} 20 | 2: {points: 0, status: WA} 21 | points: 0 22 | -------------------------------------------------------------------------------- /tests/packages/two_interactive/config.yml: -------------------------------------------------------------------------------- 1 | title: Two interactive 2 | sinol_task_id: two 3 | num_processes: 2 4 | memory_limit: 102400 5 | time_limit: 1000 6 | sinol_expected_scores: 7 | two.cpp: 8 | expected: 9 | 1: {points: 50, status: OK} 10 | 2: {points: 50, status: OK} 11 | points: 100 12 | two1.cpp: 13 | expected: 14 | 1: {points: 38, status: OK} 15 | 2: {points: 38, status: OK} 16 | points: 76 17 | two2.cpp: 18 | expected: 19 | 1: {points: 25, status: OK} 20 | 2: {points: 25, status: OK} 21 | points: 50 22 | -------------------------------------------------------------------------------- /tests/packages/wer/prog/werinwer2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | int n, a, s = 0; 7 | cin >> n; 8 | for (int i = 0; i < n; i++) { 9 | cin >> a; 10 | s += a; 11 | 12 | if (a >= n) { 13 | cout << "ERROR: " << a << " >= " << n << "\n"; 14 | return 1; 15 | } 16 | } 17 | if (n == 3 && s != 5) { 18 | cout << "ERROR: " << s << " != 5\n"; 19 | return 1; 20 | } 21 | 22 | cout << "OK" << endl << "Group " << n - 1 << endl; 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /tests/packages/vso/prog/vso5.cpp: -------------------------------------------------------------------------------- 1 | // First test is OK, 2 | // second test is WA, 3 | // third test is OK, 4 | // fourth test is RE, 5 | // fifth test is WA. 6 | // Group status should be RE. 7 | 8 | #include 9 | 10 | using namespace std; 11 | 12 | int main() { 13 | int a, b; 14 | cin >> a >> b; 15 | if (a == 1 && (b == 1 || b == 3)) { 16 | cout << a + b; 17 | } 18 | else if (a == 1 && (b == 2 || b == 5)) { 19 | cout << a + b - 1; 20 | } 21 | else if (a == 1 && b == 4) { 22 | int c = 0; 23 | cout << (a + b) / c; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/sinol_make/interfaces/BaseCommand.py: -------------------------------------------------------------------------------- 1 | class BaseCommand: 2 | """ 3 | Base class for command 4 | """ 5 | 6 | 7 | def get_name(self): 8 | """ 9 | Get name of command 10 | """ 11 | pass 12 | 13 | 14 | def get_short_name(self): 15 | """ 16 | Get short name of command 17 | """ 18 | return None 19 | 20 | 21 | def configure_subparser(self, subparser): 22 | """ 23 | Configure subparser for command 24 | """ 25 | pass 26 | 27 | 28 | def run(self, args): 29 | """ 30 | Run command 31 | """ 32 | pass 33 | -------------------------------------------------------------------------------- /tests/packages/two_interactive/prog/two.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | void process0() { 7 | int n; 8 | cin >> n; 9 | cout << n + 42 << endl; 10 | cin >> n; 11 | cout << n * 2 << endl; 12 | } 13 | 14 | void process1() { 15 | int n; 16 | cin >> n; 17 | cout << n / 3 << endl; 18 | } 19 | 20 | int main(int argc, char* argv[]) { 21 | assert(argc == 2); 22 | int proc_num = atoi(argv[1]); 23 | 24 | if (proc_num == 0) { 25 | process0(); 26 | } 27 | else if (proc_num == 1) { 28 | process1(); 29 | } 30 | else { 31 | assert(false); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /tests/packages/two_interactive/prog/two1.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | void process0() { 7 | int n; 8 | cin >> n; 9 | cout << n + 42 << endl; 10 | cin >> n; 11 | cout << n * 3 << endl; 12 | } 13 | 14 | void process1() { 15 | int n; 16 | cin >> n; 17 | cout << n / 3 << endl; 18 | } 19 | 20 | int main(int argc, char* argv[]) { 21 | assert(argc == 2); 22 | int proc_num = atoi(argv[1]); 23 | 24 | if (proc_num == 0) { 25 | process0(); 26 | } 27 | else if (proc_num == 1) { 28 | process1(); 29 | } 30 | else { 31 | assert(false); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /tests/packages/two_interactive/prog/two2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | void process0() { 7 | int n; 8 | cin >> n; 9 | cout << n + 42 << endl; 10 | cin >> n; 11 | cout << n * 3 << endl; 12 | } 13 | 14 | void process1() { 15 | int n; 16 | cin >> n; 17 | cout << n / 2 << endl; 18 | } 19 | 20 | int main(int argc, char* argv[]) { 21 | assert(argc == 2); 22 | int proc_num = atoi(argv[1]); 23 | 24 | if (proc_num == 0) { 25 | process0(); 26 | } 27 | else if (proc_num == 1) { 28 | process1(); 29 | } 30 | else { 31 | assert(false); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /tests/packages/chk/config.yml: -------------------------------------------------------------------------------- 1 | title: Package with output checker 2 | memory_limit: 16000 3 | time_limit: 1000 4 | scores: 5 | 1: 50 6 | 2: 50 7 | 8 | sinol_expected_scores: 9 | chk.cpp: 10 | expected: 11 | 1: {points: 50, status: OK} 12 | 2: {points: 50, status: OK} 13 | points: 100 14 | chk1.cpp: 15 | expected: 16 | 1: {points: 0, status: WA} 17 | 2: {points: 0, status: WA} 18 | points: 0 19 | chk2.cpp: 20 | expected: 21 | 1: {points: 25, status: OK} 22 | 2: {points: 25, status: OK} 23 | points: 50 24 | chk3.cpp: 25 | expected: 26 | 1: {points: 50, status: OK} 27 | 2: {points: 0, status: WA} 28 | points: 50 29 | -------------------------------------------------------------------------------- /tests/packages/lsa/config.yml: -------------------------------------------------------------------------------- 1 | title: Package with library and string extra_compilation_args 2 | memory_limit: 16000 3 | time_limit: 1000 4 | scores: 5 | 1: 50 6 | 2: 50 7 | extra_compilation_files: [lsalib.cpp, lsalib.h, lsalib.py] 8 | extra_compilation_args: {cpp: lsalib.cpp} 9 | sinol_expected_scores: 10 | lsa.cpp: 11 | expected: 12 | 1: {points: 50, status: OK} 13 | 2: {points: 50, status: OK} 14 | points: 100 15 | lsa.py: 16 | expected: 17 | 1: {points: 50, status: OK} 18 | 2: {points: 50, status: OK} 19 | points: 100 20 | lsas1.cpp: 21 | expected: 22 | 1: {points: 0, status: WA} 23 | 2: {points: 50, status: OK} 24 | points: 50 25 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /tests/packages/lib/config.yml: -------------------------------------------------------------------------------- 1 | title: Package with lib file 2 | memory_limit: 16000 3 | time_limit: 1000 4 | scores: 5 | 1: 50 6 | 2: 50 7 | extra_compilation_files: [liblib.cpp, liblib.h] 8 | extra_compilation_args: 9 | cpp: [liblib.cpp] 10 | extra_execution_files: 11 | py: [liblib.py] 12 | sinol_expected_scores: 13 | lib.cpp: 14 | expected: 15 | 1: {points: 50, status: OK} 16 | 2: {points: 50, status: OK} 17 | points: 100 18 | lib.py: 19 | expected: 20 | 1: {points: 50, status: OK} 21 | 2: {points: 50, status: OK} 22 | points: 100 23 | libs1.cpp: 24 | expected: 25 | 1: {points: 0, status: WA} 26 | 2: {points: 50, status: OK} 27 | points: 50 28 | -------------------------------------------------------------------------------- /tests/packages/wer/prog/werinwer7.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main(int argc, char const *argv[]) { 6 | if (argc != 2) { 7 | cout << "WRONG\nWrong number of arguments"; 8 | return 1; 9 | } 10 | int n; 11 | cin >> n; 12 | if (n == 2 && strcmp(argv[1], "wer1a.in") == 0) { 13 | cout << "OK\n"; 14 | return 0; 15 | } 16 | if (n == 3 && strcmp(argv[1], "wer2a.in") == 0) { 17 | cout << "OK\n"; 18 | return 0; 19 | } 20 | if (n == 4 && strcmp(argv[1], "wer3a.in") == 0) { 21 | cout << "OK\n"; 22 | return 0; 23 | } 24 | cout << "WRONG\nWrong test"; 25 | return 1; 26 | } 27 | -------------------------------------------------------------------------------- /tests/packages/icpc/prog/acm3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int rnd() { 6 | return rand() % 100; 7 | } 8 | 9 | int main() { 10 | int a, b; 11 | cin >> a >> b; 12 | if (a == 1) 13 | cout << a + b; 14 | else if (a == 2 || a == 3) 15 | cout << a + b + 2; 16 | else if (a == 4) { 17 | vector v; 18 | for (int i = 0; i <= 10000; i++) { 19 | int *tmp = new int[1000]; 20 | for (int j = 0; j < 1000; j++) { 21 | tmp[j] = rnd(); 22 | } 23 | v.push_back(tmp); 24 | } 25 | int s = 0; 26 | for (auto i : v) { 27 | for (int j = 0; j < 1000; j++) { 28 | s = (s + i[j]) % 1000000007; 29 | } 30 | delete[] i; 31 | } 32 | cout << a + b; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/sinol_make/structs/run_structs.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | 3 | 4 | @dataclass 5 | class ExecutionData: 6 | """ 7 | Represents data for execution of a solution on a specified test. 8 | """ 9 | # Name of the solution 10 | name: str 11 | # Filename of the executable 12 | executable: str 13 | # Filename of the test 14 | test: str 15 | # Time limit for this test in milliseconds 16 | time_limit: int 17 | # Memory limit in KB 18 | memory_limit: int 19 | # Path to the timetool executable 20 | timetool_path: str 21 | 22 | 23 | @dataclass 24 | class PrintData: 25 | """ 26 | Represents data for printing results of execution. 27 | """ 28 | 29 | i: int 30 | -------------------------------------------------------------------------------- /tests/packages/long_solution_names/prog/lsnb10_long_name.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int rnd() { 6 | return rand() % 100; 7 | } 8 | 9 | int main() { 10 | int a, b; 11 | cin >> a >> b; 12 | if (a == 1) 13 | cout << a + b; 14 | else if (a == 2 || a == 3) 15 | cout << a + b + 2; 16 | else if (a == 4) { 17 | vector v; 18 | for (int i = 0; i <= 10000; i++) { 19 | int *tmp = new int[1000]; 20 | for (int j = 0; j < 1000; j++) { 21 | tmp[j] = rnd(); 22 | } 23 | v.push_back(tmp); 24 | } 25 | int s = 0; 26 | for (auto i : v) { 27 | for (int j = 0; j < 1000; j++) { 28 | s = (s + i[j]) % 1000000007; 29 | } 30 | delete[] i; 31 | } 32 | cout << a + b; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tests/packages/abc/prog/abc3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int rnd() { 6 | return rand() % 100; 7 | } 8 | 9 | int main() { 10 | int a, b; 11 | cin >> a >> b; 12 | if (a == 1) 13 | cout << a + b; 14 | else if (a == 2 || a == 3) 15 | cout << a + b + 2; 16 | else if (a == 4) { 17 | vector v; 18 | for (int i = 0; i <= 10000; i++) { 19 | int *tmp = new int[1000]; 20 | for (int j = 0; j < 1000; j++) { 21 | tmp[j] = rnd(); 22 | } 23 | v.push_back(tmp); 24 | } 25 | int s = 0; 26 | for (auto i : v) { 27 | for (int j = 0; j < 1000; j++) { 28 | s = (s + i[j]) % 1000000007; 29 | } 30 | delete[] i; 31 | } 32 | cout << a + b; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tests/commands/doc/test_unit.py: -------------------------------------------------------------------------------- 1 | import os 2 | import pytest 3 | 4 | from sinol_make.commands.doc import Command 5 | from tests.fixtures import create_package 6 | from tests import util 7 | 8 | 9 | @pytest.mark.parametrize("create_package", [util.get_doc_package_path()], indirect=True) 10 | def test_compile_pdf_latex(create_package): 11 | command = Command() 12 | assert command.compile_pdf_latex(os.path.abspath(os.path.join(os.getcwd(), "doc/doczad.tex"))) is True 13 | 14 | @pytest.mark.parametrize("create_package", [util.get_doc_package_path()], indirect=True) 15 | def test_compile_file_latex_div(create_package): 16 | command = Command() 17 | assert command.compile_file_latex_div(os.path.abspath(os.path.join(os.getcwd(), "doc/doczad.tex"))) is True 18 | -------------------------------------------------------------------------------- /src/sinol_make/helpers/func_cache.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | __cache = {} 4 | 5 | 6 | def cache_result(cwd=False): 7 | """ 8 | Function to cache the result of a function. 9 | """ 10 | def decorator(func): 11 | def wrapper(*args, **kwargs): 12 | if cwd: 13 | key = (func.__name__, os.getcwd()) 14 | else: 15 | key = func.__name__ 16 | 17 | if key in __cache: 18 | return __cache[key] 19 | result = func(*args, **kwargs) 20 | __cache[key] = result 21 | return result 22 | return wrapper 23 | return decorator 24 | 25 | 26 | def clear_cache(): 27 | """ 28 | Function to clear the cache. 29 | """ 30 | __cache.clear() 31 | -------------------------------------------------------------------------------- /tests/packages/lib/prog/liblib.py: -------------------------------------------------------------------------------- 1 | n = 0 2 | m = 0 3 | cnt = 0 4 | finished = False 5 | 6 | 7 | def init(): 8 | global n, m 9 | n, m = map(int, input().split()) 10 | 11 | 12 | def guess(a): 13 | global finished, cnt 14 | cnt += 1 15 | 16 | if a == n: 17 | if cnt > m: 18 | print("Too_many_queries") 19 | print("WRONG") 20 | finished = True 21 | return 0 22 | else: 23 | print("Correct") 24 | print("OK") 25 | finished = True 26 | return 0 27 | if a < n: 28 | return -1 29 | if a > n: 30 | return 1 31 | 32 | 33 | def quit(): 34 | if not finished: 35 | print("Not_correct") 36 | print("WRONG") 37 | exit(0) 38 | -------------------------------------------------------------------------------- /tests/packages/lsa/prog/lsalib.py: -------------------------------------------------------------------------------- 1 | n = 0 2 | m = 0 3 | cnt = 0 4 | finished = False 5 | 6 | 7 | def init(): 8 | global n, m 9 | n, m = map(int, input().split()) 10 | 11 | 12 | def guess(a): 13 | global finished, cnt 14 | cnt += 1 15 | 16 | if a == n: 17 | if cnt > m: 18 | print("Too_many_queries") 19 | print("WRONG") 20 | finished = True 21 | return 0 22 | else: 23 | print("Correct") 24 | print("OK") 25 | finished = True 26 | return 0 27 | if a < n: 28 | return -1 29 | if a > n: 30 | return 1 31 | 32 | 33 | def quit(): 34 | if not finished: 35 | print("Not_correct") 36 | print("WRONG") 37 | exit(0) 38 | -------------------------------------------------------------------------------- /tests/packages/lim/config.yml: -------------------------------------------------------------------------------- 1 | title: Package with `time_limits` and `memory_limits` set 2 | memory_limit: 15000 3 | memory_limits: 4 | 2: 60000 5 | time_limit: 1000 6 | time_limits: 7 | 1: 5000 8 | scores: 9 | 1: 50 10 | 2: 50 11 | sinol_expected_scores: 12 | lim.cpp: 13 | expected: 14 | 1: {points: 50, status: OK} 15 | 2: {points: 50, status: OK} 16 | points: 100 17 | lim2.cpp: 18 | expected: 19 | 1: {points: 50, status: OK} 20 | 2: {points: 0, status: TL} 21 | points: 50 22 | lim3.cpp: 23 | expected: 24 | 1: {points: 0, status: ML} 25 | 2: {points: 50, status: OK} 26 | points: 50 27 | lim4.cpp: 28 | expected: 29 | 1: {points: 0, status: ML} 30 | 2: {points: 50, status: OK} 31 | points: 50 32 | -------------------------------------------------------------------------------- /tests/packages/chk/prog/chkingen.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int main() { 6 | ofstream f; 7 | 8 | f.open("chk1a.in"); 9 | f << "5" << endl; 10 | f << "1 2 3 4 5" << endl; 11 | f.close(); 12 | 13 | f.open("chk1b.in"); 14 | f << "5" << endl; 15 | f << "1 2 3 4 4" << endl; 16 | f.close(); 17 | 18 | f.open("chk1c.in"); 19 | f << "5" << endl; 20 | f << "1 1 3 5" << endl; 21 | f.close(); 22 | 23 | f.open("chk2a.in"); 24 | f << "4" << endl; 25 | f << "1 2 3 6" << endl; 26 | f.close(); 27 | 28 | f.open("chk2b.in"); 29 | f << "1" << endl; 30 | f << "6" << endl; 31 | f.close(); 32 | 33 | f.open("chk2c.in"); 34 | f << "4" << endl; 35 | f << "1 2 3 4" << endl; 36 | f.close(); 37 | } 38 | -------------------------------------------------------------------------------- /src/sinol_make/structs/compiler_structs.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | 3 | from sinol_make.helpers import compiler 4 | 5 | 6 | @dataclass 7 | class Compilers: 8 | c_compiler_path: str 9 | cpp_compiler_path: str 10 | python_interpreter_path: str 11 | java_compiler_path: str 12 | 13 | def __init__(self, c_compiler_path: str = None, cpp_compiler_path: str = None, python_interpreter_path: str = None, java_compiler_path: str = None): 14 | self.c_compiler_path = c_compiler_path or compiler.get_c_compiler_path() 15 | self.cpp_compiler_path = cpp_compiler_path or compiler.get_cpp_compiler_path() 16 | self.python_interpreter_path = python_interpreter_path or compiler.get_python_interpreter_path() 17 | self.java_compiler_path = java_compiler_path or compiler.get_java_compiler_path() 18 | -------------------------------------------------------------------------------- /tests/contest_types/test_icpc.py: -------------------------------------------------------------------------------- 1 | from sinol_make import contest_types 2 | 3 | 4 | def test_assign_scores(): 5 | contest = contest_types.ICPCContest() 6 | assert contest.assign_scores([0, 1, 2, 3]) == {0: 1, 1: 1, 2: 1, 3: 1} 7 | assert contest.assign_scores([1, 2, 3]) == {1: 1, 2: 1, 3: 1} 8 | assert contest.assign_scores([0, 1, 2]) == {0: 1, 1: 1, 2: 1} 9 | 10 | 11 | def test_get_group_score(): 12 | contest = contest_types.ICPCContest() 13 | assert contest.get_group_score([1, 1, 1, 1], 1) == 1 14 | assert contest.get_group_score([1, 0, 1], 1) == 0 15 | 16 | 17 | def test_get_global_score(): 18 | contest = contest_types.ICPCContest() 19 | assert contest.get_global_score({1: {"points": 1}, 2: {"points": 1}}, 1) == 1 20 | assert contest.get_global_score({1: {"points": 1}, 2: {"points": 0}}, 1) == 0 21 | -------------------------------------------------------------------------------- /tests/packages/ovl/prog/ovl.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | using namespace std::chrono; 6 | 7 | __attribute__((optimize("O0"))) 8 | void s2j_wait(long long instructions) { 9 | instructions /= 3; // Every pass of the loop below takes 3 instructions. 10 | while (instructions > 0) 11 | --instructions; 12 | } 13 | 14 | int wait(int secs) { 15 | if (getenv("UNDER_SIO2JAIL") != NULL) { 16 | s2j_wait((long long)secs * 2'000'000'000); 17 | return 0; 18 | } 19 | auto start = high_resolution_clock::now(); 20 | int i = 0; 21 | while (duration_cast(high_resolution_clock::now() - start).count() < secs) 22 | i++; 23 | return i; 24 | } 25 | 26 | int main() { 27 | int i = wait(2); 28 | 29 | int a, b; 30 | cin >> a >> b; 31 | b += i; 32 | cout << a + b - i; 33 | } 34 | -------------------------------------------------------------------------------- /tests/packages/vso/prog/vso3.cpp: -------------------------------------------------------------------------------- 1 | // First test ML, 2 | // second test RE, 3 | // third test WA, 4 | // other OK. 5 | // Group should have status ML. 6 | 7 | #include 8 | 9 | using namespace std; 10 | 11 | int rnd() { 12 | return rand() % 100; 13 | } 14 | 15 | int main() { 16 | int a, b; 17 | cin >> a >> b; 18 | if (a == 1 && b == 1) { 19 | vector v; 20 | for (int i = 0; i <= 10000; i++) { 21 | int *tmp = new int[1000]; 22 | for (int j = 0; j <= 1000; j++) 23 | tmp[j] = rnd(); 24 | v.push_back(tmp); 25 | } 26 | cout << a + b; 27 | } 28 | else if (a == 1 && b == 2) { 29 | int c = 0; 30 | cout << (a + b) / c; 31 | return 1; 32 | } 33 | else if (a == 1 && b == 3) { 34 | cout << "1"; 35 | } 36 | else { 37 | cout << a + b; 38 | } 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /tests/packages/vso/config.yml: -------------------------------------------------------------------------------- 1 | title: Test package for veryfing correct status order 2 | memory_limit: 16000 3 | time_limit: 1000 4 | scores: 5 | 1: 100 6 | sinol_expected_scores: 7 | vso.cpp: 8 | expected: 9 | 1: {points: 100, status: OK} 10 | points: 100 11 | vso1.cpp: 12 | expected: 13 | 1: {points: 0, status: WA} 14 | points: 0 15 | vso2.cpp: 16 | expected: 17 | 1: {points: 0, status: RE} 18 | points: 0 19 | vso3.cpp: 20 | expected: 21 | 1: {points: 0, status: ML} 22 | points: 0 23 | vso4.cpp: 24 | expected: 25 | 1: {points: 0, status: TL} 26 | points: 0 27 | vso5.cpp: 28 | expected: 29 | 1: {points: 0, status: RE} 30 | points: 0 31 | vso6.cpp: 32 | expected: 33 | 1: {points: 0, status: ML} 34 | points: 0 35 | vso7.cpp: 36 | expected: 37 | 1: {points: 0, status: TL} 38 | points: 0 39 | -------------------------------------------------------------------------------- /tests/packages/lib/prog/liblib.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "liblib.h" 3 | 4 | using namespace std; 5 | 6 | int n, m, cnt = 0; 7 | bool finished = false; 8 | 9 | void init() { 10 | cin >> n >> m; 11 | } 12 | 13 | int guess(int a) { 14 | cnt++; 15 | if (a == n) { 16 | if (cnt > m) { 17 | cout << "Too_many_queries" << endl; 18 | cout << "WRONG" << endl; 19 | finished = true; 20 | return 0; 21 | } 22 | else { 23 | cout << "Correct" << endl; 24 | cout << "OK" << endl; 25 | finished = true; 26 | return 0; 27 | } 28 | } 29 | if (a < n) { 30 | return -1; 31 | } 32 | return 1; 33 | } 34 | 35 | void quit() { 36 | if (!finished) { 37 | cout << "Not_correct" << endl; 38 | cout << "WRONG" << endl; 39 | } 40 | exit(0); 41 | } 42 | -------------------------------------------------------------------------------- /tests/packages/lsa/prog/lsalib.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "lsalib.h" 3 | 4 | using namespace std; 5 | 6 | int n, m, cnt = 0; 7 | bool finished = false; 8 | 9 | void init() { 10 | cin >> n >> m; 11 | } 12 | 13 | int guess(int a) { 14 | cnt++; 15 | if (a == n) { 16 | if (cnt > m) { 17 | cout << "Too_many_queries" << endl; 18 | cout << "WRONG" << endl; 19 | finished = true; 20 | return 0; 21 | } 22 | else { 23 | cout << "Correct" << endl; 24 | cout << "OK" << endl; 25 | finished = true; 26 | return 0; 27 | } 28 | } 29 | if (a < n) { 30 | return -1; 31 | } 32 | return 1; 33 | } 34 | 35 | void quit() { 36 | if (!finished) { 37 | cout << "Not_correct" << endl; 38 | cout << "WRONG" << endl; 39 | } 40 | exit(0); 41 | } 42 | -------------------------------------------------------------------------------- /tests/contest_types/test_oi.py: -------------------------------------------------------------------------------- 1 | from sinol_make import contest_types 2 | from sinol_make.structs.status_structs import ExecutionResult 3 | 4 | 5 | def test_get_test_score(): 6 | contest = contest_types.OIContest() 7 | result = ExecutionResult("WA") 8 | assert contest.get_test_score(result, 10, 100) == 0 9 | 10 | result = ExecutionResult("OK", 1000, Points=100) 11 | assert contest.get_test_score(result, 2000, 100) == 100 12 | 13 | result = ExecutionResult("OK", 1500, Points=100) 14 | assert contest.get_test_score(result, 2000, 100) == 50 15 | 16 | result = ExecutionResult("OK", 1999, Points=100) 17 | assert contest.get_test_score(result, 2000, 100) == 1 18 | 19 | result = ExecutionResult("OK", 1750, Points=42) 20 | assert contest.get_test_score(result, 2000, 100) == 11 21 | 22 | result = ExecutionResult("OK", 1100, Points=78) 23 | assert contest.get_test_score(result, 2000, 1000) == 70 24 | -------------------------------------------------------------------------------- /tests/packages/vso/prog/vso6.cpp: -------------------------------------------------------------------------------- 1 | // First test is OK, 2 | // second test is WA, 3 | // third test is ML, 4 | // fourth test is RE, 5 | // fifth test is OK. 6 | // Group status should be ML. 7 | 8 | #include 9 | 10 | using namespace std; 11 | 12 | int rnd() { 13 | return rand() % 100; 14 | } 15 | 16 | int main() { 17 | int a, b; 18 | cin >> a >> b; 19 | if (a == 1 && (b == 1 || b == 5)) { 20 | cout << a + b; 21 | } 22 | else if (a == 1 && b == 2) { 23 | cout << a + b - 1; 24 | } 25 | else if (a == 1 && b == 4) { 26 | int c = 0; 27 | cout << (a + b) / c; 28 | return 1; 29 | } 30 | else if (a == 1 && b == 3) { 31 | vector v; 32 | for (int i = 0; i <= 10000; i++) { 33 | int *tmp = new int[1000]; 34 | for (int j = 0; j <= 1000; j++) 35 | tmp[j] = rnd(); 36 | v.push_back(tmp); 37 | } 38 | cout << a + b; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /tests/packages/simple_interactive/prog/intsoc.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | int main(int argc, char *argv[]) { 7 | assert(argc == 4); 8 | int num_processes = atoi(argv[1]); 9 | assert(num_processes == 1); 10 | 11 | FILE *in = fdopen(atoi(argv[2]), "r"); 12 | FILE *out = fdopen(atoi(argv[3]), "w"); 13 | assert(in != NULL); 14 | assert(out != NULL); 15 | 16 | int n; 17 | cin >> n; 18 | 19 | fprintf(out, "%d\n", n); 20 | fflush(out); 21 | 22 | int ans; 23 | fscanf(in, "%d", &ans); 24 | if (feof(in) || ferror(in)) { 25 | // Exit with sigpipe. Interactor could also exit with WA and a proper comment. 26 | return 128 + 13; 27 | } 28 | if (n + 42 == ans) { 29 | cout << "OK\n"; 30 | } 31 | else if (n + 24 == ans) { 32 | cout << "OK\nCoMmEnT\n50\n"; 33 | } 34 | else { 35 | cout << "WA\nBad answer\n0\n"; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/sinol_make/contest_types/__init__.py: -------------------------------------------------------------------------------- 1 | from sinol_make.contest_types.default import DefaultContest 2 | from sinol_make.contest_types.icpc import ICPCContest 3 | from sinol_make.contest_types.oi import OIContest 4 | from sinol_make.contest_types.oij import OIJContest 5 | from sinol_make.helpers.func_cache import cache_result 6 | from sinol_make.helpers.package_util import get_config 7 | from sinol_make.interfaces.Errors import UnknownContestType 8 | 9 | 10 | @cache_result(cwd=True) 11 | def get_contest_type(): 12 | config = get_config() 13 | contest_type = config.get("sinol_contest_type", "default").lower() 14 | 15 | if contest_type == "default": 16 | return DefaultContest() 17 | elif contest_type == "oi": 18 | return OIContest() 19 | elif contest_type == "icpc": 20 | return ICPCContest() 21 | elif contest_type == "oij": 22 | return OIJContest() 23 | else: 24 | raise UnknownContestType(f'Unknown contest type "{contest_type}"') 25 | -------------------------------------------------------------------------------- /.github/workflows/GithubRunner.yaml: -------------------------------------------------------------------------------- 1 | name: pytest-github-runner 2 | run-name: Run tests for GitHub Runner 3 | on: 4 | push: 5 | branches: 'main' 6 | pull_request: 7 | jobs: 8 | pytest: 9 | strategy: 10 | matrix: 11 | python-version: ["3.9", "3.13"] 12 | name: pytest-github-runner-python-${{ matrix.python-version }} 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v3 17 | - name: Install Python ${{ matrix.python-version }} 18 | uses: actions/setup-python@v2 19 | with: 20 | python-version: ${{ matrix.python-version }} 21 | - name: Install dependencies 22 | run: | 23 | pip install .[tests] 24 | sudo apt install texlive-latex-recommended -y 25 | sudo apt install ghostscript -y 26 | - name: Run github runner pytest 27 | env: 28 | PYTEST_ADDOPTS: "--color=yes" 29 | run: | 30 | python -m pytest -v --github-runner 31 | -------------------------------------------------------------------------------- /tests/packages/lim/prog/lim2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | using namespace std::chrono; 6 | 7 | __attribute__((optimize("O0"))) 8 | void s2j_wait(long long instructions) { 9 | instructions /= 3; // Every pass of the loop below takes 3 instructions. 10 | while (instructions > 0) 11 | --instructions; 12 | } 13 | 14 | int wait(int secs) { 15 | if (getenv("UNDER_SIO2JAIL") != NULL) { 16 | s2j_wait((long long)secs * 2'000'000'000); 17 | return 0; 18 | } 19 | auto start = high_resolution_clock::now(); 20 | int i = 0; 21 | while (duration_cast(high_resolution_clock::now() - start).count() < secs) 22 | i++; 23 | return i; 24 | } 25 | 26 | int main() { 27 | int a, b; 28 | cin >> a >> b; 29 | 30 | if (a == 2 && b == 1) { 31 | int i = wait(7); 32 | a += i - i; 33 | } 34 | else { 35 | int i = wait(2); 36 | a += i - i; 37 | } 38 | 39 | cout << a + b << endl; 40 | } 41 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Run '...' 16 | 2. See error 17 | If possible, please provide a simplified version of the task package you are using, 18 | but *don't* send any code that should be kept non-public, such as solutions to tasks that haven't been used yet. 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Output** 24 | If applicable, add output from the command line. 25 | Paste your output here: 26 | ```bash 27 | $ sinol-make ... 28 | ``` 29 | 30 | **System (please complete the following information):** 31 | - OS: [e.g. Ubuntu, MacOS, Windows WSL] 32 | - Version [check with `sinol-make --version`] 33 | 34 | **Additional context** 35 | Add any other context about the problem here. 36 | -------------------------------------------------------------------------------- /example_package/.gitignore: -------------------------------------------------------------------------------- 1 | # sinol-make 2 | .cache 3 | cache 4 | in/.md5sums 5 | 6 | # Tests 7 | in/*.in 8 | out/*.out 9 | !in/???0*.in 10 | !out/???0*.out 11 | 12 | # export package file 13 | *.tgz 14 | 15 | # LaTeX 16 | *.pdf 17 | *.ps 18 | !doc/logo.* 19 | 20 | *.aux 21 | *.lof 22 | *.log 23 | *.lot 24 | *.fls 25 | doc/*.out 26 | *.toc 27 | *.fmt 28 | *.fot 29 | *.cb 30 | *.cb2 31 | .*.lb 32 | 33 | *.dvi 34 | *.xdv 35 | *-converted-to.* 36 | # these rules might exclude image files for figures etc. 37 | *.eps 38 | 39 | ## Bibliography auxiliary files (bibtex/biblatex/biber): 40 | *.bbl 41 | *.bcf 42 | *.blg 43 | *-blx.aux 44 | *-blx.bib 45 | *.run.xml 46 | 47 | # Encrypted files 48 | *.gpg 49 | 50 | # SIO binnary 51 | *.e 52 | 53 | # Python Environments 54 | .env 55 | .venv 56 | env/ 57 | venv/ 58 | ENV/ 59 | env.bak/ 60 | venv.bak/ 61 | 62 | # pyenv 63 | .python-version 64 | 65 | # IPython 66 | profile_default/ 67 | ipython_config.py 68 | 69 | # Byte-compiled / optimized / DLL files 70 | __pycache__/ 71 | *.py[cod] 72 | *$py.class 73 | 74 | # C extensions 75 | *.so 76 | *.o 77 | -------------------------------------------------------------------------------- /tests/fixtures.py: -------------------------------------------------------------------------------- 1 | import pytest, tempfile, os, shutil 2 | from .util import get_simple_package_path 3 | 4 | 5 | @pytest.fixture 6 | def create_package(request): 7 | """ 8 | Fixture to create a temporary directory with specified package (by default simple package). 9 | Changes the current working directory to the package directory. 10 | """ 11 | try: 12 | path = request.param 13 | except AttributeError: 14 | path = get_simple_package_path() 15 | task_id = os.path.basename(path) 16 | 17 | tmpdir = tempfile.TemporaryDirectory() 18 | package_path = os.path.join(tmpdir.name, task_id) 19 | shutil.copytree(path, package_path) 20 | os.chdir(package_path) 21 | 22 | yield package_path 23 | 24 | tmpdir.cleanup() 25 | 26 | 27 | @pytest.fixture 28 | def temp_workdir(): 29 | """ 30 | Fixture to change the current working directory to the temporary directory. 31 | """ 32 | tmpdir = tempfile.TemporaryDirectory() 33 | print(tmpdir) 34 | os.chdir(tmpdir.name) 35 | 36 | yield tmpdir.name 37 | 38 | tmpdir.cleanup() 39 | -------------------------------------------------------------------------------- /tests/packages/icpc/config.yml: -------------------------------------------------------------------------------- 1 | title: Package for testing ICPC contest 2 | sinol_task_id: acm 3 | sinol_contest_type: icpc 4 | memory_limit: 16000 5 | time_limit: 1000 6 | sinol_expected_scores: 7 | acm.cpp: 8 | expected: 9 | 0: {points: 1, status: OK} 10 | 1: {points: 1, status: OK} 11 | 2: {points: 1, status: OK} 12 | 3: {points: 1, status: OK} 13 | 4: {points: 1, status: OK} 14 | points: 1 15 | acm1.cpp: 16 | expected: 17 | 0: {points: 1, status: OK} 18 | 1: {points: 1, status: OK} 19 | 2: {points: 1, status: OK} 20 | 3: {points: 1, status: OK} 21 | 4: {points: 0, status: WA} 22 | points: 0 23 | acm2.cpp: 24 | expected: 25 | 0: {points: 0, status: WA} 26 | 1: {points: 1, status: OK} 27 | 2: {points: 0, status: WA} 28 | 3: {points: 0, status: WA} 29 | 4: {points: 0, status: TL} 30 | points: 0 31 | acm3.cpp: 32 | expected: 33 | 0: {points: 0, status: WA} 34 | 1: {points: 1, status: OK} 35 | 2: {points: 0, status: WA} 36 | 3: {points: 0, status: WA} 37 | 4: {points: 0, status: ML} 38 | points: 0 39 | -------------------------------------------------------------------------------- /.github/workflows/release.yaml: -------------------------------------------------------------------------------- 1 | name: publish 2 | run-name: Publish to PyPi 3 | on: 4 | release: 5 | types: [published] 6 | 7 | permissions: 8 | contents: write 9 | 10 | jobs: 11 | build-and-publish: 12 | name: Build and publish to PyPi 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - name: Checkout 17 | uses: actions/checkout@v3 18 | - name: Set up Python 19 | uses: actions/setup-python@v4 20 | with: 21 | python-version: 3.11 22 | - name: Install build 23 | run: | 24 | python3 -m pip install build 25 | python3 -m pip install setuptools --upgrade 26 | - name: Build 27 | run: | 28 | python3 -m build --sdist --wheel --outdir dist/ . 29 | - name: Upload to release 30 | env: 31 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 32 | run: | 33 | gh release upload ${{ github.event.release.tag_name }} dist/* 34 | - name: Publish 35 | # if: startsWith(github.ref, 'refs/tags') 36 | uses: pypa/gh-action-pypi-publish@release/v1 37 | with: 38 | password: ${{ secrets.TOKEN }} 39 | -------------------------------------------------------------------------------- /tests/packages/abc/config.yml: -------------------------------------------------------------------------------- 1 | title: Simple test package 2 | memory_limit: 16000 3 | time_limit: 1000 4 | scores: 5 | 1: 25 6 | 2: 25 7 | 3: 25 8 | 4: 25 9 | sinol_expected_scores: 10 | abc.cpp: 11 | expected: 12 | 1: {points: 25, status: OK} 13 | 2: {points: 25, status: OK} 14 | 3: {points: 25, status: OK} 15 | 4: {points: 25, status: OK} 16 | points: 100 17 | abc1.cpp: 18 | expected: 19 | 1: {points: 25, status: OK} 20 | 2: {points: 25, status: OK} 21 | 3: {points: 25, status: OK} 22 | 4: {points: 0, status: WA} 23 | points: 75 24 | abc2.cpp: 25 | expected: 26 | 1: {points: 25, status: OK} 27 | 2: {points: 0, status: WA} 28 | 3: {points: 0, status: WA} 29 | 4: {points: 0, status: TL} 30 | points: 25 31 | abc3.cpp: 32 | expected: 33 | 1: {points: 25, status: OK} 34 | 2: {points: 0, status: WA} 35 | 3: {points: 0, status: WA} 36 | 4: {points: 0, status: ML} 37 | points: 25 38 | abc4.cpp: 39 | expected: 40 | 1: {points: 25, status: OK} 41 | 2: {points: 25, status: OK} 42 | 3: {points: 0, status: WA} 43 | 4: {points: 0, status: RE} 44 | points: 50 45 | -------------------------------------------------------------------------------- /.github/workflows/Arch.yaml: -------------------------------------------------------------------------------- 1 | name: pytest-arch 2 | run-name: Run pytest on Arch Linux 3 | on: 4 | push: 5 | branches: 'main' 6 | pull_request: 7 | jobs: 8 | pytest: 9 | runs-on: self-hosted 10 | strategy: 11 | matrix: 12 | python-version: ["3.9", "3.13.1"] 13 | name: pytest-arch-python-${{ matrix.python-version }} 14 | container: 15 | image: archlinux:latest 16 | volumes: 17 | - /home/actions/oiejq:/github/home/.local/bin 18 | options: 19 | --privileged 20 | steps: 21 | - name: Checkout 22 | uses: actions/checkout@v3 23 | - name: Prepare system 24 | run: | 25 | sysctl kernel.perf_event_paranoid=-1 26 | pacman -Syu --noconfirm diffutils time gcc dpkg ghostscript texlive-latexextra git 27 | - name: Set up Python ${{ matrix.python-version }} 28 | uses: actions/setup-python@v4 29 | with: 30 | python-version: ${{ matrix.python-version }} 31 | - name: Install dependencies 32 | run: | 33 | pip3 install .[tests] 34 | - name: Run pytest 35 | env: 36 | PYTEST_ADDOPTS: "--color=yes" 37 | run: | 38 | python3 -m pytest -v -n $((`nproc` / 2)) 39 | -------------------------------------------------------------------------------- /tests/test_multiple_arguments.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import subprocess 3 | 4 | from tests.fixtures import create_package 5 | from tests import util 6 | 7 | 8 | def run(args): 9 | print("Running with args:", args) 10 | p = subprocess.run(args, shell=True) 11 | assert p.returncode == 0 12 | 13 | 14 | @pytest.mark.parametrize("create_package", [util.get_simple_package_path()], indirect=True) 15 | def test_simple_package(create_package): 16 | run("sinol-make gen run") 17 | run("sinol-make gen prog/abcingen.cpp run --tests abc1a.in") 18 | run("sinol-make run --tests abc1a.in run --tests abc1a.in abc2a.in ingen prog/abcingen.cpp") 19 | run("sinol-make gen run export --no-statement") 20 | 21 | 22 | @pytest.mark.parametrize("create_package", [util.get_inwer_package_path()], indirect=True) 23 | def test_inwer_package(create_package): 24 | run("sinol-make gen inwer run") 25 | run("sinol-make ingen prog/weringen.cpp inwer prog/werinwer.cpp --tests wer1a.in run --tests wer2a.in") 26 | run("sinol-make ingen inwer run export --no-statement") 27 | 28 | 29 | @pytest.mark.parametrize("create_package", [util.get_doc_package_path()], indirect=True) 30 | def test_doc_package(create_package): 31 | run("sinol-make doc doc/doczad.tex export") 32 | -------------------------------------------------------------------------------- /tests/packages/long_solution_names/config.yml: -------------------------------------------------------------------------------- 1 | title: Package with long solution names 2 | sinol_task_id: lsn 3 | memory_limit: 16000 4 | time_limit: 1000 5 | scores: 6 | 1: 25 7 | 2: 25 8 | 3: 25 9 | 4: 25 10 | sinol_expected_scores: 11 | lsn.cpp: 12 | expected: 13 | 1: {points: 25, status: OK} 14 | 2: {points: 25, status: OK} 15 | 3: {points: 25, status: OK} 16 | 4: {points: 25, status: OK} 17 | points: 100 18 | lsn1_long_name.cpp: 19 | expected: 20 | 1: {points: 25, status: OK} 21 | 2: {points: 25, status: OK} 22 | 3: {points: 25, status: OK} 23 | 4: {points: 0, status: WA} 24 | points: 75 25 | lsn_long_name.cpp: 26 | expected: 27 | 1: {points: 25, status: OK} 28 | 2: {points: 25, status: OK} 29 | 3: {points: 0, status: WA} 30 | 4: {points: 0, status: RE} 31 | points: 50 32 | lsnb10_long_name.cpp: 33 | expected: 34 | 1: {points: 25, status: OK} 35 | 2: {points: 0, status: WA} 36 | 3: {points: 0, status: WA} 37 | 4: {points: 0, status: ML} 38 | points: 25 39 | lsns1_long_name.cpp: 40 | expected: 41 | 1: {points: 25, status: OK} 42 | 2: {points: 0, status: WA} 43 | 3: {points: 0, status: WA} 44 | 4: {points: 0, status: TL} 45 | points: 25 46 | -------------------------------------------------------------------------------- /src/sinol_make/contest_types/oij.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | 3 | from sinol_make import util 4 | from sinol_make.helpers import package_util 5 | from sinol_make.contest_types.default import DefaultContest 6 | 7 | 8 | class OIJContest(DefaultContest): 9 | """ 10 | Contest type for Polish Junior Olympiad in Informatics. 11 | """ 12 | 13 | def get_type(self) -> str: 14 | return "oij" 15 | 16 | def argument_overrides(self, args: argparse.Namespace) -> argparse.Namespace: 17 | """ 18 | Add arguments for features required by OIJ contest 19 | """ 20 | args.export_ocen = True 21 | return args 22 | 23 | def verify_pre_gen(self): 24 | """ 25 | Verify if scores sum up correctly. 26 | """ 27 | config = package_util.get_config() 28 | if 'scores' not in config: 29 | util.exit_with_error("Scores are not defined in config.yml.") 30 | total_score = sum(config['scores'].values()) 31 | total_score_config = 100 if 'sinol_total_score' not in config else config['sinol_total_score'] 32 | 33 | if total_score != total_score_config: 34 | util.exit_with_error(f"Total score in config is {total_score}, but should be {total_score_config}.") 35 | 36 | def verify_tests_order(self): 37 | return True 38 | -------------------------------------------------------------------------------- /tests/commands/init/test_unit.py: -------------------------------------------------------------------------------- 1 | import os 2 | import tempfile 3 | import pytest 4 | 5 | from sinol_make.commands.init import Command 6 | 7 | 8 | def copy_template(rootdir): 9 | template_path = [rootdir, Command.DEFAULT_SUBDIR] 10 | command = Command() 11 | with tempfile.TemporaryDirectory() as tmpdir: 12 | tmp_dir = command.download_template(tmpdir, template_path) 13 | assert os.path.isfile(os.path.join(tmp_dir, 'config.yml')) 14 | 15 | 16 | def test_clones_default_template(request): 17 | # try to avoid connecting to github when cloning example_package 18 | rootdir = str(request.config.rootdir) 19 | git_dir = os.path.join(rootdir, '.git') 20 | if not os.path.exists(git_dir): 21 | # if needed we could take a dependency on gitpython and mock up a repo 22 | pytest.skip(f".git not found in rootdir {rootdir}") 23 | 24 | git_local_url = os.path.join('file://', rootdir) 25 | copy_template(git_local_url) 26 | 27 | 28 | def test_copies_local_template_absolute_path(request): 29 | rootdir_absolute = str(request.config.rootdir) 30 | copy_template(rootdir_absolute) 31 | 32 | 33 | def test_copies_local_template_relative_path(request): 34 | os.chdir(os.path.join(request.config.rootdir, '..')) 35 | rootdir_relative = os.path.relpath(request.config.rootdir, os.getcwd()) 36 | copy_template(rootdir_relative) 37 | -------------------------------------------------------------------------------- /tests/packages/gen/prog/geningen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script generates input tests in parallel. 4 | # Test names are read from file "tests" in the same directory split by spaces. 5 | 6 | function generate() { 7 | start=$1 8 | end=$2 9 | for ((i=start; i "${tests[$i]}" 11 | echo "Generated ${tests[$i]}" 12 | done 13 | } 14 | 15 | cache=$(dirname "$0")/../.cache 16 | mkdir -p "$cache" 17 | g++ "$(dirname "$0")/gen_helper.cpp" -o "$cache"/gen 18 | 19 | cpu_num=$(nproc) 20 | 21 | IFS=' ' 22 | read -a tests <<< "$(cat "$(dirname "$0")"/tests)" 23 | len=${#tests[@]} 24 | 25 | # Strip file names 26 | for ((i=0; i str: 16 | return "icpc" 17 | 18 | def assign_scores(self, groups: List[int]) -> Dict[int, int]: 19 | return {group: 1 for group in groups} 20 | 21 | def get_possible_score(self, groups: List[int], scores: Dict[int, int]) -> int: 22 | return 1 23 | 24 | def get_test_score(self, result: ExecutionResult, time_limit, memory_limit): 25 | if result.Status == Status.OK: 26 | return 1 27 | else: 28 | return 0 29 | 30 | def get_group_score(self, test_scores, group_max_score): 31 | return min(test_scores) 32 | 33 | def get_global_score(self, groups_scores: Dict[int, Dict], global_max_score): 34 | return min(group["points"] for group in groups_scores.values()) 35 | 36 | def min_score_per_test(self): 37 | return 0 38 | 39 | def max_score_per_test(self): 40 | return 1 41 | 42 | def preferred_timetool(self): 43 | return "time" 44 | 45 | def verify_tests_order(self): 46 | return True 47 | -------------------------------------------------------------------------------- /tests/packages/chk/prog/chkchk.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | void print_wrong(char num, char letter) { 6 | if (num == '1' && letter == 'a') 7 | cout << "NOT OK" << endl; 8 | else if (num == '2' && letter == 'a') 9 | cout << "BAD" << endl; 10 | else if (num == '2' && letter == 'b') 11 | cout << "ABCDEF" << endl; 12 | else 13 | cout << "WRONG" << endl; 14 | } 15 | 16 | int main(int argc, char** argv) { 17 | assert(argc == 4); 18 | ifstream in(argv[1]); 19 | ifstream out(argv[2]); 20 | ifstream correct(argv[3]); 21 | 22 | char num = argv[1][6]; 23 | char letter = argv[1][7]; 24 | 25 | int ans, out_ans; 26 | correct >> ans; 27 | out >> out_ans; 28 | 29 | if (ans == -1 && out_ans != -1) { 30 | print_wrong(num, letter); 31 | cout << "Expected -1, got " << out_ans << endl; 32 | return 0; 33 | } 34 | 35 | int n, s = 0; 36 | in >> n; 37 | for (int i = 0; i < n; i++) { 38 | int a; 39 | in >> a; 40 | s += a; 41 | } 42 | 43 | if (out_ans > s) { 44 | print_wrong(num, letter); 45 | cout << "Answer to big" << endl; 46 | return 0; 47 | } 48 | 49 | if (out_ans > s / 2) { 50 | cout << "OK" << endl; 51 | cout << "Answer to big" << endl; 52 | cout << "50" << endl; 53 | return 0; 54 | } 55 | 56 | if (out_ans <= s / 2) { 57 | cout << "OK"; 58 | return 0; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | name = sinol_make 3 | version = attr: sinol_make.__version__ 4 | author = Mateusz Masiarz 5 | author_email = m.masiarz@fri.edu.pl 6 | maintainer = Tomasz Nowak, Mateusz Masiarz 7 | maintainer_email = tomasz.nowak@tonowak.com, m.masiarz@fri.edu.pl 8 | description = CLI tool for creating sio2 task packages 9 | long_description = file: README.md 10 | long_description_content_type = text/markdown 11 | project_urls = 12 | Bug Tracker = https://github.com/sio2project/sinol-make/issues 13 | Homepage = https://github.com/sio2project/sinol-make 14 | classifiers = 15 | Programming Language :: Python :: 3 16 | License :: OSI Approved :: GNU General Public License v3 (GPLv3) 17 | Operating System :: OS Independent 18 | 19 | [options] 20 | packages = find_namespace: 21 | packages_dir = src 22 | include_package_data = True 23 | python_requires = >=3.9 24 | install_requires = 25 | argparse 26 | argcomplete 27 | requests 28 | PyYAML 29 | dictdiffer 30 | importlib-resources 31 | psutil 32 | packaging 33 | 34 | [options.packages.find] 35 | where = src 36 | 37 | [options.extras_require] 38 | tests = 39 | pytest 40 | pytest-cov 41 | pytest-xdist 42 | requests-mock 43 | 44 | [options.entry_points] 45 | console_scripts = 46 | sinol-make = sinol_make:main 47 | sm = sinol_make:main 48 | 49 | [tool:pytest] 50 | testpaths = 51 | tests 52 | markers = 53 | github_runner: Mark tests that require GitHub runner 54 | sio2jail: Mark tests that require working sio2jail 55 | -------------------------------------------------------------------------------- /src/sinol_make/helpers/paths.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | 4 | def get_cache_path(*paths): 5 | """ 6 | Function to get a path in the cache directory. Works the same as os.path.join. 7 | With no arguments, it returns the path to the cache directory. 8 | """ 9 | return os.path.join(os.getcwd(), ".cache", *paths) 10 | 11 | 12 | def get_executables_path(*paths): 13 | """ 14 | Function to get a path in executables directory. Works the same as os.path.join. 15 | With no arguments, it returns the path to the executables directory. 16 | """ 17 | return os.path.join(get_cache_path("executables"), *paths) 18 | 19 | 20 | def get_compilation_log_path(*paths): 21 | """ 22 | Function to get a path in compilation log directory. Works the same as os.path.join. 23 | With no arguments, it returns the path to the compilation log directory. 24 | """ 25 | return os.path.join(get_cache_path("compilation"), *paths) 26 | 27 | 28 | def get_executions_path(*paths): 29 | """ 30 | Function to get a path in executions directory. Works the same as os.path.join. 31 | With no arguments, it returns the path to the executions directory. 32 | """ 33 | return os.path.join(get_cache_path("executions"), *paths) 34 | 35 | 36 | def get_chkwer_path(*paths): 37 | """ 38 | Function to get a path in chkwer directory. In this directory chkwer will generate outputs. 39 | Works the same as os.path.join. With no arguments, it returns the path to the chkwer directory. 40 | """ 41 | return os.path.join(get_cache_path("chkwer"), *paths) 42 | -------------------------------------------------------------------------------- /tests/contest_types/test_default.py: -------------------------------------------------------------------------------- 1 | from sinol_make import contest_types 2 | from sinol_make.structs.status_structs import ExecutionResult 3 | 4 | 5 | def test_get_test_score(): 6 | contest = contest_types.DefaultContest() 7 | result = ExecutionResult("OK", 0, 0, 42) 8 | assert contest.get_test_score(result, 1000, 256) == 42 9 | 10 | 11 | def test_get_group_score(): 12 | contest = contest_types.DefaultContest() 13 | assert contest.get_group_score([100, 100, 100], 100) == 100 14 | assert contest.get_group_score([100, 100, 100], 200) == 200 15 | assert contest.get_group_score([50, 100, 100], 60) == 30 16 | assert contest.get_group_score([50, 100, 100], 100) == 50 17 | assert contest.get_group_score([0, 10, 20], 100) == 0 18 | assert contest.get_group_score([10, 3, 5], 50) == 2 19 | 20 | 21 | def test_assign_scores(): 22 | contest = contest_types.DefaultContest() 23 | assert contest.assign_scores([0, 1, 2, 3]) == {0: 0, 1: 33, 2: 33, 3: 34} 24 | assert contest.assign_scores([1, 2, 3]) == {1: 33, 2: 33, 3: 34} 25 | assert contest.assign_scores([0, 1, 2]) == {0: 0, 1: 50, 2: 50} 26 | 27 | 28 | def test_get_possible_score(): 29 | contest = contest_types.DefaultContest() 30 | assert contest.get_possible_score([0, 1, 2, 3], {0: 0, 1: 33, 2: 33, 3: 34}) == 100 31 | assert contest.get_possible_score([1, 2, 3], {1: 33, 2: 33, 3: 34}) == 100 32 | assert contest.get_possible_score([0, 2], {0: 0, 1: 50, 2: 50}) == 50 33 | 34 | 35 | def test_get_global_score(): 36 | contest = contest_types.DefaultContest() 37 | assert contest.get_global_score({1: {"points": 10}, 2: {"points": 20}}, 100) == 30 38 | -------------------------------------------------------------------------------- /tests/helpers/test_compile.py: -------------------------------------------------------------------------------- 1 | import os 2 | import pytest 3 | import tempfile 4 | 5 | from sinol_make.helpers.cache import save_compiled, check_compiled, create_cache_dirs 6 | from tests import util 7 | from tests.fixtures import create_package 8 | from tests.commands.gen.test_integration import simple_run 9 | 10 | 11 | def test_compilation_caching(): 12 | with tempfile.TemporaryDirectory() as tmpdir: 13 | os.chdir(tmpdir) 14 | create_cache_dirs() 15 | with open(os.path.join(os.getcwd(), "test.txt"), "w") as f: 16 | f.write("Test data") 17 | with open(os.path.join(os.getcwd(), "test.e"), "w") as f: 18 | f.write("") 19 | 20 | assert check_compiled(os.path.join(os.getcwd(), "test.txt"), "default", False) is None 21 | save_compiled(os.path.join(os.getcwd(), "test.txt"), 22 | os.path.join(os.getcwd(), "test.e"), "default", False) 23 | assert check_compiled(os.path.join(os.getcwd(), "test.txt"), "default", False) == \ 24 | os.path.join(os.getcwd(), "test.e") 25 | 26 | 27 | @pytest.mark.parametrize("create_package", [util.get_shell_ingen_pack_path()], indirect=True) 28 | def test_large_failed_output(create_package): 29 | """ 30 | Test `ingen` command with large failed output. 31 | """ 32 | with open(os.path.join(create_package, "prog", "geningen2.cpp"), "r") as f: 33 | code = f.read() 34 | code = code.replace("<<", "<") 35 | with open(os.path.join(create_package, "prog", "geningen2.cpp"), "w") as f: 36 | f.write(code) 37 | 38 | with pytest.raises(SystemExit): 39 | simple_run(["prog/geningen2.cpp"]) 40 | -------------------------------------------------------------------------------- /tests/packages/vso/prog/vso4.cpp: -------------------------------------------------------------------------------- 1 | // First test TL, 2 | // second test ML, 3 | // third test RE, 4 | // fourth test WA, 5 | // other OK. 6 | // This group should have status TL. 7 | 8 | #include 9 | 10 | using namespace std; 11 | using namespace std::chrono; 12 | 13 | int rnd() { 14 | return rand() % 100; 15 | } 16 | 17 | __attribute__((optimize("O0"))) 18 | void s2j_wait(long long instructions) { 19 | instructions /= 3; // Every pass of the loop below takes 3 instructions. 20 | while (instructions > 0) 21 | --instructions; 22 | } 23 | 24 | int wait(int secs) { 25 | if (getenv("UNDER_SIO2JAIL") != NULL) { 26 | s2j_wait((long long)secs * 2'000'000'000); 27 | return 0; 28 | } 29 | auto start = high_resolution_clock::now(); 30 | int i = 0; 31 | while (duration_cast(high_resolution_clock::now() - start).count() < secs) 32 | i++; 33 | return i; 34 | } 35 | 36 | int main() { 37 | int a, b; 38 | cin >> a >> b; 39 | if (a == 1 && b == 1) { 40 | int i = wait(3); 41 | cout << a + b + i - i; 42 | } 43 | else if (a == 1 && b == 2) { 44 | vector v; 45 | for (int i = 0; i <= 10000; i++) { 46 | int *tmp = new int[1000]; 47 | for (int j = 0; j <= 1000; j++) 48 | tmp[j] = rnd(); 49 | v.push_back(tmp); 50 | } 51 | cout << a + b; 52 | } 53 | else if (a == 1 && b == 3) { 54 | int c = 0; 55 | cout << (a + b) / c; 56 | return 1; 57 | } 58 | else if (a == 1 && b == 4) { 59 | cout << "1"; 60 | } 61 | else { 62 | cout << a + b; 63 | } 64 | return 0; 65 | } 66 | -------------------------------------------------------------------------------- /tests/packages/vso/prog/vso7.cpp: -------------------------------------------------------------------------------- 1 | // First test is WA, 2 | // second test is OK, 3 | // third test is TL, 4 | // fourth test is RE, 5 | // fifth test is ML. 6 | // Group status should be TL. 7 | 8 | #include 9 | 10 | using namespace std; 11 | using namespace std::chrono; 12 | 13 | int rnd() { 14 | return rand() % 100; 15 | } 16 | 17 | __attribute__((optimize("O0"))) 18 | void s2j_wait(long long instructions) { 19 | instructions /= 3; // Every pass of the loop below takes 3 instructions. 20 | while (instructions > 0) 21 | --instructions; 22 | } 23 | 24 | int wait(int secs) { 25 | if (getenv("UNDER_SIO2JAIL") != NULL) { 26 | s2j_wait((long long)secs * 2'000'000'000); 27 | return 0; 28 | } 29 | auto start = high_resolution_clock::now(); 30 | int i = 0; 31 | while (duration_cast(high_resolution_clock::now() - start).count() < secs) 32 | i++; 33 | return i; 34 | } 35 | 36 | int main() { 37 | int a, b; 38 | cin >> a >> b; 39 | if (a == 1 && b == 1) { 40 | cout << a + b - 1; 41 | } 42 | else if (a == 1 && b == 2) { 43 | cout << a + b; 44 | } 45 | else if (a == 1 && b == 3) { 46 | int i = wait(3); 47 | cout << a + b + i - i; 48 | } 49 | else if (a == 1 && b == 4) { 50 | int c = 0; 51 | cout << (a + b) / c; 52 | } 53 | else if (a == 1 && b == 5) { 54 | vector v; 55 | for (int i = 0; i <= 10000; i++) { 56 | int *tmp = new int[1000]; 57 | for (int j = 0; j <= 1000; j++) 58 | tmp[j] = rnd(); 59 | v.push_back(tmp); 60 | } 61 | cout << a + b; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /tests/commands/chkwer/test_integration.py: -------------------------------------------------------------------------------- 1 | from sinol_make import configure_parsers 2 | from sinol_make.commands.chkwer import Command 3 | from tests import util 4 | from tests.fixtures import * 5 | 6 | 7 | def run(arguments=None): 8 | util.create_ins_outs(os.getcwd()) 9 | if arguments is None: 10 | arguments = [] 11 | parser = configure_parsers() 12 | args = parser.parse_args(["chkwer"] + arguments) 13 | command = Command() 14 | command.run(args) 15 | 16 | 17 | @pytest.mark.parametrize("create_package", [util.get_checker_package_path()], indirect=True) 18 | def test_simple(create_package): 19 | """ 20 | Test `chkwer` command withouth any arguments. 21 | """ 22 | run() 23 | 24 | 25 | @pytest.mark.parametrize("create_package", [util.get_simple_package_path()], indirect=True) 26 | def test_no_checker(create_package, capsys): 27 | """ 28 | The command should fail because there is no checker. 29 | """ 30 | with pytest.raises(SystemExit): 31 | run() 32 | out = capsys.readouterr().out 33 | assert "Checker not found." in out 34 | 35 | 36 | @pytest.mark.parametrize("create_package", [util.get_checker_package_path()], indirect=True) 37 | def test_broken_model_solution(create_package, capsys): 38 | """ 39 | The command should fail because the model solution doesn't receive max points. 40 | """ 41 | os.unlink(os.path.join(os.getcwd(), "prog", "chk.cpp")) 42 | os.rename(os.path.join(os.getcwd(), "prog", "chk2.cpp"), os.path.join(os.getcwd(), "prog", "chk.cpp")) 43 | with pytest.raises(SystemExit): 44 | run() 45 | out = capsys.readouterr().out 46 | assert "Model solution didn't score maximum points." in out 47 | -------------------------------------------------------------------------------- /src/sinol_make/task_type/normal.py: -------------------------------------------------------------------------------- 1 | from typing import Tuple 2 | 3 | from sinol_make.interfaces.Errors import CheckerException 4 | from sinol_make.structs.status_structs import ExecutionResult, Status 5 | from sinol_make.task_type import BaseTaskType 6 | 7 | 8 | class NormalTaskType(BaseTaskType): 9 | @classmethod 10 | def identify(cls) -> Tuple[bool, int]: 11 | return True, 1 12 | 13 | @staticmethod 14 | def name() -> str: 15 | return "normal" 16 | 17 | def run(self, time_limit, hard_time_limit, memory_limit, input_file_path, output_file_path, answer_file_path, 18 | result_file_path, executable, execution_dir) -> ExecutionResult: 19 | with open(input_file_path, "r") as inf, open(output_file_path, "w") as outf: 20 | result = self.executor.execute([f'"{executable}"'], time_limit, hard_time_limit, memory_limit, 21 | result_file_path, executable, execution_dir, stdin=inf, stdout=outf) 22 | if result.Time > time_limit: 23 | result.Status = Status.TL 24 | elif result.Memory > memory_limit: 25 | result.Status = Status.ML 26 | elif result.Status == Status.OK: 27 | try: 28 | correct, points, comment, _ = self.check_output(input_file_path, output_file_path, answer_file_path) 29 | result.Points = float(points) 30 | result.Comment = comment 31 | if not correct: 32 | result.Status = Status.WA 33 | except CheckerException as e: 34 | result.Status = Status.RE 35 | result.Error = str(e) 36 | result.Fail = True 37 | return result 38 | -------------------------------------------------------------------------------- /tests/commands/init/test_integration.py: -------------------------------------------------------------------------------- 1 | import os 2 | import pytest 3 | 4 | from sinol_make import configure_parsers 5 | from sinol_make.commands.init import Command 6 | from tests.fixtures import temp_workdir 7 | 8 | 9 | @pytest.mark.parametrize("temp_workdir", [''], indirect=True) 10 | def test_init_clones_default_template(capsys, request, temp_workdir): 11 | """ 12 | Test `init` command. 13 | """ 14 | parser = configure_parsers() 15 | args = ["init", "xyz"] 16 | 17 | # try to avoid connecting to github when cloning example_package 18 | rootdir = str(request.config.rootdir) 19 | git_dir = os.path.join(rootdir, '.git') 20 | if os.path.exists(git_dir): 21 | git_local_url = os.path.join('file://', rootdir) 22 | args.extend(["-t", git_local_url, "example_package"]) 23 | else: 24 | # copy from root directory instead of cloning 25 | # if needed we could take a dependency on gitpython and mock up a repo 26 | args.extend(["-t", rootdir, "example_package"]) 27 | 28 | args = parser.parse_args(args) 29 | command = Command() 30 | command.run(args) 31 | out = capsys.readouterr().out 32 | assert 'Successfully created task "xyz"' in out 33 | 34 | # Check presence of some files: 35 | expected_files = ['config.yml', 'prog/xyz.cpp', 'prog/oi.h'] 36 | 37 | for file in expected_files: 38 | assert os.path.isfile(os.path.join(os.getcwd(), file)) 39 | 40 | # Check if task id is correctly set 41 | with open(os.path.join(os.getcwd(), 'config.yml')) as config_file: 42 | config_file_data = config_file.read() 43 | assert "sinol_task_id: xyz" in config_file_data 44 | assert "sinol_task_id: abc" not in config_file_data 45 | -------------------------------------------------------------------------------- /src/sinol_make/structs/chkwer_structs.py: -------------------------------------------------------------------------------- 1 | import os 2 | from dataclasses import dataclass 3 | from typing import Dict 4 | 5 | from sinol_make.helpers import package_util 6 | 7 | 8 | @dataclass 9 | class TestResult: 10 | test_path: str 11 | test_name: str 12 | test_group: str 13 | run: bool 14 | points: int 15 | ok: bool 16 | comment: str 17 | stderr: str 18 | 19 | def __init__(self, test_path, task_id): 20 | self.test_path = test_path 21 | self.test_name = os.path.split(test_path)[-1] 22 | self.test_group = str(package_util.get_group(self.test_path, task_id)) 23 | 24 | self.comment = "" 25 | self.points = 0 26 | self.ok = False 27 | self.run = False 28 | self.stderr = "" 29 | 30 | def set_results(self, points, ok, output, stderr): 31 | self.run = True 32 | self.points = points 33 | self.ok = ok 34 | self.comment = output 35 | self.stderr = stderr 36 | 37 | 38 | @dataclass 39 | class TableData: 40 | """ 41 | Data used for printing table with verification results. 42 | """ 43 | 44 | # Dictionary with test path as key and verification result as value. 45 | results: Dict[str, TestResult] 46 | 47 | # Number of executions finished 48 | i: int 49 | 50 | # Task id 51 | task_id: str 52 | 53 | # Max score per test for this contest type 54 | max_score: int 55 | 56 | 57 | @dataclass 58 | class ChkwerExecution: 59 | in_test_path: str 60 | in_test_name: str 61 | out_test_path: str 62 | checker_exe: str 63 | model_exe: str 64 | 65 | 66 | @dataclass 67 | class RunResult: 68 | test_path: str 69 | ok: bool 70 | points: int 71 | comment: str 72 | stderr: str 73 | -------------------------------------------------------------------------------- /example_package/prog/__ID__ingen.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "oi.h" 3 | using namespace std; 4 | 5 | // Change this function to generate one test for stresstesting. 6 | // The script prog/__ID__ingen.sh in 10 seconds generates 7 | // as much tests as possible and compares the outputs 8 | // of the model solution and brute solution. 9 | // The tests shouldn't be very big, but should be able to cover edge cases. 10 | void generate_one_stresstest(oi::Random &rng) { 11 | cout << rng.randSInt(1, 10) << ' ' << rng.randSInt(1, 10) << endl; 12 | } 13 | 14 | // Change this function to create a test with the given name. 15 | // The lists of tests to generate needs to be written in prog/__ID__ingen.sh 16 | void generate_proper_test(string test_name, oi::Random &rng) { 17 | if (test_name == "0a") 18 | cout << "0 1" << endl; 19 | else if (test_name == "1a") 20 | cout << rng.randSInt(5, 1'000) << ' ' << rng.randSInt(5, 1'000) << endl; 21 | else if (test_name == "2a") 22 | cout << "2 2" << endl; 23 | else { 24 | cerr << "Unrecognized test_name = " << test_name << endl; 25 | exit(1); 26 | } 27 | } 28 | 29 | int main(int argc, char *argv[]) { 30 | if (argc == 3 && string(argv[1]) == "stresstest") { 31 | unsigned int seed = atoi(argv[2]); 32 | oi::Random rng(seed); 33 | generate_one_stresstest(rng); 34 | return 0; 35 | } 36 | if (argc != 2) { 37 | cerr << "Run prog/__ID__ingen.sh to stresstest and create proper tests." << endl; 38 | exit(1); 39 | } 40 | string test_name = argv[1]; 41 | unsigned int seed = (unsigned int) hash{}(test_name); 42 | oi::Random rng(seed); 43 | cerr << "Generating test " << test_name << "..." << endl; 44 | generate_proper_test(test_name, rng); 45 | } 46 | -------------------------------------------------------------------------------- /example_package/prog/__ID__inwer.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "oi.h" 3 | using namespace std; 4 | 5 | int main() { 6 | oi::Scanner in(stdin, oi::PL); 7 | 8 | // Change this code to read and validate the input. 9 | int n = in.readInt(0, 1'000); 10 | in.readSpace(); 11 | int m = in.readInt(0, 1'000); 12 | in.readEoln(); 13 | in.readEof(); 14 | assert(n > 0 || m > 0); 15 | 16 | // Change this code to have functions which return 17 | // whether the test satisfies a given subtask. 18 | auto is_subtask1 = [&]() -> bool { 19 | return n >= 0 && m >= 0; 20 | }; 21 | auto is_subtask2 = [&]() -> bool { 22 | return n >= 5 && m >= 5; 23 | }; 24 | 25 | // Change this code to have functions which return 26 | // whether the test is exactly the same as 27 | // the sample tests in the statement. 28 | auto is_0a = [&]() -> bool { 29 | return n == 0 && m == 1; 30 | }; 31 | auto is_1ocen = [&]() -> bool { 32 | return n == 1000 && m == 1000; 33 | }; 34 | 35 | map subtasks = { 36 | {1, is_subtask1()}, 37 | {2, is_subtask2()}, 38 | }; 39 | string subtasks_s; 40 | for (auto [subtask_id, is_valid] : subtasks) 41 | subtasks_s += is_valid ? to_string(subtask_id) : string("-"); 42 | 43 | map sample_tests = { 44 | {"0a", is_0a()}, 45 | {"1ocen", is_1ocen()}, 46 | }; 47 | string sample_test_s = "-"; 48 | for (auto [name, is_valid] : sample_tests) 49 | if (is_valid) 50 | sample_test_s = name; 51 | 52 | cout << "OK " 53 | << "n = " << setw(4) << n << ", " 54 | << "m = " << setw(4) << m << ", " 55 | << "subtasks = " << subtasks_s << ", sample test = " << sample_test_s << endl; 56 | } 57 | -------------------------------------------------------------------------------- /example_package/prog/__ID__ingen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script first stresstests the model solution for 10 seconds 4 | # and if it passes, it will generate the proper tests. 5 | # To generate both types of tests, it executes ingen.cpp and passes it some arguments. 6 | # The `test_ids` variable needs to have a manually written list of all proper tests. 7 | 8 | prog_dir="$(realpath "$(dirname "$0")")" 9 | cache_dir="$prog_dir/../.cache" 10 | mkdir -p "$cache_dir" 11 | script_name="$(basename "$0")" 12 | task_id=${script_name%ingen.sh} 13 | gen_exe="$cache_dir/${task_id}ingen" 14 | sol_exe="$cache_dir/${task_id}solution" 15 | slo_exe="$cache_dir/${task_id}slow" 16 | stresstest_seconds=10 17 | function compile_cpp { 18 | g++ -std=c++23 -O3 -lm -Werror -Wall -Wextra -Wshadow -Wconversion -Wno-unused-result -Wfloat-equal "$1" -o "$2" \ 19 | || exit 1 20 | } 21 | 22 | # Change the list of tests to generate and (if needed) the paths of solutions. 23 | test_ids="0a 1a 2a" 24 | compile_cpp "$prog_dir/${task_id}ingen.cpp" "$gen_exe" 25 | compile_cpp "$prog_dir/${task_id}.cpp" "$sol_exe" 26 | compile_cpp "$prog_dir/${task_id}s.cpp" "$slo_exe" 27 | 28 | for (( i=0, SECONDS=0; SECONDS < stresstest_seconds; i++ )); do 29 | in_test="$cache_dir/input.in" 30 | slo_out="$cache_dir/slo.out" 31 | sol_out="$cache_dir/sol.out" 32 | printf "Running stresstest $i\r" 33 | "$gen_exe" stresstest $i > "$in_test" || { echo "Failed to generate test $i"; exit 1; } 34 | "$slo_exe" < "$in_test" > "$slo_out" || { echo "Brute crashed on test $i"; exit 1; } 35 | "$sol_exe" < "$in_test" > "$sol_out" || { echo "Solution crashed on test $i"; exit 1; } 36 | diff "$slo_out" "$sol_out" -w > /dev/null || { echo "Outputs differ on test $i"; exit 1; } 37 | done 38 | echo "Stresstest passed with $i tests" 39 | 40 | for test in $test_ids; do 41 | "$gen_exe" "$test" > "$prog_dir/../in/${task_id}${test}.in" || { echo "Failed to generate test $test"; exit 1; } 42 | done 43 | -------------------------------------------------------------------------------- /tests/packages/two_interactive/prog/twosoc.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | void write(int n, FILE *out) { 7 | fprintf(out, "%d\n", n); 8 | fflush(out); 9 | } 10 | 11 | void verdict(bool ok, string comment, int score) { 12 | cout << (ok ? "OK" : "WA") << "\n" << comment << "\n" << score << "\n"; 13 | exit(0); 14 | } 15 | 16 | void wrong(string comment, int score = 0) { 17 | verdict(false, comment, score); 18 | } 19 | 20 | void accept(string comment, int score) { 21 | verdict(true, comment, score); 22 | } 23 | 24 | int main(int argc, char *argv[]) { 25 | assert(argc == 6); 26 | int num_processes = atoi(argv[1]); 27 | assert(num_processes == 2); 28 | 29 | FILE *in1 = fdopen(atoi(argv[2]), "r"); 30 | FILE *out1 = fdopen(atoi(argv[3]), "w"); 31 | assert(in1 != NULL); 32 | assert(out1 != NULL); 33 | 34 | FILE *in2 = fdopen(atoi(argv[4]), "r"); 35 | FILE *out2 = fdopen(atoi(argv[5]), "w"); 36 | assert(in2 != NULL); 37 | assert(out2 != NULL); 38 | 39 | int n; 40 | cin >> n; 41 | write(n, out1); 42 | 43 | int ans1, ans2; 44 | fscanf(in1, "%d", &ans1); 45 | if (feof(in1) || ferror(in1)) { 46 | wrong("Process 0 exited to early"); 47 | } 48 | 49 | if (ans1 != n + 42) { 50 | wrong("Wrong answer on first interaction"); 51 | } 52 | 53 | write(ans1, out2); 54 | fscanf(in2, "%d", &ans2); 55 | if (feof(in2) || ferror(in2)) { 56 | wrong("Process 1 exited to early"); 57 | } 58 | 59 | if (ans2 != ans1 / 3) { 60 | accept("Wrong answer on second interaction", 50); 61 | } 62 | write(ans2, out1); 63 | 64 | fscanf(in1, "%d", &ans1); 65 | if (feof(in1) || ferror(in1)) { 66 | wrong("Process 0 exited to early"); 67 | } 68 | if (ans1 != ans2 * 2) { 69 | accept("Wrong answer on third interaction", 75); 70 | } 71 | accept("", 100); 72 | } 73 | -------------------------------------------------------------------------------- /src/sinol_make/contest_types/oi.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | 3 | from sinol_make import util 4 | from sinol_make.helpers import package_util 5 | from sinol_make.structs.status_structs import ExecutionResult 6 | from sinol_make.contest_types.default import DefaultContest 7 | 8 | 9 | class OIContest(DefaultContest): 10 | """ 11 | Contest type for Polish Olympiad in Informatics. 12 | """ 13 | 14 | def get_type(self) -> str: 15 | return "oi" 16 | 17 | def argument_overrides(self, args: argparse.Namespace) -> argparse.Namespace: 18 | """ 19 | Add arguments for features required by OI contest 20 | """ 21 | args.export_ocen = True 22 | return args 23 | 24 | def get_test_score(self, result: ExecutionResult, time_limit, memory_limit): 25 | """ 26 | Full score if took less than half of limit, otherwise linearly decreasing to 1. 27 | This function is copied from `oioioi` code. 28 | https://github.com/sio2project/oioioi/blob/40a377d3f2d5cd9c94d01f03e197501ce4aab597/oioioi/programs/utils.py#L107 29 | """ 30 | if result.Status != 'OK': 31 | return 0 32 | if result.Points == 0: 33 | return 0 34 | elif result.Time <= time_limit / 2.0: 35 | return result.Points 36 | else: 37 | return 1 + int((result.Points - 1) * ((time_limit - result.Time) / (time_limit / 2.0))) 38 | 39 | def verify_pre_gen(self): 40 | """ 41 | Verify if scores sum up to 100. 42 | """ 43 | config = package_util.get_config() 44 | if 'scores' not in config: 45 | util.exit_with_error("Scores are not defined in config.yml.") 46 | total_score = sum(config['scores'].values()) 47 | if total_score != 100: 48 | util.exit_with_error(f"Total score in config is {total_score}, but should be 100.") 49 | 50 | def allow_per_test_limits(self): 51 | return False 52 | 53 | def verify_tests_order(self): 54 | return True 55 | -------------------------------------------------------------------------------- /src/sinol_make/commands/outgen/outgen_util.py: -------------------------------------------------------------------------------- 1 | import os 2 | import signal 3 | import subprocess 4 | import sys 5 | 6 | import argparse 7 | 8 | from sinol_make import util 9 | from sinol_make.helpers import package_util, compiler, compile 10 | 11 | 12 | def get_correct_solution(task_id): 13 | """ 14 | Returns path to correct solution for given task. 15 | :param task_id: task id, for example abc 16 | :return: path to correct solution or None if not found 17 | """ 18 | correct_solution = package_util.get_files_matching_pattern(task_id, f'{task_id}.*') 19 | if len(correct_solution) == 0: 20 | util.exit_with_error(f'Correct solution for task {task_id} does not exist.') 21 | return correct_solution[0] 22 | 23 | 24 | def compile_correct_solution(solution_path: str, args: argparse.Namespace, compilation_flags='default'): 25 | """ 26 | Compiles correct solution and returns path to compiled executable. 27 | """ 28 | compilers = compiler.verify_compilers(args, [solution_path]) 29 | correct_solution_exe, compile_log_path = compile.compile_file(solution_path, package_util.get_executable(solution_path), compilers, 30 | compilation_flags) 31 | if correct_solution_exe is None: 32 | util.exit_with_error('Failed compilation of correct solution.', 33 | lambda: compile.print_compile_log(compile_log_path)) 34 | else: 35 | print(util.info('Successfully compiled correct solution.')) 36 | 37 | return correct_solution_exe 38 | 39 | 40 | def generate_output(arguments): 41 | """ 42 | Generates output file for given input file. 43 | :param arguments: arguments for output generation (type OutputGenerationArguments) 44 | :return: True if the output was successfully generated, False otherwise 45 | """ 46 | input_test = arguments.input_test 47 | output_test = arguments.output_test 48 | correct_solution_exe = arguments.correct_solution_exe 49 | 50 | input_file = open(input_test, 'r') 51 | output_file = open(output_test, 'w') 52 | process = subprocess.Popen([correct_solution_exe], stdin=input_file, stdout=output_file, preexec_fn=os.setsid) 53 | previous_sigint_handler = signal.getsignal(signal.SIGINT) 54 | 55 | def sigint_handler(signum, frame): 56 | try: 57 | os.killpg(os.getpgid(process.pid), signal.SIGTERM) 58 | except ProcessLookupError: 59 | pass 60 | sys.exit(1) 61 | signal.signal(signal.SIGINT, sigint_handler) 62 | 63 | process.wait() 64 | signal.signal(signal.SIGINT, previous_sigint_handler) 65 | exit_code = process.returncode 66 | input_file.close() 67 | output_file.close() 68 | 69 | return exit_code == 0 70 | -------------------------------------------------------------------------------- /src/sinol_make/commands/gen/__init__.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | 3 | from sinol_make import util 4 | from sinol_make.commands.ingen import Command as IngenCommand 5 | from sinol_make.commands.outgen import Command as OutgenCommand 6 | from sinol_make.helpers import parsers, package_util 7 | from sinol_make.interfaces.BaseCommand import BaseCommand 8 | 9 | 10 | class Command(BaseCommand): 11 | """ 12 | Class for `gen` command. 13 | """ 14 | 15 | def get_name(self): 16 | return "gen" 17 | 18 | def get_short_name(self): 19 | return "g" 20 | 21 | def configure_subparser(self, subparser): 22 | parser = subparser.add_parser( 23 | self.get_name(), 24 | help='Generate input and output files', 25 | description='Generate input files using ingen program ' 26 | '(for example prog/abcingen.cpp for abc task). Whenever ' 27 | 'the new input differs from the previous one, ' 28 | 'the model solution will be used to generate the new output ' 29 | 'file. You can also specify your ingen source ' 30 | 'file which will be used.' 31 | ) 32 | 33 | parser.add_argument('ingen_path', type=str, nargs='?', 34 | help='path to ingen source file, for example prog/abcingen.cpp') 35 | parser.add_argument('-i', '--only-inputs', action='store_true', help='generate input files only') 36 | parser.add_argument('-o', '--only-outputs', action='store_true', help='generate output files only') 37 | parsers.add_cpus_argument(parser, 'number of cpus to use to generate output files') 38 | parser.add_argument('-n', '--no-validate', default=False, action='store_true', 39 | help='do not validate test contents') 40 | parsers.add_fsanitize_argument(parser) 41 | parsers.add_compilation_arguments(parser) 42 | return parser 43 | 44 | def run(self, args: argparse.Namespace): 45 | args = util.init_package_command(args) 46 | 47 | self.args = args 48 | self.ins = args.only_inputs 49 | self.outs = args.only_outputs 50 | self.task_type = package_util.get_task_type_cls() 51 | # If no arguments are specified, generate both input and output files. 52 | if not self.ins and not self.outs: 53 | self.ins = True 54 | self.outs = True 55 | 56 | if self.ins: 57 | command = IngenCommand() 58 | command.run(args) 59 | 60 | if not self.task_type.run_outgen(): 61 | print(util.warning("Outgen is not supported for this task type.")) 62 | return 63 | 64 | if self.outs: 65 | command = OutgenCommand() 66 | command.run(args) 67 | -------------------------------------------------------------------------------- /src/sinol_make/commands/chkwer/chkwer_util.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from io import StringIO 3 | 4 | from sinol_make import util 5 | from sinol_make.commands.inwer.inwer_util import sort_tests 6 | from sinol_make.structs.chkwer_structs import TableData 7 | 8 | def print_view(term_width, term_height, table_data: TableData, args): 9 | """ 10 | Prints current results of test verification. 11 | """ 12 | 13 | previous_stdout = sys.stdout 14 | new_stdout = StringIO() 15 | sys.stdout = new_stdout 16 | 17 | results = table_data.results 18 | column_lengths = [0, len('Points') + 1, 0] 19 | tests = [] 20 | for result in results.values(): 21 | column_lengths[0] = max(column_lengths[0], len(result.test_name)) 22 | tests.append(result.test_path) 23 | tests = sort_tests(tests, table_data.task_id) 24 | 25 | # 6 is for " | " between columns, 3 for margin. 26 | column_lengths[2] = max(10, term_width - column_lengths[0] - column_lengths[1] - 6 - 3) 27 | margin = " " 28 | 29 | def print_line_separator(): 30 | res = "-" * (column_lengths[0] + 3) + "+" + "-" * (column_lengths[1] + 1) + "+" 31 | res += "-" * (term_width - len(res) - 1) 32 | print(res) 33 | 34 | print_line_separator() 35 | 36 | print(margin + "Test".ljust(column_lengths[0]) + " | " + "Points" + " | " + "Comment") 37 | print_line_separator() 38 | 39 | last_group = None 40 | for test_path in tests: 41 | result = results[test_path] 42 | if last_group is not None and last_group != result.test_group: 43 | print_line_separator() 44 | last_group = result.test_group 45 | print(margin + result.test_name.ljust(column_lengths[0]) + " | ", end='') 46 | 47 | if result.run: 48 | if result.ok: 49 | if result.points == table_data.max_score: 50 | print(util.info(str(result.points).ljust(column_lengths[1] - 1)), end='') 51 | else: 52 | print(util.warning(str(result.points).ljust(column_lengths[1] - 1)), end='') 53 | else: 54 | print(util.error(str(result.points).ljust(column_lengths[1] - 1)), end='') 55 | else: 56 | print(util.warning("...".ljust(column_lengths[1] - 1)), end='') 57 | print(" | ", end='') 58 | 59 | output = [] 60 | if result.run: 61 | if result.comment: 62 | print(result.comment) 63 | else: 64 | print(util.color_gray("No comment")) 65 | 66 | print_line_separator() 67 | 68 | if args.cerr: 69 | for test_path in tests: 70 | result = results[test_path] 71 | print(util.bold(f"Stderr on {result.test_name}: ") + result.stderr) 72 | print() 73 | print() 74 | 75 | sys.stdout = previous_stdout 76 | return new_stdout.getvalue().splitlines(), None, "Use arrows to move." 77 | -------------------------------------------------------------------------------- /src/sinol_make/helpers/parsers.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import argparse 3 | 4 | from sinol_make import util, sio2jail 5 | from sinol_make.helpers import compiler 6 | 7 | 8 | def add_compilation_arguments(parser: argparse.ArgumentParser): 9 | if sys.platform == 'darwin': 10 | gcc_versions = 'gcc-10, gcc-11, gcc-12, gcc-13, gcc-14' 11 | gpp_versions = 'g++-10, g++-11, g++-12, g++-13, g++-14' 12 | else: 13 | gcc_versions = 'gcc' 14 | gpp_versions = 'g++' 15 | 16 | parser.add_argument('--c-compiler-path', dest='c_compiler_path', type=str, 17 | default=compiler.get_c_compiler_path(), help=f'C compiler to use (default: {gcc_versions})') 18 | parser.add_argument('--cpp-compiler-path', dest='cpp_compiler_path', type=str, 19 | default=compiler.get_cpp_compiler_path(), help=f'C++ compiler to use (default: {gpp_versions})') 20 | parser.add_argument('--python-interpreter-path', dest='python_interpreter_path', type=str, 21 | default=compiler.get_python_interpreter_path(), 22 | help='Python interpreter to use (default: python3)') 23 | # Java is not currently supported by sinol-make 24 | # parser.add_argument('--java-compiler-path', dest='java_compiler_path', type=str, 25 | # default=compiler.get_java_compiler_path(), help='Java compiler to use (default: javac)') 26 | parser.add_argument('--compile-mode', '-C', dest='compile_mode', choices=['default', 'oioioi', 'weak', 'd', 'o', 'w'], 27 | help='Warning flag groups used to compile C/C++ files. Available options:\n' 28 | ' default / d - uses default flags: \n' 29 | ' (-Wshadow -Wconversion -Wno-unused-result -Wfloat-equal) + oioioi flags\n' 30 | ' oioioi / o - uses the same flags as oioioi:\n' 31 | ' (-Wall -Wno-unused-result -Werror)' 32 | ' weak / w - disable all warning flags during C and C++ compilation', default='default') 33 | 34 | 35 | def add_cpus_argument(parser: argparse.ArgumentParser, help: str): 36 | parser.add_argument('-c', '--cpus', type=int, 37 | help=f'{help} ' 38 | f'(default: {util.default_cpu_count()})', 39 | default=util.default_cpu_count()) 40 | 41 | 42 | def add_fsanitize_argument(parser: argparse.ArgumentParser): 43 | parser.add_argument('-f', '--fsanitize', default=False, action='store_true', 44 | help='Use -fsanitize=address,undefined for compilation. Warning: this may fail on some ' 45 | 'systems. Tof fix this, run `sudo sysctl vm.mmap_rnd_bits = 28`.') 46 | 47 | 48 | def add_time_tool_argument(parser: argparse.ArgumentParser): 49 | default_timetool = 'sio2jail' if sio2jail.sio2jail_supported() else 'time' 50 | parser.add_argument('-T', '--time-tool', dest='time_tool', choices=['sio2jail', 'time'], 51 | help=f'tool to measure time and memory usage (default: {default_timetool})') 52 | -------------------------------------------------------------------------------- /src/sinol_make/structs/cache_structs.py: -------------------------------------------------------------------------------- 1 | import os 2 | from dataclasses import dataclass 3 | from typing import Dict 4 | 5 | import yaml 6 | 7 | from sinol_make.helpers import paths 8 | 9 | from sinol_make.structs.status_structs import ExecutionResult 10 | 11 | 12 | @dataclass 13 | class CacheTest: 14 | # Time limit when this solution was cached 15 | time_limit: int 16 | # Memory limit when this solution was cached 17 | memory_limit: int 18 | # Time tool used when this solution was cached 19 | time_tool: str 20 | # Cached result 21 | result: ExecutionResult 22 | 23 | def __init__(self, time_limit=0, memory_limit=0, time_tool="", result=None): 24 | if result is None: 25 | result = ExecutionResult() 26 | self.time_limit = time_limit 27 | self.memory_limit = memory_limit 28 | self.time_tool = time_tool 29 | self.result = result 30 | 31 | def to_dict(self) -> Dict: 32 | return { 33 | "time_limit": self.time_limit, 34 | "memory_limit": self.memory_limit, 35 | "time_tool": self.time_tool, 36 | "result": self.result.to_dict() 37 | } 38 | 39 | 40 | @dataclass 41 | class CacheFile: 42 | # md5sum of solution 43 | md5sum: str 44 | # Path to the executable 45 | executable_path: str 46 | # Compilation flags used 47 | compilation_flags: str 48 | # Whether -fsanitize=undefined,address was used 49 | sanitizers: bool 50 | # Test results 51 | tests: Dict[str, CacheTest] 52 | 53 | def __init__(self, md5sum="", executable_path="", compilation_flags="default", sanitizers=False, tests=None): 54 | if tests is None: 55 | tests = {} 56 | self.md5sum = md5sum 57 | self.executable_path = executable_path 58 | self.compilation_flags = compilation_flags 59 | self.sanitizers = sanitizers 60 | self.tests = tests 61 | 62 | def to_dict(self) -> Dict: 63 | return { 64 | "md5sum": self.md5sum, 65 | "executable_path": self.executable_path, 66 | "compilation_flags": self.compilation_flags, 67 | "sanitizers": self.sanitizers, 68 | "tests": {k: v.to_dict() for k, v in self.tests.items()} 69 | } 70 | 71 | @staticmethod 72 | def from_dict(dict) -> 'CacheFile': 73 | return CacheFile( 74 | md5sum=dict.get("md5sum", ""), 75 | executable_path=dict.get("executable_path", ""), 76 | compilation_flags=dict.get("compilation_flags", "default"), 77 | sanitizers=dict.get("sanitizers", False), 78 | tests={k: CacheTest( 79 | time_limit=v["time_limit"], 80 | memory_limit=v["memory_limit"], 81 | time_tool=v["time_tool"], 82 | result=ExecutionResult.from_dict(v["result"]) 83 | ) for k, v in dict.get("tests", {}).items()} 84 | ) 85 | 86 | def save(self, solution_path: str): 87 | with open(paths.get_cache_path("md5sums", os.path.basename(solution_path)), 'w') as cache_file: 88 | yaml.dump(self.to_dict(), cache_file) 89 | -------------------------------------------------------------------------------- /tests/commands/export/util.py: -------------------------------------------------------------------------------- 1 | import os 2 | import argparse 3 | 4 | from sinol_make.helpers import compiler 5 | from sinol_make.commands.export import Command 6 | from sinol_make.helpers import package_util 7 | 8 | 9 | def get_command(): 10 | command = Command() 11 | command.task_id = package_util.get_task_id() 12 | command.args = argparse.Namespace( 13 | compile_mode='default', 14 | c_compiler_path=compiler.get_c_compiler_path(), 15 | cpp_compiler_path=compiler.get_cpp_compiler_path(), 16 | python_interpreter_path=compiler.get_python_interpreter_path(), 17 | java_compiler_path=compiler.get_java_compiler_path(), 18 | ) 19 | command.export_dir = os.path.join(os.getcwd(), "export") 20 | if not os.path.exists(command.export_dir): 21 | os.mkdir(command.export_dir) 22 | 23 | return command 24 | 25 | 26 | def assert_configs_equal(path1, path2): 27 | with open(os.path.join(path1, "config.yml"), "r") as config_orig, \ 28 | open(os.path.join(path2, "config.yml"), "r") as config_res: 29 | assert config_orig.read() == config_res.read() 30 | 31 | 32 | def assert_progs_equal(path1, path2): 33 | assert set(os.listdir(os.path.join(path1, "prog"))) == \ 34 | set(os.listdir(os.path.join(path2, "prog"))) 35 | 36 | 37 | def assert_makefile_in(lines, task_id, config): 38 | """ 39 | Asserts that the `makefile.in` is correct. 40 | :param lines: Lines of the makefile.in 41 | :param task_id: Task id 42 | :param config: Config dict 43 | """ 44 | def _get_values_from_key(key, separator): 45 | for line in lines: 46 | split = line.split(separator) 47 | if split[0].strip() == key: 48 | yield split[1].strip().strip('\n') 49 | 50 | def _get_value_from_key(key, separator): 51 | value, = _get_values_from_key(key, separator) 52 | return value 53 | 54 | assert _get_value_from_key("ID", "=") == task_id 55 | assert _get_value_from_key("TIMELIMIT", "=") == str(config["time_limit"]) 56 | assert _get_value_from_key("SLOW_TIMELIMIT", "=") == str(4 * config["time_limit"]) 57 | assert _get_value_from_key("MEMLIMIT", "=") == str(config["memory_limit"]) 58 | 59 | cxx_flags = '-std=c++23' 60 | c_flags = '-std=gnu99' 61 | def format_multiple_arguments(obj): 62 | if isinstance(obj, str): 63 | return obj 64 | return ' '.join(obj) 65 | 66 | cxx_flags_vals = list(_get_values_from_key("CXXFLAGS", "+=")) 67 | c_flags_vals = list(_get_values_from_key("CFLAGS", "+=")) 68 | assert cxx_flags_vals[0] == cxx_flags 69 | assert c_flags_vals[0] == c_flags 70 | if 'extra_compilation_args' in config: 71 | # extra C/CXX args should be appended after ingen/inwer/chk targets 72 | if 'cpp' in config['extra_compilation_args']: 73 | extra_cxx_args = format_multiple_arguments(config['extra_compilation_args']['cpp']) 74 | assert cxx_flags_vals[1] == extra_cxx_args 75 | if 'c' in config['extra_compilation_args']: 76 | c_flags += ' ' + format_multiple_arguments(config['extra_compilation_args']['c']) 77 | assert c_flags_vals[1] == extra_c_args 78 | -------------------------------------------------------------------------------- /src/sinol_make/executors/__init__.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | from typing import List, Tuple, Union 3 | 4 | from sinol_make.structs.status_structs import ExecutionResult, Status 5 | 6 | 7 | class BaseExecutor: 8 | """ 9 | Base class for executors. Executors are used to run commands and measure their time and memory usage. 10 | """ 11 | 12 | def __init__(self): 13 | pass 14 | 15 | def _wrap_command(self, command: List[str], result_file_path: str, time_limit: int, memory_limit: int) -> List[str]: 16 | """ 17 | Wraps the command with the necessary tools to measure time and memory usage. 18 | """ 19 | raise NotImplementedError() 20 | 21 | def _execute(self, command: List[str], time_limit: int, hard_time_limit: int, memory_limit: int, 22 | result_file_path: str, executable: str, execution_dir: str, stdin: int, stdout: int, 23 | stderr: Union[None, int], fds_to_close: Union[None, List[int]], 24 | *args, **kwargs) -> Tuple[bool, bool, int, List[str]]: 25 | """ 26 | This function should run subprocess.Popen with the given command and return a tuple of three values: 27 | - bool: whether the process was terminated due to time limit 28 | - bool: whether the process was terminated due to memory limit 29 | - int: return code of the process 30 | - List[str]: stderr of the process 31 | """ 32 | raise NotImplementedError() 33 | 34 | def _parse_result(self, tle, mle, return_code, result_file_path) -> ExecutionResult: 35 | """ 36 | Parses the result file and returns the result. 37 | """ 38 | raise NotImplementedError() 39 | 40 | def execute(self, command: List[str], time_limit, hard_time_limit, memory_limit, result_file_path, executable, 41 | execution_dir, stdin=None, stdout=subprocess.DEVNULL, stderr=None, 42 | fds_to_close: Union[None, List[int]] = None, *args, **kwargs) -> ExecutionResult: 43 | """ 44 | Executes the command and returns the result, stdout and stderr. 45 | """ 46 | 47 | command = self._wrap_command(command, result_file_path, time_limit, memory_limit) 48 | cmdline = " ".join(command) 49 | tle, mle, return_code, proc_stderr = self._execute(cmdline, time_limit, hard_time_limit, memory_limit, 50 | result_file_path, executable, execution_dir, stdin, stdout, 51 | stderr, fds_to_close, *args, **kwargs) 52 | result = self._parse_result(tle, mle, return_code, result_file_path) 53 | result.Cmdline = cmdline 54 | if not result.Stderr: 55 | result.Stderr = proc_stderr 56 | if tle: 57 | result.Status = Status.TL 58 | result.Time = time_limit + 1 59 | elif mle: 60 | result.Status = Status.ML 61 | result.Memory = memory_limit + 1 # Add one so that the memory is red in the table 62 | elif return_code != 0: 63 | result.Status = Status.RE 64 | result.Error = f"Solution returned with code {return_code}" 65 | elif result.Status is None: 66 | result.Status = Status.OK 67 | return result 68 | -------------------------------------------------------------------------------- /src/sinol_make/helpers/classinit.py: -------------------------------------------------------------------------------- 1 | # From oioioi/base/utils/__init__.py 2 | 3 | class ClassInitMeta(type): 4 | """Meta class triggering __classinit__ on class intialization.""" 5 | 6 | def __init__(cls, class_name, bases, new_attrs): 7 | super(ClassInitMeta, cls).__init__(class_name, bases, new_attrs) 8 | cls.__classinit__() 9 | 10 | 11 | class ClassInitBase(object, metaclass=ClassInitMeta): 12 | """Abstract base class injecting ClassInitMeta meta class.""" 13 | 14 | @classmethod 15 | def __classinit__(cls): 16 | """ 17 | Empty __classinit__ implementation. 18 | 19 | This must be a no-op as subclasses can't reliably call base class's 20 | __classinit__ from their __classinit__s. 21 | 22 | Subclasses of __classinit__ should look like: 23 | 24 | .. python:: 25 | 26 | class MyClass(ClassInitBase): 27 | 28 | @classmethod 29 | def __classinit__(cls): 30 | # Need globals().get as MyClass may be still undefined. 31 | super(globals().get('MyClass', cls), 32 | cls).__classinit__() 33 | ... 34 | 35 | class Derived(MyClass): 36 | 37 | @classmethod 38 | def __classinit__(cls): 39 | super(globals().get('Derived', cls), 40 | cls).__classinit__() 41 | ... 42 | """ 43 | pass 44 | 45 | 46 | class RegisteredSubclassesBase(ClassInitBase): 47 | """A base class for classes which should have a list of subclasses 48 | available. 49 | 50 | The list of subclasses is available in their :attr:`subclasses` class 51 | attributes. Classes which have *explicitly* set :attr:`abstract` class 52 | attribute to ``True`` are not added to :attr:`subclasses`. 53 | """ 54 | 55 | _subclasses_loaded = False 56 | 57 | @classmethod 58 | def __classinit__(cls): 59 | this_cls = globals().get('RegisteredSubclassesBase', cls) 60 | super(this_cls, cls).__classinit__() 61 | if this_cls is cls: 62 | # This is RegisteredSubclassesBase class. 63 | return 64 | 65 | assert 'subclasses' not in cls.__dict__, ( 66 | '%s defines attribute subclasses, but has ' 67 | 'RegisteredSubclassesMeta metaclass' % (cls,) 68 | ) 69 | cls.subclasses = [] 70 | cls.abstract = cls.__dict__.get('abstract', False) 71 | 72 | def find_superclass(cls): 73 | superclasses = [c for c in cls.__bases__ if issubclass(c, this_cls)] 74 | if not superclasses: 75 | return None 76 | if len(superclasses) > 1: 77 | raise AssertionError( 78 | '%s derives from more than one ' 79 | 'RegisteredSubclassesBase' % (cls.__name__,) 80 | ) 81 | superclass = superclasses[0] 82 | return superclass 83 | 84 | # Add the class to all superclasses' 'subclasses' attribute, including 85 | # self. 86 | superclass = cls 87 | while superclass is not this_cls: 88 | if not cls.abstract: 89 | superclass.subclasses.append(cls) 90 | superclass = find_superclass(superclass) 91 | -------------------------------------------------------------------------------- /tests/commands/export/test_unit.py: -------------------------------------------------------------------------------- 1 | import yaml 2 | import shutil 3 | import tempfile 4 | 5 | from tests import util 6 | from .util import * 7 | 8 | 9 | def _create_package(tmpdir, path): 10 | package_path = os.path.join(tmpdir, os.path.basename(path)) 11 | shutil.copytree(path, package_path) 12 | os.chdir(package_path) 13 | command = get_command() 14 | util.create_ins_outs(package_path) 15 | command.args = argparse.Namespace(cpus=1, compile_mode='default', 16 | cpp_compiler_path=compiler.get_cpp_compiler_path(), 17 | c_compiler_path=None, python_interpreter_path=None, 18 | java_compiler_path=None, export_ocen=False) 19 | command.task_type_cls = package_util.get_task_type_cls() 20 | return command 21 | 22 | 23 | def test_get_generated_tests(): 24 | """ 25 | Test getting generated tests. 26 | """ 27 | with tempfile.TemporaryDirectory() as tmpdir: 28 | command = _create_package(tmpdir, util.get_handwritten_package_path()) 29 | command.generate_input_tests() 30 | assert set(command.get_generated_tests()) == {"1a", "2a"} 31 | 32 | command = _create_package(tmpdir, util.get_simple_package_path()) 33 | command.generate_input_tests() 34 | assert set(command.get_generated_tests()) == {"1a", "2a", "3a", "4a"} 35 | 36 | 37 | def test_copy_package_required_files(): 38 | """ 39 | Test function copy_package_required_files. 40 | """ 41 | 42 | with tempfile.TemporaryDirectory() as tmpdir: 43 | res_dir = os.path.join(tmpdir, "res") 44 | os.mkdir(res_dir) 45 | command = _create_package(tmpdir, util.get_handwritten_package_path()) 46 | command.generate_input_tests() 47 | command.copy_package_required_files(res_dir) 48 | 49 | assert_configs_equal(os.getcwd(), res_dir) 50 | assert_progs_equal(os.getcwd(), res_dir) 51 | 52 | assert set(os.listdir(os.path.join(res_dir, "in"))) == {"hwr0.in", "hwr0a.in"} 53 | assert set(os.listdir(os.path.join(res_dir, "out"))) == {"hwr0.out", "hwr0a.out"} 54 | 55 | shutil.rmtree(res_dir) 56 | os.mkdir(res_dir) 57 | command = _create_package(tmpdir, util.get_simple_package_path()) 58 | command.generate_input_tests() 59 | command.copy_package_required_files(res_dir) 60 | 61 | assert_configs_equal(os.getcwd(), res_dir) 62 | assert_progs_equal(os.getcwd(), res_dir) 63 | 64 | assert set(os.listdir(os.path.join(res_dir, "in"))) == set() 65 | assert set(os.listdir(os.path.join(res_dir, "out"))) == set() 66 | 67 | 68 | def test_create_makefile_in(): 69 | """ 70 | Test function create_makefile_in. 71 | """ 72 | 73 | def _create_package(path): 74 | os.chdir(path) 75 | with open(os.path.join(os.getcwd(), "config.yml"), "r") as config_file: 76 | config = yaml.load(config_file, Loader=yaml.FullLoader) 77 | return get_command(), config 78 | 79 | with tempfile.TemporaryDirectory() as tmpdir: 80 | command, config = _create_package(util.get_handwritten_package_path()) 81 | 82 | command.create_makefile_in(tmpdir, config) 83 | with open(os.path.join(tmpdir, "makefile.in"), "r") as makefile: 84 | lines = makefile.readlines() 85 | assert_makefile_in(lines, "hwr", config) 86 | 87 | for package in [util.get_library_package_path(), util.get_library_string_args_package_path()]: 88 | task_name = os.path.basename(package) 89 | command, config = _create_package(package) 90 | command.create_makefile_in(tmpdir, config) 91 | with open(os.path.join(tmpdir, "makefile.in"), "r") as makefile: 92 | lines = makefile.readlines() 93 | assert_makefile_in(lines, task_name, config) 94 | -------------------------------------------------------------------------------- /tests/test_sio2jail.py: -------------------------------------------------------------------------------- 1 | import os 2 | import shutil 3 | import sys 4 | from urllib.request import urlretrieve 5 | import pytest 6 | 7 | from sinol_make import sio2jail, util 8 | 9 | 10 | @pytest.mark.github_runner 11 | def test_install_sio2jail(): 12 | if not sio2jail.sio2jail_supported(): 13 | return 14 | 15 | try: 16 | if os.path.exists(os.path.expanduser('~/.local/bin/oiejq')): 17 | os.remove(os.path.expanduser('~/.local/bin/oiejq')) 18 | if os.path.exists(os.path.expanduser('~/.local/bin/sio2jail')): 19 | os.remove(os.path.expanduser('~/.local/bin/sio2jail')) 20 | except IsADirectoryError: 21 | shutil.rmtree(os.path.expanduser('~/.local/bin/oiejq'), ignore_errors=True) 22 | assert not sio2jail.check_sio2jail() 23 | assert sio2jail.install_sio2jail() 24 | assert sio2jail.get_default_sio2jail_path() == os.path.expanduser('~/.local/bin/sio2jail') 25 | 26 | if os.path.exists(os.path.expanduser('~/.local/bin/oiejq')): 27 | os.remove(os.path.expanduser('~/.local/bin/oiejq')) 28 | if os.path.exists(os.path.expanduser('~/.local/bin/sio2jail')): 29 | os.remove(os.path.expanduser('~/.local/bin/sio2jail')) 30 | 31 | assert not sio2jail.check_sio2jail() 32 | sio2jail.install_sio2jail() 33 | 34 | 35 | @pytest.mark.github_runner 36 | def test_check_sio2jail(): 37 | if not sio2jail.sio2jail_supported(): 38 | return 39 | 40 | try: 41 | if os.path.exists(os.path.expanduser('~/.local/bin/oiejq')): 42 | os.remove(os.path.expanduser('~/.local/bin/oiejq')) 43 | if os.path.exists(os.path.expanduser('~/.local/bin/sio2jail')): 44 | os.remove(os.path.expanduser('~/.local/bin/sio2jail')) 45 | except IsADirectoryError: 46 | shutil.rmtree(os.path.expanduser('~/.local/bin/oiejq'), ignore_errors=True) 47 | 48 | assert not sio2jail.check_sio2jail() 49 | os.makedirs(os.path.expanduser('~/.local/bin/oiejq'), exist_ok=True) 50 | assert not sio2jail.check_sio2jail() 51 | os.rmdir(os.path.expanduser('~/.local/bin/oiejq')) 52 | with open(os.path.expanduser('~/.local/bin/oiejq'), 'w') as f: 53 | f.write('abcdef') 54 | assert not sio2jail.check_sio2jail() 55 | 56 | 57 | @pytest.mark.github_runner 58 | def test_perf_counters_not_set(): 59 | """ 60 | Test `sio2jail.check_perf_counters_enabled` with perf counters disabled 61 | """ 62 | if not sio2jail.sio2jail_supported(): 63 | return 64 | 65 | sio2jail.install_sio2jail() 66 | with pytest.raises(SystemExit): 67 | sio2jail.check_perf_counters_enabled() 68 | 69 | 70 | @pytest.mark.sio2jail 71 | def test_perf_counters_set(): 72 | """ 73 | Test `sio2jail.check_perf_counters_enabled` with perf counters enabled 74 | """ 75 | if not sio2jail.sio2jail_supported(): 76 | return 77 | sio2jail.check_perf_counters_enabled() 78 | 79 | 80 | @pytest.mark.github_runner 81 | def test_updating(): 82 | """ 83 | Test updating sio2jail 84 | """ 85 | if not sio2jail.sio2jail_supported(): 86 | return 87 | try: 88 | os.remove(os.path.expanduser('~/.local/bin/oiejq')) 89 | os.remove(os.path.expanduser('~/.local/bin/sio2jail')) 90 | except IsADirectoryError: 91 | shutil.rmtree(os.path.expanduser('~/.local/bin/oiejq'), ignore_errors=True) 92 | except FileNotFoundError: 93 | pass 94 | assert not sio2jail.check_sio2jail() 95 | assert sio2jail.install_sio2jail() 96 | assert sio2jail.get_default_sio2jail_path() == os.path.expanduser('~/.local/bin/sio2jail') 97 | 98 | # Download older sio2jail 99 | urlretrieve('https://github.com/sio2project/sio2jail/releases/download/v1.4.3/sio2jail', 100 | os.path.expanduser('~/.local/bin/sio2jail')) 101 | os.chmod(os.path.expanduser('~/.local/bin/sio2jail'), 0o777) 102 | assert not sio2jail.check_sio2jail() 103 | assert sio2jail.install_sio2jail() 104 | assert sio2jail.check_sio2jail() 105 | -------------------------------------------------------------------------------- /src/sinol_make/helpers/oicompare.py: -------------------------------------------------------------------------------- 1 | import os 2 | import re 3 | import requests 4 | import subprocess 5 | 6 | from sinol_make import util 7 | 8 | 9 | __OICOMAPRE_VERSION = 'v1.0.2' 10 | 11 | 12 | def get_path(): 13 | return os.path.expanduser('~/.local/bin/oicompare') 14 | 15 | 16 | def check_installed(): 17 | path = get_path() 18 | if not os.path.exists(path): 19 | return False 20 | try: 21 | output = subprocess.run([path, '--version'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) 22 | except PermissionError: 23 | return False 24 | if output.returncode != 0: 25 | return False 26 | if output.stdout.decode().strip() != f'oicompare version {__OICOMAPRE_VERSION[1:]}': 27 | return False 28 | return True 29 | 30 | 31 | def download_oicomapare(): 32 | url = f'https://github.com/sio2project/oicompare/releases/download/{__OICOMAPRE_VERSION}/oicompare' 33 | if util.is_macos_arm(): 34 | url += '-arm64' 35 | path = get_path() 36 | os.makedirs(os.path.dirname(path), exist_ok=True) 37 | manual_download_msg = ("You can try downloading it manually from " 38 | f"https://github.com/sio2project/oicompare/releases/tag/{__OICOMAPRE_VERSION}/ and placing " 39 | f"it in ~/.local/bin/oicomapre") 40 | try: 41 | request = requests.get(url) 42 | except requests.exceptions.ConnectionError: 43 | util.exit_with_error("Couldn't download oicompare (couldn't connect). " + manual_download_msg) 44 | if request.status_code != 200: 45 | util.exit_with_error(f"Couldn't download oicompare (returned status code: {request.status_code}). " 46 | + manual_download_msg) 47 | with open(path, 'wb') as f: 48 | f.write(request.content) 49 | os.chmod(path, 0o755) 50 | 51 | 52 | def check_and_download(): 53 | # macOS doesn't allow compiling statically and I don't want to deal with it 54 | if util.is_macos(): 55 | return 56 | if check_installed(): 57 | return 58 | download_oicomapare() 59 | if not check_installed(): 60 | util.exit_with_error("Couldn't download oicompare. Please try again later or download it manually.") 61 | 62 | 63 | def _strip(s: str) -> str: 64 | """ 65 | Replace all longest sequences of spaces with a single space. 66 | """ 67 | return re.sub(r'[\s\0]+', ' ', s).strip() 68 | 69 | 70 | def compare(file1_path: str, file2_path: str) -> bool: 71 | """ 72 | Compare two files in the same way as oicompare does. Returns True if the files are the same, False otherwise. 73 | """ 74 | with open(file1_path, "r") as file1, open(file2_path, "r") as file2: 75 | eof1 = False 76 | eof2 = False 77 | while True: 78 | try: 79 | line1 = _strip(next(file1)) 80 | except StopIteration: 81 | eof1 = True 82 | try: 83 | line2 = _strip(next(file2)) 84 | except StopIteration: 85 | eof2 = True 86 | 87 | if eof1 and eof2: 88 | return True 89 | if eof1: 90 | while line2 == "": 91 | try: 92 | line2 = _strip(next(file2)) 93 | except StopIteration: 94 | eof2 = True 95 | break 96 | elif eof2: 97 | while line1 == "": 98 | try: 99 | line1 = _strip(next(file1)) 100 | except StopIteration: 101 | eof1 = True 102 | break 103 | if line1 != "": 104 | break 105 | 106 | if eof1 and eof2: 107 | return True 108 | if (eof1 and line2 == "") or (eof2 and line1 == ""): 109 | continue 110 | if (eof1 and line2 != "") or (eof2 and line1 != ""): 111 | return False 112 | if line1 != line2: 113 | return False 114 | -------------------------------------------------------------------------------- /src/sinol_make/executors/detailed.py: -------------------------------------------------------------------------------- 1 | import os 2 | import signal 3 | import subprocess 4 | import time 5 | import psutil 6 | from typing import List, Tuple, Union 7 | 8 | from sinol_make.executors import BaseExecutor 9 | from sinol_make.structs.status_structs import ExecutionResult, Status 10 | 11 | 12 | class DetailedExecutor(BaseExecutor): 13 | """ 14 | Executor which doesn't use time or sio2jail for measuring time and memory usage. 15 | """ 16 | 17 | def _wrap_command(self, command: List[str], result_file_path: str, time_limit: int, memory_limit: int) -> List[str]: 18 | return command 19 | 20 | def _execute(self, cmdline: str, time_limit: int, hard_time_limit: int, memory_limit: int, 21 | result_file_path: str, executable: str, execution_dir: str, stdin: int, stdout: int, 22 | stderr: Union[None, int], fds_to_close: Union[None, List[int]], 23 | *args, **kwargs) -> Tuple[bool, bool, int, List[str]]: 24 | timeout = False 25 | mem_used = 0 26 | if stderr is None: 27 | stderr = subprocess.PIPE 28 | process = subprocess.Popen(cmdline, shell=True, *args, stdin=stdin, stdout=stdout, stderr=stderr, 29 | preexec_fn=os.setpgrp, cwd=execution_dir, **kwargs) 30 | if fds_to_close is not None: 31 | for fd in fds_to_close: 32 | os.close(fd) 33 | 34 | start_time = time.time() 35 | while process.poll() is None: 36 | try: 37 | time_process = psutil.Process(process.pid) 38 | executable_process = None 39 | for child in time_process.children(): 40 | if child.name() == executable: 41 | executable_process = child 42 | break 43 | if executable_process is not None: 44 | mem_used = max(mem_used, executable_process.memory_info().rss) 45 | if executable_process is not None and mem_used > memory_limit * 1024: 46 | try: 47 | os.killpg(process.pid, signal.SIGKILL) 48 | except ProcessLookupError: 49 | pass 50 | break 51 | except psutil.NoSuchProcess: 52 | pass 53 | 54 | if time.time() - start_time > hard_time_limit: 55 | try: 56 | os.killpg(process.pid, signal.SIGKILL) 57 | except ProcessLookupError: 58 | pass 59 | break 60 | time_used = time.time() - start_time 61 | mem_used = mem_used // 1024 62 | 63 | if stderr == subprocess.PIPE: 64 | _, proc_stderr = process.communicate() 65 | proc_stderr = proc_stderr.decode('utf-8').split('\n') 66 | else: 67 | proc_stderr = [] 68 | process.communicate() 69 | 70 | with open(result_file_path, "w") as result_file: 71 | result_file.write(f"{time_used}\n{mem_used}\n{process.returncode}\n") 72 | 73 | return timeout, mem_used > memory_limit, 0, proc_stderr 74 | 75 | def _parse_result(self, tle, mle, return_code, result_file_path) -> ExecutionResult: 76 | result = ExecutionResult() 77 | program_exit_code = 0 78 | with open(result_file_path, "r") as result_file: 79 | lines = result_file.readlines() 80 | if len(lines) == 3: 81 | result.Time = float(lines[0].strip()) 82 | result.Memory = float(lines[1].strip()) 83 | program_exit_code = int(lines[2].strip()) 84 | if program_exit_code == -9 or program_exit_code == 9: # Process was killed, so probably TLE 85 | program_exit_code = 0 86 | else: 87 | result.Status = Status.RE 88 | result.Error = "Unexpected output from execution:\n" + "".join(lines) 89 | result.Fail = True 90 | if program_exit_code != 0: 91 | program_exit_code = abs(program_exit_code) 92 | result.Status = Status.RE 93 | result.Error = f"Program exited with code {program_exit_code}" 94 | result.ExitSignal = os.WTERMSIG(program_exit_code) 95 | return result 96 | -------------------------------------------------------------------------------- /example_package/config.yml: -------------------------------------------------------------------------------- 1 | ### Keys used by sio2: 2 | 3 | # Title of the package is defined in `title` key. 4 | title: Example task package 5 | # Title can be different for different languages. 6 | # They are defined in `title_` keys. 7 | # is a language code (for example 'pl' or 'en'). 8 | # Available languages are defined in settings of `oioioi` instance. 9 | title_pl: Przykładowe zadanie 10 | 11 | # Number of points for each group can be defined in `scores` key. 12 | # If this key is not specified, then all groups have the same number of points. 13 | # (if number of groups doesn't divide 100, then the last groups will have the remaining points). 14 | # Group 0 always has zero points. 15 | scores: 16 | 1: 40 17 | 2: 60 18 | 19 | # Time limit for all tests is defined in `time_limit` key. 20 | # More precise time limit for each group or test can be defined in `time_limits` key. 21 | # The more precise time limit has higher priority (first group, then global time limit). 22 | # Time limit is in milliseconds. 23 | time_limit: 1000 24 | time_limits: 25 | 1: 2000 26 | 27 | # Memory limit for all tests is defined in `memory_limit` key. 28 | # More precise memory limits can be defined in `memory_limits` key. 29 | # Same as with time limits, the more precise memory limit has higher priority. 30 | # Memory limit is in kB 31 | memory_limit: 262144 32 | memory_limits: 33 | 3: 131072 34 | 35 | # Time and memory limits can be overriden for other languages in `override_limits` key. 36 | # If this key is not specified, then all languages have the same limits. 37 | override_limits: 38 | py: 39 | time_limit: 5000 40 | memory_limit: 524288 41 | 42 | # Extra compilation arguments can be defined in `extra_compile_args` key. 43 | # Each language can have different extra arguments. 44 | 45 | # extra_compilation_args: 46 | # cpp: '__ID__lib.cpp' 47 | 48 | # The arguments can also be in an array: 49 | 50 | # extra_compilation_args: 51 | # cpp: 52 | # - '__ID__lib.cpp' 53 | # - '__ID__lib2.cpp' 54 | 55 | # Additional files used in compilation can be defined in `extra_compilation_files` key. 56 | # They are copied to the directory where the source code is compiled. 57 | # All languages have the same additional files. 58 | 59 | # extra_compilation_files: ['__ID__lib.cpp', '__ID__lib.py'] 60 | 61 | 62 | ### Keys used by sinol-make: 63 | 64 | # This key represents the short name (consisting of 3 letters) of the task. 65 | # The names of files in `prog/`, `doc/`, `in/` and `out/` directories have to start with this task id. 66 | # This key is only used by `sinol-make`: running `sinol-make export` creates 67 | # an archive with the proper name, which sio2 uses as the task id. 68 | sinol_task_id: __ID__ 69 | 70 | # sinol-make can behave differently depending on the value of `sinol_contest_type` key. 71 | # Mainly, it affects how points are calculated. 72 | # If the key is not specified, then `default` is used. 73 | # See README.md for more information. 74 | sinol_contest_type: oi 75 | 76 | # You can configure how sinol-make will compile the LaTeX in `doc/`. By default, 77 | # it will attempt to choose an option that makes sense based on the presence 78 | # of *.ps/*.eps figures. You can choose between `pdflatex`, `lualatex` and 79 | # `latex_dvi`. 80 | # This option can be overridden by passing `--latex_compiler` to `sinol-make doc`. 81 | sinol_latex_compiler: auto 82 | 83 | # You can specify which tests are static (handwritten). This allows sinol-make to differentiate between 84 | # old and handwritten tests. If this key is not present old tests won't be removed. The values can be 85 | # either a list of test names (e.g. `["__ID__0.in", "__ID__1.in"]`) or glob patterns 86 | # (e.g. [`"__ID__*.in"`, "__ID__2?.in"]). 87 | # This key is optional and should be a list of tests. 88 | sinol_static_tests: ["__ID__0.in", "__ID__0a.in"] 89 | 90 | # Total score of the task is defined in `sinol_total_score` key. 91 | # If this key is not specified, then this defaults to 100. 92 | sinol_total_score: 100 93 | 94 | # sinol-make can check if the solutions run as expected when using `run` command. 95 | # Key `sinol_expected_scores` defines expected scores for each solution on each tests. 96 | # There should be no reason to change this key manually. 97 | # It is automatically generated and managed by sinol-make. 98 | sinol_expected_scores: {} 99 | -------------------------------------------------------------------------------- /src/sinol_make/structs/status_structs.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from enum import Enum 3 | from typing import List 4 | 5 | 6 | class Status(str, Enum): 7 | PENDING = " " 8 | CE = "CE" 9 | TL = "TL" 10 | ML = "ML" 11 | RE = "RE" 12 | WA = "WA" 13 | OK = "OK" 14 | 15 | def __str__(self): 16 | return self.name 17 | 18 | def __repr__(self): 19 | return self.name 20 | 21 | @staticmethod 22 | def from_str(status): 23 | if status == "CE": 24 | return Status.CE 25 | elif status == "TL" or status == "TLE": 26 | return Status.TL 27 | elif status == "ML" or status == "MLE": 28 | return Status.ML 29 | elif status == "RE": 30 | return Status.RE 31 | elif status == "WA": 32 | return Status.WA 33 | elif status == "OK": 34 | return Status.OK 35 | elif status == " ": 36 | return Status.PENDING 37 | else: 38 | raise ValueError(f"Unknown status: '{status}'") 39 | 40 | @staticmethod 41 | def possible_statuses(): 42 | return [Status.PENDING, Status.CE, Status.TL, Status.ML, Status.RE, Status.WA, Status.OK] 43 | 44 | 45 | @dataclass 46 | class ResultChange: 47 | solution: str 48 | group: int 49 | old_result: Status 50 | result: Status 51 | 52 | 53 | @dataclass 54 | class TotalPointsChange: 55 | solution: str 56 | old_points: int 57 | new_points: int 58 | 59 | @dataclass 60 | class PointsChange: 61 | solution: str 62 | group: int 63 | old_points: int 64 | new_points: int 65 | 66 | 67 | @dataclass 68 | class ValidationResult: 69 | added_solutions: set 70 | removed_solutions: set 71 | added_groups: set 72 | removed_groups: set 73 | changes: List[ResultChange] 74 | expected_scores: dict 75 | new_expected_scores: dict 76 | unknown_change: bool 77 | 78 | 79 | @dataclass 80 | class ExecutionResult: 81 | # Result status of execution. Possible values 82 | # can be found in `Status` enum definition. 83 | Status: Status 84 | # Time in milliseconds 85 | Time: float 86 | # Memory in KB 87 | Memory: int 88 | # Points for this test 89 | Points: int 90 | # Error message 91 | Error: str 92 | # Whether the program should fail due to the error 93 | Fail: bool 94 | # Exit signal of the process 95 | ExitSignal: int 96 | # Comment received from checker. 97 | Comment: str 98 | # Stderr of the program (used for checkers/interactors) 99 | Stderr: List[str] 100 | # Original command line that was run 101 | Cmdline: str 102 | 103 | def __init__(self, status=None, Time=None, Memory=None, Points=0, Error=None, Fail=False, ExitSignal=0, Comment="", 104 | Stderr=None, Cmdline=None): 105 | self.Status = status 106 | self.Time = Time 107 | self.Memory = Memory 108 | self.Points = Points 109 | self.Error = Error 110 | self.Fail = Fail 111 | self.ExitSignal = ExitSignal 112 | self.Comment = Comment 113 | self.Stderr = Stderr if Stderr is not None else [] 114 | self.Cmdline = Cmdline 115 | 116 | @staticmethod 117 | def from_dict(dict): 118 | return ExecutionResult( 119 | status=Status.from_str(dict.get("Status", "")), 120 | Time=dict.get("Time", None), 121 | Memory=dict.get("Memory", None), 122 | Points=dict.get("Points", 0), 123 | Error=dict.get("Error", None), 124 | Fail=dict.get("Fail", False), 125 | ExitSignal=dict.get("ExitSignal", 0), 126 | Comment=dict.get("Comment", ""), 127 | Stderr=dict.get("Stderr", []), 128 | Cmdline=dict.get("Cmdline", ""), 129 | ) 130 | 131 | def to_dict(self): 132 | return { 133 | "Status": str(self.Status), 134 | "Time": self.Time, 135 | "Memory": self.Memory, 136 | "Points": self.Points, 137 | "Error": self.Error, 138 | "Fail": self.Fail, 139 | "ExitSignal": self.ExitSignal, 140 | "Comment": self.Comment, 141 | "Stderr": self.Stderr, 142 | "Cmdline": self.Cmdline, 143 | } 144 | -------------------------------------------------------------------------------- /src/sinol_make/commands/ingen/ingen_util.py: -------------------------------------------------------------------------------- 1 | import stat 2 | import subprocess 3 | 4 | import argparse 5 | import os 6 | 7 | from sinol_make import util 8 | from sinol_make.helpers import package_util, compiler, compile 9 | 10 | 11 | def ingen_exists(task_id): 12 | """ 13 | Checks if ingen source file exists. 14 | :param task_id: task id, for example abc 15 | :return: True if exists, False otherwise 16 | """ 17 | return package_util.any_files_matching_pattern(task_id, f'{task_id}ingen.*') 18 | 19 | 20 | def get_ingen(task_id, ingen_path=None): 21 | """ 22 | Find ingen source file in `prog/` directory. 23 | If `ingen_path` is specified, then it will be used (if exists). 24 | :param task_id: task id, for example abc. 25 | :param ingen_path: path to ingen source file 26 | :return: path to ingen source file or None if not found 27 | """ 28 | 29 | if ingen_path is not None: 30 | if os.path.exists(ingen_path): 31 | return ingen_path 32 | else: 33 | util.exit_with_error(f'Ingen source file {ingen_path} does not exist.') 34 | 35 | ingen = package_util.get_files_matching_pattern(task_id, f'{task_id}ingen.*') 36 | if len(ingen) == 0: 37 | util.exit_with_error(f'Ingen source file for task {task_id} does not exist.') 38 | 39 | # Sio2 first chooses shell scripts, then non-shell source codes. 40 | correct_ingen = None 41 | for i in ingen: 42 | if os.path.splitext(i)[1] == '.sh': 43 | correct_ingen = i 44 | break 45 | if correct_ingen is None: 46 | correct_ingen = ingen[0] 47 | return correct_ingen 48 | 49 | 50 | def compile_ingen(ingen_path: str, args: argparse.Namespace, compilation_flags='default', use_fsanitize=False): 51 | """ 52 | Compiles ingen and returns path to compiled executable. 53 | If ingen_path is shell script, then it will be returned. 54 | """ 55 | if os.path.splitext(ingen_path)[1] == '.sh': 56 | return ingen_path 57 | 58 | compilers = compiler.verify_compilers(args, [ingen_path]) 59 | ingen_exe, compile_log_path = compile.compile_file(ingen_path, package_util.get_executable(ingen_path), 60 | compilers, compilation_flags, use_fsanitize=use_fsanitize, 61 | additional_flags='-D_INGEN', use_extras=False) 62 | 63 | if ingen_exe is None: 64 | compile.print_compile_log(compile_log_path) 65 | util.exit_with_error('Failed ingen compilation.') 66 | else: 67 | print(util.info('Successfully compiled ingen.')) 68 | return ingen_exe 69 | 70 | 71 | def run_ingen(ingen_exe, working_dir=None): 72 | """ 73 | Runs ingen and generates all input files. 74 | :param ingen_exe: path to ingen executable 75 | :param working_dir: working directory for ingen. If None, then {os.getcwd()}/in is used. 76 | :return: True if ingen was successful, False otherwise 77 | """ 78 | if working_dir is None: 79 | working_dir = os.path.join(os.getcwd(), 'in') 80 | 81 | is_shell = os.path.splitext(ingen_exe)[1] == '.sh' 82 | if is_shell: 83 | st = os.stat(ingen_exe) 84 | os.chmod(ingen_exe, st.st_mode | stat.S_IEXEC) 85 | 86 | print(util.bold(' Ingen output '.center(util.get_terminal_size()[1], '='))) 87 | process = subprocess.Popen([ingen_exe], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, 88 | cwd=working_dir, shell=is_shell) 89 | whole_output = '' 90 | while process.poll() is None: 91 | out = process.stdout.readline().decode('utf-8') 92 | if out != '': 93 | print(out, end='') 94 | whole_output += out 95 | out = process.stdout.read().decode('utf-8') 96 | whole_output += out 97 | print(out, end='') 98 | exit_code = process.returncode 99 | print(util.bold(' End of ingen output '.center(util.get_terminal_size()[1], '='))) 100 | 101 | if util.has_sanitizer_error(whole_output, exit_code): 102 | print(util.warning('Warning: if ingen failed due to sanitizer errors, you can either run ' 103 | '`sudo sysctl vm.mmap_rnd_bits=28` to fix this or disable sanitizers with the ' 104 | '--no-fsanitize flag.')) 105 | 106 | return exit_code == 0 107 | -------------------------------------------------------------------------------- /src/sinol_make/executors/sio2jail.py: -------------------------------------------------------------------------------- 1 | import os 2 | import signal 3 | import subprocess 4 | import sys 5 | import traceback 6 | from typing import List, Tuple, Union 7 | 8 | from sinol_make import util 9 | from sinol_make.executors import BaseExecutor 10 | from sinol_make.structs.status_structs import ExecutionResult, Status 11 | 12 | 13 | class Sio2jailExecutor(BaseExecutor): 14 | def __init__(self, sio2jail_path): 15 | super().__init__() 16 | self.sio2jail_path = sio2jail_path 17 | 18 | def _wrap_command(self, command: List[str], result_file_path: str, time_limit: int, memory_limit: int) -> List[str]: 19 | # see: https://github.com/sio2project/sioworkers/blob/738aa7a4e93216b0900ca128d6d48d40cd38bc1e/sio/workers/executors.py#L608 20 | return [f'"{self.sio2jail_path}"', '-f', '3', '--mount-namespace', 'off', '--pid-namespace', 'off', '--uts-namespace', 21 | 'off', '--ipc-namespace', 'off', '--net-namespace', 'off', '--capability-drop', 'off', 22 | '--user-namespace', 'off', '--instruction-count-limit', f'{int(2 * time_limit)}M', 23 | '--rtimelimit', f'{int(16 * time_limit + 1000)}ms', '--memory-limit', f'{int(memory_limit)}K', 24 | '--output-limit', '51200K', '--output', 'oiaug', '--stderr', '--'] + command + \ 25 | ['3>', f'"{result_file_path}"'] 26 | 27 | def _execute(self, cmdline: str, time_limit: int, hard_time_limit: int, memory_limit: int, 28 | result_file_path: str, executable: str, execution_dir: str, stdin: int, stdout: int, 29 | stderr: Union[None, int], fds_to_close: Union[None, List[int]], 30 | *args, **kwargs) -> Tuple[bool, bool, int, List[str]]: 31 | env = os.environ.copy() 32 | env['UNDER_SIO2JAIL'] = "1" 33 | try: 34 | process = subprocess.Popen(cmdline, *args, shell=True, stdin=stdin, stdout=stdout, env=env, 35 | stderr=subprocess.DEVNULL, preexec_fn=os.setpgrp, cwd=execution_dir, **kwargs) 36 | except TypeError as e: 37 | print(util.error(f"Invalid command: `{cmdline}`")) 38 | raise e 39 | if fds_to_close is not None: 40 | for fd in fds_to_close: 41 | os.close(fd) 42 | process.wait() 43 | 44 | return False, False, 0, [] 45 | 46 | def _parse_time(self, time_str): 47 | if len(time_str) < 3: return -1 48 | return int(time_str[:-2]) 49 | 50 | def _parse_memory(self, memory_str): 51 | if len(memory_str) < 3: return -1 52 | return int(memory_str[:-2]) 53 | 54 | def _parse_result(self, _, mle, return_code, result_file_path) -> ExecutionResult: 55 | result = ExecutionResult() 56 | with open(result_file_path, "r") as result_file: 57 | lines = result_file.readlines() 58 | 59 | try: 60 | result.stderr = lines[:-2] 61 | status, code, time_ms, _, memory_kb, _ = lines[-2].strip().split() 62 | message = lines[-1].strip() 63 | result.Time = int(time_ms) 64 | result.Memory = int(memory_kb) 65 | except: 66 | output = "".join(lines) 67 | util.exit_with_error("Could not parse sio2jail output:" 68 | f"\n---\n{output}" 69 | f"\n---\n{traceback.format_exc()}") 70 | 71 | # ignoring `status` is weird, but sio2 does it this way 72 | if message == 'ok': 73 | result.Status = Status.OK 74 | elif message == 'time limit exceeded': 75 | result.Status = Status.TL 76 | elif message == 'real time limit exceeded': 77 | result.Status = Status.TL 78 | result.Error = message 79 | elif message == 'memory limit exceeded': 80 | result.Status = Status.ML 81 | elif message.startswith('intercepted forbidden syscall'): 82 | # TODO: sinol-make does not support "RV" 83 | result.Status = Status.RE 84 | result.Error = message 85 | elif message.startswith('process exited due to signal'): 86 | code = message[len('process exited due to signal '):] 87 | result.Status = Status.RE 88 | result.Error = message 89 | result.ExitSignal = int(code) 90 | else: 91 | result.Status = Status.RE 92 | result.Error = 'Unrecognized Sio2jail result: ' + message 93 | 94 | return result 95 | -------------------------------------------------------------------------------- /src/sinol_make/commands/ingen/__init__.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import glob 3 | import os 4 | 5 | from sinol_make import util 6 | from sinol_make.commands.ingen.ingen_util import get_ingen, compile_ingen, run_ingen 7 | from sinol_make.helpers import parsers, package_util, paths 8 | from sinol_make.interfaces.BaseCommand import BaseCommand 9 | 10 | 11 | class Command(BaseCommand): 12 | """ 13 | Class for `ingen` command. 14 | """ 15 | 16 | def get_name(self): 17 | return "ingen" 18 | 19 | def configure_subparser(self, subparser): 20 | parser = subparser.add_parser( 21 | self.get_name(), 22 | help='Generate input files', 23 | description='Generate input files using ingen program ' 24 | '(for example prog/abcingen.cpp for abc task).' 25 | 'You can also specify your ingen source ' 26 | 'file which will be used.' 27 | ) 28 | 29 | parser.add_argument('ingen_path', type=str, nargs='?', 30 | help='path to ingen source file, for example prog/abcingen.cpp') 31 | parser.add_argument('-n', '--no-validate', default=False, action='store_true', 32 | help='do not validate test contents') 33 | parsers.add_cpus_argument(parser, 'number of cpus used for validating tests') 34 | parsers.add_fsanitize_argument(parser) 35 | parsers.add_compilation_arguments(parser) 36 | return parser 37 | 38 | def delete_dangling_files(self, dates): 39 | to_delete = set() 40 | for test in glob.glob(os.path.join(os.getcwd(), "in", f"{self.task_id}*.in")): 41 | basename = os.path.basename(test) 42 | if basename in dates and dates[basename] == os.path.getmtime(test): 43 | to_delete.add(os.path.basename(test)) 44 | if to_delete: 45 | config = package_util.get_config() 46 | if 'sinol_static_tests' not in config: 47 | print(util.warning('Old input files won\'t be deleted, ' 48 | 'because static tests are not defined. ' 49 | 'You can define them in config.yml with `sinol_static_tests` key.')) 50 | else: 51 | static_files = config['sinol_static_tests'] 52 | if isinstance(static_files, str): 53 | static_files = [static_files] 54 | found_static_files = set() 55 | for static in static_files: 56 | files = [os.path.basename(f) for f in glob.glob(os.path.join(os.getcwd(), "in", static))] 57 | found_static_files.update(files) 58 | to_delete = to_delete - found_static_files 59 | if to_delete: 60 | print('Cleaning up old input files.') 61 | for test in to_delete: 62 | os.remove(os.path.join(os.getcwd(), "in", test)) 63 | 64 | def run(self, args: argparse.Namespace): 65 | args = util.init_package_command(args) 66 | 67 | self.args = args 68 | 69 | self.task_id = package_util.get_task_id() 70 | util.change_stack_size_to_unlimited() 71 | self.ingen = get_ingen(self.task_id, args.ingen_path) 72 | print(f'Using ingen file {os.path.basename(self.ingen)}') 73 | self.ingen_exe = compile_ingen(self.ingen, self.args, self.args.compile_mode, self.args.fsanitize) 74 | 75 | previous_tests = [] 76 | try: 77 | with open(paths.get_cache_path("input_tests"), "r") as f: 78 | for line in f: 79 | line = line.strip() 80 | if os.path.exists(line): 81 | previous_tests.append(line) 82 | except FileNotFoundError: 83 | pass 84 | dates = {os.path.basename(test): os.path.getmtime(test) for test in previous_tests} 85 | 86 | if run_ingen(self.ingen_exe): 87 | print(util.info('Successfully generated input files.')) 88 | else: 89 | util.exit_with_error('Failed to generate input files.') 90 | 91 | self.delete_dangling_files(dates) 92 | 93 | with open(paths.get_cache_path("input_tests"), "w") as f: 94 | f.write("\n".join(glob.glob(os.path.join(os.getcwd(), "in", f"{self.task_id}*.in")))) 95 | 96 | if not self.args.no_validate: 97 | tests = sorted(glob.glob(os.path.join(os.getcwd(), "in", f"{self.task_id}*.in"))) 98 | package_util.validate_tests(tests, self.args.cpus, 'input') 99 | -------------------------------------------------------------------------------- /tests/commands/inwer/test_unit.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import re 3 | 4 | from ...fixtures import * 5 | from ... import util 6 | from sinol_make.helpers import package_util, compiler 7 | from sinol_make.commands.inwer import inwer_util, InwerExecution 8 | from sinol_make.commands.inwer import Command 9 | 10 | 11 | def test_get_inwer_path(): 12 | """ 13 | Test getting default and custom inwer. 14 | """ 15 | os.chdir(util.get_inwer_package_path()) 16 | task_id = package_util.get_task_id() 17 | assert inwer_util.get_inwer_path(task_id) is not None 18 | assert inwer_util.get_inwer_path(task_id, 'prog/werinwer2.cpp') == os.path.join(os.getcwd(), 'prog', 'werinwer2.cpp') 19 | 20 | 21 | @pytest.mark.parametrize("create_package", [util.get_inwer_package_path()], indirect=True) 22 | def test_compile_inwer(create_package): 23 | """ 24 | Test compilation of inwer. 25 | """ 26 | task_id = package_util.get_task_id() 27 | inwer_path = inwer_util.get_inwer_path(task_id) 28 | args = compiler.get_default_compilers() 29 | executable = inwer_util.compile_inwer(inwer_path, args) 30 | assert os.path.exists(executable) 31 | 32 | 33 | @pytest.mark.parametrize("create_package", [util.get_inwer_package_path()], indirect=True) 34 | def test_asserting_inwer(create_package): 35 | """ 36 | Test asserting inwer. 37 | """ 38 | package_path = create_package 39 | task_id = package_util.get_task_id() 40 | util.create_ins(package_path, task_id) 41 | inwer_path = os.path.join(os.getcwd(), 'prog', 'werinwer3.cpp') 42 | args = argparse.Namespace( 43 | c_compiler_path=compiler.get_c_compiler_path(), 44 | cpp_compiler_path=compiler.get_cpp_compiler_path(), 45 | python_interpreter_path=compiler.get_python_interpreter_path(), 46 | java_compiler_path=compiler.get_java_compiler_path() 47 | ) 48 | executable = inwer_util.compile_inwer(inwer_path, args) 49 | 50 | execution = InwerExecution( 51 | inwer_exe_path=executable, 52 | test_name='wer2a.in', 53 | test_path=os.path.join(os.getcwd(), 'in', 'wer2a.in'), 54 | ) 55 | 56 | res = Command.verify_test(execution) 57 | assert res.valid is False 58 | assertion_re = re.compile(r'.*Assertion.*failed') 59 | print(res.output) 60 | print(assertion_re.match(res.output)) 61 | assert assertion_re.match(res.output) is not None 62 | 63 | 64 | def test_tests_comparator(): 65 | for ti in ["abc", "long_task_id", ""]: 66 | assert inwer_util.sort_tests([f"{ti}2a.in", f"{ti}1a.in"], ti) == [f"{ti}1a.in", f"{ti}2a.in"] 67 | assert inwer_util.sort_tests([f"{ti}2a.in", f"{ti}1a.in", f"{ti}1b.in"], ti) == \ 68 | [f"{ti}1a.in", f"{ti}1b.in", f"{ti}2a.in"] 69 | assert inwer_util.sort_tests([f"{ti}2a.in", f"{ti}1a.in", f"{ti}1b.in", f"{ti}10a.in"], ti) == \ 70 | [f"{ti}1a.in", f"{ti}1b.in", f"{ti}2a.in", f"{ti}10a.in"] 71 | assert inwer_util.sort_tests([f"{ti}2a.in", f"{ti}1a.in", f"{ti}1b.in", f"{ti}10a.in", f"{ti}10b.in"], ti) == \ 72 | [f"{ti}1a.in", f"{ti}1b.in", f"{ti}2a.in", f"{ti}10a.in", f"{ti}10b.in"] 73 | 74 | 75 | def test_verify_tests_order(): 76 | command = Command() 77 | command.task_id = "abc" 78 | command.tests = ["abc1ocen.in", "abc2ocen.in", "abc3ocen.in", 79 | "abc1a.in", "abc1b.in", "abc1c.in", "abc1d.in", 80 | "abc2z.in", "abc2aa.in", "abc2ab.in", "abc2ac.in"] 81 | command.verify_tests_order() 82 | 83 | command.tests.remove("abc2ocen.in") 84 | with pytest.raises(SystemExit): 85 | command.verify_tests_order() 86 | 87 | command.tests.append("abc2ocen.in") 88 | command.tests.remove("abc1c.in") 89 | with pytest.raises(SystemExit): 90 | command.verify_tests_order() 91 | 92 | command.tests.append("abc1c.in") 93 | command.tests.remove("abc2aa.in") 94 | with pytest.raises(SystemExit): 95 | command.verify_tests_order() 96 | 97 | command.tests.append("abc2aa.in") 98 | command.tests.remove("abc1ocen.in") 99 | command.tests.remove("abc2ocen.in") 100 | command.tests.remove("abc3ocen.in") 101 | command.tests.append("abc9ocen.in") 102 | command.tests.append("abc10ocen.in") 103 | command.tests.append("abc11ocen.in") 104 | 105 | command.verify_tests_order() 106 | 107 | command.tests = ["abc0.in", "abc0a.in", "abc0b.in", 108 | "abc1.in", "abc1a.in", "abc1b.in"] 109 | command.verify_tests_order() 110 | 111 | command.tests.remove("abc0a.in") 112 | with pytest.raises(SystemExit): 113 | command.verify_tests_order() 114 | --------------------------------------------------------------------------------