diff --git a/server/src/threads.rs b/server/src/threads.rs index 009de199..f42d8e47 100644 --- a/server/src/threads.rs +++ b/server/src/threads.rs @@ -138,6 +138,20 @@ impl <'a> SessionInfo<'a> { current_noqa: NoqaInfo::None, } } + + /** + * Should only be used for tests, when sender is connected to the receiver, to verify messages that has been sent. + */ + pub fn _consume_message(&self) -> Option { + match self.receiver.try_recv() { + Ok(msg) => Some(msg), + Err(TryRecvError::Empty) => None, + Err(TryRecvError::Disconnected) => { + error!("Session channel disconnected"); + None + } + } + } } fn to_value(result: Result, ResponseError>) -> (Option, Option) { diff --git a/server/tests/data/python/diagnostics/ols01000.py b/server/tests/data/python/diagnostics/ols01000.py new file mode 100644 index 00000000..a4b64984 --- /dev/null +++ b/server/tests/data/python/diagnostics/ols01000.py @@ -0,0 +1 @@ +def \ No newline at end of file diff --git a/server/tests/data/python/diagnostics/ols01001.py b/server/tests/data/python/diagnostics/ols01001.py new file mode 100644 index 00000000..4758faf2 --- /dev/null +++ b/server/tests/data/python/diagnostics/ols01001.py @@ -0,0 +1,6 @@ + +class Test(a_class): + pass + +class Test2(Test): + pass \ No newline at end of file diff --git a/server/tests/data/python/diagnostics/ols01002.py b/server/tests/data/python/diagnostics/ols01002.py new file mode 100644 index 00000000..398e1827 --- /dev/null +++ b/server/tests/data/python/diagnostics/ols01002.py @@ -0,0 +1,7 @@ +Integer = 5 + +class Test(Integer): + pass + +class Test2(Test): + pass \ No newline at end of file diff --git a/server/tests/data/python/diagnostics/ols01003.py b/server/tests/data/python/diagnostics/ols01003.py new file mode 100644 index 00000000..320c7d8d --- /dev/null +++ b/server/tests/data/python/diagnostics/ols01003.py @@ -0,0 +1,12 @@ +if input(): + class A: + pass +else: + class A: + pass + +class Test(A): + pass + +class Test2(Test): + pass \ No newline at end of file diff --git a/server/tests/diagnostics/mod.rs b/server/tests/diagnostics/mod.rs new file mode 100644 index 00000000..00b5a3a6 --- /dev/null +++ b/server/tests/diagnostics/mod.rs @@ -0,0 +1,5 @@ + +pub mod ols01000; +pub mod ols01001; +pub mod ols01002; +pub mod ols01003; diff --git a/server/tests/diagnostics/ols01000.rs b/server/tests/diagnostics/ols01000.rs new file mode 100644 index 00000000..85c762a1 --- /dev/null +++ b/server/tests/diagnostics/ols01000.rs @@ -0,0 +1,24 @@ +use std::env; + +use lsp_types::{DiagnosticSeverity, NumberOrString}; +use odoo_ls_server::{S, utils::PathSanitizer}; + +use crate::setup::setup::*; + +#[test] +fn test_ols01000() { + let mut odoo = setup_server(false); + let path = env::current_dir().unwrap().join("tests/data/python/diagnostics/ols01000.py").sanitize(); + let mut session = prepare_custom_entry_point(&mut odoo, &path); + let diagnostics = get_diagnostics_for_path(&mut session, &path); + assert_eq!(diagnostics.len(), 1); + let diag = &diagnostics[0]; + assert!(diag.code.is_some()); + let code = match &diag.code { + Some(NumberOrString::String(code)) => code, + Some(NumberOrString::Number(num)) => panic!("Unexpected numeric code: {}", num), + None => panic!("Diagnostic code is None"), + }; + assert!(code == &S!("OLS01000")); + assert!(diag.severity.is_some_and(|s| s == DiagnosticSeverity::ERROR)); +} \ No newline at end of file diff --git a/server/tests/diagnostics/ols01001.rs b/server/tests/diagnostics/ols01001.rs new file mode 100644 index 00000000..c281588f --- /dev/null +++ b/server/tests/diagnostics/ols01001.rs @@ -0,0 +1,24 @@ +use std::env; + +use lsp_types::{DiagnosticSeverity, NumberOrString}; +use odoo_ls_server::{S, utils::PathSanitizer}; + +use crate::setup::setup::*; + +#[test] +fn test_ols01001() { + let mut odoo = setup_server(false); + let path = env::current_dir().unwrap().join("tests/data/python/diagnostics/ols01001.py").sanitize(); + let mut session = prepare_custom_entry_point(&mut odoo, &path); + let diagnostics = get_diagnostics_for_path(&mut session, &path); + assert_eq!(diagnostics.len(), 1); + let diag = &diagnostics[0]; + assert!(diag.code.is_some()); + let code = match &diag.code { + Some(NumberOrString::String(code)) => code, + Some(NumberOrString::Number(num)) => panic!("Unexpected numeric code: {}", num), + None => panic!("Diagnostic code is None"), + }; + assert!(code == &S!("OLS01001")); + assert!(diag.severity.is_some_and(|s| s == DiagnosticSeverity::WARNING)); +} \ No newline at end of file diff --git a/server/tests/diagnostics/ols01002.rs b/server/tests/diagnostics/ols01002.rs new file mode 100644 index 00000000..d1eacbad --- /dev/null +++ b/server/tests/diagnostics/ols01002.rs @@ -0,0 +1,24 @@ +use std::env; + +use lsp_types::{DiagnosticSeverity, NumberOrString}; +use odoo_ls_server::{S, utils::PathSanitizer}; + +use crate::setup::setup::*; + +#[test] +fn test_ols01002() { + let mut odoo = setup_server(false); + let path = env::current_dir().unwrap().join("tests/data/python/diagnostics/ols01002.py").sanitize(); + let mut session = prepare_custom_entry_point(&mut odoo, &path); + let diagnostics = get_diagnostics_for_path(&mut session, &path); + assert_eq!(diagnostics.len(), 1); + let diag = &diagnostics[0]; + assert!(diag.code.is_some()); + let code = match &diag.code { + Some(NumberOrString::String(code)) => code, + Some(NumberOrString::Number(num)) => panic!("Unexpected numeric code: {}", num), + None => panic!("Diagnostic code is None"), + }; + assert!(code == &S!("OLS01002")); + assert!(diag.severity.is_some_and(|s| s == DiagnosticSeverity::WARNING)); +} \ No newline at end of file diff --git a/server/tests/diagnostics/ols01003.rs b/server/tests/diagnostics/ols01003.rs new file mode 100644 index 00000000..11188624 --- /dev/null +++ b/server/tests/diagnostics/ols01003.rs @@ -0,0 +1,24 @@ +use std::env; + +use lsp_types::{DiagnosticSeverity, NumberOrString}; +use odoo_ls_server::{S, utils::PathSanitizer}; + +use crate::setup::setup::*; + +#[test] +fn test_ols01003() { + let mut odoo = setup_server(false); + let path = env::current_dir().unwrap().join("tests/data/python/diagnostics/ols01003.py").sanitize(); + let mut session = prepare_custom_entry_point(&mut odoo, &path); + let diagnostics = get_diagnostics_for_path(&mut session, &path); + assert_eq!(diagnostics.len(), 1); + let diag = &diagnostics[0]; + assert!(diag.code.is_some()); + let code = match &diag.code { + Some(NumberOrString::String(code)) => code, + Some(NumberOrString::Number(num)) => panic!("Unexpected numeric code: {}", num), + None => panic!("Diagnostic code is None"), + }; + assert!(code == &S!("OLS01003")); + assert!(diag.severity.is_some_and(|s| s == DiagnosticSeverity::WARNING)); +} \ No newline at end of file diff --git a/server/tests/mod.rs b/server/tests/mod.rs index 8c5cffcd..d2636f72 100644 --- a/server/tests/mod.rs +++ b/server/tests/mod.rs @@ -1 +1,3 @@ -pub mod test_utils; \ No newline at end of file +pub mod test_utils; +pub mod diagnostics; +pub mod setup; \ No newline at end of file diff --git a/server/tests/setup/setup.rs b/server/tests/setup/setup.rs index 8be22f95..c32d950a 100644 --- a/server/tests/setup/setup.rs +++ b/server/tests/setup/setup.rs @@ -4,7 +4,10 @@ use std::{env, fs}; use std::path::PathBuf; -use lsp_types::TextDocumentContentChangeEvent; +use lsp_server::Message; +use lsp_types::{Diagnostic, PublishDiagnosticsParams, TextDocumentContentChangeEvent}; +use lsp_types::notification::{Notification, PublishDiagnostics}; +use odoo_ls_server::core::file_mgr::FileMgr; use odoo_ls_server::utils::get_python_command; use odoo_ls_server::{core::{config::{ConfigEntry, DiagMissingImportsMode}, entry_point::EntryPointMgr, odoo::SyncOdoo}, threads::SessionInfo, utils::PathSanitizer as _}; @@ -77,4 +80,23 @@ pub fn prepare_custom_entry_point<'a>(odoo: &'a mut SyncOdoo, path: &str) -> Ses EntryPointMgr::create_new_custom_entry_for_path(&mut session, &ep_path, &ep_path); SyncOdoo::process_rebuilds(&mut session, false); session +} + +pub fn get_diagnostics_for_path(session: &mut SessionInfo, path: &str) -> Vec { + let mut res = vec![]; + while let Some(msg) = session._consume_message() { + match msg { + Message::Notification(n) => { + if n.method == PublishDiagnostics::METHOD { + let params: PublishDiagnosticsParams = serde_json::from_value(n.params).expect("Unable to parse PublishDiagnosticsParams"); + let params_path = FileMgr::uri2pathname(params.uri.as_str()); + if params_path == path { + res.extend(params.diagnostics); + } + } + }, + _ => {} + } + } + return res; } \ No newline at end of file