use std::rc::Rc;
use pretty_assertions::assert_eq;
use embed_licensing::{collect_from_manifest, CollectConfig, Crate, CrateLicense, Licensing};
mod common;
use common::*;
fn fixture_direct_dependencies() -> Result<TestPackage> {
let dependency = Rc::new(TestPackage::new(SimpleManifest {
name: "dependency".to_string(),
version: "1.0.0".to_string(),
license: Some(spdx::Expression::parse("MIT")?),
license_file: None,
authors: vec!["Jane Person <jane.person@example.com>".to_string()],
repository: Some("https://example.com/dependency.git".to_string()),
dependencies: vec![].into(),
dev_dependencies: vec![].into(),
build_dependencies: vec![].into(),
})?);
let dev_dependency = Rc::new(TestPackage::new(SimpleManifest {
name: "dev_dependency".to_string(),
version: "2.0.0".to_string(),
license: Some(spdx::Expression::parse("Apache-2.0")?),
license_file: None,
authors: vec!["Jude Person <jude.person@example.com>".to_string()],
repository: Some("https://example.com/dev_dependency.git".to_string()),
dependencies: vec![].into(),
dev_dependencies: vec![].into(),
build_dependencies: vec![].into(),
})?);
let build_dependency = Rc::new(TestPackage::new(SimpleManifest {
name: "build_dependency".to_string(),
version: "3.0.0".to_string(),
license: Some(spdx::Expression::parse("LGPL-2.1-or-later")?),
license_file: None,
authors: vec!["John Person <john.person@example.com>".to_string()],
repository: Some("https://example.com/build_dependency.git".to_string()),
dependencies: vec![].into(),
dev_dependencies: vec![].into(),
build_dependencies: vec![].into(),
})?);
TestPackage::new(SimpleManifest {
name: "foo".to_string(),
version: "0.1.0".to_string(),
license: Some(spdx::Expression::parse("GPL-3.0-or-later")?),
license_file: None,
authors: vec!["Jane Person <jane.person@example.com>".to_string()],
repository: Some("https://example.com/foo.git".to_string()),
dependencies: vec![(None, dependency)].into(),
dev_dependencies: vec![(None, dev_dependency)].into(),
build_dependencies: vec![(None, build_dependency)].into(),
})
}
fn fixture_transitive_dependencies() -> Result<TestPackage> {
let transitive_dependency = Rc::new(TestPackage::new(SimpleManifest {
name: "transitive_dependency".to_string(),
version: "2.0.0".to_string(),
license: Some(spdx::Expression::parse("ISC")?),
license_file: None,
authors: vec!["Jude Person <jude.person@example.com>".to_string()],
repository: Some("https://example.com/transitive_dependency.git".to_string()),
dependencies: vec![].into(),
dev_dependencies: vec![].into(),
build_dependencies: vec![].into(),
})?);
let transitive_dev_dependency = Rc::new(TestPackage::new(SimpleManifest {
name: "transitive_dev_dependency".to_string(),
version: "3.0.0".to_string(),
license: Some(spdx::Expression::parse("MIT")?),
license_file: None,
authors: vec!["Jennifer Person <jennifer.person@example.com>".to_string()],
repository: Some("https://example.com/transitive_dev_dependency.git".to_string()),
dependencies: vec![].into(),
dev_dependencies: vec![].into(),
build_dependencies: vec![].into(),
})?);
let transitive_build_dependency = Rc::new(TestPackage::new(SimpleManifest {
name: "transitive_build_dependency".to_string(),
version: "4.0.0".to_string(),
license: Some(spdx::Expression::parse("Apache-2.0")?),
license_file: None,
authors: vec!["Jasmine Person <jasmine.person@example.com>".to_string()],
repository: Some("https://example.com/transitive_build_dependency.git".to_string()),
dependencies: vec![].into(),
dev_dependencies: vec![].into(),
build_dependencies: vec![].into(),
})?);
let dependency = Rc::new(TestPackage::new(SimpleManifest {
name: "dependency".to_string(),
version: "1.0.0".to_string(),
license: Some(spdx::Expression::parse("MPL-2.0")?),
license_file: None,
authors: vec!["Jane Person <jane.person@example.com>".to_string()],
repository: Some("https://example.com/dependency.git".to_string()),
dependencies: vec![(None, transitive_dependency)].into(),
dev_dependencies: vec![(None, transitive_dev_dependency)].into(),
build_dependencies: vec![(None, transitive_build_dependency)].into(),
})?);
TestPackage::new(SimpleManifest {
name: "foo".to_string(),
version: "0.1.0".to_string(),
license: Some(spdx::Expression::parse("AGPL-3.0-or-later")?),
license_file: None,
authors: vec!["Jane Person <jane.person@example.com>".to_string()],
repository: Some("https://example.com/foo.git".to_string()),
dependencies: vec![(None, dependency)].into(),
dev_dependencies: vec![].into(),
build_dependencies: vec![].into(),
})
}
#[test]
fn no_dependencies() -> Result<()> {
let pkg = TestPackage::new(SimpleManifest {
name: "foo".to_string(),
version: "1.0.0".to_string(),
license: Some(spdx::Expression::parse("Apache-2.0 OR MIT")?),
license_file: None,
authors: vec!["Jane Person <jane.person@example.com>".to_string()],
repository: Some("https://example.com/foo.git".to_string()),
dependencies: vec![].into(),
dev_dependencies: vec![].into(),
build_dependencies: vec![].into(),
})?;
assert_eq!(
collect_from_manifest(pkg.manifest_path(), CollectConfig::default())?,
Licensing {
packages: vec![Crate {
name: "foo".to_string(),
version: "1.0.0".to_string(),
authors: vec!["Jane Person <jane.person@example.com>".to_string()],
license: CrateLicense::SpdxExpression(spdx::Expression::parse(
"Apache-2.0 OR MIT"
)?),
website: "https://example.com/foo.git".to_string()
}],
licenses: vec!["Apache-2.0", "MIT"]
.into_iter()
.map(spdx::license_id)
.map(Option::unwrap)
.collect(),
exceptions: vec![],
}
);
Ok(())
}
#[test]
fn direct_dependencies() -> Result<()> {
let pkg = fixture_direct_dependencies()?;
assert_eq!(
collect_from_manifest(
pkg.manifest_path(),
CollectConfig {
dev: true,
build: true,
..Default::default()
}
)?,
Licensing {
packages: vec![
Crate {
name: "build_dependency".to_string(),
version: "3.0.0".to_string(),
authors: vec!["John Person <john.person@example.com>".to_string()],
license: CrateLicense::SpdxExpression(spdx::Expression::parse(
"LGPL-2.1-or-later"
)?),
website: "https://example.com/build_dependency.git".to_string()
},
Crate {
name: "dependency".to_string(),
version: "1.0.0".to_string(),
authors: vec!["Jane Person <jane.person@example.com>".to_string()],
license: CrateLicense::SpdxExpression(spdx::Expression::parse("MIT")?),
website: "https://example.com/dependency.git".to_string()
},
Crate {
name: "dev_dependency".to_string(),
version: "2.0.0".to_string(),
authors: vec!["Jude Person <jude.person@example.com>".to_string()],
license: CrateLicense::SpdxExpression(spdx::Expression::parse("Apache-2.0")?),
website: "https://example.com/dev_dependency.git".to_string()
},
Crate {
name: "foo".to_string(),
version: "0.1.0".to_string(),
authors: vec!["Jane Person <jane.person@example.com>".to_string()],
license: CrateLicense::SpdxExpression(spdx::Expression::parse(
"GPL-3.0-or-later"
)?),
website: "https://example.com/foo.git".to_string()
},
],
licenses: vec!["Apache-2.0", "GPL-3.0", "LGPL-2.1", "MIT"]
.into_iter()
.map(spdx::license_id)
.map(Option::unwrap)
.collect(),
exceptions: vec![],
}
);
Ok(())
}
#[test]
fn direct_dependencies_no_dev() -> Result<()> {
let pkg = fixture_direct_dependencies()?;
assert_eq!(
collect_from_manifest(
pkg.manifest_path(),
CollectConfig {
dev: false,
build: true,
..Default::default()
}
)?,
Licensing {
packages: vec![
Crate {
name: "build_dependency".to_string(),
version: "3.0.0".to_string(),
authors: vec!["John Person <john.person@example.com>".to_string()],
license: CrateLicense::SpdxExpression(spdx::Expression::parse(
"LGPL-2.1-or-later"
)?),
website: "https://example.com/build_dependency.git".to_string()
},
Crate {
name: "dependency".to_string(),
version: "1.0.0".to_string(),
authors: vec!["Jane Person <jane.person@example.com>".to_string()],
license: CrateLicense::SpdxExpression(spdx::Expression::parse("MIT")?),
website: "https://example.com/dependency.git".to_string()
},
Crate {
name: "foo".to_string(),
version: "0.1.0".to_string(),
authors: vec!["Jane Person <jane.person@example.com>".to_string()],
license: CrateLicense::SpdxExpression(spdx::Expression::parse(
"GPL-3.0-or-later"
)?),
website: "https://example.com/foo.git".to_string()
},
],
licenses: vec!["GPL-3.0", "LGPL-2.1", "MIT"]
.into_iter()
.map(spdx::license_id)
.map(Option::unwrap)
.collect(),
exceptions: vec![],
}
);
Ok(())
}
#[test]
fn direct_dependencies_no_build() -> Result<()> {
let pkg = fixture_direct_dependencies()?;
assert_eq!(
collect_from_manifest(
pkg.manifest_path(),
CollectConfig {
dev: true,
build: false,
..Default::default()
}
)?,
Licensing {
packages: vec![
Crate {
name: "dependency".to_string(),
version: "1.0.0".to_string(),
authors: vec!["Jane Person <jane.person@example.com>".to_string()],
license: CrateLicense::SpdxExpression(spdx::Expression::parse("MIT")?),
website: "https://example.com/dependency.git".to_string()
},
Crate {
name: "dev_dependency".to_string(),
version: "2.0.0".to_string(),
authors: vec!["Jude Person <jude.person@example.com>".to_string()],
license: CrateLicense::SpdxExpression(spdx::Expression::parse("Apache-2.0")?),
website: "https://example.com/dev_dependency.git".to_string()
},
Crate {
name: "foo".to_string(),
version: "0.1.0".to_string(),
authors: vec!["Jane Person <jane.person@example.com>".to_string()],
license: CrateLicense::SpdxExpression(spdx::Expression::parse(
"GPL-3.0-or-later"
)?),
website: "https://example.com/foo.git".to_string()
},
],
licenses: vec!["Apache-2.0", "GPL-3.0", "MIT"]
.into_iter()
.map(spdx::license_id)
.map(Option::unwrap)
.collect(),
exceptions: vec![],
}
);
Ok(())
}
#[test]
fn direct_dependencies_no_dev_no_build() -> Result<()> {
let pkg = fixture_direct_dependencies()?;
assert_eq!(
collect_from_manifest(
pkg.manifest_path(),
CollectConfig {
dev: false,
build: false,
..Default::default()
}
)?,
Licensing {
packages: vec![
Crate {
name: "dependency".to_string(),
version: "1.0.0".to_string(),
authors: vec!["Jane Person <jane.person@example.com>".to_string()],
license: CrateLicense::SpdxExpression(spdx::Expression::parse("MIT")?),
website: "https://example.com/dependency.git".to_string()
},
Crate {
name: "foo".to_string(),
version: "0.1.0".to_string(),
authors: vec!["Jane Person <jane.person@example.com>".to_string()],
license: CrateLicense::SpdxExpression(spdx::Expression::parse(
"GPL-3.0-or-later"
)?),
website: "https://example.com/foo.git".to_string()
},
],
licenses: vec!["GPL-3.0", "MIT"]
.into_iter()
.map(spdx::license_id)
.map(Option::unwrap)
.collect(),
exceptions: vec![],
}
);
Ok(())
}
#[test]
fn transitive_dependencies() -> Result<()> {
let pkg = fixture_transitive_dependencies()?;
let expected = Licensing {
packages: vec![
Crate {
name: "dependency".to_string(),
version: "1.0.0".to_string(),
authors: vec!["Jane Person <jane.person@example.com>".to_string()],
license: CrateLicense::SpdxExpression(spdx::Expression::parse("MPL-2.0")?),
website: "https://example.com/dependency.git".to_string(),
},
Crate {
name: "foo".to_string(),
version: "0.1.0".to_string(),
authors: vec!["Jane Person <jane.person@example.com>".to_string()],
license: CrateLicense::SpdxExpression(spdx::Expression::parse(
"AGPL-3.0-or-later",
)?),
website: "https://example.com/foo.git".to_string(),
},
Crate {
name: "transitive_build_dependency".to_string(),
version: "4.0.0".to_string(),
authors: vec!["Jasmine Person <jasmine.person@example.com>".to_string()],
license: CrateLicense::SpdxExpression(spdx::Expression::parse("Apache-2.0")?),
website: "https://example.com/transitive_build_dependency.git".to_string(),
},
Crate {
name: "transitive_dependency".to_string(),
version: "2.0.0".to_string(),
authors: vec!["Jude Person <jude.person@example.com>".to_string()],
license: CrateLicense::SpdxExpression(spdx::Expression::parse("ISC")?),
website: "https://example.com/transitive_dependency.git".to_string(),
},
],
licenses: vec!["AGPL-3.0", "Apache-2.0", "ISC", "MPL-2.0"]
.into_iter()
.map(spdx::license_id)
.map(Option::unwrap)
.collect(),
exceptions: vec![],
};
assert_eq!(
collect_from_manifest(
pkg.manifest_path(),
CollectConfig {
dev: true,
build: true,
..Default::default()
}
)?,
expected
);
assert_eq!(
collect_from_manifest(
pkg.manifest_path(),
CollectConfig {
dev: false,
build: true,
..Default::default()
}
)?,
expected
);
Ok(())
}
#[test]
fn transitive_dependencies_no_build() -> Result<()> {
let pkg = fixture_transitive_dependencies()?;
let expected = Licensing {
packages: vec![
Crate {
name: "dependency".to_string(),
version: "1.0.0".to_string(),
authors: vec!["Jane Person <jane.person@example.com>".to_string()],
license: CrateLicense::SpdxExpression(spdx::Expression::parse("MPL-2.0")?),
website: "https://example.com/dependency.git".to_string(),
},
Crate {
name: "foo".to_string(),
version: "0.1.0".to_string(),
authors: vec!["Jane Person <jane.person@example.com>".to_string()],
license: CrateLicense::SpdxExpression(spdx::Expression::parse(
"AGPL-3.0-or-later",
)?),
website: "https://example.com/foo.git".to_string(),
},
Crate {
name: "transitive_dependency".to_string(),
version: "2.0.0".to_string(),
authors: vec!["Jude Person <jude.person@example.com>".to_string()],
license: CrateLicense::SpdxExpression(spdx::Expression::parse("ISC")?),
website: "https://example.com/transitive_dependency.git".to_string(),
},
],
licenses: vec!["AGPL-3.0", "ISC", "MPL-2.0"]
.into_iter()
.map(spdx::license_id)
.map(Option::unwrap)
.collect(),
exceptions: vec![],
};
assert_eq!(
collect_from_manifest(
pkg.manifest_path(),
CollectConfig {
dev: true,
build: false,
..Default::default()
}
)?,
expected
);
assert_eq!(
collect_from_manifest(
pkg.manifest_path(),
CollectConfig {
dev: false,
build: false,
..Default::default()
}
)?,
expected
);
Ok(())
}
#[test]
fn license_file() -> Result<()> {
let pkg = TestPackage::new(SimpleManifest {
name: "foo".to_string(),
version: "1.0.0".to_string(),
license: None,
license_file: Some((
"LICENSE".into(),
"This software is available under the MY SPECIAL CUSTOM license.".to_string(),
)),
authors: vec!["Jane Person <jane.person@example.com>".to_string()],
repository: Some("https://example.com/foo.git".to_string()),
dependencies: vec![].into(),
dev_dependencies: vec![].into(),
build_dependencies: vec![].into(),
})?;
assert_eq!(
collect_from_manifest(pkg.manifest_path(), CollectConfig::default())?,
Licensing {
packages: vec![Crate {
name: "foo".to_string(),
version: "1.0.0".to_string(),
authors: vec!["Jane Person <jane.person@example.com>".to_string()],
license: CrateLicense::Other(
"This software is available under the MY SPECIAL CUSTOM license.".to_string()
),
website: "https://example.com/foo.git".to_string()
}],
licenses: vec![],
exceptions: vec![],
}
);
Ok(())
}
#[test]
fn exceptions() -> Result<()> {
let pkg = TestPackage::new(SimpleManifest {
name: "foo".to_string(),
version: "1.0.0".to_string(),
license: Some(spdx::Expression::parse("Apache-2.0 WITH LLVM-exception")?),
license_file: None,
authors: vec!["Jane Person <jane.person@example.com>".to_string()],
repository: Some("https://example.com/foo.git".to_string()),
dependencies: vec![].into(),
dev_dependencies: vec![].into(),
build_dependencies: vec![].into(),
})?;
assert_eq!(
collect_from_manifest(pkg.manifest_path(), CollectConfig::default())?,
Licensing {
packages: vec![Crate {
name: "foo".to_string(),
version: "1.0.0".to_string(),
authors: vec!["Jane Person <jane.person@example.com>".to_string()],
license: CrateLicense::SpdxExpression(spdx::Expression::parse(
"Apache-2.0 WITH LLVM-exception"
)?),
website: "https://example.com/foo.git".to_string()
}],
licenses: vec![spdx::license_id("Apache-2.0").unwrap()],
exceptions: vec![spdx::exception_id("LLVM-exception").unwrap()],
}
);
Ok(())
}
#[test]
fn error_no_license() -> Result<()> {
let pkg = TestPackage::new(SimpleManifest {
name: "foo_no_license".to_string(),
version: "1.0.0".to_string(),
license: None,
license_file: None,
authors: vec![],
repository: Some("https://example.com/foo.git".to_string()),
dependencies: vec![].into(),
dev_dependencies: vec![].into(),
build_dependencies: vec![].into(),
})?;
match collect_from_manifest(pkg.manifest_path(), CollectConfig::default()).unwrap_err() {
embed_licensing::Error::NoLicense(name) => assert_eq!(name, "foo_no_license"),
_ => panic!("invalid error"),
}
Ok(())
}
#[test]
fn error_non_spdx_license() -> Result<()> {
let pkg = TestPackage::new(SimpleManifest {
name: "foo_non_spdx_license".to_string(),
version: "1.0.0".to_string(),
license: Some(spdx::Expression::parse(
"AGPL-3.0-or-later OR LicenseRef-Mycompany-Commercial-License",
)?),
license_file: None,
authors: vec![],
repository: Some("https://example.com/foo.git".to_string()),
dependencies: vec![].into(),
dev_dependencies: vec![].into(),
build_dependencies: vec![].into(),
})?;
match collect_from_manifest(pkg.manifest_path(), CollectConfig::default()).unwrap_err() {
embed_licensing::Error::NonSpdxLicense(name) => assert_eq!(name, "foo_non_spdx_license"),
_ => panic!("invalid error"),
}
Ok(())
}
#[test]
fn error_no_website() -> Result<()> {
let pkg = TestPackage::new(SimpleManifest {
name: "foo_no_website".to_string(),
version: "1.0.0".to_string(),
license: Some(spdx::Expression::parse("MIT")?),
license_file: None,
authors: vec![],
repository: None,
dependencies: vec![].into(),
dev_dependencies: vec![].into(),
build_dependencies: vec![].into(),
})?;
match collect_from_manifest(pkg.manifest_path(), CollectConfig::default()).unwrap_err() {
embed_licensing::Error::NoWebsite(name) => assert_eq!(name, "foo_no_website"),
_ => panic!("invalid error"),
}
Ok(())
}