From 662561b08d47cc1f47bc373d27dd5c451573bf24 Mon Sep 17 00:00:00 2001 From: Daniel Danis Date: Mon, 8 Dec 2025 22:12:22 +0100 Subject: [PATCH 1/2] Add use case stub. --- tests/use_cases.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 tests/use_cases.rs diff --git a/tests/use_cases.rs b/tests/use_cases.rs new file mode 100644 index 0000000..2c8669d --- /dev/null +++ b/tests/use_cases.rs @@ -0,0 +1,30 @@ +use phenolint::phenolint::Phenolint; +use phenolint::traits::Lint; +use phenolint::LinterContext; +use serde_json::json; +use std::path::PathBuf; +use std::sync::OnceLock; + +static PHENOLINT: OnceLock = OnceLock::new(); + +#[test] +fn lint_minimal_valid_phenopacket() { + let phenolint = PHENOLINT.get_or_init(init_phenolint); + + let value = json!({ + "id": "phenopacket", + }); + let payload_str = serde_json::to_string(&value).unwrap(); + + // TODO: is it absolutely necessary for `lint` to take `&mut self`? + let result = phenolint.lint(payload_str.as_str(), true, true); + + // TODO: assert properly + eprintln!("{:?}", result); +} + +fn init_phenolint() -> Phenolint { + let context = LinterContext::new(Some(PathBuf::from("tests/assets/hp.toy.json"))); + let rule_ids = vec!["CURIE001".into(), "INTER001".into()]; + Phenolint::new(context, rule_ids) +} From 0d706303f29f1486fd8823c398b46050252cd265 Mon Sep 17 00:00:00 2001 From: SmartMonkey Date: Wed, 10 Dec 2025 10:44:27 +0100 Subject: [PATCH 2/2] Make phenolint thread safe --- src/materializer.rs | 2 +- src/patches/traits.rs | 4 ++-- src/phenolint.rs | 6 +++--- src/report/traits.rs | 4 ++-- src/rules/traits.rs | 6 +++--- src/traits.rs | 2 +- tests/use_cases.rs | 2 +- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/materializer.rs b/src/materializer.rs index 4434caf..06f91b9 100644 --- a/src/materializer.rs +++ b/src/materializer.rs @@ -11,7 +11,7 @@ use phenopackets::schema::v2::core::{ pub(crate) struct NodeMaterializer; impl NodeMaterializer { - pub fn materialize_nodes(&mut self, dyn_node: &DynamicNode, repo: &mut NodeRepository) { + pub fn materialize_nodes(&self, dyn_node: &DynamicNode, repo: &mut NodeRepository) { if let Some(oc) = OntologyClass::parse(dyn_node) { Self::push_to_repo(oc, dyn_node, repo); } else if let Some(pf) = PhenotypicFeature::parse(dyn_node) { diff --git a/src/patches/traits.rs b/src/patches/traits.rs index d7f540f..7061ce9 100644 --- a/src/patches/traits.rs +++ b/src/patches/traits.rs @@ -15,7 +15,7 @@ pub trait PatchFromContext { ) -> Result, FromContextError>; } -impl RegisterablePatch for T { +impl RegisterablePatch for T { fn compile_patches(&self, value: &dyn Node, lint_violation: &LintViolation) -> Vec { CompilePatches::compile_patches(self, value, lint_violation) } @@ -30,6 +30,6 @@ pub trait RulePatch: PatchFromContext + RegisterablePatch + CompilePatches { } /// Tries to compile patches for a given rule. -pub trait CompilePatches: Send + Sync { +pub trait CompilePatches { fn compile_patches(&self, node: &dyn Node, lint_violation: &LintViolation) -> Vec; } diff --git a/src/phenolint.rs b/src/phenolint.rs index 1a374d3..1f59892 100644 --- a/src/phenolint.rs +++ b/src/phenolint.rs @@ -53,7 +53,7 @@ impl Phenolint { } impl Lint for Phenolint { - fn lint(&mut self, phenostr: &str, patch: bool, quiet: bool) -> LintResult { + fn lint(&self, phenostr: &str, patch: bool, quiet: bool) -> LintResult { let mut report = LintReport::default(); let (values, spans, input_type) = match PhenopacketParser::to_abstract_tree(phenostr) { @@ -142,7 +142,7 @@ impl Lint for Phenolint { } impl Lint for Phenolint { - fn lint(&mut self, phenopath: &PathBuf, patch: bool, quit: bool) -> LintResult { + fn lint(&self, phenopath: &PathBuf, patch: bool, quit: bool) -> LintResult { let phenodata = match fs::read(phenopath) { Ok(phenodata) => phenodata, Err(err) => { @@ -155,7 +155,7 @@ impl Lint for Phenolint { } impl Lint<[u8]> for Phenolint { - fn lint(&mut self, phenodata: &[u8], patch: bool, quit: bool) -> LintResult { + fn lint(&self, phenodata: &[u8], patch: bool, quit: bool) -> LintResult { let (phenostr, input_type) = match PhenopacketParser::to_string(phenodata) { Ok(phenostr) => phenostr, Err(err) => { diff --git a/src/report/traits.rs b/src/report/traits.rs index b69b318..03fb58a 100644 --- a/src/report/traits.rs +++ b/src/report/traits.rs @@ -8,12 +8,12 @@ pub trait RuleReport: ReportFromContext + RegisterableReport + CompileReport { const RULE_ID: &'static str; } -pub trait RegisterableReport { +pub trait RegisterableReport: Send + Sync { fn compile_report(&self, value: &dyn Node, lint_violation: &LintViolation) -> ReportSpecs; fn rule_id(&self) -> String; } -impl RegisterableReport for T { +impl RegisterableReport for T { fn compile_report(&self, value: &dyn Node, lint_violation: &LintViolation) -> ReportSpecs { CompileReport::compile_report(self, value, lint_violation) } diff --git a/src/rules/traits.rs b/src/rules/traits.rs index 97173cb..ffd2b4e 100644 --- a/src/rules/traits.rs +++ b/src/rules/traits.rs @@ -9,7 +9,7 @@ pub trait LintRule: RuleFromContext + Send + Sync { fn check_erased(&self, board: &NodeRepository) -> Vec; } -pub trait RuleMetaData: Send + Sync { +pub trait RuleMetaData { fn rule_id(&self) -> &str; } @@ -19,12 +19,12 @@ pub trait RuleFromContext { Self: Sized; } -pub trait RuleCheck: Send + Sync + 'static { +pub trait RuleCheck: 'static { type Data<'a>: LintData<'a> + ?Sized; fn check(&self, data: Self::Data<'_>) -> Vec; } -impl LintRule for T +impl LintRule for T where T: RuleCheck + RuleFromContext + RuleMetaData, for<'a> ::Data<'a>: Sized, diff --git a/src/traits.rs b/src/traits.rs index 5b6157b..e914467 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -1,5 +1,5 @@ use crate::error::LintResult; pub trait Lint { - fn lint(&mut self, phenodata: &T, patch: bool, quit: bool) -> LintResult; + fn lint(&self, phenodata: &T, patch: bool, quit: bool) -> LintResult; } diff --git a/tests/use_cases.rs b/tests/use_cases.rs index 2c8669d..ec7326a 100644 --- a/tests/use_cases.rs +++ b/tests/use_cases.rs @@ -1,6 +1,6 @@ +use phenolint::LinterContext; use phenolint::phenolint::Phenolint; use phenolint::traits::Lint; -use phenolint::LinterContext; use serde_json::json; use std::path::PathBuf; use std::sync::OnceLock;