use std::{
fs::{File, FileTimes, create_dir, create_dir_all, read},
io::Write,
os::unix::fs::symlink,
path::{Path, PathBuf},
time::SystemTime,
};
use alpm_compress::compression::{
Bzip2CompressionLevel,
CompressionSettings,
GzipCompressionLevel,
XzCompressionLevel,
ZstdCompressionLevel,
ZstdThreads,
};
use alpm_mtree::create_mtree_v2_from_input_dir;
use alpm_package::{
Error,
InputDir,
MetadataEntry,
OutputDir,
Package,
PackageCreationConfig,
PackageEntry,
PackageInput,
PackageReader,
};
use alpm_types::{Blake2b512Checksum, INSTALL_SCRIPTLET_FILE_NAME, MetadataFileName};
use filetime::{FileTime, set_symlink_file_times};
use log::{LevelFilter, debug};
use rstest::rstest;
use simplelog::{ColorChoice, Config, TermLogger, TerminalMode};
use tar::EntryType;
use tempfile::TempDir;
use testresult::TestResult;
const VALID_BUILDINFO_V2_DATA: &str = r#"
format = 2
builddate = 1
builddir = /build
startdir = /startdir/
buildtool = devtools
buildtoolver = 1:1.2.1-1-any
buildenv = ccache
buildenv = color
installed = bar-1.2.3-1-any
installed = beh-2.2.3-4-any
options = lto
options = !strip
packager = John Doe <john@example.org>
pkgarch = any
pkgbase = example
pkgbuild_sha256sum = b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c
pkgname = example
pkgver = 1:1.0.0-1
"#;
const VALID_PKGINFO_V2_DATA: &str = r#"
pkgname = example
pkgbase = example
xdata = pkgtype=pkg
pkgver = 1:1.0.0-1
pkgdesc = A project that does something
url = https://example.org/
builddate = 1
packager = John Doe <john@example.org>
size = 181849963
arch = any
license = GPL-3.0-or-later
license = LGPL-3.0-or-later
replaces = other-package>0.9.0-3
group = package-group
group = other-package-group
conflict = conflicting-package<1.0.0
conflict = other-conflicting-package<1.0.0
provides = some-component
provides = some-other-component=1:1.0.0-1
backup = etc/example/config.toml
backup = etc/example/other-config.txt
depend = glibc
depend = gcc-libs
optdepend = python: for special-python-script.py
optdepend = ruby: for special-ruby-script.rb
makedepend = cmake
makedepend = python-sphinx
checkdepend = extra-test-tool
checkdepend = other-extra-test-tool
"#;
const VALID_INSTALL_SCRIPTLET: &str = r#"
pre_install() {
echo "Preparing to install package version $1"
}
post_install() {
echo "Package version $1 installed"
}
pre_upgrade() {
echo "Preparing to upgrade from version $2 to $1"
}
post_upgrade() {
echo "Upgraded from version $2 to $1"
}
pre_remove() {
echo "Preparing to remove package version $1"
}
post_remove() {
echo "Package version $1 removed"
}
"#;
fn init_logger() {
if TermLogger::init(
LevelFilter::Debug,
Config::default(),
TerminalMode::Mixed,
ColorChoice::Auto,
)
.is_err()
{
debug!("Not initializing another logger, as one is initialized already.");
}
}
fn default_filetimes() -> FileTimes {
FileTimes::new()
.set_accessed(SystemTime::UNIX_EPOCH)
.set_modified(SystemTime::UNIX_EPOCH)
}
fn default_filetime() -> FileTime {
FileTime::from_unix_time(0, 0)
}
fn create_data_files(path: impl AsRef<Path>) -> TestResult {
let path = path.as_ref();
let mut file = File::create(path.join(".ARBITRARY"))?;
write!(file, "This is an arbitrary file.")?;
file.set_times(default_filetimes())?;
create_dir_all(path.join("foo/bar/baz"))?;
create_dir_all(path.join("foo/bar/buh"))?;
let mut file = File::create(path.join("foo/beh.txt"))?;
write!(file, "test")?;
file.set_times(default_filetimes())?;
let existing_target_link = path.join("foo/bar/baz/beh.txt");
symlink("../../beh.txt", &existing_target_link)?;
set_symlink_file_times(
&existing_target_link,
default_filetime(),
default_filetime(),
)?;
let non_existing_target_link = path.join("foo/bar/baz/buh.txt");
symlink(
"/tmp/something/very/unlikely/to/ever/exist/hopefully.txt",
&non_existing_target_link,
)?;
set_symlink_file_times(
&non_existing_target_link,
default_filetime(),
default_filetime(),
)?;
for path in [
path.join("foo/bar/baz"),
path.join("foo/bar/buh"),
path.join("foo/bar"),
path.join("foo"),
] {
let file = File::open(path)?;
file.set_times(default_filetimes())?;
}
Ok(())
}
fn create_build_info_file(path: impl AsRef<Path>) -> TestResult {
let path = path.as_ref();
let mut file = File::create(path.join(MetadataFileName::BuildInfo.as_ref()))?;
write!(file, "{VALID_BUILDINFO_V2_DATA}")?;
file.set_times(default_filetimes())?;
Ok(())
}
fn create_package_info_file(path: impl AsRef<Path>) -> TestResult {
let path = path.as_ref();
let mut file = File::create(path.join(MetadataFileName::PackageInfo.as_ref()))?;
write!(file, "{VALID_PKGINFO_V2_DATA}")?;
file.set_times(default_filetimes())?;
Ok(())
}
fn create_install_scriptlet(path: impl AsRef<Path>) -> TestResult {
let path = path.as_ref();
let mut file = File::create(path.join(INSTALL_SCRIPTLET_FILE_NAME))?;
write!(file, "{VALID_INSTALL_SCRIPTLET}")?;
file.set_times(default_filetimes())?;
Ok(())
}
fn create_mtree_file(path: impl AsRef<Path>) -> TestResult {
let path = path.as_ref();
let _mtree_file = create_mtree_v2_from_input_dir(path)?;
let file = File::open(path.join(MetadataFileName::Mtree.as_ref()))?;
file.set_times(default_filetimes())?;
Ok(())
}
struct InputDirConfig {
build_info: bool,
data_files: bool,
mtree: bool,
package_info: bool,
scriptlet: bool,
}
fn prepare_input_dir(path: impl AsRef<Path>, config: &InputDirConfig) -> TestResult {
let path = path.as_ref();
if config.data_files {
create_data_files(path)?;
}
if config.scriptlet {
create_install_scriptlet(path)?;
}
if config.build_info {
create_build_info_file(path)?;
}
if config.package_info {
create_package_info_file(path)?;
}
if config.mtree {
create_mtree_file(path)?;
}
Ok(())
}
fn package_digest(
path: impl AsRef<Path>,
input: &str,
output: &str,
compression: CompressionSettings,
input_dir_config: &InputDirConfig,
) -> TestResult<(PathBuf, Blake2b512Checksum)> {
let path = path.as_ref();
debug!("Creating package digest while using test dir {path:?}");
let input_dir_path = path.join(input);
create_dir(&input_dir_path)?;
let input_dir = InputDir::new(input_dir_path)?;
let output_dir = OutputDir::new(path.join(output))?;
prepare_input_dir(&input_dir, input_dir_config)?;
let package_input: PackageInput = input_dir.try_into()?;
let config = PackageCreationConfig::new(package_input, output_dir, compression)?;
let package = Package::try_from(&config)?;
let buf = read(package.to_path_buf())?;
Ok((
package.to_path_buf(),
Blake2b512Checksum::calculate_from(buf),
))
}
#[rstest]
#[case::bzip2_compression_all_files(
CompressionSettings::Bzip2 { compression_level: Bzip2CompressionLevel::default() },
InputDirConfig { build_info: true, data_files: true, mtree: true, package_info: true, scriptlet: true },
)]
#[case::bzip2_compression_no_scriptlet(
CompressionSettings::Bzip2 { compression_level: Bzip2CompressionLevel::default() },
InputDirConfig { build_info: true, data_files: true, mtree: true, package_info: true, scriptlet: false },
)]
#[case::bzip2_compression_no_data_files(
CompressionSettings::Bzip2 { compression_level: Bzip2CompressionLevel::default() },
InputDirConfig { build_info: true, data_files: false, mtree: true, package_info: true, scriptlet: false },
)]
#[case::gzip_compression_all_files(
CompressionSettings::Gzip { compression_level: GzipCompressionLevel::default() },
InputDirConfig { build_info: true, data_files: true, mtree: true, package_info: true, scriptlet: true },
)]
#[case::gzip_compression_no_scriptlet(
CompressionSettings::Gzip { compression_level: GzipCompressionLevel::default() },
InputDirConfig { build_info: true, data_files: true, mtree: true, package_info: true, scriptlet: false },
)]
#[case::gzip_compression_no_data_files(
CompressionSettings::Gzip { compression_level: GzipCompressionLevel::default() },
InputDirConfig { build_info: true, data_files: false, mtree: true, package_info: true, scriptlet: false },
)]
#[case::xz_compression_all_files(
CompressionSettings::Xz { compression_level: XzCompressionLevel::default() },
InputDirConfig { build_info: true, data_files: true, mtree: true, package_info: true, scriptlet: true },
)]
#[case::xz_compression_no_scriptlet(
CompressionSettings::Xz { compression_level: XzCompressionLevel::default() },
InputDirConfig { build_info: true, data_files: true, mtree: true, package_info: true, scriptlet: false },
)]
#[case::xz_compression_no_data_files(
CompressionSettings::Xz { compression_level: XzCompressionLevel::default() },
InputDirConfig { build_info: true, data_files: false, mtree: true, package_info: true, scriptlet: false },
)]
#[case::zstd_compression_all_files(
CompressionSettings::Zstd { compression_level: ZstdCompressionLevel::default(), threads: ZstdThreads::all() },
InputDirConfig { build_info: true, data_files: true, mtree: true, package_info: true, scriptlet: true },
)]
#[case::zstd_compression_no_scriptlet(
CompressionSettings::Zstd { compression_level: ZstdCompressionLevel::default(), threads: ZstdThreads::all() },
InputDirConfig { build_info: true, data_files: true, mtree: true, package_info: true, scriptlet: false },
)]
#[case::zstd_compression_no_data_files(
CompressionSettings::Zstd { compression_level: ZstdCompressionLevel::default(), threads: ZstdThreads::all() },
InputDirConfig { build_info: true, data_files: false, mtree: true, package_info: true, scriptlet: false },
)]
#[case::no_compression_all_files(
CompressionSettings::None,
InputDirConfig { build_info: true, data_files: true, mtree: true, package_info: true, scriptlet: true },
)]
#[case::no_compression_no_scriptlet(
CompressionSettings::None,
InputDirConfig { build_info: true, data_files: true, mtree: true, package_info: true, scriptlet: false },
)]
#[case::no_compression_no_data_files(
CompressionSettings::None,
InputDirConfig { build_info: true, data_files: false, mtree: true, package_info: true, scriptlet: false },
)]
fn create_package_from_input(
#[case] compression: CompressionSettings,
#[case] input_dir_config: InputDirConfig,
) -> TestResult {
init_logger();
let temp_dir = TempDir::new()?;
let test_dir = temp_dir.path();
let (package_a, package_digest_a) = package_digest(
test_dir,
"input1",
"output1",
compression.clone(),
&input_dir_config,
)?;
debug!("Created package A: {package_a:?}");
let (package_b, package_digest_b) = package_digest(
test_dir,
"input2",
"output2",
compression.clone(),
&input_dir_config,
)?;
debug!("Created package B: {package_b:?}");
assert_eq!(package_digest_a, package_digest_b);
Ok(())
}
#[rstest]
#[case::no_build_info(
InputDirConfig { build_info: false, data_files: false, mtree: true, package_info: true, scriptlet: false },
PathBuf::from(MetadataFileName::BuildInfo.as_ref()),
)]
#[case::no_package_info(
InputDirConfig { build_info: true, data_files: false, mtree: true, package_info: false, scriptlet: false },
PathBuf::from(MetadataFileName::PackageInfo.as_ref()),
)]
#[case::no_mtree(
InputDirConfig { build_info: true, data_files: false, mtree: false, package_info: true, scriptlet: false },
PathBuf::from(MetadataFileName::Mtree.as_ref()),
)]
fn package_input_fails_on_missing_metadata(
#[case] config: InputDirConfig,
#[case] expected: PathBuf,
) -> TestResult {
init_logger();
let temp_dir = TempDir::new()?;
let input_dir = InputDir::new(temp_dir.path().to_path_buf())?;
prepare_input_dir(&input_dir, &config)?;
if let Err(error) = PackageInput::try_from(input_dir) {
match error {
alpm_package::Error::Input(alpm_package::input::Error::FileIsMissing {
path,
input_dir: _,
}) => assert_eq!(path, expected),
_ => panic!("Did not return the correct error variant"),
}
} else {
panic!("Should have returned an error but succeeded");
}
Ok(())
}
#[rstest]
#[case::all_files(
InputDirConfig { build_info: true, data_files: true, mtree: true, package_info: true, scriptlet: true },
)]
#[case::no_scriptlet(
InputDirConfig { build_info: true, data_files: true, mtree: true, package_info: true, scriptlet: false },
)]
#[case::no_data_files_no_scriptlet(
InputDirConfig { build_info: true, data_files: false, mtree: true, package_info: true, scriptlet: false },
)]
fn test_package_input_methods(#[case] config: InputDirConfig) -> TestResult {
init_logger();
let temp_dir = TempDir::new()?;
let input_dir = InputDir::new(temp_dir.path().to_path_buf())?;
prepare_input_dir(&input_dir, &config)?;
let package_input: PackageInput = input_dir.try_into()?;
let _mtree = package_input.mtree()?;
let _build_info = package_input.build_info();
let _package_info = package_input.package_info();
if config.scriptlet {
assert!(package_input.install_scriptlet().is_some());
if !config.data_files {
assert!(package_input.relative_paths().len() == 4)
} else {
assert!(package_input.relative_paths().len() > 4)
}
} else {
assert!(package_input.install_scriptlet().is_none());
if !config.data_files {
assert!(package_input.relative_paths().len() == 3)
} else {
assert!(package_input.relative_paths().len() > 3)
}
}
Ok(())
}
#[test]
fn package_creation_config_new_fails() -> TestResult {
init_logger();
let config = InputDirConfig {
build_info: true,
data_files: false,
mtree: true,
package_info: true,
scriptlet: false,
};
let temp_dir = TempDir::new()?;
let path_equal = temp_dir.path().join("equal-input");
create_dir_all(&path_equal)?;
let input_dir = InputDir::new(path_equal)?;
prepare_input_dir(&input_dir, &config)?;
let package_input: PackageInput = input_dir.clone().try_into()?;
let output_dir = OutputDir::new(input_dir.to_path_buf())?;
match PackageCreationConfig::new(package_input.clone(), output_dir, CompressionSettings::None) {
Err(error) => assert!(matches!(
error,
alpm_package::Error::InputDirIsOutputDir { path: _ }
)),
Ok(_) => panic!("Succeeded, but should have failed"),
}
let output_dir = OutputDir::new(input_dir.join("output-in-input"))?;
match PackageCreationConfig::new(package_input.clone(), output_dir, CompressionSettings::None) {
Err(error) => assert!(matches!(
error,
alpm_package::Error::OutputDirInInputDir {
input_path: _,
output_path: _
}
)),
Ok(_) => panic!("Succeeded, but should have failed"),
}
let output_dir = OutputDir::new(temp_dir.path().to_path_buf())?;
match PackageCreationConfig::new(package_input, output_dir, CompressionSettings::None) {
Err(error) => assert!(matches!(
error,
alpm_package::Error::InputDirInOutputDir {
input_path: _,
output_path: _
}
)),
Ok(_) => panic!("Succeeded, but should have failed"),
}
Ok(())
}
fn create_package(
temp_dir: &TempDir,
config: &InputDirConfig,
compression: CompressionSettings,
) -> TestResult<Package> {
let input_dir_path = temp_dir.path().join("input");
let output_dir_path = temp_dir.path().join("output");
create_dir(&input_dir_path)?;
let input_dir = InputDir::new(input_dir_path)?;
prepare_input_dir(&input_dir, config)?;
let package_input: PackageInput = input_dir.try_into()?;
let output_dir = OutputDir::new(output_dir_path)?;
let config = PackageCreationConfig::new(package_input, output_dir, compression)?;
Ok(Package::try_from(&config)?)
}
#[rstest]
#[case::all_files_bzip2(
CompressionSettings::Bzip2 { compression_level: Default::default() },
InputDirConfig {
build_info: true,
data_files: true,
mtree: true,
package_info: true,
scriptlet: true,
}
)]
#[case::no_data_files_bzip2(
CompressionSettings::Bzip2 { compression_level: Default::default() },
InputDirConfig {
build_info: true,
data_files: false,
mtree: true,
package_info: true,
scriptlet: true,
}
)]
#[case::no_scriptlet_bzip2(
CompressionSettings::Bzip2 { compression_level: Default::default() },
InputDirConfig {
build_info: true,
data_files: true,
mtree: true,
package_info: true,
scriptlet: false,
}
)]
#[case::no_data_files_no_scriptlet_bzip2(
CompressionSettings::Bzip2 { compression_level: Default::default() },
InputDirConfig {
build_info: true,
data_files: false,
mtree: true,
package_info: true,
scriptlet: false,
}
)]
#[case::all_files_gzip(
CompressionSettings::Gzip { compression_level: Default::default() },
InputDirConfig {
build_info: true,
data_files: true,
mtree: true,
package_info: true,
scriptlet: true,
}
)]
#[case::no_data_files_gzip(
CompressionSettings::Gzip { compression_level: Default::default() },
InputDirConfig {
build_info: true,
data_files: false,
mtree: true,
package_info: true,
scriptlet: true,
}
)]
#[case::no_scriptlet_gzip(
CompressionSettings::Gzip { compression_level: Default::default() },
InputDirConfig {
build_info: true,
data_files: true,
mtree: true,
package_info: true,
scriptlet: false,
}
)]
#[case::no_data_files_no_scriptlet_gzip(
CompressionSettings::Gzip { compression_level: Default::default() },
InputDirConfig {
build_info: true,
data_files: false,
mtree: true,
package_info: true,
scriptlet: false,
}
)]
#[case::all_files_xz(
CompressionSettings::Xz { compression_level: Default::default() },
InputDirConfig {
build_info: true,
data_files: true,
mtree: true,
package_info: true,
scriptlet: true,
}
)]
#[case::no_data_files_xz(
CompressionSettings::Xz { compression_level: Default::default() },
InputDirConfig {
build_info: true,
data_files: false,
mtree: true,
package_info: true,
scriptlet: true,
}
)]
#[case::no_scriptlet_xz(
CompressionSettings::Xz { compression_level: Default::default() },
InputDirConfig {
build_info: true,
data_files: true,
mtree: true,
package_info: true,
scriptlet: false,
}
)]
#[case::no_data_files_no_scriptlet_xz(
CompressionSettings::Xz { compression_level: Default::default() },
InputDirConfig {
build_info: true,
data_files: false,
mtree: true,
package_info: true,
scriptlet: false,
}
)]
#[case::all_files_zstd(
CompressionSettings::Zstd {
compression_level: Default::default(),
threads: ZstdThreads::all(),
},
InputDirConfig {
build_info: true,
data_files: true,
mtree: true,
package_info: true,
scriptlet: true,
}
)]
#[case::no_data_files_zstd(
CompressionSettings::Zstd {
compression_level: Default::default(),
threads: ZstdThreads::all(),
},
InputDirConfig {
build_info: true,
data_files: false,
mtree: true,
package_info: true,
scriptlet: true,
}
)]
#[case::no_scriptlet_zstd(
CompressionSettings::Zstd {
compression_level: Default::default(),
threads: ZstdThreads::all(),
},
InputDirConfig {
build_info: true,
data_files: true,
mtree: true,
package_info: true,
scriptlet: false,
}
)]
#[case::no_data_files_no_scriptlet_zstd(
CompressionSettings::Zstd {
compression_level: Default::default(),
threads: ZstdThreads::all(),
},
InputDirConfig {
build_info: true,
data_files: false,
mtree: true,
package_info: true,
scriptlet: false,
}
)]
fn read_package_contents(
#[case] compression: CompressionSettings,
#[case] config_flags: InputDirConfig,
) -> TestResult {
use std::io::Read;
init_logger();
let temp_dir = TempDir::new()?;
let package = create_package(&temp_dir, &config_flags, compression)?;
let pkginfo = package.read_pkginfo()?;
let pkgname = match &pkginfo {
alpm_pkginfo::PackageInfo::V1(v) => &v.pkgname,
alpm_pkginfo::PackageInfo::V2(v) => &v.pkgname,
};
assert_eq!(pkgname.to_string(), "example");
let buildinfo = package.read_buildinfo()?;
let pkgbase = match &buildinfo {
alpm_buildinfo::BuildInfo::V1(v) => &v.pkgbase,
alpm_buildinfo::BuildInfo::V2(v) => &v.pkgbase,
};
assert_eq!(pkgbase.to_string(), "example");
let mtree = package.read_mtree()?;
let paths = match &mtree {
alpm_mtree::Mtree::V1(paths) | alpm_mtree::Mtree::V2(paths) => paths,
}
.iter()
.map(|p| p.to_path_buf())
.collect::<Vec<_>>();
assert!(paths.contains(&PathBuf::from("./.BUILDINFO")));
if config_flags.data_files {
assert!(paths.contains(&PathBuf::from("./foo/bar/baz/buh.txt")));
assert!(paths.contains(&PathBuf::from("./foo/bar/baz/beh.txt")));
}
let mut reader: PackageReader = package.clone().try_into()?;
let metadata = reader.metadata()?;
assert_eq!(buildinfo, metadata.buildinfo);
assert_eq!(pkginfo, metadata.pkginfo);
assert_eq!(mtree, metadata.mtree);
if config_flags.scriptlet {
let install_scriptlet = package.read_install_scriptlet()?;
assert_eq!(Some(VALID_INSTALL_SCRIPTLET), install_scriptlet.as_deref());
} else {
assert!(package.read_install_scriptlet()?.is_none());
}
if config_flags.data_files {
let mut reader: PackageReader = package.clone().try_into()?;
let data_files = reader.data_entries()?;
assert_eq!(
vec![
PathBuf::from(".ARBITRARY"),
PathBuf::from("foo/bar/baz/beh.txt"),
PathBuf::from("foo/bar/baz/buh.txt"),
PathBuf::from("foo/beh.txt"),
],
data_files
.flatten()
.filter(|entry| entry.is_file() || entry.is_symlink())
.map(|entry| entry.path().to_path_buf())
.collect::<Vec<_>>()
);
let mut reader: PackageReader = package.clone().try_into()?;
let data_files = reader.data_entries()?;
assert_eq!(
vec![
PathBuf::from("foo"),
PathBuf::from("foo/bar"),
PathBuf::from("foo/bar/baz"),
PathBuf::from("foo/bar/buh"),
],
data_files
.flatten()
.filter(|entry| entry.is_dir())
.map(|entry| entry.path().to_path_buf())
.collect::<Vec<_>>()
);
let mut reader: PackageReader = package.clone().try_into()?;
let mut entry = match reader.read_data_entry(".ARBITRARY")? {
Some(entry) => entry,
None => panic!("Expected .ARBITRARY entry, but found none"),
};
let content = entry.content()?;
let content = String::from_utf8(content)?;
assert_eq!("This is an arbitrary file.", content);
let mut reader: PackageReader = package.clone().try_into()?;
let mut entry = match reader.read_data_entry(".ARBITRARY")? {
Some(entry) => entry,
None => panic!("Expected .ARBITRARY entry, but found none"),
};
let mut buffer = vec![0; 4];
entry.read_exact(&mut buffer)?;
assert_eq!(b"This", buffer.as_slice());
assert!(format!("{entry:?}").contains(&entry.path().to_string_lossy().to_string()));
assert_eq!(0o644, entry.permissions()?);
assert_eq!(26, entry.raw().header().size()?);
assert_eq!(0o100644, entry.raw().header().mode()?);
assert_eq!(EntryType::Regular, entry.raw().header().entry_type());
} else {
let mut reader: PackageReader = package.clone().try_into()?;
assert_eq!(0, reader.data_entries()?.count());
}
let reader_debug = format!("{reader:?}");
assert!(reader_debug.contains("Archive<CompressionDecoder>"));
Ok(())
}
#[test]
fn package_metadata_iterator() -> TestResult {
init_logger();
let temp_dir = TempDir::new()?;
let package = create_package(
&temp_dir,
&InputDirConfig {
build_info: true,
data_files: true,
mtree: true,
package_info: true,
scriptlet: true,
},
CompressionSettings::Xz {
compression_level: Default::default(),
},
)?;
let mut reader: PackageReader = package.clone().try_into()?;
let mut metadata_entries = reader.metadata_entries()?;
assert!(matches!(
metadata_entries.next(),
Some(Ok(MetadataEntry::BuildInfo(_)))
));
assert!(matches!(
metadata_entries.next(),
Some(Ok(MetadataEntry::Mtree(_)))
));
assert!(matches!(
metadata_entries.next(),
Some(Ok(MetadataEntry::PackageInfo(_)))
));
assert!(metadata_entries.next().is_none());
let mut inner_iter = metadata_entries.into_inner().into_inner();
assert!(
inner_iter.next().is_some(),
"Expected the non-filtering iterator to still return a value."
);
Ok(())
}
fn assert_metadata_entry(entry: Option<Result<PackageEntry, Error>>) -> TestResult<MetadataEntry> {
assert!(
entry.is_some(),
"Expected package entry to be of some value."
);
match entry.unwrap()? {
PackageEntry::Metadata(entry) => Ok(*entry),
PackageEntry::InstallScriptlet(_) => {
panic!("Expected Metadata entry, got install scriptlet.")
}
}
}
#[test]
fn package_entry_iterator() -> TestResult {
init_logger();
let temp_dir = TempDir::new()?;
let package = create_package(
&temp_dir,
&InputDirConfig {
build_info: true,
data_files: true,
mtree: true,
package_info: true,
scriptlet: true,
},
CompressionSettings::Xz {
compression_level: Default::default(),
},
)?;
let mut reader: PackageReader = package.clone().try_into()?;
let mut entries = reader.entries()?;
assert!(matches!(
assert_metadata_entry(entries.next())?,
MetadataEntry::BuildInfo(_)
));
assert!(matches!(
entries.next(),
Some(Ok(PackageEntry::InstallScriptlet(_)))
));
assert!(matches!(
assert_metadata_entry(entries.next())?,
MetadataEntry::Mtree(_)
));
assert!(matches!(
assert_metadata_entry(entries.next())?,
MetadataEntry::PackageInfo(_)
));
assert!(entries.next().is_none());
let mut inner_iter = entries.into_inner();
assert!(
inner_iter.next().is_some(),
"Expected the non-filtering iterator to still return a value."
);
Ok(())
}
#[test]
fn package_entry_iterator_without_scriptlet() -> TestResult {
init_logger();
let temp_dir = TempDir::new()?;
let package = create_package(
&temp_dir,
&InputDirConfig {
build_info: true,
data_files: true,
mtree: true,
package_info: true,
scriptlet: false, },
CompressionSettings::Xz {
compression_level: Default::default(),
},
)?;
let mut reader: PackageReader = package.clone().try_into()?;
let mut entries = reader.entries()?;
assert!(matches!(
assert_metadata_entry(entries.next())?,
MetadataEntry::BuildInfo(_)
));
assert!(matches!(
assert_metadata_entry(entries.next())?,
MetadataEntry::Mtree(_)
));
assert!(matches!(
assert_metadata_entry(entries.next())?,
MetadataEntry::PackageInfo(_)
));
assert!(entries.next().is_none());
let mut inner_iter = entries.into_inner();
assert!(
inner_iter.next().is_some(),
"Expected the non-filtering iterator to still return a value."
);
Ok(())
}