use perl_diagnostics::codes::{
DiagnosticCategory, DiagnosticCode, DiagnosticSeverity, DiagnosticTag,
};
#[test]
fn as_str_missing_pod_coverage_is_pl304() -> Result<(), Box<dyn std::error::Error>> {
assert_eq!(DiagnosticCode::MissingPodCoverage.as_str(), "PL304");
Ok(())
}
#[test]
fn as_str_unreachable_code_is_pl406() -> Result<(), Box<dyn std::error::Error>> {
assert_eq!(DiagnosticCode::UnreachableCode.as_str(), "PL406");
Ok(())
}
#[test]
fn as_str_security_system_call_is_pl603() -> Result<(), Box<dyn std::error::Error>> {
assert_eq!(DiagnosticCode::SecuritySystemCall.as_str(), "PL603");
Ok(())
}
#[test]
fn as_str_security_exec_call_is_pl604() -> Result<(), Box<dyn std::error::Error>> {
assert_eq!(DiagnosticCode::SecurityExecCall.as_str(), "PL604");
Ok(())
}
#[test]
fn as_str_security_pipe_open_is_pl605() -> Result<(), Box<dyn std::error::Error>> {
assert_eq!(DiagnosticCode::SecurityPipeOpen.as_str(), "PL605");
Ok(())
}
#[test]
fn as_str_security_readpipe_is_pl606() -> Result<(), Box<dyn std::error::Error>> {
assert_eq!(DiagnosticCode::SecurityReadpipe.as_str(), "PL606");
Ok(())
}
#[test]
fn as_str_version_incompat_feature_is_pl900() -> Result<(), Box<dyn std::error::Error>> {
assert_eq!(DiagnosticCode::VersionIncompatFeature.as_str(), "PL900");
Ok(())
}
#[test]
fn documentation_url_security_system_call() -> Result<(), Box<dyn std::error::Error>> {
let url = DiagnosticCode::SecuritySystemCall.documentation_url();
assert_eq!(url, Some("https://docs.perl-lsp.org/errors/PL603"));
Ok(())
}
#[test]
fn documentation_url_security_exec_call() -> Result<(), Box<dyn std::error::Error>> {
let url = DiagnosticCode::SecurityExecCall.documentation_url();
assert_eq!(url, Some("https://docs.perl-lsp.org/errors/PL604"));
Ok(())
}
#[test]
fn documentation_url_security_pipe_open() -> Result<(), Box<dyn std::error::Error>> {
let url = DiagnosticCode::SecurityPipeOpen.documentation_url();
assert_eq!(url, Some("https://docs.perl-lsp.org/errors/PL605"));
Ok(())
}
#[test]
fn documentation_url_security_readpipe() -> Result<(), Box<dyn std::error::Error>> {
let url = DiagnosticCode::SecurityReadpipe.documentation_url();
assert_eq!(url, Some("https://docs.perl-lsp.org/errors/PL606"));
Ok(())
}
#[test]
fn documentation_url_unused_import() -> Result<(), Box<dyn std::error::Error>> {
let url = DiagnosticCode::UnusedImport.documentation_url();
assert_eq!(url, Some("https://docs.perl-lsp.org/errors/PL700"));
Ok(())
}
#[test]
fn documentation_url_module_not_found() -> Result<(), Box<dyn std::error::Error>> {
let url = DiagnosticCode::ModuleNotFound.documentation_url();
assert_eq!(url, Some("https://docs.perl-lsp.org/errors/PL701"));
Ok(())
}
#[test]
fn documentation_url_heredoc_in_format() -> Result<(), Box<dyn std::error::Error>> {
let url = DiagnosticCode::HeredocInFormat.documentation_url();
assert_eq!(url, Some("https://docs.perl-lsp.org/errors/PL800"));
Ok(())
}
#[test]
fn documentation_url_heredoc_in_begin() -> Result<(), Box<dyn std::error::Error>> {
let url = DiagnosticCode::HeredocInBegin.documentation_url();
assert_eq!(url, Some("https://docs.perl-lsp.org/errors/PL801"));
Ok(())
}
#[test]
fn documentation_url_heredoc_dynamic_delimiter() -> Result<(), Box<dyn std::error::Error>> {
let url = DiagnosticCode::HeredocDynamicDelimiter.documentation_url();
assert_eq!(url, Some("https://docs.perl-lsp.org/errors/PL802"));
Ok(())
}
#[test]
fn documentation_url_heredoc_in_source_filter() -> Result<(), Box<dyn std::error::Error>> {
let url = DiagnosticCode::HeredocInSourceFilter.documentation_url();
assert_eq!(url, Some("https://docs.perl-lsp.org/errors/PL803"));
Ok(())
}
#[test]
fn documentation_url_heredoc_in_regex_code() -> Result<(), Box<dyn std::error::Error>> {
let url = DiagnosticCode::HeredocInRegexCode.documentation_url();
assert_eq!(url, Some("https://docs.perl-lsp.org/errors/PL804"));
Ok(())
}
#[test]
fn documentation_url_heredoc_in_eval() -> Result<(), Box<dyn std::error::Error>> {
let url = DiagnosticCode::HeredocInEval.documentation_url();
assert_eq!(url, Some("https://docs.perl-lsp.org/errors/PL805"));
Ok(())
}
#[test]
fn documentation_url_heredoc_tied_handle() -> Result<(), Box<dyn std::error::Error>> {
let url = DiagnosticCode::HeredocTiedHandle.documentation_url();
assert_eq!(url, Some("https://docs.perl-lsp.org/errors/PL806"));
Ok(())
}
#[test]
fn documentation_url_version_incompat_feature() -> Result<(), Box<dyn std::error::Error>> {
let url = DiagnosticCode::VersionIncompatFeature.documentation_url();
assert_eq!(url, Some("https://docs.perl-lsp.org/errors/PL900"));
Ok(())
}
#[test]
fn tags_deprecated_defined_has_deprecated_tag() -> Result<(), Box<dyn std::error::Error>> {
let tags = DiagnosticCode::DeprecatedDefined.tags();
assert_eq!(tags.len(), 1);
assert_eq!(tags[0], DiagnosticTag::Deprecated);
Ok(())
}
#[test]
fn tags_deprecated_array_base_has_deprecated_tag() -> Result<(), Box<dyn std::error::Error>> {
let tags = DiagnosticCode::DeprecatedArrayBase.tags();
assert_eq!(tags.len(), 1);
assert_eq!(tags[0], DiagnosticTag::Deprecated);
Ok(())
}
#[test]
fn tags_unused_parameter_has_unnecessary_tag() -> Result<(), Box<dyn std::error::Error>> {
let tags = DiagnosticCode::UnusedParameter.tags();
assert_eq!(tags.len(), 1);
assert_eq!(tags[0], DiagnosticTag::Unnecessary);
Ok(())
}
#[test]
fn tags_unused_import_has_unnecessary_tag() -> Result<(), Box<dyn std::error::Error>> {
let tags = DiagnosticCode::UnusedImport.tags();
assert_eq!(tags.len(), 1);
assert_eq!(tags[0], DiagnosticTag::Unnecessary);
Ok(())
}
#[test]
fn tags_unreachable_code_has_unnecessary_tag() -> Result<(), Box<dyn std::error::Error>> {
let tags = DiagnosticCode::UnreachableCode.tags();
assert_eq!(tags.len(), 1);
assert_eq!(tags[0], DiagnosticTag::Unnecessary);
Ok(())
}
#[test]
fn context_hint_role_conflict_is_some() -> Result<(), Box<dyn std::error::Error>> {
let hint = DiagnosticCode::RoleConflict.context_hint();
assert!(hint.is_some(), "RoleConflict should have a context hint");
let hint = hint.ok_or("missing hint")?;
assert!(hint.contains("Moo") || hint.contains("role"), "hint should mention roles");
Ok(())
}
#[test]
fn context_hint_missing_pod_coverage_is_some() -> Result<(), Box<dyn std::error::Error>> {
let hint = DiagnosticCode::MissingPodCoverage.context_hint();
assert!(hint.is_some(), "MissingPodCoverage should have a context hint");
let hint = hint.ok_or("missing hint")?;
assert!(
hint.contains("POD") || hint.contains("documentation"),
"hint should mention documentation"
);
Ok(())
}
#[test]
fn context_hint_invalid_prototype_is_some() -> Result<(), Box<dyn std::error::Error>> {
let hint = DiagnosticCode::InvalidPrototype.context_hint();
assert!(hint.is_some(), "InvalidPrototype should have a context hint");
let hint = hint.ok_or("missing hint")?;
assert!(hint.contains("prototype"), "hint should mention prototype");
Ok(())
}
#[test]
fn context_hint_assignment_in_condition_is_some() -> Result<(), Box<dyn std::error::Error>> {
let hint = DiagnosticCode::AssignmentInCondition.context_hint();
assert!(hint.is_some(), "AssignmentInCondition should have a context hint");
let hint = hint.ok_or("missing hint")?;
assert!(
hint.contains("assignment") || hint.contains("comparison"),
"hint should describe assignment vs comparison"
);
Ok(())
}
#[test]
fn context_hint_numeric_comparison_with_undef_is_some() -> Result<(), Box<dyn std::error::Error>> {
let hint = DiagnosticCode::NumericComparisonWithUndef.context_hint();
assert!(hint.is_some(), "NumericComparisonWithUndef should have a context hint");
let hint = hint.ok_or("missing hint")?;
assert!(
hint.contains("undefined") || hint.contains("defined"),
"hint should mention definedness"
);
Ok(())
}
#[test]
fn context_hint_unreachable_code_is_some() -> Result<(), Box<dyn std::error::Error>> {
let hint = DiagnosticCode::UnreachableCode.context_hint();
assert!(hint.is_some(), "UnreachableCode should have a context hint");
let hint = hint.ok_or("missing hint")?;
assert!(
hint.contains("unreachable") || hint.contains("cannot be executed"),
"hint should describe unreachability"
);
Ok(())
}
#[test]
fn context_hint_printf_format_mismatch_is_some() -> Result<(), Box<dyn std::error::Error>> {
let hint = DiagnosticCode::PrintfFormatMismatch.context_hint();
assert!(hint.is_some(), "PrintfFormatMismatch should have a context hint");
let hint = hint.ok_or("missing hint")?;
assert!(
hint.contains("format") || hint.contains("specifier"),
"hint should describe format specifiers"
);
Ok(())
}
#[test]
fn context_hint_variable_shadowing_is_some() -> Result<(), Box<dyn std::error::Error>> {
let hint = DiagnosticCode::VariableShadowing.context_hint();
assert!(hint.is_some(), "VariableShadowing should have a context hint");
let hint = hint.ok_or("missing hint")?;
assert!(hint.contains("shadow"), "hint should describe shadowing");
Ok(())
}
#[test]
fn context_hint_variable_redeclaration_is_some() -> Result<(), Box<dyn std::error::Error>> {
let hint = DiagnosticCode::VariableRedeclaration.context_hint();
assert!(hint.is_some(), "VariableRedeclaration should have a context hint");
let hint = hint.ok_or("missing hint")?;
assert!(
hint.contains("redeclar") || hint.contains("declared"),
"hint should describe redeclaration"
);
Ok(())
}
#[test]
fn context_hint_duplicate_parameter_is_some() -> Result<(), Box<dyn std::error::Error>> {
let hint = DiagnosticCode::DuplicateParameter.context_hint();
assert!(hint.is_some(), "DuplicateParameter should have a context hint");
let hint = hint.ok_or("missing hint")?;
assert!(
hint.contains("parameter") || hint.contains("signature"),
"hint should describe parameter"
);
Ok(())
}
#[test]
fn context_hint_parameter_shadows_global_is_some() -> Result<(), Box<dyn std::error::Error>> {
let hint = DiagnosticCode::ParameterShadowsGlobal.context_hint();
assert!(hint.is_some(), "ParameterShadowsGlobal should have a context hint");
let hint = hint.ok_or("missing hint")?;
assert!(
hint.contains("global") || hint.contains("parameter"),
"hint should mention global and parameter"
);
Ok(())
}
#[test]
fn context_hint_unused_parameter_is_some() -> Result<(), Box<dyn std::error::Error>> {
let hint = DiagnosticCode::UnusedParameter.context_hint();
assert!(hint.is_some(), "UnusedParameter should have a context hint");
let hint = hint.ok_or("missing hint")?;
assert!(
hint.contains("parameter") || hint.contains("unused"),
"hint should describe unused parameter"
);
Ok(())
}
#[test]
fn context_hint_unquoted_bareword_is_some() -> Result<(), Box<dyn std::error::Error>> {
let hint = DiagnosticCode::UnquotedBareword.context_hint();
assert!(hint.is_some(), "UnquotedBareword should have a context hint");
let hint = hint.ok_or("missing hint")?;
assert!(
hint.contains("bareword") || hint.contains("quoted"),
"hint should describe bareword quoting"
);
Ok(())
}
#[test]
fn context_hint_uninitialized_variable_is_some() -> Result<(), Box<dyn std::error::Error>> {
let hint = DiagnosticCode::UninitializedVariable.context_hint();
assert!(hint.is_some(), "UninitializedVariable should have a context hint");
let hint = hint.ok_or("missing hint")?;
assert!(
hint.contains("uninitialized") || hint.contains("assigned"),
"hint should describe initialization"
);
Ok(())
}
#[test]
fn context_hint_misspelled_pragma_is_some() -> Result<(), Box<dyn std::error::Error>> {
let hint = DiagnosticCode::MisspelledPragma.context_hint();
assert!(hint.is_some(), "MisspelledPragma should have a context hint");
let hint = hint.ok_or("missing hint")?;
assert!(
hint.contains("pragma") || hint.contains("misspelled"),
"hint should describe pragma spelling"
);
Ok(())
}
#[test]
fn context_hint_capture_var_without_regex_match_is_some() -> Result<(), Box<dyn std::error::Error>>
{
let hint = DiagnosticCode::CaptureVarWithoutRegexMatch.context_hint();
assert!(hint.is_some(), "CaptureVarWithoutRegexMatch should have a context hint");
let hint = hint.ok_or("missing hint")?;
assert!(
hint.contains("capture") || hint.contains("regex"),
"hint should describe capture variable usage"
);
Ok(())
}
#[test]
fn context_hint_deprecated_defined_is_some() -> Result<(), Box<dyn std::error::Error>> {
let hint = DiagnosticCode::DeprecatedDefined.context_hint();
assert!(hint.is_some(), "DeprecatedDefined should have a context hint");
let hint = hint.ok_or("missing hint")?;
assert!(
hint.contains("defined") || hint.contains("deprecated"),
"hint should describe deprecation"
);
Ok(())
}
#[test]
fn context_hint_deprecated_array_base_is_some() -> Result<(), Box<dyn std::error::Error>> {
let hint = DiagnosticCode::DeprecatedArrayBase.context_hint();
assert!(hint.is_some(), "DeprecatedArrayBase should have a context hint");
let hint = hint.ok_or("missing hint")?;
assert!(
hint.contains("deprecated") || hint.contains("array"),
"hint should describe deprecation"
);
Ok(())
}
#[test]
fn context_hint_security_string_eval_is_some() -> Result<(), Box<dyn std::error::Error>> {
let hint = DiagnosticCode::SecurityStringEval.context_hint();
assert!(hint.is_some(), "SecurityStringEval should have a context hint");
let hint = hint.ok_or("missing hint")?;
assert!(
hint.contains("eval") || hint.contains("security"),
"hint should describe eval security"
);
Ok(())
}
#[test]
fn context_hint_security_backtick_exec_is_some() -> Result<(), Box<dyn std::error::Error>> {
let hint = DiagnosticCode::SecurityBacktickExec.context_hint();
assert!(hint.is_some(), "SecurityBacktickExec should have a context hint");
let hint = hint.ok_or("missing hint")?;
assert!(
hint.contains("backtick") || hint.contains("shell"),
"hint should describe backtick security"
);
Ok(())
}
#[test]
fn context_hint_security_system_call_is_some() -> Result<(), Box<dyn std::error::Error>> {
let hint = DiagnosticCode::SecuritySystemCall.context_hint();
assert!(hint.is_some(), "SecuritySystemCall should have a context hint");
let hint = hint.ok_or("missing hint")?;
assert!(
hint.contains("system") || hint.contains("shell"),
"hint should describe system() security"
);
Ok(())
}
#[test]
fn context_hint_security_exec_call_is_some() -> Result<(), Box<dyn std::error::Error>> {
let hint = DiagnosticCode::SecurityExecCall.context_hint();
assert!(hint.is_some(), "SecurityExecCall should have a context hint");
let hint = hint.ok_or("missing hint")?;
assert!(
hint.contains("exec") || hint.contains("shell"),
"hint should describe exec() security"
);
Ok(())
}
#[test]
fn context_hint_security_pipe_open_is_some() -> Result<(), Box<dyn std::error::Error>> {
let hint = DiagnosticCode::SecurityPipeOpen.context_hint();
assert!(hint.is_some(), "SecurityPipeOpen should have a context hint");
let hint = hint.ok_or("missing hint")?;
assert!(
hint.contains("pipe") || hint.contains("open"),
"hint should describe pipe open security"
);
Ok(())
}
#[test]
fn context_hint_security_readpipe_is_some() -> Result<(), Box<dyn std::error::Error>> {
let hint = DiagnosticCode::SecurityReadpipe.context_hint();
assert!(hint.is_some(), "SecurityReadpipe should have a context hint");
let hint = hint.ok_or("missing hint")?;
assert!(
hint.contains("readpipe") || hint.contains("command"),
"hint should describe readpipe security"
);
Ok(())
}
#[test]
fn context_hint_unused_import_is_some() -> Result<(), Box<dyn std::error::Error>> {
let hint = DiagnosticCode::UnusedImport.context_hint();
assert!(hint.is_some(), "UnusedImport should have a context hint");
let hint = hint.ok_or("missing hint")?;
assert!(
hint.contains("import") || hint.contains("module"),
"hint should describe unused import"
);
Ok(())
}
#[test]
fn context_hint_heredoc_in_format_is_some() -> Result<(), Box<dyn std::error::Error>> {
let hint = DiagnosticCode::HeredocInFormat.context_hint();
assert!(hint.is_some(), "HeredocInFormat should have a context hint");
let hint = hint.ok_or("missing hint")?;
assert!(
hint.contains("heredoc") || hint.contains("format"),
"hint should describe heredoc in format"
);
Ok(())
}
#[test]
fn context_hint_heredoc_in_begin_is_some() -> Result<(), Box<dyn std::error::Error>> {
let hint = DiagnosticCode::HeredocInBegin.context_hint();
assert!(hint.is_some(), "HeredocInBegin should have a context hint");
let hint = hint.ok_or("missing hint")?;
assert!(
hint.contains("BEGIN") || hint.contains("heredoc"),
"hint should describe heredoc in BEGIN"
);
Ok(())
}
#[test]
fn context_hint_heredoc_dynamic_delimiter_is_some() -> Result<(), Box<dyn std::error::Error>> {
let hint = DiagnosticCode::HeredocDynamicDelimiter.context_hint();
assert!(hint.is_some(), "HeredocDynamicDelimiter should have a context hint");
let hint = hint.ok_or("missing hint")?;
assert!(
hint.contains("delimiter") || hint.contains("dynamic"),
"hint should describe dynamic delimiter"
);
Ok(())
}
#[test]
fn context_hint_heredoc_in_source_filter_is_some() -> Result<(), Box<dyn std::error::Error>> {
let hint = DiagnosticCode::HeredocInSourceFilter.context_hint();
assert!(hint.is_some(), "HeredocInSourceFilter should have a context hint");
let hint = hint.ok_or("missing hint")?;
assert!(
hint.contains("filter") || hint.contains("heredoc"),
"hint should describe source filter"
);
Ok(())
}
#[test]
fn context_hint_heredoc_in_regex_code_is_some() -> Result<(), Box<dyn std::error::Error>> {
let hint = DiagnosticCode::HeredocInRegexCode.context_hint();
assert!(hint.is_some(), "HeredocInRegexCode should have a context hint");
let hint = hint.ok_or("missing hint")?;
assert!(
hint.contains("regex") || hint.contains("heredoc"),
"hint should describe heredoc in regex"
);
Ok(())
}
#[test]
fn context_hint_heredoc_in_eval_is_some() -> Result<(), Box<dyn std::error::Error>> {
let hint = DiagnosticCode::HeredocInEval.context_hint();
assert!(hint.is_some(), "HeredocInEval should have a context hint");
let hint = hint.ok_or("missing hint")?;
assert!(
hint.contains("eval") || hint.contains("heredoc"),
"hint should describe heredoc in eval"
);
Ok(())
}
#[test]
fn context_hint_heredoc_tied_handle_is_some() -> Result<(), Box<dyn std::error::Error>> {
let hint = DiagnosticCode::HeredocTiedHandle.context_hint();
assert!(hint.is_some(), "HeredocTiedHandle should have a context hint");
let hint = hint.ok_or("missing hint")?;
assert!(
hint.contains("tied") || hint.contains("filehandle"),
"hint should describe tied filehandle"
);
Ok(())
}
#[test]
fn context_hint_version_incompat_feature_is_some() -> Result<(), Box<dyn std::error::Error>> {
let hint = DiagnosticCode::VersionIncompatFeature.context_hint();
assert!(hint.is_some(), "VersionIncompatFeature should have a context hint");
let hint = hint.ok_or("missing hint")?;
assert!(
hint.contains("version") || hint.contains("feature"),
"hint should describe version incompatibility"
);
Ok(())
}
#[test]
fn context_hint_phase_scoped_strict_pragma_is_some() -> Result<(), Box<dyn std::error::Error>> {
let hint = DiagnosticCode::PhaseScopedStrictPragma.context_hint();
assert!(hint.is_some(), "PhaseScopedStrictPragma should have a context hint");
let hint = hint.ok_or("missing hint")?;
assert!(
hint.contains("strict") || hint.contains("phase"),
"hint should describe strict-pragma phase scoping"
);
Ok(())
}
#[test]
fn context_hint_phase_scoped_warnings_pragma_is_some() -> Result<(), Box<dyn std::error::Error>> {
let hint = DiagnosticCode::PhaseScopedWarningsPragma.context_hint();
assert!(hint.is_some(), "PhaseScopedWarningsPragma should have a context hint");
let hint = hint.ok_or("missing hint")?;
assert!(
hint.contains("warnings") || hint.contains("phase"),
"hint should describe warnings-pragma phase scoping"
);
Ok(())
}
#[test]
fn context_hint_critic_codes_return_none() -> Result<(), Box<dyn std::error::Error>> {
assert_eq!(DiagnosticCode::CriticSeverity1.context_hint(), None);
assert_eq!(DiagnosticCode::CriticSeverity2.context_hint(), None);
assert_eq!(DiagnosticCode::CriticSeverity3.context_hint(), None);
assert_eq!(DiagnosticCode::CriticSeverity4.context_hint(), None);
assert_eq!(DiagnosticCode::CriticSeverity5.context_hint(), None);
Ok(())
}
#[test]
fn from_message_invalid_prototype_character() -> Result<(), Box<dyn std::error::Error>> {
assert_eq!(
DiagnosticCode::from_message("invalid prototype character in definition"),
Some(DiagnosticCode::InvalidPrototype)
);
Ok(())
}
#[test]
fn from_message_illegal_character_in_prototype() -> Result<(), Box<dyn std::error::Error>> {
assert_eq!(
DiagnosticCode::from_message("Illegal character in prototype definition"),
Some(DiagnosticCode::InvalidPrototype)
);
Ok(())
}
#[test]
fn category_deprecated_defined() -> Result<(), Box<dyn std::error::Error>> {
assert_eq!(DiagnosticCode::DeprecatedDefined.category(), DiagnosticCategory::Deprecated);
Ok(())
}
#[test]
fn category_deprecated_array_base() -> Result<(), Box<dyn std::error::Error>> {
assert_eq!(DiagnosticCode::DeprecatedArrayBase.category(), DiagnosticCategory::Deprecated);
Ok(())
}
#[test]
fn category_unused_import() -> Result<(), Box<dyn std::error::Error>> {
assert_eq!(DiagnosticCode::UnusedImport.category(), DiagnosticCategory::Import);
Ok(())
}
#[test]
fn category_module_not_found() -> Result<(), Box<dyn std::error::Error>> {
assert_eq!(DiagnosticCode::ModuleNotFound.category(), DiagnosticCategory::Import);
Ok(())
}
#[test]
fn category_heredoc_in_format() -> Result<(), Box<dyn std::error::Error>> {
assert_eq!(DiagnosticCode::HeredocInFormat.category(), DiagnosticCategory::Heredoc);
Ok(())
}
#[test]
fn category_heredoc_in_begin() -> Result<(), Box<dyn std::error::Error>> {
assert_eq!(DiagnosticCode::HeredocInBegin.category(), DiagnosticCategory::Heredoc);
Ok(())
}
#[test]
fn category_heredoc_dynamic_delimiter() -> Result<(), Box<dyn std::error::Error>> {
assert_eq!(DiagnosticCode::HeredocDynamicDelimiter.category(), DiagnosticCategory::Heredoc);
Ok(())
}
#[test]
fn category_heredoc_in_source_filter() -> Result<(), Box<dyn std::error::Error>> {
assert_eq!(DiagnosticCode::HeredocInSourceFilter.category(), DiagnosticCategory::Heredoc);
Ok(())
}
#[test]
fn category_heredoc_in_regex_code() -> Result<(), Box<dyn std::error::Error>> {
assert_eq!(DiagnosticCode::HeredocInRegexCode.category(), DiagnosticCategory::Heredoc);
Ok(())
}
#[test]
fn category_heredoc_in_eval() -> Result<(), Box<dyn std::error::Error>> {
assert_eq!(DiagnosticCode::HeredocInEval.category(), DiagnosticCategory::Heredoc);
Ok(())
}
#[test]
fn category_heredoc_tied_handle() -> Result<(), Box<dyn std::error::Error>> {
assert_eq!(DiagnosticCode::HeredocTiedHandle.category(), DiagnosticCategory::Heredoc);
Ok(())
}
#[test]
fn category_version_incompat_feature_is_best_practices() -> Result<(), Box<dyn std::error::Error>> {
assert_eq!(
DiagnosticCode::VersionIncompatFeature.category(),
DiagnosticCategory::BestPractices
);
Ok(())
}
#[test]
fn category_display_parser() -> Result<(), Box<dyn std::error::Error>> {
assert_eq!(format!("{}", DiagnosticCategory::Parser), "Parser");
Ok(())
}
#[test]
fn category_display_strict_warnings() -> Result<(), Box<dyn std::error::Error>> {
assert_eq!(format!("{}", DiagnosticCategory::StrictWarnings), "Strict/Warnings");
Ok(())
}
#[test]
fn category_display_package_module() -> Result<(), Box<dyn std::error::Error>> {
assert_eq!(format!("{}", DiagnosticCategory::PackageModule), "Package/Module");
Ok(())
}
#[test]
fn category_display_subroutine() -> Result<(), Box<dyn std::error::Error>> {
assert_eq!(format!("{}", DiagnosticCategory::Subroutine), "Subroutine");
Ok(())
}
#[test]
fn category_display_best_practices() -> Result<(), Box<dyn std::error::Error>> {
assert_eq!(format!("{}", DiagnosticCategory::BestPractices), "Best Practices");
Ok(())
}
#[test]
fn category_display_deprecated() -> Result<(), Box<dyn std::error::Error>> {
assert_eq!(format!("{}", DiagnosticCategory::Deprecated), "Deprecated");
Ok(())
}
#[test]
fn category_display_security() -> Result<(), Box<dyn std::error::Error>> {
assert_eq!(format!("{}", DiagnosticCategory::Security), "Security");
Ok(())
}
#[test]
fn category_display_import() -> Result<(), Box<dyn std::error::Error>> {
assert_eq!(format!("{}", DiagnosticCategory::Import), "Import");
Ok(())
}
#[test]
fn category_display_heredoc() -> Result<(), Box<dyn std::error::Error>> {
assert_eq!(format!("{}", DiagnosticCategory::Heredoc), "Heredoc");
Ok(())
}
#[test]
fn category_display_perl_critic() -> Result<(), Box<dyn std::error::Error>> {
assert_eq!(format!("{}", DiagnosticCategory::PerlCritic), "Perl::Critic");
Ok(())
}
#[test]
fn parse_code_round_trip_all_variants_exhaustive() -> Result<(), Box<dyn std::error::Error>> {
let all_variants = [
DiagnosticCode::ParseError,
DiagnosticCode::SyntaxError,
DiagnosticCode::UnexpectedEof,
DiagnosticCode::MissingStrict,
DiagnosticCode::MissingWarnings,
DiagnosticCode::UnusedVariable,
DiagnosticCode::UndefinedVariable,
DiagnosticCode::VariableShadowing,
DiagnosticCode::VariableRedeclaration,
DiagnosticCode::DuplicateParameter,
DiagnosticCode::ParameterShadowsGlobal,
DiagnosticCode::UnusedParameter,
DiagnosticCode::UnquotedBareword,
DiagnosticCode::UninitializedVariable,
DiagnosticCode::MisspelledPragma,
DiagnosticCode::CaptureVarWithoutRegexMatch,
DiagnosticCode::MissingPackageDeclaration,
DiagnosticCode::DuplicatePackage,
DiagnosticCode::DuplicateSubroutine,
DiagnosticCode::MissingReturn,
DiagnosticCode::InvalidPrototype,
DiagnosticCode::RoleConflict,
DiagnosticCode::MissingPodCoverage,
DiagnosticCode::BarewordFilehandle,
DiagnosticCode::TwoArgOpen,
DiagnosticCode::ImplicitReturn,
DiagnosticCode::AssignmentInCondition,
DiagnosticCode::NumericComparisonWithUndef,
DiagnosticCode::PrintfFormatMismatch,
DiagnosticCode::UnreachableCode,
DiagnosticCode::EvalErrorFlow,
DiagnosticCode::DuplicateHashKey,
DiagnosticCode::GotoUndefinedLabel,
DiagnosticCode::LoopControlUndefinedLabel,
DiagnosticCode::DeprecatedDefined,
DiagnosticCode::DeprecatedArrayBase,
DiagnosticCode::PhaseScopedStrictPragma,
DiagnosticCode::PhaseScopedWarningsPragma,
DiagnosticCode::SecurityStringEval,
DiagnosticCode::SecurityBacktickExec,
DiagnosticCode::SecuritySignalHandler,
DiagnosticCode::SecuritySystemCall,
DiagnosticCode::SecurityExecCall,
DiagnosticCode::SecurityPipeOpen,
DiagnosticCode::SecurityReadpipe,
DiagnosticCode::UnusedImport,
DiagnosticCode::ModuleNotFound,
DiagnosticCode::HeredocInFormat,
DiagnosticCode::HeredocInBegin,
DiagnosticCode::HeredocDynamicDelimiter,
DiagnosticCode::HeredocInSourceFilter,
DiagnosticCode::HeredocInRegexCode,
DiagnosticCode::HeredocInEval,
DiagnosticCode::HeredocTiedHandle,
DiagnosticCode::VersionIncompatFeature,
DiagnosticCode::CriticSeverity1,
DiagnosticCode::CriticSeverity2,
DiagnosticCode::CriticSeverity3,
DiagnosticCode::CriticSeverity4,
DiagnosticCode::CriticSeverity5,
];
assert_eq!(
all_variants.len(),
60,
"expected exhaustive DiagnosticCode variant list to cover 60 variants"
);
for code in &all_variants {
let s = code.as_str();
let parsed = DiagnosticCode::parse_code(s);
assert_eq!(parsed, Some(*code), "parse_code({s}) should round-trip back to {code:?}");
}
Ok(())
}
#[test]
fn severity_missing_pod_coverage_is_hint() -> Result<(), Box<dyn std::error::Error>> {
assert_eq!(DiagnosticCode::MissingPodCoverage.severity(), DiagnosticSeverity::Hint);
Ok(())
}
#[test]
fn severity_unreachable_code_is_hint() -> Result<(), Box<dyn std::error::Error>> {
assert_eq!(DiagnosticCode::UnreachableCode.severity(), DiagnosticSeverity::Hint);
Ok(())
}
#[test]
fn severity_unused_import_is_hint() -> Result<(), Box<dyn std::error::Error>> {
assert_eq!(DiagnosticCode::UnusedImport.severity(), DiagnosticSeverity::Hint);
Ok(())
}
#[test]
fn severity_version_incompat_feature_is_warning() -> Result<(), Box<dyn std::error::Error>> {
assert_eq!(DiagnosticCode::VersionIncompatFeature.severity(), DiagnosticSeverity::Warning);
Ok(())
}
#[test]
fn severity_security_codes_are_all_warning() -> Result<(), Box<dyn std::error::Error>> {
let security_codes = [
DiagnosticCode::SecuritySystemCall,
DiagnosticCode::SecurityExecCall,
DiagnosticCode::SecurityPipeOpen,
DiagnosticCode::SecurityReadpipe,
];
for code in &security_codes {
assert_eq!(
code.severity(),
DiagnosticSeverity::Warning,
"{} should be Warning severity",
code.as_str()
);
}
Ok(())
}
#[test]
fn severity_heredoc_codes_are_all_information() -> Result<(), Box<dyn std::error::Error>> {
let heredoc_codes = [
DiagnosticCode::HeredocInFormat,
DiagnosticCode::HeredocInBegin,
DiagnosticCode::HeredocDynamicDelimiter,
DiagnosticCode::HeredocInSourceFilter,
DiagnosticCode::HeredocInRegexCode,
DiagnosticCode::HeredocInEval,
DiagnosticCode::HeredocTiedHandle,
];
for code in &heredoc_codes {
assert_eq!(
code.severity(),
DiagnosticSeverity::Information,
"{} should be Information severity",
code.as_str()
);
}
Ok(())
}
#[test]
fn severity_deprecated_codes_are_warning() -> Result<(), Box<dyn std::error::Error>> {
assert_eq!(DiagnosticCode::DeprecatedDefined.severity(), DiagnosticSeverity::Warning);
assert_eq!(DiagnosticCode::DeprecatedArrayBase.severity(), DiagnosticSeverity::Warning);
Ok(())
}
#[test]
fn all_pl_codes_have_documentation_url() -> Result<(), Box<dyn std::error::Error>> {
let pl_only = [
DiagnosticCode::ParseError,
DiagnosticCode::SyntaxError,
DiagnosticCode::UnexpectedEof,
DiagnosticCode::MissingStrict,
DiagnosticCode::MissingWarnings,
DiagnosticCode::UnusedVariable,
DiagnosticCode::UndefinedVariable,
DiagnosticCode::VariableShadowing,
DiagnosticCode::VariableRedeclaration,
DiagnosticCode::DuplicateParameter,
DiagnosticCode::ParameterShadowsGlobal,
DiagnosticCode::UnusedParameter,
DiagnosticCode::UnquotedBareword,
DiagnosticCode::UninitializedVariable,
DiagnosticCode::MisspelledPragma,
DiagnosticCode::CaptureVarWithoutRegexMatch,
DiagnosticCode::MissingPackageDeclaration,
DiagnosticCode::DuplicatePackage,
DiagnosticCode::DuplicateSubroutine,
DiagnosticCode::MissingReturn,
DiagnosticCode::InvalidPrototype,
DiagnosticCode::RoleConflict,
DiagnosticCode::MissingPodCoverage,
DiagnosticCode::BarewordFilehandle,
DiagnosticCode::TwoArgOpen,
DiagnosticCode::ImplicitReturn,
DiagnosticCode::AssignmentInCondition,
DiagnosticCode::NumericComparisonWithUndef,
DiagnosticCode::PrintfFormatMismatch,
DiagnosticCode::UnreachableCode,
DiagnosticCode::EvalErrorFlow,
DiagnosticCode::DuplicateHashKey,
DiagnosticCode::GotoUndefinedLabel,
DiagnosticCode::LoopControlUndefinedLabel,
DiagnosticCode::DeprecatedDefined,
DiagnosticCode::DeprecatedArrayBase,
DiagnosticCode::PhaseScopedStrictPragma,
DiagnosticCode::PhaseScopedWarningsPragma,
DiagnosticCode::SecurityStringEval,
DiagnosticCode::SecurityBacktickExec,
DiagnosticCode::SecuritySignalHandler,
DiagnosticCode::SecuritySystemCall,
DiagnosticCode::SecurityExecCall,
DiagnosticCode::SecurityPipeOpen,
DiagnosticCode::SecurityReadpipe,
DiagnosticCode::UnusedImport,
DiagnosticCode::ModuleNotFound,
DiagnosticCode::HeredocInFormat,
DiagnosticCode::HeredocInBegin,
DiagnosticCode::HeredocDynamicDelimiter,
DiagnosticCode::HeredocInSourceFilter,
DiagnosticCode::HeredocInRegexCode,
DiagnosticCode::HeredocInEval,
DiagnosticCode::HeredocTiedHandle,
DiagnosticCode::VersionIncompatFeature,
];
for code in &pl_only {
let url = code.documentation_url();
assert!(url.is_some(), "PL code {} should have a documentation URL", code.as_str());
let url_str = url.ok_or("missing url")?;
assert!(
url_str.starts_with("https://docs.perl-lsp.org/errors/"),
"URL for {} should start with base URL, got {}",
code.as_str(),
url_str
);
assert!(
url_str.ends_with(code.as_str()),
"URL for {} should end with its code string, got {}",
code.as_str(),
url_str
);
}
Ok(())
}