mirror of
https://github.com/astral-sh/uv.git
synced 2025-10-29 11:07:59 +00:00
chore: Move all integration tests to a single binary (#8093)
As per https://matklad.github.io/2021/02/27/delete-cargo-integration-tests.html Before that, there were 91 separate integration tests binary. (As discussed on Discord — I've done the `uv` crate, there's still a few more commits coming before this is mergeable, and I want to see how it performs in CI and locally).
This commit is contained in:
parent
fce7a838e9
commit
715f28fd39
231 changed files with 15585 additions and 15507 deletions
|
|
@ -498,142 +498,4 @@ fn write_record(
|
|||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use insta::{assert_snapshot, with_settings};
|
||||
use std::str::FromStr;
|
||||
use tempfile::TempDir;
|
||||
use uv_normalize::PackageName;
|
||||
use uv_pep440::Version;
|
||||
|
||||
#[test]
|
||||
fn test_wheel() {
|
||||
let filename = WheelFilename {
|
||||
name: PackageName::from_str("foo").unwrap(),
|
||||
version: Version::from_str("1.2.3").unwrap(),
|
||||
build_tag: None,
|
||||
python_tag: vec!["py2".to_string(), "py3".to_string()],
|
||||
abi_tag: vec!["none".to_string()],
|
||||
platform_tag: vec!["any".to_string()],
|
||||
};
|
||||
|
||||
with_settings!({
|
||||
filters => [(uv_version::version(), "[VERSION]")],
|
||||
}, {
|
||||
assert_snapshot!(wheel_info(&filename), @r"
|
||||
Wheel-Version: 1.0
|
||||
Generator: uv [VERSION]
|
||||
Root-Is-Purelib: true
|
||||
Tag: py2-none-any
|
||||
Tag: py3-none-any
|
||||
");
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_record() {
|
||||
let record = vec![RecordEntry {
|
||||
path: "uv_backend/__init__.py".to_string(),
|
||||
hash: "89f869e53a3a0061a52c0233e6442d4d72de80a8a2d3406d9ea0bfd397ed7865".to_string(),
|
||||
size: 37,
|
||||
}];
|
||||
|
||||
let mut writer = Vec::new();
|
||||
write_record(&mut writer, "uv_backend-0.1.0", record).unwrap();
|
||||
assert_snapshot!(String::from_utf8(writer).unwrap(), @r"
|
||||
uv_backend/__init__.py,sha256=89f869e53a3a0061a52c0233e6442d4d72de80a8a2d3406d9ea0bfd397ed7865,37
|
||||
uv_backend-0.1.0/RECORD,,
|
||||
");
|
||||
}
|
||||
|
||||
/// Check that we write deterministic wheels.
|
||||
#[test]
|
||||
fn test_determinism() {
|
||||
let temp1 = TempDir::new().unwrap();
|
||||
let uv_backend = Path::new("../../scripts/packages/uv_backend");
|
||||
build(uv_backend, temp1.path(), None).unwrap();
|
||||
|
||||
// Touch the file to check that we don't serialize the last modified date.
|
||||
fs_err::write(
|
||||
uv_backend.join("src/uv_backend/__init__.py"),
|
||||
"def greet():\n print(\"Hello 👋\")\n",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let temp2 = TempDir::new().unwrap();
|
||||
build(uv_backend, temp2.path(), None).unwrap();
|
||||
|
||||
let wheel_filename = "uv_backend-0.1.0-py3-none-any.whl";
|
||||
assert_eq!(
|
||||
fs_err::read(temp1.path().join(wheel_filename)).unwrap(),
|
||||
fs_err::read(temp2.path().join(wheel_filename)).unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
/// Snapshot all files from the prepare metadata hook.
|
||||
#[test]
|
||||
fn test_prepare_metadata() {
|
||||
let metadata_dir = TempDir::new().unwrap();
|
||||
let uv_backend = Path::new("../../scripts/packages/uv_backend");
|
||||
metadata(uv_backend, metadata_dir.path()).unwrap();
|
||||
|
||||
let mut files: Vec<_> = WalkDir::new(metadata_dir.path())
|
||||
.into_iter()
|
||||
.map(|entry| {
|
||||
entry
|
||||
.unwrap()
|
||||
.path()
|
||||
.strip_prefix(metadata_dir.path())
|
||||
.unwrap()
|
||||
.portable_display()
|
||||
.to_string()
|
||||
})
|
||||
.filter(|path| !path.is_empty())
|
||||
.collect();
|
||||
files.sort();
|
||||
assert_snapshot!(files.join("\n"), @r"
|
||||
uv_backend-0.1.0.dist-info
|
||||
uv_backend-0.1.0.dist-info/METADATA
|
||||
uv_backend-0.1.0.dist-info/RECORD
|
||||
uv_backend-0.1.0.dist-info/WHEEL
|
||||
");
|
||||
|
||||
let metadata_file = metadata_dir
|
||||
.path()
|
||||
.join("uv_backend-0.1.0.dist-info/METADATA");
|
||||
assert_snapshot!(fs_err::read_to_string(metadata_file).unwrap(), @r###"
|
||||
Metadata-Version: 2.3
|
||||
Name: uv-backend
|
||||
Version: 0.1.0
|
||||
Summary: Add your description here
|
||||
Requires-Python: >=3.12
|
||||
Description-Content-Type: text/markdown
|
||||
|
||||
# uv_backend
|
||||
|
||||
A simple package to be built with the uv build backend.
|
||||
"###);
|
||||
|
||||
let record_file = metadata_dir
|
||||
.path()
|
||||
.join("uv_backend-0.1.0.dist-info/RECORD");
|
||||
assert_snapshot!(fs_err::read_to_string(record_file).unwrap(), @r###"
|
||||
uv_backend-0.1.0.dist-info/WHEEL,sha256=70ce44709b6a53e0d0c5a6755b0290179697020f1f867e794f26154fe4825738,79
|
||||
uv_backend-0.1.0.dist-info/METADATA,sha256=e4a0d390317d7182f65ea978254c71ed283e0a4242150cf1c99a694b113ff68d,224
|
||||
uv_backend-0.1.0.dist-info/RECORD,,
|
||||
"###);
|
||||
|
||||
let wheel_file = metadata_dir.path().join("uv_backend-0.1.0.dist-info/WHEEL");
|
||||
let filters = vec![(uv_version::version(), "[VERSION]")];
|
||||
with_settings!({
|
||||
filters => filters
|
||||
}, {
|
||||
assert_snapshot!(fs_err::read_to_string(wheel_file).unwrap(), @r###"
|
||||
Wheel-Version: 1.0
|
||||
Generator: uv [VERSION]
|
||||
Root-Is-Purelib: true
|
||||
Tag: py3-none-any
|
||||
"###);
|
||||
});
|
||||
}
|
||||
}
|
||||
mod tests;
|
||||
|
|
|
|||
|
|
@ -629,406 +629,4 @@ struct BuildSystem {
|
|||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use indoc::{formatdoc, indoc};
|
||||
use insta::assert_snapshot;
|
||||
use std::iter;
|
||||
use tempfile::TempDir;
|
||||
|
||||
fn extend_project(payload: &str) -> String {
|
||||
formatdoc! {r#"
|
||||
[project]
|
||||
name = "hello-world"
|
||||
version = "0.1.0"
|
||||
{payload}
|
||||
|
||||
[build-system]
|
||||
requires = ["uv>=0.4.15,<5"]
|
||||
build-backend = "uv"
|
||||
"#
|
||||
}
|
||||
}
|
||||
|
||||
fn format_err(err: impl std::error::Error) -> String {
|
||||
let mut formatted = err.to_string();
|
||||
for source in iter::successors(err.source(), |&err| err.source()) {
|
||||
formatted += &format!("\n Caused by: {source}");
|
||||
}
|
||||
formatted
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn valid() {
|
||||
let temp_dir = TempDir::new().unwrap();
|
||||
|
||||
fs_err::write(
|
||||
temp_dir.path().join("Readme.md"),
|
||||
indoc! {r"
|
||||
# Foo
|
||||
|
||||
This is the foo library.
|
||||
"},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
fs_err::write(
|
||||
temp_dir.path().join("License.txt"),
|
||||
indoc! {r#"
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
||||
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
"#},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let contents = indoc! {r#"
|
||||
# See https://github.com/pypa/sampleproject/blob/main/pyproject.toml for another example
|
||||
|
||||
[project]
|
||||
name = "hello-world"
|
||||
version = "0.1.0"
|
||||
description = "A Python package"
|
||||
readme = "Readme.md"
|
||||
requires_python = ">=3.12"
|
||||
license = { file = "License.txt" }
|
||||
authors = [{ name = "Ferris the crab", email = "ferris@rustacean.net" }]
|
||||
maintainers = [{ name = "Konsti", email = "konstin@mailbox.org" }]
|
||||
keywords = ["demo", "example", "package"]
|
||||
classifiers = [
|
||||
"Development Status :: 6 - Mature",
|
||||
"License :: OSI Approved :: MIT License",
|
||||
# https://github.com/pypa/trove-classifiers/issues/17
|
||||
"License :: OSI Approved :: Apache Software License",
|
||||
"Programming Language :: Python",
|
||||
]
|
||||
dependencies = ["flask>=3,<4", "sqlalchemy[asyncio]>=2.0.35,<3"]
|
||||
# We don't support dynamic fields, the default empty array is the only allowed value.
|
||||
dynamic = []
|
||||
|
||||
[project.optional-dependencies]
|
||||
postgres = ["psycopg>=3.2.2,<4"]
|
||||
mysql = ["pymysql>=1.1.1,<2"]
|
||||
|
||||
[project.urls]
|
||||
"Homepage" = "https://github.com/astral-sh/uv"
|
||||
"Repository" = "https://astral.sh"
|
||||
|
||||
[project.scripts]
|
||||
foo = "foo.cli:__main__"
|
||||
|
||||
[project.gui-scripts]
|
||||
foo-gui = "foo.gui"
|
||||
|
||||
[project.entry-points.bar_group]
|
||||
foo-bar = "foo:bar"
|
||||
|
||||
[build-system]
|
||||
requires = ["uv>=0.4.15,<5"]
|
||||
build-backend = "uv"
|
||||
"#
|
||||
};
|
||||
|
||||
let pyproject_toml = PyProjectToml::parse(contents).unwrap();
|
||||
let metadata = pyproject_toml.to_metadata(temp_dir.path()).unwrap();
|
||||
|
||||
assert_snapshot!(metadata.core_metadata_format(), @r###"
|
||||
Metadata-Version: 2.3
|
||||
Name: hello-world
|
||||
Version: 0.1.0
|
||||
Summary: A Python package
|
||||
Keywords: demo,example,package
|
||||
Author: Ferris the crab
|
||||
License: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
||||
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
Classifier: Development Status :: 6 - Mature
|
||||
Classifier: License :: OSI Approved :: MIT License
|
||||
Classifier: License :: OSI Approved :: Apache Software License
|
||||
Classifier: Programming Language :: Python
|
||||
Requires-Dist: flask>=3,<4
|
||||
Requires-Dist: sqlalchemy[asyncio]>=2.0.35,<3
|
||||
Maintainer: Konsti
|
||||
Project-URL: Homepage, https://github.com/astral-sh/uv
|
||||
Project-URL: Repository, https://astral.sh
|
||||
Provides-Extra: mysql
|
||||
Provides-Extra: postgres
|
||||
Description-Content-Type: text/markdown
|
||||
|
||||
# Foo
|
||||
|
||||
This is the foo library.
|
||||
"###);
|
||||
|
||||
assert_snapshot!(pyproject_toml.to_entry_points().unwrap().unwrap(), @r###"
|
||||
[console_scripts]
|
||||
foo = foo.cli:__main__
|
||||
|
||||
[gui_scripts]
|
||||
foo-gui = foo.gui
|
||||
|
||||
[bar_group]
|
||||
foo-bar = foo:bar
|
||||
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_system_valid() {
|
||||
let contents = extend_project("");
|
||||
let pyproject_toml = PyProjectToml::parse(&contents).unwrap();
|
||||
assert!(pyproject_toml.check_build_system());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_system_no_bound() {
|
||||
let contents = indoc! {r#"
|
||||
[project]
|
||||
name = "hello-world"
|
||||
version = "0.1.0"
|
||||
|
||||
[build-system]
|
||||
requires = ["uv"]
|
||||
build-backend = "uv"
|
||||
"#};
|
||||
let pyproject_toml = PyProjectToml::parse(contents).unwrap();
|
||||
assert!(!pyproject_toml.check_build_system());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_system_multiple_packages() {
|
||||
let contents = indoc! {r#"
|
||||
[project]
|
||||
name = "hello-world"
|
||||
version = "0.1.0"
|
||||
|
||||
[build-system]
|
||||
requires = ["uv>=0.4.15,<5", "wheel"]
|
||||
build-backend = "uv"
|
||||
"#};
|
||||
let pyproject_toml = PyProjectToml::parse(contents).unwrap();
|
||||
assert!(!pyproject_toml.check_build_system());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_system_no_requires_uv() {
|
||||
let contents = indoc! {r#"
|
||||
[project]
|
||||
name = "hello-world"
|
||||
version = "0.1.0"
|
||||
|
||||
[build-system]
|
||||
requires = ["setuptools"]
|
||||
build-backend = "uv"
|
||||
"#};
|
||||
let pyproject_toml = PyProjectToml::parse(contents).unwrap();
|
||||
assert!(!pyproject_toml.check_build_system());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_system_not_uv() {
|
||||
let contents = indoc! {r#"
|
||||
[project]
|
||||
name = "hello-world"
|
||||
version = "0.1.0"
|
||||
|
||||
[build-system]
|
||||
requires = ["uv>=0.4.15,<5"]
|
||||
build-backend = "setuptools"
|
||||
"#};
|
||||
let pyproject_toml = PyProjectToml::parse(contents).unwrap();
|
||||
assert!(!pyproject_toml.check_build_system());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn minimal() {
|
||||
let contents = extend_project("");
|
||||
|
||||
let metadata = PyProjectToml::parse(&contents)
|
||||
.unwrap()
|
||||
.to_metadata(Path::new("/do/not/read"))
|
||||
.unwrap();
|
||||
|
||||
assert_snapshot!(metadata.core_metadata_format(), @r###"
|
||||
Metadata-Version: 2.3
|
||||
Name: hello-world
|
||||
Version: 0.1.0
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_readme_spec() {
|
||||
let contents = extend_project(indoc! {r#"
|
||||
readme = { path = "Readme.md" }
|
||||
"#
|
||||
});
|
||||
|
||||
let err = PyProjectToml::parse(&contents).unwrap_err();
|
||||
assert_snapshot!(format_err(err), @r###"
|
||||
Invalid pyproject.toml
|
||||
Caused by: TOML parse error at line 4, column 10
|
||||
|
|
||||
4 | readme = { path = "Readme.md" }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
data did not match any variant of untagged enum Readme
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn missing_readme() {
|
||||
let contents = extend_project(indoc! {r#"
|
||||
readme = "Readme.md"
|
||||
"#
|
||||
});
|
||||
|
||||
let err = PyProjectToml::parse(&contents)
|
||||
.unwrap()
|
||||
.to_metadata(Path::new("/do/not/read"))
|
||||
.unwrap_err();
|
||||
// Simplified for windows compatibility.
|
||||
assert_snapshot!(err.to_string().replace('\\', "/"), @"failed to open file `/do/not/read/Readme.md`");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiline_description() {
|
||||
let contents = extend_project(indoc! {r#"
|
||||
description = "Hi :)\nThis is my project"
|
||||
"#
|
||||
});
|
||||
|
||||
let err = PyProjectToml::parse(&contents)
|
||||
.unwrap()
|
||||
.to_metadata(Path::new("/do/not/read"))
|
||||
.unwrap_err();
|
||||
assert_snapshot!(format_err(err), @r###"
|
||||
Invalid pyproject.toml
|
||||
Caused by: `project.description` must be a single line
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mixed_licenses() {
|
||||
let contents = extend_project(indoc! {r#"
|
||||
license-files = ["licenses/*"]
|
||||
license = { text = "MIT" }
|
||||
"#
|
||||
});
|
||||
|
||||
let err = PyProjectToml::parse(&contents)
|
||||
.unwrap()
|
||||
.to_metadata(Path::new("/do/not/read"))
|
||||
.unwrap_err();
|
||||
assert_snapshot!(format_err(err), @r###"
|
||||
Invalid pyproject.toml
|
||||
Caused by: When `project.license-files` is defined, `project.license` must be an SPDX expression string
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn valid_license() {
|
||||
let contents = extend_project(indoc! {r#"
|
||||
license = "MIT OR Apache-2.0"
|
||||
"#
|
||||
});
|
||||
let metadata = PyProjectToml::parse(&contents)
|
||||
.unwrap()
|
||||
.to_metadata(Path::new("/do/not/read"))
|
||||
.unwrap();
|
||||
assert_snapshot!(metadata.core_metadata_format(), @r###"
|
||||
Metadata-Version: 2.4
|
||||
Name: hello-world
|
||||
Version: 0.1.0
|
||||
License-Expression: MIT OR Apache-2.0
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_license() {
|
||||
let contents = extend_project(indoc! {r#"
|
||||
license = "MIT XOR Apache-2"
|
||||
"#
|
||||
});
|
||||
let err = PyProjectToml::parse(&contents)
|
||||
.unwrap()
|
||||
.to_metadata(Path::new("/do/not/read"))
|
||||
.unwrap_err();
|
||||
// TODO(konsti): We mess up the indentation in the error.
|
||||
assert_snapshot!(format_err(err), @r###"
|
||||
Invalid pyproject.toml
|
||||
Caused by: `project.license` is not a valid SPDX expression: `MIT XOR Apache-2`
|
||||
Caused by: MIT XOR Apache-2
|
||||
^^^ unknown term
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dynamic() {
|
||||
let contents = extend_project(indoc! {r#"
|
||||
dynamic = ["dependencies"]
|
||||
"#
|
||||
});
|
||||
|
||||
let err = PyProjectToml::parse(&contents)
|
||||
.unwrap()
|
||||
.to_metadata(Path::new("/do/not/read"))
|
||||
.unwrap_err();
|
||||
assert_snapshot!(format_err(err), @r###"
|
||||
Invalid pyproject.toml
|
||||
Caused by: Dynamic metadata is not supported
|
||||
"###);
|
||||
}
|
||||
|
||||
fn script_error(contents: &str) -> String {
|
||||
let err = PyProjectToml::parse(contents)
|
||||
.unwrap()
|
||||
.to_entry_points()
|
||||
.unwrap_err();
|
||||
format_err(err)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_entry_point_group() {
|
||||
let contents = extend_project(indoc! {r#"
|
||||
[project.entry-points."a@b"]
|
||||
foo = "bar"
|
||||
"#
|
||||
});
|
||||
assert_snapshot!(script_error(&contents), @"Entrypoint groups must consist of letters and numbers separated by dots, invalid group: `a@b`");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_entry_point_name() {
|
||||
let contents = extend_project(indoc! {r#"
|
||||
[project.scripts]
|
||||
"a@b" = "bar"
|
||||
"#
|
||||
});
|
||||
assert_snapshot!(script_error(&contents), @"Entrypoint names must consist of letters, numbers, dots and dashes; invalid name: `a@b`");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_entry_point_conflict_scripts() {
|
||||
let contents = extend_project(indoc! {r#"
|
||||
[project.entry-points.console_scripts]
|
||||
foo = "bar"
|
||||
"#
|
||||
});
|
||||
assert_snapshot!(script_error(&contents), @"Use `project.scripts` instead of `project.entry-points.console_scripts`");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_entry_point_conflict_gui_scripts() {
|
||||
let contents = extend_project(indoc! {r#"
|
||||
[project.entry-points.gui_scripts]
|
||||
foo = "bar"
|
||||
"#
|
||||
});
|
||||
assert_snapshot!(script_error(&contents), @"Use `project.gui-scripts` instead of `project.entry-points.gui_scripts`");
|
||||
}
|
||||
}
|
||||
mod tests;
|
||||
|
|
|
|||
401
crates/uv-build-backend/src/metadata/tests.rs
Normal file
401
crates/uv-build-backend/src/metadata/tests.rs
Normal file
|
|
@ -0,0 +1,401 @@
|
|||
use super::*;
|
||||
use indoc::{formatdoc, indoc};
|
||||
use insta::assert_snapshot;
|
||||
use std::iter;
|
||||
use tempfile::TempDir;
|
||||
|
||||
fn extend_project(payload: &str) -> String {
|
||||
formatdoc! {r#"
|
||||
[project]
|
||||
name = "hello-world"
|
||||
version = "0.1.0"
|
||||
{payload}
|
||||
|
||||
[build-system]
|
||||
requires = ["uv>=0.4.15,<5"]
|
||||
build-backend = "uv"
|
||||
"#
|
||||
}
|
||||
}
|
||||
|
||||
fn format_err(err: impl std::error::Error) -> String {
|
||||
let mut formatted = err.to_string();
|
||||
for source in iter::successors(err.source(), |&err| err.source()) {
|
||||
formatted += &format!("\n Caused by: {source}");
|
||||
}
|
||||
formatted
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn valid() {
|
||||
let temp_dir = TempDir::new().unwrap();
|
||||
|
||||
fs_err::write(
|
||||
temp_dir.path().join("Readme.md"),
|
||||
indoc! {r"
|
||||
# Foo
|
||||
|
||||
This is the foo library.
|
||||
"},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
fs_err::write(
|
||||
temp_dir.path().join("License.txt"),
|
||||
indoc! {r#"
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
||||
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
"#},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let contents = indoc! {r#"
|
||||
# See https://github.com/pypa/sampleproject/blob/main/pyproject.toml for another example
|
||||
|
||||
[project]
|
||||
name = "hello-world"
|
||||
version = "0.1.0"
|
||||
description = "A Python package"
|
||||
readme = "Readme.md"
|
||||
requires_python = ">=3.12"
|
||||
license = { file = "License.txt" }
|
||||
authors = [{ name = "Ferris the crab", email = "ferris@rustacean.net" }]
|
||||
maintainers = [{ name = "Konsti", email = "konstin@mailbox.org" }]
|
||||
keywords = ["demo", "example", "package"]
|
||||
classifiers = [
|
||||
"Development Status :: 6 - Mature",
|
||||
"License :: OSI Approved :: MIT License",
|
||||
# https://github.com/pypa/trove-classifiers/issues/17
|
||||
"License :: OSI Approved :: Apache Software License",
|
||||
"Programming Language :: Python",
|
||||
]
|
||||
dependencies = ["flask>=3,<4", "sqlalchemy[asyncio]>=2.0.35,<3"]
|
||||
# We don't support dynamic fields, the default empty array is the only allowed value.
|
||||
dynamic = []
|
||||
|
||||
[project.optional-dependencies]
|
||||
postgres = ["psycopg>=3.2.2,<4"]
|
||||
mysql = ["pymysql>=1.1.1,<2"]
|
||||
|
||||
[project.urls]
|
||||
"Homepage" = "https://github.com/astral-sh/uv"
|
||||
"Repository" = "https://astral.sh"
|
||||
|
||||
[project.scripts]
|
||||
foo = "foo.cli:__main__"
|
||||
|
||||
[project.gui-scripts]
|
||||
foo-gui = "foo.gui"
|
||||
|
||||
[project.entry-points.bar_group]
|
||||
foo-bar = "foo:bar"
|
||||
|
||||
[build-system]
|
||||
requires = ["uv>=0.4.15,<5"]
|
||||
build-backend = "uv"
|
||||
"#
|
||||
};
|
||||
|
||||
let pyproject_toml = PyProjectToml::parse(contents).unwrap();
|
||||
let metadata = pyproject_toml.to_metadata(temp_dir.path()).unwrap();
|
||||
|
||||
assert_snapshot!(metadata.core_metadata_format(), @r###"
|
||||
Metadata-Version: 2.3
|
||||
Name: hello-world
|
||||
Version: 0.1.0
|
||||
Summary: A Python package
|
||||
Keywords: demo,example,package
|
||||
Author: Ferris the crab
|
||||
License: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
||||
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
Classifier: Development Status :: 6 - Mature
|
||||
Classifier: License :: OSI Approved :: MIT License
|
||||
Classifier: License :: OSI Approved :: Apache Software License
|
||||
Classifier: Programming Language :: Python
|
||||
Requires-Dist: flask>=3,<4
|
||||
Requires-Dist: sqlalchemy[asyncio]>=2.0.35,<3
|
||||
Maintainer: Konsti
|
||||
Project-URL: Homepage, https://github.com/astral-sh/uv
|
||||
Project-URL: Repository, https://astral.sh
|
||||
Provides-Extra: mysql
|
||||
Provides-Extra: postgres
|
||||
Description-Content-Type: text/markdown
|
||||
|
||||
# Foo
|
||||
|
||||
This is the foo library.
|
||||
"###);
|
||||
|
||||
assert_snapshot!(pyproject_toml.to_entry_points().unwrap().unwrap(), @r###"
|
||||
[console_scripts]
|
||||
foo = foo.cli:__main__
|
||||
|
||||
[gui_scripts]
|
||||
foo-gui = foo.gui
|
||||
|
||||
[bar_group]
|
||||
foo-bar = foo:bar
|
||||
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_system_valid() {
|
||||
let contents = extend_project("");
|
||||
let pyproject_toml = PyProjectToml::parse(&contents).unwrap();
|
||||
assert!(pyproject_toml.check_build_system());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_system_no_bound() {
|
||||
let contents = indoc! {r#"
|
||||
[project]
|
||||
name = "hello-world"
|
||||
version = "0.1.0"
|
||||
|
||||
[build-system]
|
||||
requires = ["uv"]
|
||||
build-backend = "uv"
|
||||
"#};
|
||||
let pyproject_toml = PyProjectToml::parse(contents).unwrap();
|
||||
assert!(!pyproject_toml.check_build_system());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_system_multiple_packages() {
|
||||
let contents = indoc! {r#"
|
||||
[project]
|
||||
name = "hello-world"
|
||||
version = "0.1.0"
|
||||
|
||||
[build-system]
|
||||
requires = ["uv>=0.4.15,<5", "wheel"]
|
||||
build-backend = "uv"
|
||||
"#};
|
||||
let pyproject_toml = PyProjectToml::parse(contents).unwrap();
|
||||
assert!(!pyproject_toml.check_build_system());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_system_no_requires_uv() {
|
||||
let contents = indoc! {r#"
|
||||
[project]
|
||||
name = "hello-world"
|
||||
version = "0.1.0"
|
||||
|
||||
[build-system]
|
||||
requires = ["setuptools"]
|
||||
build-backend = "uv"
|
||||
"#};
|
||||
let pyproject_toml = PyProjectToml::parse(contents).unwrap();
|
||||
assert!(!pyproject_toml.check_build_system());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_system_not_uv() {
|
||||
let contents = indoc! {r#"
|
||||
[project]
|
||||
name = "hello-world"
|
||||
version = "0.1.0"
|
||||
|
||||
[build-system]
|
||||
requires = ["uv>=0.4.15,<5"]
|
||||
build-backend = "setuptools"
|
||||
"#};
|
||||
let pyproject_toml = PyProjectToml::parse(contents).unwrap();
|
||||
assert!(!pyproject_toml.check_build_system());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn minimal() {
|
||||
let contents = extend_project("");
|
||||
|
||||
let metadata = PyProjectToml::parse(&contents)
|
||||
.unwrap()
|
||||
.to_metadata(Path::new("/do/not/read"))
|
||||
.unwrap();
|
||||
|
||||
assert_snapshot!(metadata.core_metadata_format(), @r###"
|
||||
Metadata-Version: 2.3
|
||||
Name: hello-world
|
||||
Version: 0.1.0
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_readme_spec() {
|
||||
let contents = extend_project(indoc! {r#"
|
||||
readme = { path = "Readme.md" }
|
||||
"#
|
||||
});
|
||||
|
||||
let err = PyProjectToml::parse(&contents).unwrap_err();
|
||||
assert_snapshot!(format_err(err), @r###"
|
||||
Invalid pyproject.toml
|
||||
Caused by: TOML parse error at line 4, column 10
|
||||
|
|
||||
4 | readme = { path = "Readme.md" }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
data did not match any variant of untagged enum Readme
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn missing_readme() {
|
||||
let contents = extend_project(indoc! {r#"
|
||||
readme = "Readme.md"
|
||||
"#
|
||||
});
|
||||
|
||||
let err = PyProjectToml::parse(&contents)
|
||||
.unwrap()
|
||||
.to_metadata(Path::new("/do/not/read"))
|
||||
.unwrap_err();
|
||||
// Simplified for windows compatibility.
|
||||
assert_snapshot!(err.to_string().replace('\\', "/"), @"failed to open file `/do/not/read/Readme.md`");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiline_description() {
|
||||
let contents = extend_project(indoc! {r#"
|
||||
description = "Hi :)\nThis is my project"
|
||||
"#
|
||||
});
|
||||
|
||||
let err = PyProjectToml::parse(&contents)
|
||||
.unwrap()
|
||||
.to_metadata(Path::new("/do/not/read"))
|
||||
.unwrap_err();
|
||||
assert_snapshot!(format_err(err), @r###"
|
||||
Invalid pyproject.toml
|
||||
Caused by: `project.description` must be a single line
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mixed_licenses() {
|
||||
let contents = extend_project(indoc! {r#"
|
||||
license-files = ["licenses/*"]
|
||||
license = { text = "MIT" }
|
||||
"#
|
||||
});
|
||||
|
||||
let err = PyProjectToml::parse(&contents)
|
||||
.unwrap()
|
||||
.to_metadata(Path::new("/do/not/read"))
|
||||
.unwrap_err();
|
||||
assert_snapshot!(format_err(err), @r###"
|
||||
Invalid pyproject.toml
|
||||
Caused by: When `project.license-files` is defined, `project.license` must be an SPDX expression string
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn valid_license() {
|
||||
let contents = extend_project(indoc! {r#"
|
||||
license = "MIT OR Apache-2.0"
|
||||
"#
|
||||
});
|
||||
let metadata = PyProjectToml::parse(&contents)
|
||||
.unwrap()
|
||||
.to_metadata(Path::new("/do/not/read"))
|
||||
.unwrap();
|
||||
assert_snapshot!(metadata.core_metadata_format(), @r###"
|
||||
Metadata-Version: 2.4
|
||||
Name: hello-world
|
||||
Version: 0.1.0
|
||||
License-Expression: MIT OR Apache-2.0
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_license() {
|
||||
let contents = extend_project(indoc! {r#"
|
||||
license = "MIT XOR Apache-2"
|
||||
"#
|
||||
});
|
||||
let err = PyProjectToml::parse(&contents)
|
||||
.unwrap()
|
||||
.to_metadata(Path::new("/do/not/read"))
|
||||
.unwrap_err();
|
||||
// TODO(konsti): We mess up the indentation in the error.
|
||||
assert_snapshot!(format_err(err), @r###"
|
||||
Invalid pyproject.toml
|
||||
Caused by: `project.license` is not a valid SPDX expression: `MIT XOR Apache-2`
|
||||
Caused by: MIT XOR Apache-2
|
||||
^^^ unknown term
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dynamic() {
|
||||
let contents = extend_project(indoc! {r#"
|
||||
dynamic = ["dependencies"]
|
||||
"#
|
||||
});
|
||||
|
||||
let err = PyProjectToml::parse(&contents)
|
||||
.unwrap()
|
||||
.to_metadata(Path::new("/do/not/read"))
|
||||
.unwrap_err();
|
||||
assert_snapshot!(format_err(err), @r###"
|
||||
Invalid pyproject.toml
|
||||
Caused by: Dynamic metadata is not supported
|
||||
"###);
|
||||
}
|
||||
|
||||
fn script_error(contents: &str) -> String {
|
||||
let err = PyProjectToml::parse(contents)
|
||||
.unwrap()
|
||||
.to_entry_points()
|
||||
.unwrap_err();
|
||||
format_err(err)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_entry_point_group() {
|
||||
let contents = extend_project(indoc! {r#"
|
||||
[project.entry-points."a@b"]
|
||||
foo = "bar"
|
||||
"#
|
||||
});
|
||||
assert_snapshot!(script_error(&contents), @"Entrypoint groups must consist of letters and numbers separated by dots, invalid group: `a@b`");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_entry_point_name() {
|
||||
let contents = extend_project(indoc! {r#"
|
||||
[project.scripts]
|
||||
"a@b" = "bar"
|
||||
"#
|
||||
});
|
||||
assert_snapshot!(script_error(&contents), @"Entrypoint names must consist of letters, numbers, dots and dashes; invalid name: `a@b`");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_entry_point_conflict_scripts() {
|
||||
let contents = extend_project(indoc! {r#"
|
||||
[project.entry-points.console_scripts]
|
||||
foo = "bar"
|
||||
"#
|
||||
});
|
||||
assert_snapshot!(script_error(&contents), @"Use `project.scripts` instead of `project.entry-points.console_scripts`");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_entry_point_conflict_gui_scripts() {
|
||||
let contents = extend_project(indoc! {r#"
|
||||
[project.entry-points.gui_scripts]
|
||||
foo = "bar"
|
||||
"#
|
||||
});
|
||||
assert_snapshot!(script_error(&contents), @"Use `project.gui-scripts` instead of `project.entry-points.gui_scripts`");
|
||||
}
|
||||
|
|
@ -78,59 +78,4 @@ pub(crate) fn parse_pep639_glob(glob: &str) -> Result<Pattern, Pep639GlobError>
|
|||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use insta::assert_snapshot;
|
||||
|
||||
#[test]
|
||||
fn test_error() {
|
||||
let parse_err = |glob| parse_pep639_glob(glob).unwrap_err().to_string();
|
||||
assert_snapshot!(
|
||||
parse_err(".."),
|
||||
@"The parent directory operator (`..`) at position 0 is not allowed in license file globs"
|
||||
);
|
||||
assert_snapshot!(
|
||||
parse_err("licenses/.."),
|
||||
@"The parent directory operator (`..`) at position 9 is not allowed in license file globs"
|
||||
);
|
||||
assert_snapshot!(
|
||||
parse_err("licenses/LICEN!E.txt"),
|
||||
@"Glob contains invalid character at position 14: `!`"
|
||||
);
|
||||
assert_snapshot!(
|
||||
parse_err("licenses/LICEN[!C]E.txt"),
|
||||
@"Glob contains invalid character in range at position 15: `!`"
|
||||
);
|
||||
assert_snapshot!(
|
||||
parse_err("licenses/LICEN[C?]E.txt"),
|
||||
@"Glob contains invalid character in range at position 16: `?`"
|
||||
);
|
||||
assert_snapshot!(parse_err("******"), @"Pattern syntax error near position 2: wildcards are either regular `*` or recursive `**`");
|
||||
assert_snapshot!(
|
||||
parse_err(r"licenses\eula.txt"),
|
||||
@r"Glob contains invalid character at position 8: `\`"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_valid() {
|
||||
let cases = [
|
||||
"licenses/*.txt",
|
||||
"licenses/**/*.txt",
|
||||
"LICEN[CS]E.txt",
|
||||
"LICEN?E.txt",
|
||||
"[a-z].txt",
|
||||
"[a-z._-].txt",
|
||||
"*/**",
|
||||
"LICENSE..txt",
|
||||
"LICENSE_file-1.txt",
|
||||
// (google translate)
|
||||
"licenses/라이센스*.txt",
|
||||
"licenses/ライセンス*.txt",
|
||||
"licenses/执照*.txt",
|
||||
];
|
||||
for case in cases {
|
||||
parse_pep639_glob(case).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
mod tests;
|
||||
|
|
|
|||
54
crates/uv-build-backend/src/pep639_glob/tests.rs
Normal file
54
crates/uv-build-backend/src/pep639_glob/tests.rs
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
use super::*;
|
||||
use insta::assert_snapshot;
|
||||
|
||||
#[test]
|
||||
fn test_error() {
|
||||
let parse_err = |glob| parse_pep639_glob(glob).unwrap_err().to_string();
|
||||
assert_snapshot!(
|
||||
parse_err(".."),
|
||||
@"The parent directory operator (`..`) at position 0 is not allowed in license file globs"
|
||||
);
|
||||
assert_snapshot!(
|
||||
parse_err("licenses/.."),
|
||||
@"The parent directory operator (`..`) at position 9 is not allowed in license file globs"
|
||||
);
|
||||
assert_snapshot!(
|
||||
parse_err("licenses/LICEN!E.txt"),
|
||||
@"Glob contains invalid character at position 14: `!`"
|
||||
);
|
||||
assert_snapshot!(
|
||||
parse_err("licenses/LICEN[!C]E.txt"),
|
||||
@"Glob contains invalid character in range at position 15: `!`"
|
||||
);
|
||||
assert_snapshot!(
|
||||
parse_err("licenses/LICEN[C?]E.txt"),
|
||||
@"Glob contains invalid character in range at position 16: `?`"
|
||||
);
|
||||
assert_snapshot!(parse_err("******"), @"Pattern syntax error near position 2: wildcards are either regular `*` or recursive `**`");
|
||||
assert_snapshot!(
|
||||
parse_err(r"licenses\eula.txt"),
|
||||
@r"Glob contains invalid character at position 8: `\`"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_valid() {
|
||||
let cases = [
|
||||
"licenses/*.txt",
|
||||
"licenses/**/*.txt",
|
||||
"LICEN[CS]E.txt",
|
||||
"LICEN?E.txt",
|
||||
"[a-z].txt",
|
||||
"[a-z._-].txt",
|
||||
"*/**",
|
||||
"LICENSE..txt",
|
||||
"LICENSE_file-1.txt",
|
||||
// (google translate)
|
||||
"licenses/라이센스*.txt",
|
||||
"licenses/ライセンス*.txt",
|
||||
"licenses/执照*.txt",
|
||||
];
|
||||
for case in cases {
|
||||
parse_pep639_glob(case).unwrap();
|
||||
}
|
||||
}
|
||||
137
crates/uv-build-backend/src/tests.rs
Normal file
137
crates/uv-build-backend/src/tests.rs
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
use super::*;
|
||||
use insta::{assert_snapshot, with_settings};
|
||||
use std::str::FromStr;
|
||||
use tempfile::TempDir;
|
||||
use uv_normalize::PackageName;
|
||||
use uv_pep440::Version;
|
||||
|
||||
#[test]
|
||||
fn test_wheel() {
|
||||
let filename = WheelFilename {
|
||||
name: PackageName::from_str("foo").unwrap(),
|
||||
version: Version::from_str("1.2.3").unwrap(),
|
||||
build_tag: None,
|
||||
python_tag: vec!["py2".to_string(), "py3".to_string()],
|
||||
abi_tag: vec!["none".to_string()],
|
||||
platform_tag: vec!["any".to_string()],
|
||||
};
|
||||
|
||||
with_settings!({
|
||||
filters => [(uv_version::version(), "[VERSION]")],
|
||||
}, {
|
||||
assert_snapshot!(wheel_info(&filename), @r"
|
||||
Wheel-Version: 1.0
|
||||
Generator: uv [VERSION]
|
||||
Root-Is-Purelib: true
|
||||
Tag: py2-none-any
|
||||
Tag: py3-none-any
|
||||
");
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_record() {
|
||||
let record = vec![RecordEntry {
|
||||
path: "uv_backend/__init__.py".to_string(),
|
||||
hash: "89f869e53a3a0061a52c0233e6442d4d72de80a8a2d3406d9ea0bfd397ed7865".to_string(),
|
||||
size: 37,
|
||||
}];
|
||||
|
||||
let mut writer = Vec::new();
|
||||
write_record(&mut writer, "uv_backend-0.1.0", record).unwrap();
|
||||
assert_snapshot!(String::from_utf8(writer).unwrap(), @r"
|
||||
uv_backend/__init__.py,sha256=89f869e53a3a0061a52c0233e6442d4d72de80a8a2d3406d9ea0bfd397ed7865,37
|
||||
uv_backend-0.1.0/RECORD,,
|
||||
");
|
||||
}
|
||||
|
||||
/// Check that we write deterministic wheels.
|
||||
#[test]
|
||||
fn test_determinism() {
|
||||
let temp1 = TempDir::new().unwrap();
|
||||
let uv_backend = Path::new("../../scripts/packages/uv_backend");
|
||||
build(uv_backend, temp1.path(), None).unwrap();
|
||||
|
||||
// Touch the file to check that we don't serialize the last modified date.
|
||||
fs_err::write(
|
||||
uv_backend.join("src/uv_backend/__init__.py"),
|
||||
"def greet():\n print(\"Hello 👋\")\n",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let temp2 = TempDir::new().unwrap();
|
||||
build(uv_backend, temp2.path(), None).unwrap();
|
||||
|
||||
let wheel_filename = "uv_backend-0.1.0-py3-none-any.whl";
|
||||
assert_eq!(
|
||||
fs_err::read(temp1.path().join(wheel_filename)).unwrap(),
|
||||
fs_err::read(temp2.path().join(wheel_filename)).unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
/// Snapshot all files from the prepare metadata hook.
|
||||
#[test]
|
||||
fn test_prepare_metadata() {
|
||||
let metadata_dir = TempDir::new().unwrap();
|
||||
let uv_backend = Path::new("../../scripts/packages/uv_backend");
|
||||
metadata(uv_backend, metadata_dir.path()).unwrap();
|
||||
|
||||
let mut files: Vec<_> = WalkDir::new(metadata_dir.path())
|
||||
.into_iter()
|
||||
.map(|entry| {
|
||||
entry
|
||||
.unwrap()
|
||||
.path()
|
||||
.strip_prefix(metadata_dir.path())
|
||||
.unwrap()
|
||||
.portable_display()
|
||||
.to_string()
|
||||
})
|
||||
.filter(|path| !path.is_empty())
|
||||
.collect();
|
||||
files.sort();
|
||||
assert_snapshot!(files.join("\n"), @r"
|
||||
uv_backend-0.1.0.dist-info
|
||||
uv_backend-0.1.0.dist-info/METADATA
|
||||
uv_backend-0.1.0.dist-info/RECORD
|
||||
uv_backend-0.1.0.dist-info/WHEEL
|
||||
");
|
||||
|
||||
let metadata_file = metadata_dir
|
||||
.path()
|
||||
.join("uv_backend-0.1.0.dist-info/METADATA");
|
||||
assert_snapshot!(fs_err::read_to_string(metadata_file).unwrap(), @r###"
|
||||
Metadata-Version: 2.3
|
||||
Name: uv-backend
|
||||
Version: 0.1.0
|
||||
Summary: Add your description here
|
||||
Requires-Python: >=3.12
|
||||
Description-Content-Type: text/markdown
|
||||
|
||||
# uv_backend
|
||||
|
||||
A simple package to be built with the uv build backend.
|
||||
"###);
|
||||
|
||||
let record_file = metadata_dir
|
||||
.path()
|
||||
.join("uv_backend-0.1.0.dist-info/RECORD");
|
||||
assert_snapshot!(fs_err::read_to_string(record_file).unwrap(), @r###"
|
||||
uv_backend-0.1.0.dist-info/WHEEL,sha256=70ce44709b6a53e0d0c5a6755b0290179697020f1f867e794f26154fe4825738,79
|
||||
uv_backend-0.1.0.dist-info/METADATA,sha256=e4a0d390317d7182f65ea978254c71ed283e0a4242150cf1c99a694b113ff68d,224
|
||||
uv_backend-0.1.0.dist-info/RECORD,,
|
||||
"###);
|
||||
|
||||
let wheel_file = metadata_dir.path().join("uv_backend-0.1.0.dist-info/WHEEL");
|
||||
let filters = vec![(uv_version::version(), "[VERSION]")];
|
||||
with_settings!({
|
||||
filters => filters
|
||||
}, {
|
||||
assert_snapshot!(fs_err::read_to_string(wheel_file).unwrap(), @r###"
|
||||
Wheel-Version: 1.0
|
||||
Generator: uv [VERSION]
|
||||
Root-Is-Purelib: true
|
||||
Tag: py3-none-any
|
||||
"###);
|
||||
});
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue