use sql_dialect_fmt_hover::{hover_at, HoverKind, CREATE_PROCEDURE_DOCS, CREATE_TASK_DOCS};
fn hover_on(sql: &str, needle: &str) -> sql_dialect_fmt_hover::Hover {
let offset = sql.find(needle).expect("needle exists");
hover_at(sql, offset).expect("hover is available")
}
#[test]
fn procedure_name_hover_summarizes_signature() {
let sql = r#"
CREATE OR REPLACE PROCEDURE normalize_events(src VARIANT, limit_rows NUMBER)
RETURNS NUMBER
LANGUAGE JAVASCRIPT
HANDLER = 'run'
AS $$
return 1;
$$;
"#;
let hover = hover_on(sql, "normalize_events");
assert_eq!(hover.kind, HoverKind::Procedure);
assert_eq!(hover.title, "Stored procedure `normalize_events`");
assert!(hover
.body
.contains("Arguments: `src VARIANT, limit_rows NUMBER`."));
assert!(hover.body.contains("Returns: `NUMBER`."));
assert!(hover.body.contains("Language: `JAVASCRIPT`."));
assert_eq!(hover.docs_url, Some(CREATE_PROCEDURE_DOCS));
assert_eq!(&sql[hover.range], "normalize_events");
}
#[test]
fn procedure_name_hover_summarizes_external_language_options() {
let sql = r#"
CREATE OR REPLACE PROCEDURE train_model(src STRING)
RETURNS STRING
LANGUAGE SCALA
RUNTIME_VERSION = '2.12'
PACKAGES = ('com.snowflake:snowpark:latest', 'com.acme:ml:1.0')
IMPORTS = ('@code/jars/lib.jar')
HANDLER = 'Model.run'
TARGET_PATH = '@code/jars/model.jar'
AS $$
class Model {}
$$;
"#;
let hover = hover_on(sql, "train_model");
assert_eq!(hover.kind, HoverKind::Procedure);
assert!(hover.body.contains("Language: `SCALA`."));
assert!(hover.body.contains("Handler: `'Model.run'`."));
assert!(hover.body.contains("Runtime: `'2.12'`."));
assert!(hover
.body
.contains("Packages: `('com.snowflake:snowpark:latest', 'com.acme:ml:1.0')`."));
assert!(hover.body.contains("Imports: `('@code/jars/lib.jar')`."));
assert!(hover
.body
.contains("Target path: `'@code/jars/model.jar'`."));
}
#[test]
fn task_name_hover_summarizes_compute_schedule_and_condition() {
let sql = r#"
CREATE TASK load_events
WAREHOUSE = etl_wh
SCHEDULE = 'USING CRON 0 * * * * UTC'
WHEN SYSTEM$STREAM_HAS_DATA('raw_events')
AS
CALL normalize_events();
"#;
let hover = hover_on(sql, "load_events");
assert_eq!(hover.kind, HoverKind::Task);
assert_eq!(hover.title, "Task `load_events`");
assert!(hover.body.contains("Compute: `etl_wh`."));
assert!(hover
.body
.contains("Schedule: `'USING CRON 0 * * * * UTC'`."));
assert!(hover
.body
.contains("Condition: `SYSTEM$STREAM_HAS_DATA('raw_events')`."));
assert_eq!(hover.docs_url, Some(CREATE_TASK_DOCS));
}
#[test]
fn task_properties_have_direct_hover() {
let sql = "CREATE TASK t WAREHOUSE = wh SCHEDULE = '5 MINUTES' AS SELECT 1;";
let schedule = hover_on(sql, "SCHEDULE");
assert_eq!(schedule.kind, HoverKind::Property);
assert!(schedule.body.contains("interval strings"));
let warehouse = hover_on(sql, "WAREHOUSE");
assert_eq!(warehouse.kind, HoverKind::Property);
assert!(warehouse.body.contains("Virtual warehouse"));
}
#[test]
fn procedure_properties_and_languages_have_direct_hover() {
let sql = "CREATE PROCEDURE p() RETURNS STRING LANGUAGE PYTHON RUNTIME_VERSION = '3.12' PACKAGES = ('snowflake-snowpark-python') IMPORTS = ('@code/app.py') HANDLER = 'run' EXTERNAL_ACCESS_INTEGRATIONS = (net) SECRETS = ('cred'=my_secret) AS $$pass$$;";
let returns = hover_on(sql, "RETURNS");
assert_eq!(returns.kind, HoverKind::Property);
assert!(returns.body.contains("procedure result type"));
let python = hover_on(sql, "PYTHON");
assert_eq!(python.kind, HoverKind::Language);
assert!(python.body.contains("Snowpark Python"));
let runtime = hover_on(sql, "RUNTIME_VERSION");
assert_eq!(runtime.kind, HoverKind::Property);
assert!(runtime.body.contains("runtime version"));
let packages = hover_on(sql, "PACKAGES");
assert_eq!(packages.kind, HoverKind::Property);
assert!(packages.body.contains("runtime packages"));
let imports = hover_on(sql, "IMPORTS");
assert_eq!(imports.kind, HoverKind::Property);
assert!(imports.body.contains("staged files"));
let external = hover_on(sql, "EXTERNAL_ACCESS_INTEGRATIONS");
assert_eq!(external.kind, HoverKind::Property);
assert!(external.body.contains("outbound network access"));
let secrets = hover_on(sql, "SECRETS");
assert_eq!(secrets.kind, HoverKind::Property);
assert!(secrets.body.contains("Snowflake secrets"));
let scala = hover_on("CREATE PROCEDURE p() LANGUAGE SCALA AS $$x$$;", "SCALA");
assert_eq!(scala.kind, HoverKind::Language);
assert!(scala.body.contains("Snowpark Scala"));
let sql_language = hover_on(
"CREATE PROCEDURE p() LANGUAGE SQL AS BEGIN RETURN 1; END",
"SQL",
);
assert_eq!(sql_language.kind, HoverKind::Language);
assert!(sql_language.body.contains("Snowflake Scripting"));
}
#[test]
fn snowflake_types_have_hover_even_in_unicode_and_crlf_source() {
let sql = "SELECT '長芋'::VARIANT AS payload\r\nSELECT 1::NUMBER;";
let variant = hover_on(sql, "VARIANT");
assert_eq!(variant.kind, HoverKind::Type);
assert!(variant.body.contains("Semi-structured"));
let number = hover_on(sql, "NUMBER");
assert_eq!(number.kind, HoverKind::Type);
assert!(number.body.contains("fixed-point"));
}
#[test]
fn broken_mid_edit_sql_does_not_panic() {
let sql = "CREATE TASK t SCHEDULE = '5 MINUTES AS SELECT";
let hover = hover_on(sql, "TASK");
assert_eq!(hover.kind, HoverKind::Task);
}