mirror of
https://github.com/j178/prek.git
synced 2026-04-03 17:34:03 +02:00
331 lines
9.8 KiB
Rust
331 lines
9.8 KiB
Rust
use assert_fs::assert::PathAssert;
|
|
use assert_fs::fixture::{FileWriteStr, PathChild};
|
|
|
|
use crate::common::{TestContext, cmd_snapshot};
|
|
|
|
/// Test `language_version` parsing.
|
|
/// Python 3.12.11 is installed in the CI environment, when running tests uv can find them.
|
|
/// Other versions may need to be downloaded while running the tests.
|
|
#[test]
|
|
fn language_version() -> anyhow::Result<()> {
|
|
let context = TestContext::new();
|
|
context.init_project();
|
|
context.write_pre_commit_config(indoc::indoc! {r#"
|
|
repos:
|
|
- repo: local
|
|
hooks:
|
|
- id: python3
|
|
name: python3
|
|
language: python
|
|
entry: python -c 'print("Hello, World!")'
|
|
language_version: python3
|
|
always_run: true
|
|
- id: python3.12
|
|
name: python3.12
|
|
language: python
|
|
entry: python -c 'import sys; print(sys.version_info[:3])'
|
|
language_version: python3.12
|
|
always_run: true
|
|
- id: python3.12
|
|
name: python3.12
|
|
language: python
|
|
entry: python -c 'import sys; print(sys.version_info[:3])'
|
|
language_version: '3.12'
|
|
always_run: true
|
|
- id: python3.12
|
|
name: python3.12
|
|
language: python
|
|
entry: python -c 'import sys; print(sys.version_info[:3])'
|
|
language_version: 'python312'
|
|
- id: python3.12
|
|
name: python3.12
|
|
language: python
|
|
entry: python -c 'import sys; print(sys.version_info[:3])'
|
|
language_version: '312'
|
|
always_run: true
|
|
- id: python3.12
|
|
name: python3.12
|
|
language: python
|
|
entry: python -c 'import sys; print(sys.version_info[:3])'
|
|
language_version: python3.12
|
|
always_run: true
|
|
- id: python3.12
|
|
name: python3.12
|
|
language: python
|
|
entry: python -c 'import sys; print(sys.version_info[:3])'
|
|
language_version: '3.12.1' # will auto download
|
|
always_run: true
|
|
"#});
|
|
context.git_add(".");
|
|
|
|
context
|
|
.home_dir()
|
|
.child("tools")
|
|
.child("python")
|
|
.assert(predicates::path::missing());
|
|
|
|
cmd_snapshot!(context.filters(), context.run().arg("-v"), @r#"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
python3..................................................................Passed
|
|
- hook id: python3
|
|
- duration: [TIME]
|
|
Hello, World!
|
|
python3.12...............................................................Passed
|
|
- hook id: python3.12
|
|
- duration: [TIME]
|
|
(3, 12, 11)
|
|
python3.12...............................................................Passed
|
|
- hook id: python3.12
|
|
- duration: [TIME]
|
|
(3, 12, 11)
|
|
python3.12...............................................................Passed
|
|
- hook id: python3.12
|
|
- duration: [TIME]
|
|
(3, 12, 11)
|
|
python3.12...............................................................Passed
|
|
- hook id: python3.12
|
|
- duration: [TIME]
|
|
(3, 12, 11)
|
|
python3.12...............................................................Passed
|
|
- hook id: python3.12
|
|
- duration: [TIME]
|
|
(3, 12, 11)
|
|
python3.12...............................................................Passed
|
|
- hook id: python3.12
|
|
- duration: [TIME]
|
|
(3, 12, 1)
|
|
|
|
----- stderr -----
|
|
"#);
|
|
|
|
let tools_python_dir = context.home_dir().join("tools").join("python");
|
|
|
|
// Check that either no downloads were needed (directory doesn't exist)
|
|
// or some downloads happened (directory exists with content)
|
|
if tools_python_dir.exists() {
|
|
let count = tools_python_dir
|
|
.read_dir()?
|
|
.flatten()
|
|
.filter(|d| !d.file_name().to_string_lossy().starts_with('.'))
|
|
.count();
|
|
assert!(count > 0, "tools/python directory exists but is empty");
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn invalid_version() {
|
|
let context = TestContext::new();
|
|
context.init_project();
|
|
context.write_pre_commit_config(indoc::indoc! {r#"
|
|
repos:
|
|
- repo: local
|
|
hooks:
|
|
- id: local
|
|
name: local
|
|
language: python
|
|
entry: python -c 'print("Hello, world!")'
|
|
language_version: 'invalid-version' # invalid version
|
|
always_run: true
|
|
verbose: true
|
|
pass_filenames: false
|
|
"#});
|
|
|
|
context.git_add(".");
|
|
|
|
cmd_snapshot!(context.filters(), context.run(), @r#"
|
|
success: false
|
|
exit_code: 2
|
|
----- stdout -----
|
|
|
|
----- stderr -----
|
|
error: Hook `local` is invalid
|
|
caused by: Invalid `language_version` value: `invalid-version`
|
|
"#);
|
|
}
|
|
|
|
/// Request a version that neither can be found nor downloaded.
|
|
#[test]
|
|
fn can_not_download() {
|
|
let context = TestContext::new();
|
|
context.init_project();
|
|
context.write_pre_commit_config(indoc::indoc! {r"
|
|
repos:
|
|
- repo: local
|
|
hooks:
|
|
- id: less-than-3.6
|
|
name: less-than-3.6
|
|
language: python
|
|
entry: python -c 'import sys; print(sys.version_info[:3])'
|
|
language_version: '<=3.6' # not supported version
|
|
always_run: true
|
|
"});
|
|
context.git_add(".");
|
|
|
|
let mut filters = context
|
|
.filters()
|
|
.into_iter()
|
|
.chain([(
|
|
"managed installations, search path, or registry",
|
|
"managed installations or search path",
|
|
)])
|
|
.collect::<Vec<_>>();
|
|
if cfg!(windows) {
|
|
// Unix uses "exit status", Windows uses "exit code"
|
|
filters.push((r"exit code: ", "exit status: "));
|
|
}
|
|
|
|
cmd_snapshot!(filters, context.run().arg("-v"), @r#"
|
|
success: false
|
|
exit_code: 2
|
|
----- stdout -----
|
|
|
|
----- stderr -----
|
|
error: Failed to install hook `less-than-3.6`
|
|
caused by: Failed to create Python virtual environment
|
|
caused by: command `create venv` exited with an error:
|
|
|
|
[status]
|
|
exit status: 2
|
|
|
|
[stderr]
|
|
error: No interpreter found for Python <=3.6 in managed installations or search path
|
|
"#);
|
|
}
|
|
|
|
/// Test that `additional_dependencies` are installed correctly.
|
|
#[test]
|
|
fn additional_dependencies() {
|
|
let context = TestContext::new();
|
|
context.init_project();
|
|
|
|
context.write_pre_commit_config(indoc::indoc! {r#"
|
|
repos:
|
|
- repo: local
|
|
hooks:
|
|
- id: local
|
|
name: local
|
|
language: python
|
|
language_version: '3.11' # will auto download
|
|
entry: pyecho Hello, world!
|
|
additional_dependencies: ["pyecho-cli"]
|
|
always_run: true
|
|
verbose: true
|
|
pass_filenames: false
|
|
"#});
|
|
|
|
context.git_add(".");
|
|
|
|
cmd_snapshot!(context.filters(), context.run(), @r#"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
local....................................................................Passed
|
|
- hook id: local
|
|
- duration: [TIME]
|
|
Hello, world!
|
|
|
|
----- stderr -----
|
|
"#);
|
|
}
|
|
|
|
/// Ensure that stderr from hooks is captured and shown to the user.
|
|
#[test]
|
|
fn hook_stderr() -> anyhow::Result<()> {
|
|
let context = TestContext::new();
|
|
context.init_project();
|
|
|
|
context.write_pre_commit_config(indoc::indoc! {r"
|
|
repos:
|
|
- repo: local
|
|
hooks:
|
|
- id: local
|
|
name: local
|
|
language: python
|
|
entry: python ./hook.py
|
|
"});
|
|
|
|
context
|
|
.work_dir()
|
|
.child("hook.py")
|
|
.write_str("import sys; print('How are you', file=sys.stderr); sys.exit(1)")?;
|
|
|
|
context.git_add(".");
|
|
|
|
cmd_snapshot!(context.filters(), context.run(), @r#"
|
|
success: false
|
|
exit_code: 1
|
|
----- stdout -----
|
|
local....................................................................Failed
|
|
- hook id: local
|
|
- exit code: 1
|
|
How are you
|
|
|
|
----- stderr -----
|
|
"#);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Test that pep723 script for local hook is installed correctly.
|
|
/// Only if no additional dependencies are specified.
|
|
#[test]
|
|
fn pep723_script() -> anyhow::Result<()> {
|
|
let context = TestContext::new();
|
|
context.init_project();
|
|
context.write_pre_commit_config(indoc::indoc! {r#"
|
|
repos:
|
|
- repo: local
|
|
hooks:
|
|
- id: other-hook
|
|
name: other-hook
|
|
language: python
|
|
entry: python -c 'print("hello from other-hook")'
|
|
verbose: true
|
|
pass_filenames: false
|
|
- id: local
|
|
name: local
|
|
language: python
|
|
entry: ./script.py hello world
|
|
verbose: true
|
|
pass_filenames: false
|
|
"#});
|
|
// On Windows, uv venv does not create `python3.exe`, `python3.12.exe` symlink,
|
|
// be sure to use `python` as the interpreter name.
|
|
context
|
|
.work_dir()
|
|
.child("script.py")
|
|
.write_str(indoc::indoc! {r#"
|
|
#!/usr/bin/env python
|
|
# /// script
|
|
# requires-python = ">=3.10"
|
|
# dependencies = [ "pyecho-cli" ]
|
|
# ///
|
|
from pyecho import main
|
|
main()
|
|
"#})?;
|
|
|
|
context.git_add(".");
|
|
|
|
cmd_snapshot!(context.filters(), context.run(), @r#"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
other-hook...............................................................Passed
|
|
- hook id: other-hook
|
|
- duration: [TIME]
|
|
hello from other-hook
|
|
local....................................................................Passed
|
|
- hook id: local
|
|
- duration: [TIME]
|
|
hello world
|
|
|
|
----- stderr -----
|
|
"#);
|
|
|
|
Ok(())
|
|
}
|