#![allow(clippy::cast_possible_truncation)]
use super::*;
use crate::{
ConcreteVersion, Dependency, InvalidPackageName, PackageName, ParseResult, PublishTime,
RemovalStatus, VersionReq,
};
use std::any::Any;
use tower_lsp_server::ls_types::{CodeAction, CodeActionKind};
pub(crate) fn pkg(s: &str) -> PackageName {
PackageName::new(s)
}
pub(crate) struct MockFormatter;
impl PackageNaming for MockFormatter {}
impl PackageRendering for MockFormatter {
fn format_version_for_text_edit(&self, version: &ConcreteVersion) -> String {
format!("\"{}\"", version)
}
fn package_url(&self, name: &PackageName) -> String {
format!("https://example.com/{}", name)
}
}
impl RequirementResolution for MockFormatter {}
impl DiagnosticMessages for MockFormatter {}
impl DiagnosticPolicy for MockFormatter {}
impl SourcePolicy for MockFormatter {}
impl OsvNaming for MockFormatter {}
pub(crate) struct MockUnresolvedFormatter;
impl PackageNaming for MockUnresolvedFormatter {}
impl PackageRendering for MockUnresolvedFormatter {
fn format_version_for_text_edit(&self, version: &ConcreteVersion) -> String {
version.to_string()
}
fn package_url(&self, name: &PackageName) -> String {
format!("https://example.com/{}", name)
}
}
impl RequirementResolution for MockUnresolvedFormatter {
fn requirement_status(
&self,
_requirement: &VersionReq,
_latest: &ConcreteVersion,
) -> RequirementStatus {
RequirementStatus::Unresolved
}
}
impl DiagnosticMessages for MockUnresolvedFormatter {}
impl DiagnosticPolicy for MockUnresolvedFormatter {}
impl SourcePolicy for MockUnresolvedFormatter {}
impl OsvNaming for MockUnresolvedFormatter {}
pub(crate) struct MockGoFormatter;
impl PackageNaming for MockGoFormatter {}
impl PackageRendering for MockGoFormatter {
fn format_version_for_text_edit(&self, version: &ConcreteVersion) -> String {
version.to_string()
}
fn package_url(&self, name: &PackageName) -> String {
format!("https://pkg.go.dev/{}", name)
}
}
impl RequirementResolution for MockGoFormatter {
fn manifest_requirement_is_resolved_version(&self, _dep: &dyn Dependency) -> bool {
true
}
}
impl DiagnosticMessages for MockGoFormatter {}
impl DiagnosticPolicy for MockGoFormatter {}
impl SourcePolicy for MockGoFormatter {}
impl OsvNaming for MockGoFormatter {}
pub(crate) struct MockWidenedResolveFormatter;
impl PackageNaming for MockWidenedResolveFormatter {}
impl PackageRendering for MockWidenedResolveFormatter {
fn format_version_for_text_edit(&self, version: &ConcreteVersion) -> String {
version.to_string()
}
fn package_url(&self, name: &PackageName) -> String {
format!("https://example.com/{name}")
}
}
impl RequirementResolution for MockWidenedResolveFormatter {}
impl DiagnosticMessages for MockWidenedResolveFormatter {}
impl DiagnosticPolicy for MockWidenedResolveFormatter {}
impl SourcePolicy for MockWidenedResolveFormatter {
fn can_resolve_source(&self, source: &crate::parser::DependencySource) -> bool {
matches!(
source,
crate::parser::DependencySource::Registry
| crate::parser::DependencySource::AlternateRegistry { .. }
)
}
}
impl OsvNaming for MockWidenedResolveFormatter {}
pub(crate) struct RejectingFormatter;
impl PackageNaming for RejectingFormatter {
fn validate_package_name(&self, _name: &str) -> Result<(), InvalidPackageName> {
Err(InvalidPackageName::new("name is rejected for testing"))
}
}
impl PackageRendering for RejectingFormatter {
fn format_version_for_text_edit(&self, version: &ConcreteVersion) -> String {
version.to_string()
}
fn package_url(&self, name: &PackageName) -> String {
format!("https://example.com/{}", name)
}
}
impl RequirementResolution for RejectingFormatter {}
impl DiagnosticMessages for RejectingFormatter {}
impl DiagnosticPolicy for RejectingFormatter {}
impl SourcePolicy for RejectingFormatter {}
impl OsvNaming for RejectingFormatter {}
pub(crate) struct MockParseResult {
pub(crate) deps: Vec<MockDep>,
pub(crate) uri: Uri,
}
impl ParseResult for MockParseResult {
fn dependencies(&self) -> Vec<&dyn Dependency> {
self.deps.iter().map(|d| d as &dyn Dependency).collect()
}
fn workspace_root(&self) -> Option<&std::path::Path> {
None
}
fn uri(&self) -> &Uri {
&self.uri
}
fn as_any(&self) -> &dyn Any {
self
}
}
pub(crate) struct MockMixedParseResult {
pub(crate) deps: Vec<Box<dyn Dependency>>,
pub(crate) uri: Uri,
}
impl ParseResult for MockMixedParseResult {
fn dependencies(&self) -> Vec<&dyn Dependency> {
self.deps.iter().map(AsRef::as_ref).collect()
}
fn workspace_root(&self) -> Option<&std::path::Path> {
None
}
fn uri(&self) -> &Uri {
&self.uri
}
fn as_any(&self) -> &dyn Any {
self
}
}
pub(crate) struct MockDep {
pub(crate) name: PackageName,
pub(crate) version_req: VersionReq,
pub(crate) version_range: Range,
pub(crate) name_range: Range,
}
impl Dependency for MockDep {
fn name(&self) -> &PackageName {
&self.name
}
fn name_range(&self) -> Range {
self.name_range
}
fn version_requirement(&self) -> Option<&VersionReq> {
Some(&self.version_req)
}
fn version_range(&self) -> Option<Range> {
Some(self.version_range)
}
fn source(&self) -> crate::parser::DependencySource {
crate::parser::DependencySource::Registry
}
fn as_any(&self) -> &dyn Any {
self
}
}
pub(crate) struct MockSyntheticRangeDep {
pub(crate) name: PackageName,
}
impl Dependency for MockSyntheticRangeDep {
fn name(&self) -> &PackageName {
&self.name
}
fn name_range(&self) -> Range {
Range::default()
}
fn version_requirement(&self) -> Option<&VersionReq> {
None
}
fn version_range(&self) -> Option<Range> {
None
}
fn source(&self) -> crate::parser::DependencySource {
crate::parser::DependencySource::Registry
}
fn name_range_is_synthetic(&self) -> bool {
true
}
fn as_any(&self) -> &dyn Any {
self
}
}
pub(crate) struct MockMarkedDep {
pub(crate) name: PackageName,
pub(crate) name_range: Range,
pub(crate) markers: Option<String>,
}
impl Dependency for MockMarkedDep {
fn name(&self) -> &PackageName {
&self.name
}
fn name_range(&self) -> Range {
self.name_range
}
fn version_requirement(&self) -> Option<&VersionReq> {
None
}
fn version_range(&self) -> Option<Range> {
None
}
fn source(&self) -> crate::parser::DependencySource {
crate::parser::DependencySource::Registry
}
fn markers(&self) -> Option<&str> {
self.markers.as_deref()
}
fn as_any(&self) -> &dyn Any {
self
}
}
pub(crate) struct MockMarkedParseResult {
pub(crate) dep: MockMarkedDep,
pub(crate) uri: Uri,
}
impl ParseResult for MockMarkedParseResult {
fn dependencies(&self) -> Vec<&dyn Dependency> {
vec![&self.dep]
}
fn workspace_root(&self) -> Option<&std::path::Path> {
None
}
fn uri(&self) -> &Uri {
&self.uri
}
fn as_any(&self) -> &dyn Any {
self
}
}
pub(crate) struct MockRegistry;
impl crate::Registry for MockRegistry {
fn get_versions<'a>(
&'a self,
_name: &'a PackageName,
) -> crate::ecosystem::BoxFuture<'a, crate::error::Result<Vec<Box<dyn crate::Version>>>> {
Box::pin(async move { Ok(Vec::new()) })
}
fn get_latest_matching<'a>(
&'a self,
_name: &'a PackageName,
_req: &'a VersionReq,
) -> crate::ecosystem::BoxFuture<'a, crate::error::Result<Option<Box<dyn crate::Version>>>>
{
Box::pin(async move { Ok(None) })
}
fn search<'a>(
&'a self,
_query: &'a str,
_limit: usize,
) -> crate::ecosystem::BoxFuture<'a, crate::error::Result<Vec<Box<dyn crate::Metadata>>>> {
Box::pin(async move { Ok(Vec::new()) })
}
fn as_any(&self) -> &dyn Any {
self
}
}
pub(crate) struct ErrorRegistry;
impl crate::Registry for ErrorRegistry {
fn get_versions<'a>(
&'a self,
_name: &'a PackageName,
) -> crate::ecosystem::BoxFuture<'a, crate::error::Result<Vec<Box<dyn crate::Version>>>> {
Box::pin(async move {
Err(crate::error::DepsError::CacheError(
"mock registry error".to_string(),
))
})
}
fn get_latest_matching<'a>(
&'a self,
_name: &'a PackageName,
_req: &'a VersionReq,
) -> crate::ecosystem::BoxFuture<'a, crate::error::Result<Option<Box<dyn crate::Version>>>>
{
Box::pin(async move { Ok(None) })
}
fn search<'a>(
&'a self,
_query: &'a str,
_limit: usize,
) -> crate::ecosystem::BoxFuture<'a, crate::error::Result<Vec<Box<dyn crate::Metadata>>>> {
Box::pin(async move { Ok(Vec::new()) })
}
fn as_any(&self) -> &dyn Any {
self
}
}
pub(crate) struct NotFoundRegistry;
impl crate::Registry for NotFoundRegistry {
fn get_versions<'a>(
&'a self,
name: &'a PackageName,
) -> crate::ecosystem::BoxFuture<'a, crate::error::Result<Vec<Box<dyn crate::Version>>>> {
Box::pin(async move {
Err(crate::error::DepsError::PackageNotFound {
package: name.to_string(),
registry: "mock",
})
})
}
fn get_latest_matching<'a>(
&'a self,
_name: &'a PackageName,
_req: &'a VersionReq,
) -> crate::ecosystem::BoxFuture<'a, crate::error::Result<Option<Box<dyn crate::Version>>>>
{
Box::pin(async move { Ok(None) })
}
fn search<'a>(
&'a self,
_query: &'a str,
_limit: usize,
) -> crate::ecosystem::BoxFuture<'a, crate::error::Result<Vec<Box<dyn crate::Metadata>>>> {
Box::pin(async move { Ok(Vec::new()) })
}
fn as_any(&self) -> &dyn Any {
self
}
}
pub(crate) struct MockVersionWithAge {
pub(crate) version: ConcreteVersion,
pub(crate) yanked: bool,
pub(crate) published_at: Option<PublishTime>,
}
impl crate::Version for MockVersionWithAge {
fn version_string(&self) -> &ConcreteVersion {
&self.version
}
fn removal_status(&self) -> crate::RemovalStatus {
crate::RemovalStatus::from_yanked(self.yanked)
}
fn published_at(&self) -> Option<PublishTime> {
self.published_at
}
fn as_any(&self) -> &dyn Any {
self
}
}
pub(crate) struct TestVersion {
pub(crate) version: ConcreteVersion,
pub(crate) yanked: bool,
}
impl crate::Version for TestVersion {
fn version_string(&self) -> &ConcreteVersion {
&self.version
}
fn removal_status(&self) -> crate::RemovalStatus {
crate::RemovalStatus::from_yanked(self.yanked)
}
fn as_any(&self) -> &dyn Any {
self
}
}
pub(crate) struct MockRegistryWithVersions {
pub(crate) versions: Vec<MockVersionWithAge>,
}
impl crate::Registry for MockRegistryWithVersions {
fn get_versions<'a>(
&'a self,
_name: &'a crate::PackageName,
) -> crate::ecosystem::BoxFuture<'a, crate::error::Result<Vec<Box<dyn crate::Version>>>> {
let versions = self
.versions
.iter()
.map(|v| {
Box::new(MockVersionWithAge {
version: v.version.clone(),
yanked: v.yanked,
published_at: v.published_at,
}) as Box<dyn crate::Version>
})
.collect();
Box::pin(async move { Ok(versions) })
}
fn get_latest_matching<'a>(
&'a self,
_name: &'a crate::PackageName,
_req: &'a crate::VersionReq,
) -> crate::ecosystem::BoxFuture<'a, crate::error::Result<Option<Box<dyn crate::Version>>>>
{
Box::pin(async move { Ok(None) })
}
fn search<'a>(
&'a self,
_query: &'a str,
_limit: usize,
) -> crate::ecosystem::BoxFuture<'a, crate::error::Result<Vec<Box<dyn crate::Metadata>>>> {
Box::pin(async move { Ok(Vec::new()) })
}
fn select_latest_matching(
&self,
versions: &[Box<dyn crate::Version>],
_req: &crate::VersionReq,
) -> Option<usize> {
versions.iter().position(|v| v.is_stable())
}
fn as_any(&self) -> &dyn Any {
self
}
}
pub(crate) struct MockVersionWithLicense {
pub(crate) version: ConcreteVersion,
pub(crate) license: Vec<String>,
}
impl crate::Version for MockVersionWithLicense {
fn version_string(&self) -> &ConcreteVersion {
&self.version
}
fn license(&self) -> &[String] {
&self.license
}
fn as_any(&self) -> &dyn Any {
self
}
}
pub(crate) struct MockRegistryWithLicensedVersions {
pub(crate) versions: Vec<MockVersionWithLicense>,
}
impl crate::Registry for MockRegistryWithLicensedVersions {
fn get_versions<'a>(
&'a self,
_name: &'a crate::PackageName,
) -> crate::ecosystem::BoxFuture<'a, crate::error::Result<Vec<Box<dyn crate::Version>>>> {
let versions = self
.versions
.iter()
.map(|v| {
Box::new(MockVersionWithLicense {
version: v.version.clone(),
license: v.license.clone(),
}) as Box<dyn crate::Version>
})
.collect();
Box::pin(async move { Ok(versions) })
}
fn get_latest_matching<'a>(
&'a self,
_name: &'a crate::PackageName,
_req: &'a crate::VersionReq,
) -> crate::ecosystem::BoxFuture<'a, crate::error::Result<Option<Box<dyn crate::Version>>>>
{
Box::pin(async move { Ok(None) })
}
fn search<'a>(
&'a self,
_query: &'a str,
_limit: usize,
) -> crate::ecosystem::BoxFuture<'a, crate::error::Result<Vec<Box<dyn crate::Metadata>>>> {
Box::pin(async move { Ok(Vec::new()) })
}
fn select_latest_matching(
&self,
versions: &[Box<dyn crate::Version>],
_req: &crate::VersionReq,
) -> Option<usize> {
versions.iter().position(|v| v.is_stable())
}
fn as_any(&self) -> &dyn Any {
self
}
}
pub(crate) struct MockVersionWithStatus {
pub(crate) version: ConcreteVersion,
pub(crate) status: RemovalStatus,
}
impl crate::Version for MockVersionWithStatus {
fn version_string(&self) -> &ConcreteVersion {
&self.version
}
fn removal_status(&self) -> RemovalStatus {
self.status
}
fn as_any(&self) -> &dyn Any {
self
}
}
pub(crate) struct MockRegistryPreferringUnflagged {
pub(crate) versions: Vec<MockVersionWithStatus>,
}
impl crate::Registry for MockRegistryPreferringUnflagged {
fn get_versions<'a>(
&'a self,
_name: &'a crate::PackageName,
) -> crate::ecosystem::BoxFuture<'a, crate::error::Result<Vec<Box<dyn crate::Version>>>> {
let versions = self
.versions
.iter()
.map(|v| {
Box::new(MockVersionWithStatus {
version: v.version.clone(),
status: v.status,
}) as Box<dyn crate::Version>
})
.collect();
Box::pin(async move { Ok(versions) })
}
fn get_latest_matching<'a>(
&'a self,
_name: &'a crate::PackageName,
_req: &'a crate::VersionReq,
) -> crate::ecosystem::BoxFuture<'a, crate::error::Result<Option<Box<dyn crate::Version>>>>
{
Box::pin(async move { Ok(None) })
}
fn search<'a>(
&'a self,
_query: &'a str,
_limit: usize,
) -> crate::ecosystem::BoxFuture<'a, crate::error::Result<Vec<Box<dyn crate::Metadata>>>> {
Box::pin(async move { Ok(Vec::new()) })
}
fn select_latest_matching(
&self,
versions: &[Box<dyn crate::Version>],
_req: &crate::VersionReq,
) -> Option<usize> {
crate::select_latest_for_existence(versions, |v| v.as_ref())
}
fn as_any(&self) -> &dyn Any {
self
}
}
pub(crate) struct MockRegistryListFailsLatestFallbackSucceeds {
pub(crate) versions: Vec<MockVersionWithAge>,
pub(crate) fallback_latest: MockVersionWithAge,
pub(crate) list_pick_index: Option<usize>,
pub(crate) get_latest_matching_calls: std::sync::atomic::AtomicUsize,
}
impl crate::Registry for MockRegistryListFailsLatestFallbackSucceeds {
fn get_versions<'a>(
&'a self,
_name: &'a crate::PackageName,
) -> crate::ecosystem::BoxFuture<'a, crate::error::Result<Vec<Box<dyn crate::Version>>>> {
let versions = self
.versions
.iter()
.map(|v| {
Box::new(MockVersionWithAge {
version: v.version.clone(),
yanked: v.yanked,
published_at: v.published_at,
}) as Box<dyn crate::Version>
})
.collect();
Box::pin(async move { Ok(versions) })
}
fn get_latest_matching<'a>(
&'a self,
_name: &'a crate::PackageName,
_req: &'a crate::VersionReq,
) -> crate::ecosystem::BoxFuture<'a, crate::error::Result<Option<Box<dyn crate::Version>>>>
{
self.get_latest_matching_calls
.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
let fallback = MockVersionWithAge {
version: self.fallback_latest.version.clone(),
yanked: self.fallback_latest.yanked,
published_at: self.fallback_latest.published_at,
};
Box::pin(async move { Ok(Some(Box::new(fallback) as Box<dyn crate::Version>)) })
}
fn search<'a>(
&'a self,
_query: &'a str,
_limit: usize,
) -> crate::ecosystem::BoxFuture<'a, crate::error::Result<Vec<Box<dyn crate::Metadata>>>> {
Box::pin(async move { Ok(Vec::new()) })
}
fn select_latest_matching(
&self,
_versions: &[Box<dyn crate::Version>],
_req: &crate::VersionReq,
) -> Option<usize> {
self.list_pick_index
}
fn as_any(&self) -> &dyn Any {
self
}
}
pub(crate) struct FixedVersionRegistry {
pub(crate) versions: Vec<(&'static str, bool)>,
}
impl crate::Registry for FixedVersionRegistry {
fn get_versions<'a>(
&'a self,
_name: &'a PackageName,
) -> crate::ecosystem::BoxFuture<'a, crate::error::Result<Vec<Box<dyn crate::Version>>>> {
let versions: Vec<Box<dyn crate::Version>> = self
.versions
.iter()
.map(|(version, yanked)| {
Box::new(TestVersion {
version: (*version).into(),
yanked: *yanked,
}) as Box<dyn crate::Version>
})
.collect();
Box::pin(async move { Ok(versions) })
}
fn get_latest_matching<'a>(
&'a self,
_name: &'a PackageName,
_req: &'a VersionReq,
) -> crate::ecosystem::BoxFuture<'a, crate::error::Result<Option<Box<dyn crate::Version>>>>
{
Box::pin(async move { Ok(None) })
}
fn search<'a>(
&'a self,
_query: &'a str,
_limit: usize,
) -> crate::ecosystem::BoxFuture<'a, crate::error::Result<Vec<Box<dyn crate::Metadata>>>> {
Box::pin(async move { Ok(Vec::new()) })
}
fn select_latest_matching(
&self,
versions: &[Box<dyn crate::Version>],
_req: &VersionReq,
) -> Option<usize> {
crate::select_latest_for_existence(versions, |v| v.as_ref())
}
fn as_any(&self) -> &dyn Any {
self
}
}
pub(crate) fn freshness_test_parse_result(name: &str) -> MockParseResult {
MockParseResult {
deps: vec![MockDep {
name: name.into(),
version_req: "1.0.0".into(),
version_range: Range::new(Position::new(0, 10), Position::new(0, 20)),
name_range: Range::new(Position::new(0, 0), Position::new(0, name.len() as u32)),
}],
uri: crate::test_util::test_uri("/test/Cargo.toml"),
}
}
pub(crate) struct IdentityFormatter;
impl PackageNaming for IdentityFormatter {}
impl PackageRendering for IdentityFormatter {
fn format_version_for_text_edit(&self, version: &ConcreteVersion) -> String {
version.to_string()
}
fn package_url(&self, name: &PackageName) -> String {
format!("https://example.com/{name}")
}
}
impl RequirementResolution for IdentityFormatter {}
impl DiagnosticMessages for IdentityFormatter {}
impl DiagnosticPolicy for IdentityFormatter {}
impl SourcePolicy for IdentityFormatter {}
impl OsvNaming for IdentityFormatter {}
pub(crate) struct CaretWrappingFormatter;
impl PackageNaming for CaretWrappingFormatter {}
impl PackageRendering for CaretWrappingFormatter {
fn format_version_for_text_edit(&self, version: &ConcreteVersion) -> String {
format!("^{version}")
}
fn package_url(&self, name: &PackageName) -> String {
format!("https://example.com/{name}")
}
}
impl RequirementResolution for CaretWrappingFormatter {}
impl DiagnosticMessages for CaretWrappingFormatter {}
impl DiagnosticPolicy for CaretWrappingFormatter {}
impl SourcePolicy for CaretWrappingFormatter {}
impl OsvNaming for CaretWrappingFormatter {}
pub(crate) struct PinPreservingFormatter;
impl PackageNaming for PinPreservingFormatter {}
impl PackageRendering for PinPreservingFormatter {
fn format_version_for_text_edit(&self, version: &ConcreteVersion) -> String {
format!(">={version}")
}
fn format_version_replacing(&self, version: &ConcreteVersion, current: &str) -> String {
if current.starts_with("==") {
format!("=={version}")
} else {
self.format_version_for_text_edit(version)
}
}
fn package_url(&self, name: &PackageName) -> String {
format!("https://example.com/{name}")
}
}
impl RequirementResolution for PinPreservingFormatter {}
impl DiagnosticMessages for PinPreservingFormatter {}
impl DiagnosticPolicy for PinPreservingFormatter {}
impl SourcePolicy for PinPreservingFormatter {}
impl OsvNaming for PinPreservingFormatter {}
pub(crate) fn vulnerable_dep(
version_req: &str,
) -> (MockDep, tower_lsp_server::ls_types::Range, String) {
use tower_lsp_server::ls_types::{Position, Range};
let content = format!("pkg = \"{version_req}\"");
let start = 7u32; let end = start + version_req.chars().count() as u32;
let version_range = Range::new(Position::new(0, start), Position::new(0, end));
(
MockDep {
name: pkg("pkg"),
version_req: VersionReq::new(version_req),
version_range,
name_range: Range::new(Position::new(0, 0), Position::new(0, 3)),
},
version_range,
content,
)
}
pub(crate) fn quickfix_titles(actions: &[CodeAction]) -> Vec<&str> {
actions
.iter()
.filter(|a| a.kind == Some(CodeActionKind::QUICKFIX))
.map(|a| a.title.as_str())
.collect()
}
pub(crate) fn refactor_titles(actions: &[CodeAction]) -> Vec<&str> {
actions
.iter()
.filter(|a| a.kind == Some(CodeActionKind::REFACTOR))
.map(|a| a.title.as_str())
.collect()
}
pub(crate) struct TrailingSpaceFormatter;
impl PackageNaming for TrailingSpaceFormatter {}
impl PackageRendering for TrailingSpaceFormatter {
fn format_version_for_text_edit(&self, version: &ConcreteVersion) -> String {
format!("{version} ")
}
fn package_url(&self, name: &PackageName) -> String {
format!("https://example.com/{name}")
}
}
impl RequirementResolution for TrailingSpaceFormatter {}
impl DiagnosticMessages for TrailingSpaceFormatter {}
impl DiagnosticPolicy for TrailingSpaceFormatter {}
impl SourcePolicy for TrailingSpaceFormatter {}
impl OsvNaming for TrailingSpaceFormatter {}
pub(crate) struct TruncatingFormatter;
impl PackageNaming for TruncatingFormatter {}
impl PackageRendering for TruncatingFormatter {
fn format_version_for_text_edit(&self, version: &ConcreteVersion) -> String {
version.to_string()
}
fn format_version_replacing(&self, version: &ConcreteVersion, _current: &str) -> String {
let mut parts = version.as_str().split('.');
let major = parts.next().unwrap_or("0");
let minor = parts.next().unwrap_or("0");
format!("=={major}.{minor}")
}
fn package_url(&self, name: &PackageName) -> String {
format!("https://example.com/{name}")
}
}
impl RequirementResolution for TruncatingFormatter {}
impl DiagnosticMessages for TruncatingFormatter {}
impl DiagnosticPolicy for TruncatingFormatter {}
impl SourcePolicy for TruncatingFormatter {}
impl OsvNaming for TruncatingFormatter {}
pub(crate) fn sample_advisory(
id: &str,
severity: crate::osv::VulnSeverity,
) -> std::sync::Arc<crate::osv::Advisory> {
std::sync::Arc::new(crate::osv::Advisory {
id: id.to_string(),
modified: "2023-01-01T00:00:00Z".to_string(),
summary: Some("Something went wrong".to_string()),
aliases: vec!["CVE-2020-0001".to_string()],
severity,
cvss_vector: None,
fixed_versions: vec!["1.2.0".to_string(), "1.5.0".to_string()],
url: format!("https://osv.dev/vulnerability/{id}"),
})
}
pub(crate) fn dep_at(name: &str) -> MockDep {
MockDep {
name: PackageName::new(name),
version_req: VersionReq::new("1.0.0"),
version_range: Range::new(Position::new(0, 10), Position::new(0, 20)),
name_range: Range::new(Position::new(0, 0), Position::new(0, name.len() as u32)),
}
}
pub(crate) struct NonRegistryDep(
pub(crate) MockDep,
pub(crate) crate::parser::DependencySource,
);
impl Dependency for NonRegistryDep {
fn name(&self) -> &PackageName {
self.0.name()
}
fn name_range(&self) -> Range {
self.0.name_range()
}
fn version_requirement(&self) -> Option<&VersionReq> {
self.0.version_requirement()
}
fn version_range(&self) -> Option<Range> {
self.0.version_range()
}
fn source(&self) -> crate::parser::DependencySource {
self.1.clone()
}
fn as_any(&self) -> &dyn Any {
self
}
}
pub(crate) struct SingleDepParseResult<D> {
pub(crate) dep: D,
pub(crate) uri: Uri,
}
impl<D: Dependency + 'static> ParseResult for SingleDepParseResult<D> {
fn dependencies(&self) -> Vec<&dyn Dependency> {
vec![&self.dep]
}
fn workspace_root(&self) -> Option<&std::path::Path> {
None
}
fn uri(&self) -> &Uri {
&self.uri
}
fn as_any(&self) -> &dyn Any {
self
}
}
pub(crate) struct ExactMatchFormatter;
pub(crate) struct ExactMatcher(pub(crate) String);
impl RequirementMatcher for ExactMatcher {
fn matches(&self, version: &ConcreteVersion) -> Option<bool> {
Some(version.as_str() == self.0)
}
}
impl PackageNaming for ExactMatchFormatter {}
impl PackageRendering for ExactMatchFormatter {
fn format_version_for_text_edit(&self, version: &ConcreteVersion) -> String {
version.to_string()
}
fn package_url(&self, name: &PackageName) -> String {
format!("https://example.com/{}", name)
}
}
impl RequirementResolution for ExactMatchFormatter {
fn compile_requirement(&self, requirement: &VersionReq) -> Option<Box<dyn RequirementMatcher>> {
Some(Box::new(ExactMatcher(requirement.as_str().to_string())))
}
}
impl DiagnosticMessages for ExactMatchFormatter {}
impl DiagnosticPolicy for ExactMatchFormatter {}
impl SourcePolicy for ExactMatchFormatter {}
impl OsvNaming for ExactMatchFormatter {}
pub(crate) struct RealSemverMatcher(pub(crate) semver::VersionReq);
impl RequirementMatcher for RealSemverMatcher {
fn matches(&self, version: &ConcreteVersion) -> Option<bool> {
version
.as_str()
.parse::<semver::Version>()
.ok()
.map(|v| self.0.matches(&v))
}
}
pub(crate) struct StrictSemverFormatter;
impl PackageNaming for StrictSemverFormatter {}
impl PackageRendering for StrictSemverFormatter {
fn format_version_for_text_edit(&self, version: &ConcreteVersion) -> String {
version.to_string()
}
fn package_url(&self, name: &PackageName) -> String {
name.to_string()
}
}
impl RequirementResolution for StrictSemverFormatter {
fn compile_requirement(&self, requirement: &VersionReq) -> Option<Box<dyn RequirementMatcher>> {
requirement
.as_str()
.parse::<semver::VersionReq>()
.ok()
.map(|req| Box::new(RealSemverMatcher(req)) as Box<dyn RequirementMatcher>)
}
}
impl DiagnosticMessages for StrictSemverFormatter {}
impl DiagnosticPolicy for StrictSemverFormatter {
fn strict_semver_prerelease_exclusion(&self) -> bool {
true
}
}
impl SourcePolicy for StrictSemverFormatter {}
impl OsvNaming for StrictSemverFormatter {}