diff --git a/.vscode/launch.json b/.vscode/launch.json index 70c4c2fc..809ee6af 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -293,5 +293,18 @@ }, "justMyCode": false, }, + { + "name": "Apio test", + "type": "debugpy", + "request": "launch", + "module": "pytest", + "args": [ + "-s", + "test/commands/test_build.py" + ], + "console": "integratedTerminal", + "justMyCode": false, + "cwd": "${workspaceFolder}" + }, ] } \ No newline at end of file diff --git a/apio/apio_context.py b/apio/apio_context.py index dcc65365..8547a73d 100644 --- a/apio/apio_context.py +++ b/apio/apio_context.py @@ -183,7 +183,7 @@ def _load_resource(self, name: str, allow_custom: bool = False) -> dict: if filepath.exists(): if allow_custom: - click.secho(f"Loading project's custom '{name}' file.") + click.secho(f"Loading custom '{name}'.") return self._load_resource_file(filepath) # -- Load the stock resource file from the APIO package. diff --git a/apio/commands/boards.py b/apio/commands/boards.py index e572e12d..63fbd878 100644 --- a/apio/commands/boards.py +++ b/apio/commands/boards.py @@ -14,9 +14,6 @@ from apio.commands import options -# ) - - # R0914: Too many local variables (17/15) # pylint: disable=R0914 def list_boards(apio_ctx: ApioContext): @@ -88,13 +85,11 @@ def list_boards(apio_ctx: ApioContext): # -- bullet points. click.secho(f"{board:<{max_board_name_len}} | {item_fpga}") + # -- Print the footer. if config.terminal_mode(): - # -- Print the Footer click.secho(seperator_line) - click.secho(f"Total: {len(apio_ctx.boards)} boards") - # -- Help message - # click.secho(BOARDS_MSG, fg="green") + click.secho(f"Total of {util.plurality(apio_ctx.boards, 'board')}") # --------------------------- diff --git a/apio/commands/fpgas.py b/apio/commands/fpgas.py index 055af503..b047539e 100644 --- a/apio/commands/fpgas.py +++ b/apio/commands/fpgas.py @@ -59,7 +59,8 @@ def list_fpgas(apio_ctx: ApioContext): # -- Print the Footer if config.terminal_mode(): click.secho(seperator_line) - click.secho(f"Total: {len(apio_ctx.fpgas)} fpgas\n") + + click.secho(f"Total of {util.plurality(apio_ctx.fpgas, 'fpga')}") # --------------------------- diff --git a/test/commands/test_boards.py b/test/commands/test_boards.py index 1a534afb..4bc9d75c 100644 --- a/test/commands/test_boards.py +++ b/test/commands/test_boards.py @@ -5,16 +5,65 @@ # -- apio boards entry point from apio.commands.boards import cli as cmd_boards +CUSTOM_BOARDS = """ +{ + "my_custom_board": { + "name": "My Custom Board v3.1c", + "fpga": "iCE40-UP5K-SG48", + "programmer": { + "type": "iceprog" + }, + "usb": { + "vid": "0403", + "pid": "6010" + }, + "ftdi": { + "desc": "My Custom Board" + } + } +} +""" + -def test_boards(clirunner, configenv, validate_cliresult): - """Test "apio boards" command.""" +def test_list_ok(click_cmd_runner, setup_apio_test_env, assert_apio_cmd_ok): + """Test normal board listing with the apio's boards.json.""" - with clirunner.isolated_filesystem(): + with click_cmd_runner.isolated_filesystem(): - # -- Config the environment (conftest.configenv()) - configenv() + # -- Config the apio test environment + setup_apio_test_env() # -- Execute "apio boards" - result = clirunner.invoke(cmd_boards) - validate_cliresult(result) + result = click_cmd_runner.invoke(cmd_boards) + assert_apio_cmd_ok(result) + # -- Note: pytest sees the piped version of the command's output. + # -- Run 'apio build' | cat' to reproduce it. + assert "Loading custom 'boards.json'" not in result.output assert "alhambra-ii" in result.output + assert "my_custom_board" not in result.output + assert "Total of 1 board" not in result.output + + +def test_custom_board( + click_cmd_runner, setup_apio_test_env, assert_apio_cmd_ok +): + """Test boards listing with a custom boards.json file.""" + + with click_cmd_runner.isolated_filesystem(): + + # -- Config the apio test environment + setup_apio_test_env() + + # -- Write a custom boards.json file in the project's directory. + with open("boards.json", "w", encoding="utf-8") as f: + f.write(CUSTOM_BOARDS) + + # -- Execute "apio boards" + result = click_cmd_runner.invoke(cmd_boards) + assert_apio_cmd_ok(result) + # -- Note: pytest sees the piped version of the command's output. + # -- Run 'apio build' | cat' to reproduce it. + assert "Loading custom 'boards.json'" in result.output + assert "alhambra-ii" not in result.output + assert "my_custom_board" in result.output + assert "Total of 1 board" in result.output diff --git a/test/commands/test_build.py b/test/commands/test_build.py index b583d24e..2ef5f8fc 100644 --- a/test/commands/test_build.py +++ b/test/commands/test_build.py @@ -5,85 +5,52 @@ # -- apio build entry point from apio.commands.build import cli as cmd_build -# -- This is for testing "apio create" -from apio.commands.create import cli as cmd_create +# pylint: disable=too-many-statements +def test_errors_without_apio_ini_1(click_cmd_runner, setup_apio_test_env): + """Test: Various errors 1/2. All tests are without apio.ini and without + apio packages installed.""" -def test_build(clirunner, configenv): - """Test: apio build - when no apio.ini file is given - No additional parameters are given - """ + with click_cmd_runner.isolated_filesystem(): - with clirunner.isolated_filesystem(): - - # -- Config the environment (conftest.configenv()) - configenv() + # -- Config the apio test environment + setup_apio_test_env() # -- Execute "apio build" - result = clirunner.invoke(cmd_build) - - # -- It is an error. Exit code should not be 0 + result = click_cmd_runner.invoke(cmd_build) assert result.exit_code != 0, result.output - - # -- Messages thtat should appear assert "Info: Project has no apio.ini file" in result.output assert "Error: insufficient arguments: missing board" in result.output assert "Error: Missing FPGA" in result.output - -def test_build_board(clirunner, configenv): - """Test: apio build --board icezum - No oss-cad-suite package is installed - """ - - with clirunner.isolated_filesystem(): - - # -- Config the environment (conftest.configenv()) - configenv() - - # -- Execute "apio build --board icezum" - result = clirunner.invoke(cmd_build, ["--board", "icezum"]) - - # -- Check the result - assert result.exit_code != 0, result.output - assert "apio packages --install --force oss-cad-suite" in result.output - - -def test_build_complete1(clirunner, configenv): - """Test: apio build with different arguments. Part 1/2""" - - with clirunner.isolated_filesystem(): - - # -- Config the environment (conftest.configenv()) - configenv() - # apio build --board icestick - result = clirunner.invoke(cmd_build, ["--board", "icestick"]) + result = click_cmd_runner.invoke(cmd_build, ["--board", "icestick"]) assert result.exit_code == 1, result.output assert "apio packages --install --force oss-cad-suite" in result.output # apio build --fpga iCE40-HX1K-VQ100 - result = clirunner.invoke(cmd_build, ["--fpga", "iCE40-HX1K-VQ100"]) + result = click_cmd_runner.invoke( + cmd_build, ["--fpga", "iCE40-HX1K-VQ100"] + ) assert result.exit_code == 1, result.output assert "apio packages --install --force oss-cad-suite" in result.output # apio build --type lp --size 8k --pack cm225:4k - result = clirunner.invoke( + result = click_cmd_runner.invoke( cmd_build, ["--type", "lp", "--size", "8k", "--pack", "cm225:4k"] ) assert result.exit_code == 1, result.output assert "Error: insufficient arguments" in result.output # apio build --board icezum --size 1k - result = clirunner.invoke( + result = click_cmd_runner.invoke( cmd_build, ["--board", "icezum", "--size", "1k"] ) assert result.exit_code != 0, result.output assert "apio packages --install --force oss-cad-suite" in result.output # apio build --board icezum --fpga iCE40-HX1K-TQ144 --type hx - result = clirunner.invoke( + result = click_cmd_runner.invoke( cmd_build, [ "--board", @@ -98,14 +65,14 @@ def test_build_complete1(clirunner, configenv): assert "apio packages --install --force oss-cad-suite" in result.output # apio build --board icezum --pack tq144 - result = clirunner.invoke( + result = click_cmd_runner.invoke( cmd_build, ["--board", "icezum", "--pack", "tq144"] ) assert result.exit_code != 0, result.output assert "apio packages --install --force oss-cad-suite" in result.output # apio build --fpga iCE40-HX1K-TQ144 --pack tq144 --size 1k - result = clirunner.invoke( + result = click_cmd_runner.invoke( cmd_build, ["--fpga", "iCE40-HX1K-TQ144", "--pack", "tq144", "--size", "1k"], ) @@ -113,14 +80,14 @@ def test_build_complete1(clirunner, configenv): assert "apio packages --install --force oss-cad-suite" in result.output # apio build --fpga iCE40-HX1K-TQ144 --type hx - result = clirunner.invoke( + result = click_cmd_runner.invoke( cmd_build, ["--fpga", "iCE40-HX1K-TQ144", "--type", "hx"] ) assert result.exit_code != 0, result.output assert "apio packages --install --force oss-cad-suite" in result.output # apio build --board icezum --size 8k - result = clirunner.invoke( + result = click_cmd_runner.invoke( cmd_build, ["--board", "icezum", "--size", "8k"] ) assert result.exit_code != 0, result.output @@ -130,7 +97,7 @@ def test_build_complete1(clirunner, configenv): ) # apio build --board icezum --fpga iCE40-HX1K-TQ144 --type lp - result = clirunner.invoke( + result = click_cmd_runner.invoke( cmd_build, [ "--board", @@ -148,7 +115,7 @@ def test_build_complete1(clirunner, configenv): ) # apio build --board icezum --fpga iCE40-HX1K-VQ100 - result = clirunner.invoke( + result = click_cmd_runner.invoke( cmd_build, ["--board", "icezum", "--fpga", "iCE40-HX1K-VQ100"] ) assert result.exit_code != 0, result.output @@ -158,7 +125,7 @@ def test_build_complete1(clirunner, configenv): ) # apio build --fpga iCE40-HX1K-TQ144 --type lp --size 8k - result = clirunner.invoke( + result = click_cmd_runner.invoke( cmd_build, ["--fpga", "iCE40-HX1K-TQ144", "--type", "lp", "--size", "8k"], ) @@ -169,7 +136,7 @@ def test_build_complete1(clirunner, configenv): ) # apio build --fpga iCE40-HX1K-TQ144 --pack vq100 - result = clirunner.invoke( + result = click_cmd_runner.invoke( cmd_build, ["--fpga", "iCE40-HX1K-TQ144", "--pack", "vq100"] ) assert result.exit_code != 0, result.output @@ -179,7 +146,7 @@ def test_build_complete1(clirunner, configenv): ) # apio build --board icezum --pack vq100 - result = clirunner.invoke( + result = click_cmd_runner.invoke( cmd_build, ["--board", "icezum", "--pack", "vq100"] ) assert result.exit_code != 0, result.output @@ -189,55 +156,57 @@ def test_build_complete1(clirunner, configenv): ) # apio build --size 8k - result = clirunner.invoke(cmd_build, ["--size", "8k"]) + result = click_cmd_runner.invoke(cmd_build, ["--size", "8k"]) assert result.exit_code != 0, result.output assert "Error: insufficient arguments" in result.output -def test_build_complete2(clirunner, configenv): - """Test: apio build with different arguments. Part 2/2""" +def test_errors_without_apio_ini_2(click_cmd_runner, setup_apio_test_env): + """Test: Various errors 2/2. All tests are without apio.ini and without + apio packages installed.""" + with click_cmd_runner.isolated_filesystem(): - with clirunner.isolated_filesystem(): - - # -- Config the environment (conftest.configenv()) - configenv() + # -- Config the apio test environment + setup_apio_test_env() # apio build --type lp - result = clirunner.invoke(cmd_build, ["--type", "lp"]) + result = click_cmd_runner.invoke(cmd_build, ["--type", "lp"]) assert result.exit_code != 0, result.output assert "Error: insufficient arguments" in result.output # apio build --type lp --size 8k - result = clirunner.invoke(cmd_build, ["--type", "lp", "--size", "8k"]) + result = click_cmd_runner.invoke( + cmd_build, ["--type", "lp", "--size", "8k"] + ) assert result.exit_code != 0, result.output assert "Error: insufficient arguments" in result.output # apio build --board icefake - result = clirunner.invoke(cmd_build, ["--board", "icefake"]) + result = click_cmd_runner.invoke(cmd_build, ["--board", "icefake"]) assert result.exit_code != 0, result.output assert "Error: unknown board: icefake" in result.output # apio build --board icefake --fpga iCE40-HX1K-TQ144 - result = clirunner.invoke( + result = click_cmd_runner.invoke( cmd_build, ["--board", "icefake", "--fpga", "iCE40-HX1K-TQ144"] ) assert result.exit_code != 0, result.output assert "Error: unknown board: icefake" in result.output # apio build --fpga iCE40-FAKE - result = clirunner.invoke(cmd_build, ["--fpga", "iCE40-FAKE"]) + result = click_cmd_runner.invoke(cmd_build, ["--fpga", "iCE40-FAKE"]) assert result.exit_code != 0, result.output assert "Error: unknown FPGA: iCE40-FAKE" in result.output # apio build --fpga iCE40-FAKE --size 8k - result = clirunner.invoke( + result = click_cmd_runner.invoke( cmd_build, ["--fpga", "iCE40-FAKE", "--size", "8k"] ) assert result.exit_code != 0, result.output assert "Error: unknown FPGA: iCE40-FAKE" in result.output # apio build --board icezum --fpga iCE40-FAKE - result = clirunner.invoke( + result = click_cmd_runner.invoke( cmd_build, ["--board", "icezum", "--fpga", "iCE40-FAKE"] ) assert result.exit_code != 0, result.output @@ -247,26 +216,25 @@ def test_build_complete2(clirunner, configenv): ) -def test_build_create(clirunner, configenv): +def test_errors_with_apio_ini( + click_cmd_runner, setup_apio_test_env, write_apio_ini +): """Test: apio build with apio create""" - with clirunner.isolated_filesystem(): + with click_cmd_runner.isolated_filesystem(): - # -- Config the environment (conftest.configenv()) - configenv() + # -- Config the apio test environment + setup_apio_test_env() - # apio create --board icezum - result = clirunner.invoke(cmd_create, ["--board", "icezum"]) - assert result.exit_code == 0, result.output - assert "Creating apio.ini file ..." in result.output - assert "was created successfully" in result.output + # -- Write apio.ini + write_apio_ini({"board": "icezum", "top-module": "main"}) # apio build - result = clirunner.invoke(cmd_build) + result = click_cmd_runner.invoke(cmd_build) assert result.exit_code != 0, result.output - # apio build --board icezum - result = clirunner.invoke(cmd_build, ["--board", "icestick"]) + # apio build --board icestick + result = click_cmd_runner.invoke(cmd_build, ["--board", "icestick"]) assert result.exit_code != 0, result.output assert ( "Info: ignoring board specification from apio.ini." @@ -274,7 +242,9 @@ def test_build_create(clirunner, configenv): ) # apio build --fpga iCE40-HX1K-VQ100 - result = clirunner.invoke(cmd_build, ["--fpga", "iCE40-HX1K-VQ100"]) + result = click_cmd_runner.invoke( + cmd_build, ["--fpga", "iCE40-HX1K-VQ100"] + ) assert result.exit_code != 0, result.output assert ( "Error: contradictory argument values: 'fpga' = " @@ -282,7 +252,7 @@ def test_build_create(clirunner, configenv): ) # apio build --type lp --size 8k --pack cm225:4k - result = clirunner.invoke( + result = click_cmd_runner.invoke( cmd_build, ["--type", "lp", "--size", "8k", "--pack", "cm225:4k"] ) assert result.exit_code != 0, result.output @@ -292,7 +262,9 @@ def test_build_create(clirunner, configenv): ) # apio build --type lp --size 8k - result = clirunner.invoke(cmd_build, ["--type", "lp", "--size", "8k"]) + result = click_cmd_runner.invoke( + cmd_build, ["--type", "lp", "--size", "8k"] + ) assert result.exit_code != 0, result.output assert ( "Error: contradictory argument values: 'type' = (hx vs lp)" diff --git a/test/commands/test_clean.py b/test/commands/test_clean.py index f8db0ad3..1eff97c0 100644 --- a/test/commands/test_clean.py +++ b/test/commands/test_clean.py @@ -5,23 +5,19 @@ # -- apio clean entry point from apio.commands.clean import cli as cmd_clean -# -- apio create entry point -from apio.commands.create import cli as cmd_create - -def test_clean(clirunner, configenv): - """Test: apio clean - when no apio.ini file is given +def test_clean_no_apio_ini_no_params(click_cmd_runner, setup_apio_test_env): + """Test: apio clean when no apio.ini file is given No additional parameters are given """ - with clirunner.isolated_filesystem(): + with click_cmd_runner.isolated_filesystem(): - # -- Config the environment (conftest.configenv()) - configenv() + # -- Config the apio test environment + setup_apio_test_env() # -- Execute "apio clean" - result = clirunner.invoke(cmd_clean) + result = click_cmd_runner.invoke(cmd_clean) # -- It is an error. Exit code should not be 0 assert result.exit_code != 0, result.output @@ -29,26 +25,70 @@ def test_clean(clirunner, configenv): assert "Error: insufficient arguments: missing board" in result.output # -- Execute "apio clean --board alhambra-ii" - result = clirunner.invoke(cmd_clean, ["--board", "alhambra-ii"]) + result = click_cmd_runner.invoke(cmd_clean, ["--board", "alhambra-ii"]) assert result.exit_code == 0, result.output -def test_clean_create(clirunner, configenv): - """Test: apio clean - when there is an apio.ini file +def test_clean_no_apio_ini_params( + click_cmd_runner, setup_apio_test_env, path_in_project +): + """Test: apio clean when no apio.ini file is given. Board definition + comes from --board parameter. """ - with clirunner.isolated_filesystem(): + with click_cmd_runner.isolated_filesystem(): + + # -- Config the apio test environment + setup_apio_test_env() + + # -- Create a legacy artifact file. + path_in_project("main_tb.vcd").touch() + + # -- Create a current artifact file. + path_in_project("_build").mkdir() + path_in_project("_build/main_tb.vcd").touch() - # -- Config the environment (conftest.configenv()) - configenv() + # Confirm that the files exists + assert path_in_project("main_tb.vcd").is_file() + assert path_in_project("_build/main_tb.vcd").is_file() - # apio create --board icezum - result = clirunner.invoke(cmd_create, ["--board", "alhambra-ii"]) + # -- Execute "apio clean --board alhambra-ii" + result = click_cmd_runner.invoke(cmd_clean, ["--board", "alhambra-ii"]) assert result.exit_code == 0, result.output - assert "Creating apio.ini file ..." in result.output - assert "was created successfully" in result.output + + # Confirm that the files do not exist. + assert not path_in_project("main_tb.vcd").exists() + assert not path_in_project("_build/main_tb.vcd").exists() + + +def test_clean_create( + click_cmd_runner, setup_apio_test_env, path_in_project, write_apio_ini +): + """Test: apio clean when there is an apio.ini file""" + + with click_cmd_runner.isolated_filesystem(): + + # -- Config the apio test environment + setup_apio_test_env() + + # -- Create apio.ini + write_apio_ini({"board": "icezum", "top-module": "main"}) + + # -- Create a legacy artifact file. + path_in_project("main_tb.vcd").touch() + + # -- Create a current artifact file. + path_in_project("_build").mkdir() + path_in_project("_build/main_tb.vcd").touch() + + # Confirm that the files exists + assert path_in_project("main_tb.vcd").is_file() + assert path_in_project("_build/main_tb.vcd").is_file() # --- Execute "apio clean" - result = clirunner.invoke(cmd_clean) + result = click_cmd_runner.invoke(cmd_clean) assert result.exit_code == 0, result.output + + # Confirm that the files do not exist. + assert not path_in_project("main_tb.vcd").exists() + assert not path_in_project("_build/main_tb.vcd").exists() diff --git a/test/commands/test_create.py b/test/commands/test_create.py index 64e011c3..a217cdd2 100644 --- a/test/commands/test_create.py +++ b/test/commands/test_create.py @@ -13,7 +13,7 @@ # R0801: Similar lines in 2 files # pylint: disable=R0801 -def check_ini_file(apio_ini: Path, expected_vars: Dict[str, str]) -> None: +def _check_ini_file(apio_ini: Path, expected_vars: Dict[str, str]) -> None: """Assert that apio.ini contains exactly the given vars.""" # Read the ini file. assert isfile(apio_ini) @@ -24,68 +24,72 @@ def check_ini_file(apio_ini: Path, expected_vars: Dict[str, str]) -> None: assert conf.dict() == {"env": expected_vars} -def test_create(clirunner, configenv, validate_cliresult): +def test_create(click_cmd_runner, setup_apio_test_env, assert_apio_cmd_ok): """Test "apio create" with different parameters""" - with clirunner.isolated_filesystem(): + with click_cmd_runner.isolated_filesystem(): - # -- Config the environment (conftest.configenv()) - configenv() + # -- Config the apio test environment + setup_apio_test_env() apio_ini = Path("apio.ini") assert not exists(apio_ini) # -- Execute "apio create" - result = clirunner.invoke(cmd_create) + result = click_cmd_runner.invoke(cmd_create) assert result.exit_code != 0, result.output assert "Error: Missing option" in result.output assert not exists(apio_ini) # -- Execute "apio create --board missed_board" - result = clirunner.invoke(cmd_create, ["--board", "missed_board"]) + result = click_cmd_runner.invoke( + cmd_create, ["--board", "missed_board"] + ) assert result.exit_code == 1, result.output assert "Error: no such board" in result.output assert not exists(apio_ini) # -- Execute "apio create --board icezum" - result = clirunner.invoke(cmd_create, ["--board", "icezum"]) - validate_cliresult(result) + result = click_cmd_runner.invoke(cmd_create, ["--board", "icezum"]) + assert_apio_cmd_ok(result) + assert "file already exists" not in result.output + assert "Do you want to replace it?" not in result.output assert "Creating apio.ini file ..." in result.output assert "was created successfully." in result.output - check_ini_file(apio_ini, {"board": "icezum", "top-module": "main"}) + _check_ini_file(apio_ini, {"board": "icezum", "top-module": "main"}) # -- Execute "apio create --board alhambra-ii # -- --top-module my_module" with 'y' input" - result = clirunner.invoke( + result = click_cmd_runner.invoke( cmd_create, ["--board", "alhambra-ii", "--top-module", "my_module"], input="y", ) - validate_cliresult(result) + assert_apio_cmd_ok(result) assert "Warning" in result.output assert "file already exists" in result.output assert "Do you want to replace it?" in result.output assert "was created successfully." in result.output - check_ini_file( + _check_ini_file( apio_ini, {"board": "alhambra-ii", "top-module": "my_module"} ) # -- Execute "apio create --board icezum # -- --top-module my_module # -- --sayyse" with 'y' input - result = clirunner.invoke( + result = click_cmd_runner.invoke( cmd_create, ["--board", "icezum", "--top-module", "my_module", "--sayyes"], ) - validate_cliresult(result) + assert_apio_cmd_ok(result) assert "was created successfully." in result.output - check_ini_file( + _check_ini_file( apio_ini, {"board": "icezum", "top-module": "my_module"} ) # -- Execute "apio create --board alhambra-ii # -- --top-module my_module" with 'n' input - result = clirunner.invoke( + result = click_cmd_runner.invoke( cmd_create, ["--board", "alhambra-ii", "--top-module", "my_module"], input="n", @@ -95,6 +99,6 @@ def test_create(clirunner, configenv, validate_cliresult): assert "file already exists" in result.output assert "Do you want to replace it?" in result.output assert "Abort!" in result.output - check_ini_file( + _check_ini_file( apio_ini, {"board": "icezum", "top-module": "my_module"} ) diff --git a/test/commands/test_drivers.py b/test/commands/test_drivers.py index 8b7bfe09..a743c591 100644 --- a/test/commands/test_drivers.py +++ b/test/commands/test_drivers.py @@ -6,14 +6,24 @@ from apio.commands.drivers import cli as cmd_drivers -def test_drivers(clirunner, validate_cliresult, configenv): - """Test "apio drivers" with different parameters""" +def test_drivers(click_cmd_runner, assert_apio_cmd_ok, setup_apio_test_env): + """Test "apio drivers" """ - with clirunner.isolated_filesystem(): + with click_cmd_runner.isolated_filesystem(): - # -- Config the environment (conftest.configenv()) - configenv() + # -- Config the apio test environment + setup_apio_test_env() # -- Execute "apio drivers" - result = clirunner.invoke(cmd_drivers) - validate_cliresult(result) + result = click_cmd_runner.invoke(cmd_drivers) + assert_apio_cmd_ok(result) + + # -- Execute "apio --ftdi-install, --serial-install" + result = click_cmd_runner.invoke( + cmd_drivers, ["--ftdi-install", "--serial-install"] + ) + assert result.exit_code == 1, result.output + assert ( + "Error: [--ftdi-install, --serial-install] " + "are mutually exclusive" in result.output + ) diff --git a/test/commands/test_examples.py b/test/commands/test_examples.py index a82e038e..8592a7e8 100644 --- a/test/commands/test_examples.py +++ b/test/commands/test_examples.py @@ -6,16 +6,16 @@ from apio.commands.examples import cli as cmd_examples -def test_examples(clirunner, configenv): +def test_examples(click_cmd_runner, setup_apio_test_env): """Test "apio examples" with different parameters""" - with clirunner.isolated_filesystem(): + with click_cmd_runner.isolated_filesystem(): - # -- Config the environment (conftest.configenv()) - configenv() + # -- Config the apio test environment + setup_apio_test_env() # -- Execute "apio examples" - result = clirunner.invoke(cmd_examples) + result = click_cmd_runner.invoke(cmd_examples) assert result.exit_code == 1, result.output assert ( "One of [--list, --fetch-dir, --fetch-files] " @@ -23,16 +23,21 @@ def test_examples(clirunner, configenv): ) # -- Execute "apio examples --list" - result = clirunner.invoke(cmd_examples, ["--list"]) + result = click_cmd_runner.invoke(cmd_examples, ["--list"]) assert result.exit_code == 1, result.output + assert "Error: package 'examples' is not installed" in result.output assert "apio packages --install --force examples" in result.output - # -- Execute "apio examples --dir dir" - result = clirunner.invoke(cmd_examples, ["--fetch-dir", "dir"]) + # -- Execute "apio examples --fetch-dir dir" + result = click_cmd_runner.invoke(cmd_examples, ["--fetch-dir", "dir"]) assert result.exit_code == 1, result.output + assert "Error: package 'examples' is not installed" in result.output assert "apio packages --install --force examples" in result.output # -- Execute "apio examples --files file" - result = clirunner.invoke(cmd_examples, ["--fetch-files", "file"]) + result = click_cmd_runner.invoke( + cmd_examples, ["--fetch-files", "file"] + ) assert result.exit_code == 1, result.output + assert "Error: package 'examples' is not installed" in result.output assert "apio packages --install --force examples" in result.output diff --git a/test/commands/test_fpgas.py b/test/commands/test_fpgas.py index 3e838342..58bf3704 100644 --- a/test/commands/test_fpgas.py +++ b/test/commands/test_fpgas.py @@ -5,16 +5,56 @@ # -- apio fpgas entry point from apio.commands.fpgas import cli as cmd_fpgas +CUSTOM_FPGAS = """ +{ + "my_custom_fpga": { + "arch": "ice40", + "type": "lp", + "size": "1k", + "pack": "swg16tr" + } +} +""" + -def test_boards(clirunner, configenv, validate_cliresult): - """Test "apio fpgas" command.""" +def test_fpgas_ok(click_cmd_runner, setup_apio_test_env, assert_apio_cmd_ok): + """Test "apio fpgas" command with standard fpgas.json.""" - with clirunner.isolated_filesystem(): + with click_cmd_runner.isolated_filesystem(): - # -- Config the environment (conftest.configenv()) - configenv() + # -- Config the apio test environment + setup_apio_test_env() # -- Execute "apio fpgas" - result = clirunner.invoke(cmd_fpgas) - validate_cliresult(result) + result = click_cmd_runner.invoke(cmd_fpgas) + assert_apio_cmd_ok(result) + # -- Note: pytest sees the piped version of the command's output. + # -- Run 'apio fpgas' | cat' to reproduce it. + assert "Loading custom 'fpgas.json'" not in result.output assert "iCE40-HX4K-TQ144" in result.output + assert "my_custom_fpga" not in result.output + + +def test_custom_fpga( + click_cmd_runner, setup_apio_test_env, assert_apio_cmd_ok +): + """Test "apio fpgas" command with a custom fpgas.json.""" + + with click_cmd_runner.isolated_filesystem(): + + # -- Config the apio test environment + setup_apio_test_env() + + # -- Write a custom boards.json file in the project's directory. + with open("fpgas.json", "w", encoding="utf-8") as f: + f.write(CUSTOM_FPGAS) + + # -- Execute "apio boards" + result = click_cmd_runner.invoke(cmd_fpgas) + assert_apio_cmd_ok(result) + # -- Note: pytest sees the piped version of the command's output. + # -- Run 'apio build' | cat' to reproduce it. + assert "Loading custom 'fpgas.json'" in result.output + assert "iCE40-HX4K-TQ144" not in result.output + assert "my_custom_fpga" in result.output + assert "Total of 1 fpga" in result.output diff --git a/test/commands/test_graph.py b/test/commands/test_graph.py index 80348753..ad8fe832 100644 --- a/test/commands/test_graph.py +++ b/test/commands/test_graph.py @@ -6,20 +6,47 @@ from apio.commands.graph import cli as cmd_graph -def test_graph(clirunner, configenv): - """Test: apio graph - when no apio.ini file is given - No additional parameters are given - """ +def test_graph_no_apio_ini(click_cmd_runner, setup_apio_test_env): + """Test: apio graph with no apio.ini""" - with clirunner.isolated_filesystem(): + with click_cmd_runner.isolated_filesystem(): - # -- Config the environment (conftest.configenv()) - configenv() + # -- Config the apio test environment + setup_apio_test_env() # -- Execute "apio graph" - result = clirunner.invoke(cmd_graph) + result = click_cmd_runner.invoke(cmd_graph) + assert result.exit_code == 1, result.output + assert "Error: insufficient arguments: missing board" in result.output - # -- Check the result - assert result.exit_code != 0, result.output - # -- TODO (FIXME!) + +def test_graph_with_apio_ini( + click_cmd_runner, setup_apio_test_env, write_apio_ini +): + """Test: apio graph with apio.ini""" + + with click_cmd_runner.isolated_filesystem(): + + # -- Config the apio test environment + setup_apio_test_env() + + # -- Create an apio.ini file + write_apio_ini({"board": "icezum", "top-module": "main"}) + + # -- Execute "apio graph" + result = click_cmd_runner.invoke(cmd_graph) + assert result.exit_code == 1, result.output + assert "package 'oss-cad-suite' is not installed" in result.output + assert "apio packages --install --force oss-cad-suite" in result.output + + # -- Execute "apio graph -pdf" + result = click_cmd_runner.invoke(cmd_graph) + assert result.exit_code == 1, result.output + assert "package 'oss-cad-suite' is not installed" in result.output + assert "apio packages --install --force oss-cad-suite" in result.output + + # -- Execute "apio graph -png" + result = click_cmd_runner.invoke(cmd_graph) + assert result.exit_code == 1, result.output + assert "package 'oss-cad-suite' is not installed" in result.output + assert "apio packages --install --force oss-cad-suite" in result.output diff --git a/test/commands/test_install.py b/test/commands/test_install.py index e746e469..8db4ca2c 100644 --- a/test/commands/test_install.py +++ b/test/commands/test_install.py @@ -6,23 +6,23 @@ from apio.commands.install import cli as cmd_install -def test_install(clirunner, configenv, validate_cliresult): +def test_install(click_cmd_runner, setup_apio_test_env, assert_apio_cmd_ok): """Test "apio install" with different parameters""" - with clirunner.isolated_filesystem(): + with click_cmd_runner.isolated_filesystem(): - # -- Config the environment (conftest.configenv()) - configenv() + # -- Config the apio test environment + setup_apio_test_env() # -- Execute "apio install" - result = clirunner.invoke(cmd_install) - validate_cliresult(result) + result = click_cmd_runner.invoke(cmd_install) + assert_apio_cmd_ok(result) # -- Execute "apio install --list" - result = clirunner.invoke(cmd_install, ["--list"]) - validate_cliresult(result) + result = click_cmd_runner.invoke(cmd_install, ["--list"]) + assert_apio_cmd_ok(result) # -- Execute "apio install missing_package" - result = clirunner.invoke(cmd_install, ["missing_package"]) + result = click_cmd_runner.invoke(cmd_install, ["missing_package"]) assert result.exit_code == 1, result.output assert "Error: no such package" in result.output diff --git a/test/commands/test_lint.py b/test/commands/test_lint.py index 30dbf86a..61a7cb83 100644 --- a/test/commands/test_lint.py +++ b/test/commands/test_lint.py @@ -6,17 +6,23 @@ from apio.commands.lint import cli as cmd_lint -def test_lint(clirunner, configenv): - """Test: apio lint - when no apio.ini file is given - No additional parameters are given - """ +def test_lint_no_packages( + click_cmd_runner, setup_apio_test_env, write_apio_ini +): + """Test: apio lint with missing packages.""" - with clirunner.isolated_filesystem(): + with click_cmd_runner.isolated_filesystem(): - # -- Config the environment (conftest.configenv()) - configenv() + # -- Config the apio test environment + setup_apio_test_env() + + # -- Create apio.ini file. + write_apio_ini({"board": "icezum", "top-module": "main"}) # -- Execute "apio lint" - result = clirunner.invoke(cmd_lint, ["--board", "alhambra-ii"]) - assert result.exit_code != 0, result.output + result = click_cmd_runner.invoke(cmd_lint) + assert result.exit_code == 1, result.output + assert ( + "Error: package 'oss-cad-suite' is not installed" in result.output + ) + assert "apio packages --install --force oss-cad-suite" in result.output diff --git a/test/commands/test_modify.py b/test/commands/test_modify.py index 9db7e911..92aed60f 100644 --- a/test/commands/test_modify.py +++ b/test/commands/test_modify.py @@ -24,19 +24,21 @@ def check_ini_file(apio_ini: Path, expected_vars: Dict[str, str]) -> None: assert conf.dict() == {"env": expected_vars} -def test_modify(clirunner, configenv, validate_cliresult): +def test_modify(click_cmd_runner, setup_apio_test_env, assert_apio_cmd_ok): """Test "apio modify" with different parameters""" - with clirunner.isolated_filesystem(): + with click_cmd_runner.isolated_filesystem(): - # -- Config the environment (conftest.configenv()) - configenv() + # -- Config the apio test environment + setup_apio_test_env() apio_ini = Path("apio.ini") assert not exists(apio_ini) # -- Execute "apio modify --top-module my_module" - result = clirunner.invoke(cmd_modify, ["--top-module", "my_module"]) + result = click_cmd_runner.invoke( + cmd_modify, ["--top-module", "my_module"] + ) assert result.exit_code != 0, result.output assert "Error: 'apio.ini' not found" in result.output assert not exists(apio_ini) @@ -60,7 +62,9 @@ def test_modify(clirunner, configenv, validate_cliresult): ) # -- Execute "apio modify --board missed_board" - result = clirunner.invoke(cmd_modify, ["--board", "missed_board"]) + result = click_cmd_runner.invoke( + cmd_modify, ["--board", "missed_board"] + ) assert result.exit_code == 1, result.output assert "Error: no such board" in result.output check_ini_file( @@ -73,8 +77,10 @@ def test_modify(clirunner, configenv, validate_cliresult): ) # -- Execute "apio modify --board alhambra-ii" - result = clirunner.invoke(cmd_modify, ["--board", "alhambra-ii"]) - validate_cliresult(result) + result = click_cmd_runner.invoke( + cmd_modify, ["--board", "alhambra-ii"] + ) + assert_apio_cmd_ok(result) assert "was modified successfully." in result.output check_ini_file( apio_ini, @@ -86,8 +92,10 @@ def test_modify(clirunner, configenv, validate_cliresult): ) # -- Execute "apio modify --top-module my_main" - result = clirunner.invoke(cmd_modify, ["--top-module", "my_main"]) - validate_cliresult(result) + result = click_cmd_runner.invoke( + cmd_modify, ["--top-module", "my_main"] + ) + assert_apio_cmd_ok(result) assert "was modified successfully." in result.output check_ini_file( apio_ini, @@ -99,10 +107,10 @@ def test_modify(clirunner, configenv, validate_cliresult): ) # -- Execute "apio modify --board icezum --top-module my_top" - result = clirunner.invoke( + result = click_cmd_runner.invoke( cmd_modify, ["--board", "icezum", "--top-module", "my_top"] ) - validate_cliresult(result) + assert_apio_cmd_ok(result) assert "was modified successfully." in result.output check_ini_file( apio_ini, diff --git a/test/commands/test_packages.py b/test/commands/test_packages.py index 54baec90..75f7db79 100644 --- a/test/commands/test_packages.py +++ b/test/commands/test_packages.py @@ -6,16 +6,16 @@ from apio.commands.packages import cli as cmd_packages -def test_packages(clirunner, configenv): +def test_packages(click_cmd_runner, setup_apio_test_env): """Test "apio packages" with different parameters""" - with clirunner.isolated_filesystem(): + with click_cmd_runner.isolated_filesystem(): - # -- Config the environment (conftest.configenv()) - configenv() + # -- Config the apio test environment + setup_apio_test_env() # -- Execute "apio packages" - result = clirunner.invoke(cmd_packages) + result = click_cmd_runner.invoke(cmd_packages) assert result.exit_code == 1, result.output assert ( "One of [--list, --install, --uninstall, --fix] " @@ -23,19 +23,19 @@ def test_packages(clirunner, configenv): ) # -- Execute "apio packages --list" - result = clirunner.invoke(cmd_packages, ["--list"]) + result = click_cmd_runner.invoke(cmd_packages, ["--list"]) assert result.exit_code == 0, result.output assert "No errors" in result.output # -- Execute "apio packages --install missing_package" - result = clirunner.invoke( + result = click_cmd_runner.invoke( cmd_packages, ["--install", "missing_package"] ) assert result.exit_code == 1, result.output assert "Error: unknown package 'missing_package'" in result.output # -- Execute "apio packages --uninstall --sayyes missing_package" - result = clirunner.invoke( + result = click_cmd_runner.invoke( cmd_packages, ["--uninstall", "--sayyes", "missing_package"] ) assert result.exit_code == 1, result.output diff --git a/test/commands/test_report.py b/test/commands/test_report.py index 4aa4296c..c0bf80fb 100644 --- a/test/commands/test_report.py +++ b/test/commands/test_report.py @@ -8,19 +8,19 @@ # R0801: Similar lines in 2 files # pylint: disable=R0801 -def test_report(clirunner, configenv): +def test_report(click_cmd_runner, setup_apio_test_env): """Test: apio report when no apio.ini file is given No additional parameters are given """ - with clirunner.isolated_filesystem(): + with click_cmd_runner.isolated_filesystem(): - # -- Config the environment (conftest.configenv()) - configenv() + # -- Config the apio test environment + setup_apio_test_env() # -- Execute "apio report" - result = clirunner.invoke(cmd_report) + result = click_cmd_runner.invoke(cmd_report) # -- Check the result assert result.exit_code != 0, result.output @@ -28,18 +28,18 @@ def test_report(clirunner, configenv): assert "Error: insufficient arguments: missing board" in result.output -def test_report_board(clirunner, configenv): +def test_report_board(click_cmd_runner, setup_apio_test_env): """Test: apio report when parameters are given """ - with clirunner.isolated_filesystem(): + with click_cmd_runner.isolated_filesystem(): - # -- Config the environment (conftest.configenv()) - configenv() + # -- Config the apio test environment + setup_apio_test_env() # -- Execute "apio report" - result = clirunner.invoke(cmd_report, ["--board", "icezum"]) + result = click_cmd_runner.invoke(cmd_report, ["--board", "icezum"]) # -- Check the result assert result.exit_code != 0, result.output diff --git a/test/commands/test_sim.py b/test/commands/test_sim.py index 3d2457d1..87350f06 100644 --- a/test/commands/test_sim.py +++ b/test/commands/test_sim.py @@ -6,18 +6,18 @@ from apio.commands.sim import cli as cmd_sim -def test_sim(clirunner, configenv): +def test_sim(click_cmd_runner, setup_apio_test_env): """Test: apio sim when no apio.ini file is given No additional parameters are given """ - with clirunner.isolated_filesystem(): + with click_cmd_runner.isolated_filesystem(): - # -- Config the environment (conftest.configenv()) - configenv() + # -- Config the apio test environment + setup_apio_test_env() # -- apio sim --board icezum - result = clirunner.invoke(cmd_sim) + result = click_cmd_runner.invoke(cmd_sim) assert result.exit_code != 0, result.output # -- TODO diff --git a/test/commands/test_system.py b/test/commands/test_system.py index 91de6e39..2b969eeb 100644 --- a/test/commands/test_system.py +++ b/test/commands/test_system.py @@ -6,16 +6,16 @@ from apio.commands.system import cli as cmd_system -def test_system(clirunner, configenv): +def test_system(click_cmd_runner, setup_apio_test_env): """Test "apio system" with different parameters""" - with clirunner.isolated_filesystem(): + with click_cmd_runner.isolated_filesystem(): - # -- Config the environment (conftest.configenv()) - configenv() + # -- Config the apio test environment + setup_apio_test_env() # -- Execute "apio system" - result = clirunner.invoke(cmd_system) + result = click_cmd_runner.invoke(cmd_system) assert result.exit_code == 1, result.output assert ( "One of [--lsftdi, --lsusb, --lsserial, --info, --platforms] " @@ -23,22 +23,22 @@ def test_system(clirunner, configenv): ) # -- Execute "apio system --lsftdi" - result = clirunner.invoke(cmd_system, ["--lsftdi"]) + result = click_cmd_runner.invoke(cmd_system, ["--lsftdi"]) assert result.exit_code == 1, result.output assert "apio packages --install --force oss-cad-suite" in result.output # -- Execute "apio system --lsusb" - result = clirunner.invoke(cmd_system, ["--lsusb"]) + result = click_cmd_runner.invoke(cmd_system, ["--lsusb"]) assert result.exit_code == 1, result.output assert "apio packages --install --force oss-cad-suite" in result.output # -- Execute "apio system --lsserial" - clirunner.invoke(cmd_system, ["--lsserial"]) + click_cmd_runner.invoke(cmd_system, ["--lsserial"]) assert result.exit_code == 1, result.output assert "apio packages --install --force oss-cad-suite" in result.output # -- Execute "apio system --info" - result = clirunner.invoke(cmd_system, ["--info"]) + result = click_cmd_runner.invoke(cmd_system, ["--info"]) assert result.exit_code == 0, result.output assert "Platform id" in result.output # -- The these env options are set by the apio text fixture. diff --git a/test/commands/test_test.py b/test/commands/test_test.py index adf64788..36cdca27 100644 --- a/test/commands/test_test.py +++ b/test/commands/test_test.py @@ -6,18 +6,18 @@ from apio.commands.sim import cli as cmd_test -def test_test(clirunner, configenv): +def test_test(click_cmd_runner, setup_apio_test_env): """Test: apio test when no apio.ini file is given No additional parameters are given """ - with clirunner.isolated_filesystem(): + with click_cmd_runner.isolated_filesystem(): - # -- Config the environment (conftest.configenv()) - configenv() + # -- Config the apio test environment + setup_apio_test_env() # -- Execute "apio test" - result = clirunner.invoke(cmd_test) + result = click_cmd_runner.invoke(cmd_test) assert result.exit_code != 0, result.output # -- TODO diff --git a/test/commands/test_time.py b/test/commands/test_time.py index 57f8fa57..ed083c9c 100644 --- a/test/commands/test_time.py +++ b/test/commands/test_time.py @@ -8,19 +8,19 @@ # R0801: Similar lines in 2 files # pylint: disable=R0801 -def test_time(clirunner, configenv): +def test_time(click_cmd_runner, setup_apio_test_env): """Test: apio time when no apio.ini file is given No additional parameters are given """ - with clirunner.isolated_filesystem(): + with click_cmd_runner.isolated_filesystem(): - # -- Config the environment (conftest.configenv()) - configenv() + # -- Config the apio test environment + setup_apio_test_env() # -- Execute "apio time" - result = clirunner.invoke(cmd_time) + result = click_cmd_runner.invoke(cmd_time) # -- Check the result assert result.exit_code != 0, result.output @@ -28,18 +28,18 @@ def test_time(clirunner, configenv): assert "Error: insufficient arguments: missing board" in result.output -def test_time_board(clirunner, configenv): +def test_time_board(click_cmd_runner, setup_apio_test_env): """Test: apio time when parameters are given """ - with clirunner.isolated_filesystem(): + with click_cmd_runner.isolated_filesystem(): - # -- Config the environment (conftest.configenv()) - configenv() + # -- Config the apio test environment + setup_apio_test_env() # -- Execute "apio time" - result = clirunner.invoke(cmd_time, ["--board", "icezum"]) + result = click_cmd_runner.invoke(cmd_time, ["--board", "icezum"]) # -- Check the result assert result.exit_code != 0, result.output diff --git a/test/commands/test_uninstall.py b/test/commands/test_uninstall.py index 361bcc98..d56c8b6a 100644 --- a/test/commands/test_uninstall.py +++ b/test/commands/test_uninstall.py @@ -6,24 +6,24 @@ from apio.commands.uninstall import cli as cmd_uninstall -def test_uninstall(clirunner, configenv, validate_cliresult): +def test_uninstall(click_cmd_runner, setup_apio_test_env, assert_apio_cmd_ok): """Test "apio uninstall" with different parameters""" - with clirunner.isolated_filesystem(): + with click_cmd_runner.isolated_filesystem(): - # -- Config the environment (conftest.configenv()) - configenv() + # -- Config the apio test environment + setup_apio_test_env() # -- Execute "apio uninstall" - result = clirunner.invoke(cmd_uninstall) - validate_cliresult(result) + result = click_cmd_runner.invoke(cmd_uninstall) + assert_apio_cmd_ok(result) # -- Execute "apio uninstall --list" - result = clirunner.invoke(cmd_uninstall, ["--list"]) - validate_cliresult(result) + result = click_cmd_runner.invoke(cmd_uninstall, ["--list"]) + assert_apio_cmd_ok(result) # -- Execute "apio uninstall missing_packge" - result = clirunner.invoke( + result = click_cmd_runner.invoke( cmd_uninstall, ["missing_package"], input="y" ) assert result.exit_code == 1, result.output diff --git a/test/commands/test_upgrade.py b/test/commands/test_upgrade.py index deb95735..987fc9a7 100644 --- a/test/commands/test_upgrade.py +++ b/test/commands/test_upgrade.py @@ -8,19 +8,21 @@ from apio.commands.upgrade import cli as cmd_upgrade -def test_upgrade(clirunner, configenv, validate_cliresult, offline): +def test_upgrade( + click_cmd_runner, setup_apio_test_env, assert_apio_cmd_ok, offline_flag +): """Test "apio upgrade" """ # -- If the option 'offline' is passed, the test is skip # -- (apio upgrade uses internet) - if offline: + if offline_flag: pytest.skip("requires internet connection") - with clirunner.isolated_filesystem(): + with click_cmd_runner.isolated_filesystem(): - # -- Config the environment (conftest.configenv()) - configenv() + # -- Config the apio test environment + setup_apio_test_env() # -- Execute "apio upgrade" - result = clirunner.invoke(cmd_upgrade) - validate_cliresult(result) + result = click_cmd_runner.invoke(cmd_upgrade) + assert_apio_cmd_ok(result) diff --git a/test/commands/test_upload.py b/test/commands/test_upload.py index 1810ea37..932ae650 100644 --- a/test/commands/test_upload.py +++ b/test/commands/test_upload.py @@ -6,19 +6,19 @@ from apio.commands.upload import cli as cmd_upload -def test_upload(clirunner, configenv): +def test_upload(click_cmd_runner, setup_apio_test_env): """Test: apio upload when no apio.ini file is given No additional parameters are given """ - with clirunner.isolated_filesystem(): + with click_cmd_runner.isolated_filesystem(): - # -- Config the environment (conftest.configenv()) - configenv() + # -- Config the apio test environment + setup_apio_test_env() # -- Execute "apio upload" - result = clirunner.invoke(cmd_upload) + result = click_cmd_runner.invoke(cmd_upload) # -- Check the result assert result.exit_code == 1, result.output @@ -26,18 +26,18 @@ def test_upload(clirunner, configenv): assert "Error: insufficient arguments: missing board" in result.output -def test_upload_board(clirunner, configenv): +def test_upload_board(click_cmd_runner, setup_apio_test_env): """Test: apio upload --board icezum No oss-cad-suite package is installed """ - with clirunner.isolated_filesystem(): + with click_cmd_runner.isolated_filesystem(): - # -- Config the environment (conftest.configenv()) - configenv() + # -- Config the apio test environment + setup_apio_test_env() # -- Execute "apio upload --board icezum" - result = clirunner.invoke(cmd_upload, ["--board", "icezum"]) + result = click_cmd_runner.invoke(cmd_upload, ["--board", "icezum"]) # -- Check the result assert result.exit_code == 1 @@ -46,36 +46,36 @@ def test_upload_board(clirunner, configenv): ) -def test_upload_complete(clirunner, configenv): +def test_upload_complete(click_cmd_runner, setup_apio_test_env): """Test: apio upload with different arguments No apio.ini file is given """ - with clirunner.isolated_filesystem(): + with click_cmd_runner.isolated_filesystem(): - # -- Config the environment (conftest.configenv()) - configenv() + # -- Config the apio test environment + setup_apio_test_env() # -- Execute "apio upload --serial-port COM0" - result = clirunner.invoke(cmd_upload, ["--serial-port", "COM0"]) + result = click_cmd_runner.invoke(cmd_upload, ["--serial-port", "COM0"]) assert result.exit_code == 1, result.output assert "Info: Project has no apio.ini file" in result.output assert "Error: insufficient arguments: missing board" in result.output # -- Execute "apio upload --ftdi-id 0" - result = clirunner.invoke(cmd_upload, ["--ftdi-id", "0"]) + result = click_cmd_runner.invoke(cmd_upload, ["--ftdi-id", "0"]) assert result.exit_code == 1, result.output assert "Info: Project has no apio.ini file" in result.output assert "Error: insufficient arguments: missing board" in result.output # -- Execute "apio upload --sram" - result = clirunner.invoke(cmd_upload, ["--sram"]) + result = click_cmd_runner.invoke(cmd_upload, ["--sram"]) assert result.exit_code == 1, result.output assert "Info: Project has no apio.ini file" in result.output assert "Error: insufficient arguments: missing board" in result.output # -- Execute "apio upload --board icezum --serial-port COM0" - result = clirunner.invoke( + result = click_cmd_runner.invoke( cmd_upload, ["--board", "icezum", "--serial-port", "COM0"] ) assert result.exit_code == 1, result.output @@ -84,7 +84,7 @@ def test_upload_complete(clirunner, configenv): ) # -- Execute "apio upload --board icezum --ftdi-id 0" - result = clirunner.invoke( + result = click_cmd_runner.invoke( cmd_upload, ["--board", "icezum", "--ftdi-id", "0"] ) assert result.exit_code == 1, result.output @@ -93,7 +93,9 @@ def test_upload_complete(clirunner, configenv): ) # -- Execute "apio upload --board icezum --sram" - result = clirunner.invoke(cmd_upload, ["--board", "icezum", "--sram"]) + result = click_cmd_runner.invoke( + cmd_upload, ["--board", "icezum", "--sram"] + ) assert result.exit_code == 1, result.output assert ( "Error: package 'oss-cad-suite' is not installed" in result.output diff --git a/test/commands/test_verify.py b/test/commands/test_verify.py index 05fb66da..7acb82c9 100644 --- a/test/commands/test_verify.py +++ b/test/commands/test_verify.py @@ -6,19 +6,19 @@ from apio.commands.verify import cli as cmd_verify -def test_verify(clirunner, configenv): +def test_verify(click_cmd_runner, setup_apio_test_env): """Test: apio verify when no apio.ini file is given No additional parameters are given """ - with clirunner.isolated_filesystem(): + with click_cmd_runner.isolated_filesystem(): - # -- Config the environment (conftest.configenv()) - configenv() + # -- Config the apio test environment + setup_apio_test_env() # -- Execute "apio verify" - result = clirunner.invoke(cmd_verify, ["--board", "icezum"]) + result = click_cmd_runner.invoke(cmd_verify, ["--board", "icezum"]) # -- Check the result assert result.exit_code != 0, result.output diff --git a/test/conftest.py b/test/conftest.py index 6345002b..8574d0dd 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -5,8 +5,9 @@ # os.environ: Access to environment variables # https://docs.python.org/3/library/os.html#os.environ -from os import environ +from os import environ, listdir from pathlib import Path +from typing import Dict import pytest @@ -23,42 +24,55 @@ @pytest.fixture(scope="module") -def clirunner(): - """Return a special oject for executing a click cli command""" +def click_cmd_runner(): + """A pytest fixture that provides tests with a click commands runner.""" return CliRunner() @pytest.fixture(scope="session") -def configenv(): - """Return a function for configuring the apio test environment - By default it is tested in a temporaly folder (in /tmp/xxxxx) +def setup_apio_test_env(): + """An pytest fixture that provides tests with a function to set up the + apio test environment. By default, the tests run in a temporaly folder + (in /tmp/xxxxx). """ def decorator(): + # -- Current directory is the project dir. + project_dir = Path.cwd() + # -- Set a strange directory for executing # -- apio: it contains spaces and unicode characters # -- for testing. It should work - cwd = Path.cwd() / " ñ" + apio_home_dir = project_dir / " ñ" + apio_packages_dir = apio_home_dir / "packages" # -- Debug if DEBUG: print("") - print(" --> configenv():") - print(f" apio working directory: {str(cwd)}") + print(" --> setup_apio_test_env():") + print(f" apio project dir : {str(project_dir)}") + print(f" apio home dir : {str(apio_home_dir)}") + print(f" apio packages dir : {str(apio_packages_dir)}") + + # -- Since the test run in a fresh temp directory, we expect it to be + # -- empty with no left over files (such as apio.ini) from a previous + # -- tests. + project_dir_content = listdir(".") + assert not project_dir_content, project_dir_content # -- Set the apio home dir and apio packages dir to # -- this test folder - environ["APIO_HOME_DIR"] = str(cwd) - environ["APIO_PACKAGES_DIR"] = str(cwd / "packages") + environ["APIO_HOME_DIR"] = str(apio_home_dir) + environ["APIO_PACKAGES_DIR"] = str(apio_packages_dir) environ["TESTING"] = "" return decorator @pytest.fixture(scope="session") -def validate_cliresult(): - """Return a function for Checking if a given click command - has executed ok +def assert_apio_cmd_ok(): + """A pytest fixture that provides a function to assert that apio click + command result were ok. """ def decorator(result: Result): @@ -76,6 +90,47 @@ def decorator(result: Result): return decorator +@pytest.fixture(scope="session") +def write_apio_ini(): + """A pytest fixture to write a project apio.ini file. If properties + is Nonethe file apio.ini is deleted if it exists. + """ + + def decorator(properties: Dict[str, str]): + """The apio.ini actual writer""" + + path = Path("apio.ini") + + if properties is None: + path.unlink(missing_ok=True) + return + + with open(path, "w", encoding="utf-8") as f: + f.write("[env]\n") + for name, value in properties.items(): + f.write(f"{name} = {value}\n") + + return decorator + + +@pytest.fixture(scope="session") +def path_in_project(): + """A pytest fixutre that provides a function that convert a file name + to a path within the project. + """ + + def decorator(name: str): + """The implementation""" + + return Path.cwd() / name + + return decorator + + +# -- This function is called by pytest. It addes the pytest --offline flag +# -- which is is passed to tests that ask for it using the fixture +# -- 'offline_flag' below. +# -- # -- More info: https://docs.pytest.org/en/7.1.x/example/simple.html def pytest_addoption(parser: pytest.Parser): """Register the --offline command line option when invoking pytest""" @@ -89,8 +144,9 @@ def pytest_addoption(parser: pytest.Parser): @pytest.fixture -def offline(request): - """Return the value of the offline parameter, given by the user - when calling pytest +def offline_flag(request): + """Return the value of the pytest '--offline' flag register above. + This flag can be set by the user when invoking pytest to disable + test functionality that requires internet connectivity. """ return request.config.getoption("--offline") diff --git a/test/test_apio.py b/test/test_apio.py index 3e13bf4e..9691de68 100644 --- a/test/test_apio.py +++ b/test/test_apio.py @@ -20,26 +20,28 @@ from apio.__main__ import cli as cmd_apio -def test_apio(clirunner: CliRunner, validate_cliresult, configenv): +def test_apio( + click_cmd_runner: CliRunner, assert_apio_cmd_ok, setup_apio_test_env +): """Test command "apio" without arguments $ apio Usage: apio [OPTIONS] COMMAND [ARGS]... [...] """ - with clirunner.isolated_filesystem(): + with click_cmd_runner.isolated_filesystem(): - # -- Config the environment (conftest.configenv()) - configenv() + # -- Config the apio test environment + setup_apio_test_env() # -- Invoke the apio command - result = clirunner.invoke(cmd_apio) + result = click_cmd_runner.invoke(cmd_apio) # -- Check that everything is ok - validate_cliresult(result) + assert_apio_cmd_ok(result) -def test_apio_wrong_command(clirunner: CliRunner, configenv): +def test_apio_wrong_command(click_cmd_runner: CliRunner, setup_apio_test_env): """Test apio command with an invalid command $ apio wrong Usage: apio [OPTIONS] COMMAND [ARGS]... @@ -48,13 +50,13 @@ def test_apio_wrong_command(clirunner: CliRunner, configenv): Error: No such command 'wrong'. """ - with clirunner.isolated_filesystem(): + with click_cmd_runner.isolated_filesystem(): # -- Config the environment - configenv() + setup_apio_test_env() # -- Execute "apio mmissing_command" - result = clirunner.invoke(cmd_apio, ["wrong_command"]) + result = click_cmd_runner.invoke(cmd_apio, ["wrong_command"]) # -- Check the error code assert result.exit_code == 2, result.output diff --git a/test/test_end_to_end.py b/test/test_end_to_end.py index 8625c561..f4ad9c2b 100644 --- a/test/test_end_to_end.py +++ b/test/test_end_to_end.py @@ -39,54 +39,62 @@ def validate_dir_leds(folder=""): assert leds_dir.is_dir() and nfiles > 0 -def test_end_to_end1(clirunner, validate_cliresult, configenv, offline): +def test_end_to_end1( + click_cmd_runner, assert_apio_cmd_ok, setup_apio_test_env, offline_flag +): """Test the installation of the examples package""" # -- If the option 'offline' is passed, the test is skip # -- (These tests require internet) - if offline: + if offline_flag: pytest.skip("requires internet connection") - with clirunner.isolated_filesystem(): + with click_cmd_runner.isolated_filesystem(): - # -- Config the environment (conftest.configenv()) - configenv() + # -- Config the apio test environment + setup_apio_test_env() # -- Execute "apio packages --uninstall examples" - result = clirunner.invoke( + result = click_cmd_runner.invoke( cmd_packages, ["--uninstall", "examples"], input="y" ) assert "Do you want to uninstall 1 package?" in result.output assert "Package 'examples' was not installed" in result.output # -- Execute "apio packages --install examples@X" - result = clirunner.invoke(cmd_packages, ["--install", "examples@X"]) + result = click_cmd_runner.invoke( + cmd_packages, ["--install", "examples@X"] + ) assert "Error: package not found" in result.output # -- Execute "apio packages --install examples@0.0.34" - result = clirunner.invoke( + result = click_cmd_runner.invoke( cmd_packages, ["--install", "examples@0.0.34"] ) - validate_cliresult(result) + assert_apio_cmd_ok(result) assert "Installing package 'examples@" in result.output assert "Download" in result.output assert "Package 'examples' installed successfully" in result.output # -- Execute "apio packages --install examples" - result = clirunner.invoke(cmd_packages, ["--install", "examples"]) - validate_cliresult(result) + result = click_cmd_runner.invoke( + cmd_packages, ["--install", "examples"] + ) + assert_apio_cmd_ok(result) assert "Installing package 'examples'" in result.output assert "Download" in result.output assert "Package 'examples' installed successfully" in result.output # -- Execute "apio packages --install examples" again - result = clirunner.invoke(cmd_packages, ["--install", "examples"]) - validate_cliresult(result) + result = click_cmd_runner.invoke( + cmd_packages, ["--install", "examples"] + ) + assert_apio_cmd_ok(result) assert "Installing package 'examples'" in result.output assert "was already installed" in result.output # -- Execute "apio packages --install examples --force" - result = clirunner.invoke( + result = click_cmd_runner.invoke( cmd_packages, [ "--install", @@ -94,86 +102,92 @@ def test_end_to_end1(clirunner, validate_cliresult, configenv, offline): "--force", ], ) - validate_cliresult(result) + assert_apio_cmd_ok(result) assert "Installing package 'examples'" in result.output assert "Download" in result.output assert "Package 'examples' installed successfully" in result.output # -- Execute "apio packages --list" - result = clirunner.invoke(cmd_packages, ["--list"]) + result = click_cmd_runner.invoke(cmd_packages, ["--list"]) assert result.exit_code == 0, result.output assert "No errors" in result.output assert "Installed packages:" in result.output assert "examples" in result.output -def test_end_to_end2(clirunner, validate_cliresult, configenv, offline): +def test_end_to_end2( + click_cmd_runner, assert_apio_cmd_ok, setup_apio_test_env, offline_flag +): """Test more 'apio examples' commands""" # -- If the option 'offline' is passed, the test is skip # -- (These tests require internet) - if offline: + if offline_flag: pytest.skip("requires internet connection") - with clirunner.isolated_filesystem(): + with click_cmd_runner.isolated_filesystem(): - # -- Config the environment (conftest.configenv()) - configenv() + # -- Config the apio test environment + setup_apio_test_env() # -- Execute "apio create --board alhambra-ii" - result = clirunner.invoke(cmd_create, ["--board", "alhambra-ii"]) - validate_cliresult(result) + result = click_cmd_runner.invoke( + cmd_create, ["--board", "alhambra-ii"] + ) + assert_apio_cmd_ok(result) assert "Creating apio.ini file ..." in result.output assert "was created successfully" in result.output # -- Execute "apio upload" - result = clirunner.invoke(cmd_upload) + result = click_cmd_runner.invoke(cmd_upload) assert result.exit_code == 1, result.output assert "package 'oss-cad-suite' is not installed" in result.output # -- Execute "apio packages --install examples" - result = clirunner.invoke(cmd_packages, ["--install", "examples"]) - validate_cliresult(result) + result = click_cmd_runner.invoke( + cmd_packages, ["--install", "examples"] + ) + assert_apio_cmd_ok(result) assert "Installing package 'examples'" in result.output assert "Download" in result.output assert "Package 'examples' installed successfully" in result.output # -- Execute "apio examples --list" - result = clirunner.invoke(cmd_examples, ["--list"]) - validate_cliresult(result) + result = click_cmd_runner.invoke(cmd_examples, ["--list"]) + assert_apio_cmd_ok(result) assert "leds" in result.output assert "icezum" in result.output # -- Execute "apio examples --fetch-files missing_example" - result = clirunner.invoke( + result = click_cmd_runner.invoke( cmd_examples, ["--fetch-files", "missing_example"] ) assert result.exit_code == 1, result.output assert "Warning: this example does not exist" in result.output # -- Execute "apio examples --fetch-files Alhambra-II/ledon" - result = clirunner.invoke( + result = click_cmd_runner.invoke( cmd_examples, ["--fetch-files", "Alhambra-II/ledon"] ) - validate_cliresult(result) + assert_apio_cmd_ok(result) assert "Copying Alhambra-II/ledon example files ..." in result.output assert "have been successfully created!" in result.output validate_files_leds(pathlib.Path()) # -- Execute "apio examples --fetch-dir Alhambra-II/ledon" - result = clirunner.invoke( + result = click_cmd_runner.invoke( cmd_examples, ["--fetch-dir", "Alhambra-II/ledon"] ) - validate_cliresult(result) + assert_apio_cmd_ok(result) assert "Creating Alhambra-II/ledon directory ..." in result.output assert "has been successfully created" in result.output validate_dir_leds() # -- Execute "apio examples --fetch-dir Alhambra-II/ledon" - result = clirunner.invoke( + result = click_cmd_runner.invoke( cmd_examples, ["--fetch-dir", "Alhambra-II/ledon"], input="y" ) - validate_cliresult(result) + assert_apio_cmd_ok(result) assert ( "Warning: Alhambra-II/ledon directory already exists" in result.output @@ -184,22 +198,26 @@ def test_end_to_end2(clirunner, validate_cliresult, configenv, offline): validate_dir_leds() -def test_end_to_end3(clirunner, validate_cliresult, configenv, offline): +def test_end_to_end3( + click_cmd_runner, assert_apio_cmd_ok, setup_apio_test_env, offline_flag +): """Test more 'apio examples' commands""" # -- If the option 'offline' is passed, the test is skip # -- (These tests require internet) - if offline: + if offline_flag: pytest.skip("requires internet connection") - with clirunner.isolated_filesystem(): + with click_cmd_runner.isolated_filesystem(): - # -- Config the environment (conftest.configenv()) - configenv() + # -- Config the apio test environment + setup_apio_test_env() # -- Execute "apio packages --install examples" - result = clirunner.invoke(cmd_packages, ["--install", "examples"]) - validate_cliresult(result) + result = click_cmd_runner.invoke( + cmd_packages, ["--install", "examples"] + ) + assert_apio_cmd_ok(result) assert "Installing package 'examples'" in result.output assert "Download" in result.output assert "Package 'examples' installed successfully" in result.output @@ -213,11 +231,11 @@ def test_end_to_end3(clirunner, validate_cliresult, configenv, offline): # -- Execute "apio examples --fetch-files Alhambra-II/ledon # -- --project-dir=tmp" - result = clirunner.invoke( + result = click_cmd_runner.invoke( cmd_examples, ["--fetch-files", "Alhambra-II/ledon", "--project-dir=tmp"], ) - validate_cliresult(result) + assert_apio_cmd_ok(result) assert "Copying Alhambra-II/ledon example files ..." in result.output assert "have been successfully created!" in result.output @@ -226,27 +244,27 @@ def test_end_to_end3(clirunner, validate_cliresult, configenv, offline): # -- Execute # -- "apio examples --fetch-dir Alhambra-II/ledon --project-dir=tmp" - result = clirunner.invoke( + result = click_cmd_runner.invoke( cmd_examples, ["--fetch-dir", "Alhambra-II/ledon", "--project-dir=tmp"], ) - validate_cliresult(result) + assert_apio_cmd_ok(result) assert "Creating Alhambra-II/ledon directory ..." in result.output assert "has been successfully created" in result.output validate_dir_leds("tmp") # -- Execute "apio packages --uninstall examples" - result = clirunner.invoke( + result = click_cmd_runner.invoke( cmd_packages, ["--uninstall", "examples"], input="n" ) assert result.exit_code != 0, result.output assert "User said no" in result.output # -- Execute "apio packages --uninstall examples" - result = clirunner.invoke( + result = click_cmd_runner.invoke( cmd_packages, ["--uninstall", "examples"], input="y" ) - validate_cliresult(result) + assert_apio_cmd_ok(result) assert "Uninstalling package 'examples'" in result.output assert "Do you want to uninstall 1 package?" in result.output assert "Package 'examples' uninstalled successfuly" in result.output