diff --git a/tests/common/mod.rs b/tests/common/mod.rs index e7ca2e3b..35db34e6 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -53,25 +53,34 @@ pub async fn req_path( main_handler(req).await } -pub async fn srv_req_path_with_app_data( +const REQ_TIMEOUT: Duration = Duration::from_secs(8); +pub async fn req_path_with_app_data( path: impl AsRef, app_data: Data, -) -> actix_web::dev::ServiceRequest { - test::TestRequest::get() - .uri(path.as_ref()) - .app_data(app_data) - .insert_header(("cookie", "test_cook=123")) - .insert_header(("authorization", "Basic dGVzdDp0ZXN0")) // test:test - .to_srv_request() +) -> anyhow::Result { + req_path_with_app_data_and_accept(path, app_data, header::Accept::html()).await } -const REQ_TIMEOUT: Duration = Duration::from_secs(8); -pub async fn req_path_with_app_data( +pub async fn req_path_with_app_data_json( path: impl AsRef, app_data: Data, +) -> anyhow::Result { + req_path_with_app_data_and_accept(path, app_data, header::Accept::json()).await +} + +async fn req_path_with_app_data_and_accept( + path: impl AsRef, + app_data: Data, + accept: header::Accept, ) -> anyhow::Result { let path = path.as_ref(); - let req = srv_req_path_with_app_data(path, app_data).await; + let req = test::TestRequest::get() + .uri(path) + .app_data(app_data) + .insert_header(("cookie", "test_cook=123")) + .insert_header(("authorization", "Basic dGVzdDp0ZXN0")) + .insert_header(accept) + .to_srv_request(); let resp = tokio::time::timeout(REQ_TIMEOUT, main_handler(req)) .await .map_err(|e| anyhow::anyhow!("Request to {path} timed out: {e}"))? diff --git a/tests/core/mod.rs b/tests/core/mod.rs index 70f552e4..25efc764 100644 --- a/tests/core/mod.rs +++ b/tests/core/mod.rs @@ -88,7 +88,7 @@ async fn test_routing_with_prefix() { let app_data = actix_web::web::Data::new(state); let resp = req_path_with_app_data( - "/prefix/tests/sql_test_files/it_works_simple.sql", + "/prefix/tests/sql_test_files/component_rendering/simple.sql", app_data.clone(), ) .await @@ -121,9 +121,12 @@ async fn test_routing_with_prefix() { .to_string(); assert!(resp.to_lowercase().contains("forbidden"), "{resp}"); - let resp = req_path_with_app_data("/tests/sql_test_files/it_works_simple.sql", app_data) - .await - .unwrap(); + let resp = req_path_with_app_data( + "/tests/sql_test_files/component_rendering/simple.sql", + app_data, + ) + .await + .unwrap(); assert_eq!(resp.status(), StatusCode::MOVED_PERMANENTLY); let location = resp .headers() diff --git a/tests/core/select_temp_t.sql b/tests/core/select_temp_t.sql index ec74c193..aed09336 100644 --- a/tests/core/select_temp_t.sql +++ b/tests/core/select_temp_t.sql @@ -1,2 +1,2 @@ --- see tests/sql_test_files/it_works_temp_table_accessible_in_run_sql.sql +-- see tests/sql_test_files/component_rendering/temp_table_accessible_in_run_sql_nomssql.sql select 'text' as component, x as contents from temp_t; \ No newline at end of file diff --git a/tests/data_formats/mod.rs b/tests/data_formats/mod.rs index 1416f0f0..c195d554 100644 --- a/tests/data_formats/mod.rs +++ b/tests/data_formats/mod.rs @@ -96,7 +96,7 @@ async fn test_json_columns() { #[actix_web::test] async fn test_accept_json_returns_json_array() -> actix_web::Result<()> { let resp = req_with_accept( - "/tests/sql_test_files/it_works_simple.sql", + "/tests/sql_test_files/component_rendering/simple.sql", "application/json", ) .await?; @@ -117,7 +117,7 @@ async fn test_accept_json_returns_json_array() -> actix_web::Result<()> { #[actix_web::test] async fn test_accept_ndjson_returns_jsonlines() -> actix_web::Result<()> { let resp = req_with_accept( - "/tests/sql_test_files/it_works_simple.sql", + "/tests/sql_test_files/component_rendering/simple.sql", "application/x-ndjson", ) .await?; @@ -143,7 +143,11 @@ async fn test_accept_ndjson_returns_jsonlines() -> actix_web::Result<()> { #[actix_web::test] async fn test_accept_html_returns_html() -> actix_web::Result<()> { - let resp = req_with_accept("/tests/sql_test_files/it_works_simple.sql", "text/html").await?; + let resp = req_with_accept( + "/tests/sql_test_files/component_rendering/simple.sql", + "text/html", + ) + .await?; assert_eq!(resp.status(), StatusCode::OK); assert_eq!( resp.headers().get(header::CONTENT_TYPE).unwrap(), @@ -156,7 +160,11 @@ async fn test_accept_html_returns_html() -> actix_web::Result<()> { #[actix_web::test] async fn test_accept_wildcard_returns_html() -> actix_web::Result<()> { - let resp = req_with_accept("/tests/sql_test_files/it_works_simple.sql", "*/*").await?; + let resp = req_with_accept( + "/tests/sql_test_files/component_rendering/simple.sql", + "*/*", + ) + .await?; assert_eq!(resp.status(), StatusCode::OK); assert_eq!( resp.headers().get(header::CONTENT_TYPE).unwrap(), diff --git a/tests/server_timing/mod.rs b/tests/server_timing/mod.rs index 1cbb752c..6d0a42fa 100644 --- a/tests/server_timing/mod.rs +++ b/tests/server_timing/mod.rs @@ -10,7 +10,7 @@ async fn test_server_timing_disabled_in_production() -> actix_web::Result<()> { let app_data = make_app_data_from_config(config).await; let req = crate::common::get_request_to_with_data( - "/tests/sql_test_files/it_works_simple.sql", + "/tests/sql_test_files/component_rendering/simple.sql", app_data, ) .await? @@ -32,7 +32,7 @@ async fn test_server_timing_enabled_in_development() -> actix_web::Result<()> { let app_data = make_app_data_from_config(config).await; let req = crate::common::get_request_to_with_data( - "/tests/sql_test_files/it_works_sqrt.sql", + "/tests/sql_test_files/data/postgres_cast_syntax.sql", app_data, ) .await? @@ -72,7 +72,7 @@ async fn test_server_timing_enabled_in_development() -> actix_web::Result<()> { #[actix_web::test] async fn test_server_timing_format() -> actix_web::Result<()> { - let req = get_request_to("/tests/sql_test_files/it_works_sqrt.sql") + let req = get_request_to("/tests/sql_test_files/data/postgres_cast_syntax.sql") .await? .to_srv_request(); let resp = main_handler(req).await?; diff --git a/tests/sql_test_files/README.md b/tests/sql_test_files/README.md index a3447f4e..f28b3722 100644 --- a/tests/sql_test_files/README.md +++ b/tests/sql_test_files/README.md @@ -1,16 +1,18 @@ -The sql files in this folder are all tested automatically. +The sql files in this folder are all tested automatically. They are organized in +two subdirectories: -## `it_works_` files +## `component_rendering/` -Files with names starting with `it_works` should all -return a page that contains the text "It works !" and does not contain the -text "error" (case insensitive) when executed. +Files that depend on SQLPage's HTML rendering (components, shells, redirects, +etc.). Every file that does not start with `error_` must render a page that +contains the text "It works !" and no occurrence of the word "error" (case +insensitive). `error_` files should return a page containing the word "error" +and the rest of the file name. Files may include `nosqlite`, `nomssql`, +`nopostgres` or `nomysql` in their name to skip incompatible backends. -If a file name contains `nosqlite`, `nomssql`, `nopostgres` or `nomysql`, then -the test will be ignored when running against the corresponding database. -This allows using syntax that is not supported on all databases in some tests. +## `data/` -## `error_` files - -Files with names starting with `error` should all return a page that contains -the text "error" and the rest of the file name when executed. \ No newline at end of file +Files that only validate data-processing functions should live here. They must +return rows with an `actual` column plus either `expected` (exact match) or +`expected_contains` (substring match). Tests in this directory are fetched as +JSON and validated row by row. \ No newline at end of file diff --git a/tests/sql_test_files/it_works_columns_component_json_nomssql_nopostgres.sql b/tests/sql_test_files/component_rendering/columns_component_json_nomssql_nopostgres.sql similarity index 100% rename from tests/sql_test_files/it_works_columns_component_json_nomssql_nopostgres.sql rename to tests/sql_test_files/component_rendering/columns_component_json_nomssql_nopostgres.sql diff --git a/tests/sql_test_files/it_works_deeply_nested_dynamic_components.sql b/tests/sql_test_files/component_rendering/deeply_nested_dynamic_components.sql similarity index 100% rename from tests/sql_test_files/it_works_deeply_nested_dynamic_components.sql rename to tests/sql_test_files/component_rendering/deeply_nested_dynamic_components.sql diff --git a/tests/sql_test_files/it_works_default_component.sql b/tests/sql_test_files/component_rendering/default_component.sql similarity index 100% rename from tests/sql_test_files/it_works_default_component.sql rename to tests/sql_test_files/component_rendering/default_component.sql diff --git a/tests/sql_test_files/it_works_download_base64.sql b/tests/sql_test_files/component_rendering/download_base64.sql similarity index 100% rename from tests/sql_test_files/it_works_download_base64.sql rename to tests/sql_test_files/component_rendering/download_base64.sql diff --git a/tests/sql_test_files/it_works_download_raw.sql b/tests/sql_test_files/component_rendering/download_raw.sql similarity index 100% rename from tests/sql_test_files/it_works_download_raw.sql rename to tests/sql_test_files/component_rendering/download_raw.sql diff --git a/tests/sql_test_files/it_works_dynamic_nested.sql b/tests/sql_test_files/component_rendering/dynamic_nested.sql similarity index 100% rename from tests/sql_test_files/it_works_dynamic_nested.sql rename to tests/sql_test_files/component_rendering/dynamic_nested.sql diff --git a/tests/sql_test_files/it_works_dynamic_repeated_properties.sql b/tests/sql_test_files/component_rendering/dynamic_repeated_properties.sql similarity index 100% rename from tests/sql_test_files/it_works_dynamic_repeated_properties.sql rename to tests/sql_test_files/component_rendering/dynamic_repeated_properties.sql diff --git a/tests/sql_test_files/component_rendering/dynamic_run_sql_include.sql b/tests/sql_test_files/component_rendering/dynamic_run_sql_include.sql new file mode 100644 index 00000000..c834e1f0 --- /dev/null +++ b/tests/sql_test_files/component_rendering/dynamic_run_sql_include.sql @@ -0,0 +1,2 @@ +select 'dynamic' as component, + sqlpage.run_sql('tests/sql_test_files/component_rendering/dynamic_shell.sql') as properties; diff --git a/tests/sql_test_files/it_works_dynamic_shell.sql b/tests/sql_test_files/component_rendering/dynamic_shell.sql similarity index 100% rename from tests/sql_test_files/it_works_dynamic_shell.sql rename to tests/sql_test_files/component_rendering/dynamic_shell.sql diff --git a/tests/sql_test_files/it_works_dynamic_toplevel.sql b/tests/sql_test_files/component_rendering/dynamic_toplevel.sql similarity index 100% rename from tests/sql_test_files/it_works_dynamic_toplevel.sql rename to tests/sql_test_files/component_rendering/dynamic_toplevel.sql diff --git a/tests/sql_test_files/error_arbitrary_SQL_expressions_as_function_arguments_are_not_supported.sql b/tests/sql_test_files/component_rendering/error_arbitrary_SQL_expressions_as_function_arguments_are_not_supported.sql similarity index 100% rename from tests/sql_test_files/error_arbitrary_SQL_expressions_as_function_arguments_are_not_supported.sql rename to tests/sql_test_files/component_rendering/error_arbitrary_SQL_expressions_as_function_arguments_are_not_supported.sql diff --git a/tests/sql_test_files/error_cookie_component_cannot_be_used_after_data_has_already_been_sent.sql b/tests/sql_test_files/component_rendering/error_cookie_component_cannot_be_used_after_data_has_already_been_sent.sql similarity index 100% rename from tests/sql_test_files/error_cookie_component_cannot_be_used_after_data_has_already_been_sent.sql rename to tests/sql_test_files/component_rendering/error_cookie_component_cannot_be_used_after_data_has_already_been_sent.sql diff --git a/tests/sql_test_files/error_failed_to_import_the_csv.sql b/tests/sql_test_files/component_rendering/error_failed_to_import_the_csv.sql similarity index 100% rename from tests/sql_test_files/error_failed_to_import_the_csv.sql rename to tests/sql_test_files/component_rendering/error_failed_to_import_the_csv.sql diff --git a/tests/sql_test_files/error_invalid_json_in_dynamic_component.sql b/tests/sql_test_files/component_rendering/error_invalid_json_in_dynamic_component.sql similarity index 100% rename from tests/sql_test_files/error_invalid_json_in_dynamic_component.sql rename to tests/sql_test_files/component_rendering/error_invalid_json_in_dynamic_component.sql diff --git a/tests/sql_test_files/error_single_shell_per_page.sql b/tests/sql_test_files/component_rendering/error_single_shell_per_page.sql similarity index 100% rename from tests/sql_test_files/error_single_shell_per_page.sql rename to tests/sql_test_files/component_rendering/error_single_shell_per_page.sql diff --git a/tests/sql_test_files/error_the_dynamic_component_requires_a_property_named.sql b/tests/sql_test_files/component_rendering/error_the_dynamic_component_requires_a_property_named.sql similarity index 100% rename from tests/sql_test_files/error_the_dynamic_component_requires_a_property_named.sql rename to tests/sql_test_files/component_rendering/error_the_dynamic_component_requires_a_property_named.sql diff --git a/tests/sql_test_files/component_rendering/error_too_many_nested_inclusions.sql b/tests/sql_test_files/component_rendering/error_too_many_nested_inclusions.sql new file mode 100644 index 00000000..c35c0322 --- /dev/null +++ b/tests/sql_test_files/component_rendering/error_too_many_nested_inclusions.sql @@ -0,0 +1,4 @@ +select 'debug' as component, + sqlpage.run_sql( + 'tests/sql_test_files/component_rendering/error_too_many_nested_inclusions.sql' + ) as contents; \ No newline at end of file diff --git a/tests/sql_test_files/error_unknown_field.sql b/tests/sql_test_files/component_rendering/error_unknown_field.sql similarity index 100% rename from tests/sql_test_files/error_unknown_field.sql rename to tests/sql_test_files/component_rendering/error_unknown_field.sql diff --git a/tests/sql_test_files/it_works_log.sql b/tests/sql_test_files/component_rendering/log.sql similarity index 100% rename from tests/sql_test_files/it_works_log.sql rename to tests/sql_test_files/component_rendering/log.sql diff --git a/tests/sql_test_files/it_works_markdown_in_table.sql b/tests/sql_test_files/component_rendering/markdown_in_table.sql similarity index 100% rename from tests/sql_test_files/it_works_markdown_in_table.sql rename to tests/sql_test_files/component_rendering/markdown_in_table.sql diff --git a/tests/sql_test_files/component_rendering/run_sql.sql b/tests/sql_test_files/component_rendering/run_sql.sql new file mode 100644 index 00000000..420b306a --- /dev/null +++ b/tests/sql_test_files/component_rendering/run_sql.sql @@ -0,0 +1,2 @@ +select 'dynamic' as component, + sqlpage.run_sql('tests/sql_test_files/component_rendering/simple.sql') as properties; diff --git a/tests/sql_test_files/it_works_run_sql_from_database.sql b/tests/sql_test_files/component_rendering/run_sql_from_database.sql similarity index 100% rename from tests/sql_test_files/it_works_run_sql_from_database.sql rename to tests/sql_test_files/component_rendering/run_sql_from_database.sql diff --git a/tests/sql_test_files/it_works_run_sql_variable_access.sql b/tests/sql_test_files/component_rendering/run_sql_variable_access.sql similarity index 100% rename from tests/sql_test_files/it_works_run_sql_variable_access.sql rename to tests/sql_test_files/component_rendering/run_sql_variable_access.sql diff --git a/tests/sql_test_files/it_works_shell_search.sql b/tests/sql_test_files/component_rendering/shell_search.sql similarity index 100% rename from tests/sql_test_files/it_works_shell_search.sql rename to tests/sql_test_files/component_rendering/shell_search.sql diff --git a/tests/sql_test_files/it_works_simple.sql b/tests/sql_test_files/component_rendering/simple.sql similarity index 100% rename from tests/sql_test_files/it_works_simple.sql rename to tests/sql_test_files/component_rendering/simple.sql diff --git a/tests/sql_test_files/it_works_temp_table_accessible_in_run_sql_nomssql.sql b/tests/sql_test_files/component_rendering/temp_table_accessible_in_run_sql_nomssql.sql similarity index 100% rename from tests/sql_test_files/it_works_temp_table_accessible_in_run_sql_nomssql.sql rename to tests/sql_test_files/component_rendering/temp_table_accessible_in_run_sql_nomssql.sql diff --git a/tests/sql_test_files/it_works_text_markdown.sql b/tests/sql_test_files/component_rendering/text_markdown.sql similarity index 100% rename from tests/sql_test_files/it_works_text_markdown.sql rename to tests/sql_test_files/component_rendering/text_markdown.sql diff --git a/tests/sql_test_files/it_works_text_unsafe_markdown.sql b/tests/sql_test_files/component_rendering/text_unsafe_markdown.sql similarity index 100% rename from tests/sql_test_files/it_works_text_unsafe_markdown.sql rename to tests/sql_test_files/component_rendering/text_unsafe_markdown.sql diff --git a/tests/sql_test_files/it_works_without_a_shell.sql b/tests/sql_test_files/component_rendering/without_a_shell.sql similarity index 100% rename from tests/sql_test_files/it_works_without_a_shell.sql rename to tests/sql_test_files/component_rendering/without_a_shell.sql diff --git a/tests/sql_test_files/data/basic_auth_password.sql b/tests/sql_test_files/data/basic_auth_password.sql new file mode 100644 index 00000000..9bded9cd --- /dev/null +++ b/tests/sql_test_files/data/basic_auth_password.sql @@ -0,0 +1 @@ +select 'test' as expected, sqlpage.basic_auth_password() as actual; diff --git a/tests/sql_test_files/data/basic_auth_username.sql b/tests/sql_test_files/data/basic_auth_username.sql new file mode 100644 index 00000000..f32170d1 --- /dev/null +++ b/tests/sql_test_files/data/basic_auth_username.sql @@ -0,0 +1 @@ +select 'test' as expected, sqlpage.basic_auth_username() as actual; diff --git a/tests/sql_test_files/it_works_case_variables.sql b/tests/sql_test_files/data/case_variables.sql similarity index 80% rename from tests/sql_test_files/it_works_case_variables.sql rename to tests/sql_test_files/data/case_variables.sql index 44d68510..7733ac01 100644 --- a/tests/sql_test_files/it_works_case_variables.sql +++ b/tests/sql_test_files/data/case_variables.sql @@ -3,8 +3,8 @@ set success = 'It works !'; set failure = 'You should never see this'; -select 'text' as component, +select 'It works !' as expected, case $success when $success then $success when $failure then $failure - end AS contents; \ No newline at end of file + end as actual; \ No newline at end of file diff --git a/tests/sql_test_files/data/client_ip.sql b/tests/sql_test_files/data/client_ip.sql new file mode 100644 index 00000000..ac1996e7 --- /dev/null +++ b/tests/sql_test_files/data/client_ip.sql @@ -0,0 +1,2 @@ +select NULL as expected, + sqlpage.client_ip() as actual; \ No newline at end of file diff --git a/tests/sql_test_files/data/coalesce_eval.sql b/tests/sql_test_files/data/coalesce_eval.sql new file mode 100644 index 00000000..4f455e5b --- /dev/null +++ b/tests/sql_test_files/data/coalesce_eval.sql @@ -0,0 +1 @@ +select 'https://example.com' as expected, sqlpage.link(coalesce($i_do_not_exist, 'https://example.com')) as actual; diff --git a/tests/sql_test_files/data/concat_str_in_pseudofunction.sql b/tests/sql_test_files/data/concat_str_in_pseudofunction.sql new file mode 100644 index 00000000..724e44b1 --- /dev/null +++ b/tests/sql_test_files/data/concat_str_in_pseudofunction.sql @@ -0,0 +1,3 @@ +select '%2F1' as expected, sqlpage.url_encode('/' || $x) as actual; +select '%2F1' as expected, sqlpage.url_encode(CONCAT('/', $x)) as actual; +select NULL as expected, sqlpage.url_encode(CONCAT('/', $thisisnull)) as actual; diff --git a/tests/sql_test_files/data/cookie.sql b/tests/sql_test_files/data/cookie.sql new file mode 100644 index 00000000..4e7275ee --- /dev/null +++ b/tests/sql_test_files/data/cookie.sql @@ -0,0 +1 @@ +select '123' as expected, sqlpage.cookie('test_cook') as actual; diff --git a/tests/sql_test_files/it_works_create_table.sql b/tests/sql_test_files/data/create_table.sql similarity index 65% rename from tests/sql_test_files/it_works_create_table.sql rename to tests/sql_test_files/data/create_table.sql index e3ec8f39..1bfb3ecb 100644 --- a/tests/sql_test_files/it_works_create_table.sql +++ b/tests/sql_test_files/data/create_table.sql @@ -3,5 +3,4 @@ create table my_tmp_store(x varchar(100)); insert into my_tmp_store(x) values ('It works !'); -select 'card' as component; -select x as description from my_tmp_store; \ No newline at end of file +select 'It works !' as expected, x as actual from my_tmp_store; \ No newline at end of file diff --git a/tests/sql_test_files/data/decimal.sql b/tests/sql_test_files/data/decimal.sql new file mode 100644 index 00000000..8b8cb82f --- /dev/null +++ b/tests/sql_test_files/data/decimal.sql @@ -0,0 +1,2 @@ +set result = CAST(0.47 AS DECIMAL(3,2)); +select '0.47' as expected, $result as actual; diff --git a/tests/sql_test_files/it_works_delayed_function_call.sql b/tests/sql_test_files/data/delayed_function_call.sql similarity index 59% rename from tests/sql_test_files/it_works_delayed_function_call.sql rename to tests/sql_test_files/data/delayed_function_call.sql index 30a9db51..57c15660 100644 --- a/tests/sql_test_files/it_works_delayed_function_call.sql +++ b/tests/sql_test_files/data/delayed_function_call.sql @@ -1,4 +1,6 @@ drop table if exists files_to_read; create table files_to_read(filepath varchar(100)); insert into files_to_read(filepath) values ('tests/it_works.txt'); -select 'text' as component, sqlpage.read_file_as_text(filepath) as contents from files_to_read; +select 'It works !' as expected, + sqlpage.read_file_as_text(filepath) as actual +from files_to_read; diff --git a/tests/sql_test_files/data/env_var_empty.sql b/tests/sql_test_files/data/env_var_empty.sql new file mode 100644 index 00000000..a5c7e39b --- /dev/null +++ b/tests/sql_test_files/data/env_var_empty.sql @@ -0,0 +1,2 @@ +select NULL as expected, + sqlpage.environment_variable('I_DO_NOT_EXIST') as actual; \ No newline at end of file diff --git a/tests/sql_test_files/data/exec.sql b/tests/sql_test_files/data/exec.sql new file mode 100644 index 00000000..cd04a5a4 --- /dev/null +++ b/tests/sql_test_files/data/exec.sql @@ -0,0 +1,2 @@ +select 'It works !' as expected_contains, + sqlpage.exec('echo', 'It', $thisisnull, 'works', '!') as actual; \ No newline at end of file diff --git a/tests/sql_test_files/data/fetch_base64.sql b/tests/sql_test_files/data/fetch_base64.sql new file mode 100644 index 00000000..8bda27e4 --- /dev/null +++ b/tests/sql_test_files/data/fetch_base64.sql @@ -0,0 +1,6 @@ +set res = sqlpage.fetch('{ + "url": "http://localhost:' || $echo_port || '/hello_world", + "response_encoding": "base64" +}'); +select 'R0VUIC9oZWxsb193b3Js' as expected_contains, + $res as actual; diff --git a/tests/sql_test_files/data/fetch_hex.sql b/tests/sql_test_files/data/fetch_hex.sql new file mode 100644 index 00000000..f4eb1286 --- /dev/null +++ b/tests/sql_test_files/data/fetch_hex.sql @@ -0,0 +1,6 @@ +set res = sqlpage.fetch('{ + "url": "http://localhost:' || $echo_port || '/hello_world", + "response_encoding": "hex" +}'); +select '474554202f68656c6c6f5f776f726c64' as expected_contains, + $res as actual; diff --git a/tests/sql_test_files/it_works_fetch_native_json_array_impl.sql b/tests/sql_test_files/data/fetch_native_json_array_impl.sql similarity index 70% rename from tests/sql_test_files/it_works_fetch_native_json_array_impl.sql rename to tests/sql_test_files/data/fetch_native_json_array_impl.sql index 6e2c6e49..f98c56d9 100644 --- a/tests/sql_test_files/it_works_fetch_native_json_array_impl.sql +++ b/tests/sql_test_files/data/fetch_native_json_array_impl.sql @@ -6,11 +6,5 @@ set res = sqlpage.fetch(json_object( 'body', json_array('hello', 'world') )); set expected = 'POST /post|accept-encoding: br, gzip, deflate, zstd|content-length: 17|content-type: application/json|host: localhost:' || $echo_port || '|user-agent: sqlpage|x-custom: 1|["hello","world"]'; -select 'text' as component, - case $res - when $expected then 'It works !' - else 'It failed ! Expected: -' || $expected || ' -Got: -' || $res - end as contents; \ No newline at end of file +select $expected as expected, + $res as actual; \ No newline at end of file diff --git a/tests/sql_test_files/it_works_fetch_post.sql b/tests/sql_test_files/data/fetch_post.sql similarity index 66% rename from tests/sql_test_files/it_works_fetch_post.sql rename to tests/sql_test_files/data/fetch_post.sql index 0503ec28..6c4c8bdb 100644 --- a/tests/sql_test_files/it_works_fetch_post.sql +++ b/tests/sql_test_files/data/fetch_post.sql @@ -2,11 +2,5 @@ set url = 'http://localhost:' || $echo_port || '/post'; set fetch_request = '{"method": "POST", "url": "' || $url || '", "headers": {"x-custom": "1"}, "body": {"hello": "world"}}'; set res = sqlpage.fetch($fetch_request); set expected = 'POST /post|accept-encoding: br, gzip, deflate, zstd|content-length: 18|content-type: application/json|host: localhost:' || $echo_port || '|user-agent: sqlpage|x-custom: 1|{"hello": "world"}'; -select 'text' as component, - case $res - when $expected then 'It works !' - else 'It failed ! Expected: -' || COALESCE($expected, 'null') || ' -Got: -' || COALESCE($res, 'null') - end as contents; \ No newline at end of file +select $expected as expected, + $res as actual; \ No newline at end of file diff --git a/tests/sql_test_files/data/fetch_simple.sql b/tests/sql_test_files/data/fetch_simple.sql new file mode 100644 index 00000000..3dd3f4d5 --- /dev/null +++ b/tests/sql_test_files/data/fetch_simple.sql @@ -0,0 +1,4 @@ +set url = 'http://localhost:' || $echo_port || '/hello_world'; +set res = sqlpage.fetch($url); +select 'GET /hello_world' as expected_contains, + $res as actual; \ No newline at end of file diff --git a/tests/sql_test_files/data/fetch_with_meta_error.sql b/tests/sql_test_files/data/fetch_with_meta_error.sql new file mode 100644 index 00000000..2910ae62 --- /dev/null +++ b/tests/sql_test_files/data/fetch_with_meta_error.sql @@ -0,0 +1,3 @@ +set res = sqlpage.fetch_with_meta('http://not-a-real-url'); + +select '"error":"Request failed' as expected_contains, $res as actual; diff --git a/tests/sql_test_files/it_works_fetch_with_meta_simple.sql b/tests/sql_test_files/data/fetch_with_meta_simple.sql similarity index 53% rename from tests/sql_test_files/it_works_fetch_with_meta_simple.sql rename to tests/sql_test_files/data/fetch_with_meta_simple.sql index ef1d6e73..4f4ab11f 100644 --- a/tests/sql_test_files/it_works_fetch_with_meta_simple.sql +++ b/tests/sql_test_files/data/fetch_with_meta_simple.sql @@ -8,8 +8,7 @@ set fetch_req = '{ }'; set res = sqlpage.fetch_with_meta($fetch_req); -select 'text' as component, - case - when $res LIKE '%"status":200%' AND $res LIKE '%"headers":{%' AND $res LIKE '%"body":"%' then 'It works !' - else 'Error! Got: ' || $res - end as contents; \ No newline at end of file +select '"status":200' as expected_contains, + '"headers":{' as expected_contains, + '"body":"' as expected_contains, + $res as actual; diff --git a/tests/sql_test_files/data/hash_password.sql b/tests/sql_test_files/data/hash_password.sql new file mode 100644 index 00000000..42a9b40a --- /dev/null +++ b/tests/sql_test_files/data/hash_password.sql @@ -0,0 +1,2 @@ +select '$argon2id$' as expected_contains, + coalesce(sqlpage.hash_password($x), 'NULL') as actual; diff --git a/tests/sql_test_files/data/hash_password_null.sql b/tests/sql_test_files/data/hash_password_null.sql new file mode 100644 index 00000000..c39826e1 --- /dev/null +++ b/tests/sql_test_files/data/hash_password_null.sql @@ -0,0 +1 @@ +select NULL as expected, sqlpage.hash_password(null) as actual; diff --git a/tests/sql_test_files/data/header.sql b/tests/sql_test_files/data/header.sql new file mode 100644 index 00000000..50cbac97 --- /dev/null +++ b/tests/sql_test_files/data/header.sql @@ -0,0 +1 @@ +select 'test_cook=123' as expected, sqlpage.header('cookie') as actual; diff --git a/tests/sql_test_files/data/headers.sql b/tests/sql_test_files/data/headers.sql new file mode 100644 index 00000000..01ce101c --- /dev/null +++ b/tests/sql_test_files/data/headers.sql @@ -0,0 +1 @@ +select '"cookie":"test_cook=123"' as expected_contains, sqlpage.headers() as actual; diff --git a/tests/sql_test_files/data/hmac_base64.sql b/tests/sql_test_files/data/hmac_base64.sql new file mode 100644 index 00000000..d68a1c18 --- /dev/null +++ b/tests/sql_test_files/data/hmac_base64.sql @@ -0,0 +1,2 @@ +select '97yD9DBThCSxMpjmqm+xQ+9NWaFJRhdZl0edvC0aPNg=' as expected, + sqlpage.hmac('The quick brown fox jumps over the lazy dog', 'key', 'sha256-base64') as actual; \ No newline at end of file diff --git a/tests/sql_test_files/data/hmac_default.sql b/tests/sql_test_files/data/hmac_default.sql new file mode 100644 index 00000000..f3420316 --- /dev/null +++ b/tests/sql_test_files/data/hmac_default.sql @@ -0,0 +1,2 @@ +select sqlpage.hmac('test data', 'test key', 'sha256') as expected, + sqlpage.hmac('test data', 'test key') as actual; \ No newline at end of file diff --git a/tests/sql_test_files/data/hmac_sha256.sql b/tests/sql_test_files/data/hmac_sha256.sql new file mode 100644 index 00000000..f104bd8e --- /dev/null +++ b/tests/sql_test_files/data/hmac_sha256.sql @@ -0,0 +1,2 @@ +select 'f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8' as expected, + sqlpage.hmac('The quick brown fox jumps over the lazy dog', 'key', 'sha256') as actual; \ No newline at end of file diff --git a/tests/sql_test_files/data/hmac_sha512.sql b/tests/sql_test_files/data/hmac_sha512.sql new file mode 100644 index 00000000..837f642e --- /dev/null +++ b/tests/sql_test_files/data/hmac_sha512.sql @@ -0,0 +1,2 @@ +select 'b42af09057bac1e2d41708e48a902e09b5ff7f12ab428a4fe86653c73dd248fb82f948a549f7b791a5b41915ee4d1ec3935357e4e2317250d0372afa2ebeeb3a' as expected, + sqlpage.hmac('The quick brown fox jumps over the lazy dog', 'key', 'sha512') as actual; \ No newline at end of file diff --git a/tests/sql_test_files/data/hmac_shopify_webhook.sql b/tests/sql_test_files/data/hmac_shopify_webhook.sql new file mode 100644 index 00000000..552cccb9 --- /dev/null +++ b/tests/sql_test_files/data/hmac_shopify_webhook.sql @@ -0,0 +1,7 @@ +-- Test Shopify webhook HMAC validation with base64 output +select 'QNyObTlKbMx2qDlPF/ZOZcBqg5OgPg+2oky3zldc0Gw=' as expected, + sqlpage.hmac( + '{"id":1234567890,"email":"customer@example.com","total_price":"123.45"}', + 'test-webhook-secret', + 'sha256-base64' + ) as actual; \ No newline at end of file diff --git a/tests/sql_test_files/data/immutable_variables.sql b/tests/sql_test_files/data/immutable_variables.sql new file mode 100644 index 00000000..2fe3285c --- /dev/null +++ b/tests/sql_test_files/data/immutable_variables.sql @@ -0,0 +1,10 @@ +set x = 'set_value'; +set set_only = 'only_in_set'; + +select 'set_value' as expected, $x as actual; +select 'only_in_set' as expected, $set_only as actual; +select '{"x":"1"}' as expected, sqlpage.variables('get') as actual; +select '"x":"set_value"' as expected_contains, sqlpage.variables('set') as actual; +select '"set_only":"only_in_set"' as expected_contains, sqlpage.variables('set') as actual; +select '"x":"set_value"' as expected_contains, sqlpage.variables() as actual; +select '"set_only":"only_in_set"' as expected_contains, sqlpage.variables() as actual; diff --git a/tests/sql_test_files/data/link.sql b/tests/sql_test_files/data/link.sql new file mode 100644 index 00000000..47ca6003 --- /dev/null +++ b/tests/sql_test_files/data/link.sql @@ -0,0 +1 @@ +select 'test.sql?x=123' as expected, sqlpage.link('test.sql', json_object('x', 123)) as actual; diff --git a/tests/sql_test_files/data/link_null.sql b/tests/sql_test_files/data/link_null.sql new file mode 100644 index 00000000..4c7b82da --- /dev/null +++ b/tests/sql_test_files/data/link_null.sql @@ -0,0 +1 @@ +select 'test.sql' as expected, sqlpage.link('test.sql', json_object('x', null)) as actual; diff --git a/tests/sql_test_files/it_works_lower.sql b/tests/sql_test_files/data/lower.sql similarity index 58% rename from tests/sql_test_files/it_works_lower.sql rename to tests/sql_test_files/data/lower.sql index 5ddfde56..9ce03244 100644 --- a/tests/sql_test_files/it_works_lower.sql +++ b/tests/sql_test_files/data/lower.sql @@ -1,3 +1,4 @@ -- in SQLite, we provide our own unicode-aware lower function -- see https://github.com/sqlpage/SQLPage/issues/452 -select 'text' as component, COALESCE(lower(NULL), 'It works !') AS contents; \ No newline at end of file +select 'It works !' as expected, + coalesce(lower(NULL), 'It works !') as actual; \ No newline at end of file diff --git a/tests/sql_test_files/data/nested_sqlpage_functions.sql b/tests/sql_test_files/data/nested_sqlpage_functions.sql new file mode 100644 index 00000000..49eeb48e --- /dev/null +++ b/tests/sql_test_files/data/nested_sqlpage_functions.sql @@ -0,0 +1 @@ +select 'It%20works%20%21' as expected, sqlpage.url_encode(sqlpage.read_file_as_text('tests/it_works.txt')) as actual; diff --git a/tests/sql_test_files/data/path.sql b/tests/sql_test_files/data/path.sql new file mode 100644 index 00000000..31cb614a --- /dev/null +++ b/tests/sql_test_files/data/path.sql @@ -0,0 +1,2 @@ +select '/tests/sql_test_files/data/path.sql' as expected, + sqlpage.path() as actual; \ No newline at end of file diff --git a/tests/sql_test_files/data/postgres_cast_syntax.sql b/tests/sql_test_files/data/postgres_cast_syntax.sql new file mode 100644 index 00000000..53ce2ff8 --- /dev/null +++ b/tests/sql_test_files/data/postgres_cast_syntax.sql @@ -0,0 +1 @@ +select 2 as expected, $x::decimal + 1 as actual; diff --git a/tests/sql_test_files/data/protocol.sql b/tests/sql_test_files/data/protocol.sql new file mode 100644 index 00000000..ae6bbad7 --- /dev/null +++ b/tests/sql_test_files/data/protocol.sql @@ -0,0 +1,2 @@ +select 'http' as expected, + sqlpage.protocol() as actual; \ No newline at end of file diff --git a/tests/sql_test_files/data/query_string.sql b/tests/sql_test_files/data/query_string.sql new file mode 100644 index 00000000..c7624f09 --- /dev/null +++ b/tests/sql_test_files/data/query_string.sql @@ -0,0 +1 @@ +select '?x=1' as expected, sqlpage.link('', sqlpage.variables('get')) as actual; diff --git a/tests/sql_test_files/data/random_string.sql b/tests/sql_test_files/data/random_string.sql new file mode 100644 index 00000000..e187c573 --- /dev/null +++ b/tests/sql_test_files/data/random_string.sql @@ -0,0 +1 @@ +select '' as expected, sqlpage.random_string(0) as actual; diff --git a/tests/sql_test_files/data/read_file_as_data_url.sql b/tests/sql_test_files/data/read_file_as_data_url.sql new file mode 100644 index 00000000..9aecf721 --- /dev/null +++ b/tests/sql_test_files/data/read_file_as_data_url.sql @@ -0,0 +1,3 @@ +set actual = sqlpage.read_file_as_data_url('tests/it_works.txt'); +select 'data:text/plain;base64,SXQgd29ya3MgIQ==' as expected, + coalesce($actual, 'NULL') as actual; diff --git a/tests/sql_test_files/data/read_file_as_text.sql b/tests/sql_test_files/data/read_file_as_text.sql new file mode 100644 index 00000000..bfb135b8 --- /dev/null +++ b/tests/sql_test_files/data/read_file_as_text.sql @@ -0,0 +1,2 @@ +select 'It works !' as expected, + sqlpage.read_file_as_text('tests/it_works.txt') as actual; diff --git a/tests/sql_test_files/data/request_method.sql b/tests/sql_test_files/data/request_method.sql new file mode 100644 index 00000000..fffb1337 --- /dev/null +++ b/tests/sql_test_files/data/request_method.sql @@ -0,0 +1,3 @@ +set actual = sqlpage.request_method(); +select 'GET' as expected, + coalesce($actual, 'NULL') as actual; diff --git a/tests/sql_test_files/data/set_case.sql b/tests/sql_test_files/data/set_case.sql new file mode 100644 index 00000000..8c573abc --- /dev/null +++ b/tests/sql_test_files/data/set_case.sql @@ -0,0 +1,2 @@ +set msg = case when 1=1 then 'It works !' else 'It failed !' end; +select 'It works !' as expected, $msg as actual; diff --git a/tests/sql_test_files/data/set_variable.sql b/tests/sql_test_files/data/set_variable.sql new file mode 100644 index 00000000..ba1bafe3 --- /dev/null +++ b/tests/sql_test_files/data/set_variable.sql @@ -0,0 +1,3 @@ +set what_does_it_do = 'wo' || 'rks'; +select 'It works !' as expected, + 'It ' || $what_does_it_do || ' !' as actual; diff --git a/tests/sql_test_files/data/set_variable_func.sql b/tests/sql_test_files/data/set_variable_func.sql new file mode 100644 index 00000000..d0fc5abc --- /dev/null +++ b/tests/sql_test_files/data/set_variable_func.sql @@ -0,0 +1,2 @@ +set result = sqlpage.set_variable('y', '2'); +select '?x=1&y=2' as expected, $result as actual; diff --git a/tests/sql_test_files/data/set_variable_func_null.sql b/tests/sql_test_files/data/set_variable_func_null.sql new file mode 100644 index 00000000..8cf9a2b5 --- /dev/null +++ b/tests/sql_test_files/data/set_variable_func_null.sql @@ -0,0 +1,2 @@ +set result = sqlpage.set_variable('x', null); +select '?' as expected, $result as actual; diff --git a/tests/sql_test_files/data/set_variable_func_replace.sql b/tests/sql_test_files/data/set_variable_func_replace.sql new file mode 100644 index 00000000..859e280c --- /dev/null +++ b/tests/sql_test_files/data/set_variable_func_replace.sql @@ -0,0 +1,2 @@ +set result = sqlpage.set_variable('x', '2'); +select '?x=2' as expected, $result as actual; diff --git a/tests/sql_test_files/data/set_variable_large_integer.sql b/tests/sql_test_files/data/set_variable_large_integer.sql new file mode 100644 index 00000000..0c839afd --- /dev/null +++ b/tests/sql_test_files/data/set_variable_large_integer.sql @@ -0,0 +1,2 @@ +SET result = 123456789123456789123456789; +select '123456789123456789123456789' as expected, $result as actual; diff --git a/tests/sql_test_files/data/set_variable_numeric.sql b/tests/sql_test_files/data/set_variable_numeric.sql new file mode 100644 index 00000000..60d25fbb --- /dev/null +++ b/tests/sql_test_files/data/set_variable_numeric.sql @@ -0,0 +1,3 @@ +set two = 2; +select '2' as expected, + $two as actual; diff --git a/tests/sql_test_files/data/set_variable_to_null.sql b/tests/sql_test_files/data/set_variable_to_null.sql new file mode 100644 index 00000000..505b9991 --- /dev/null +++ b/tests/sql_test_files/data/set_variable_to_null.sql @@ -0,0 +1,3 @@ +set i_am_null = NULL; +select NULL as expected, + $i_am_null as actual; diff --git a/tests/sql_test_files/data/set_variable_to_other_variable.sql b/tests/sql_test_files/data/set_variable_to_other_variable.sql new file mode 100644 index 00000000..e6c8a52c --- /dev/null +++ b/tests/sql_test_files/data/set_variable_to_other_variable.sql @@ -0,0 +1,4 @@ +SET x = 42; +SET y = $x; +SET z = $y; +select '42' as expected, $z as actual; diff --git a/tests/sql_test_files/data/set_variable_to_sqlpage_function.sql b/tests/sql_test_files/data/set_variable_to_sqlpage_function.sql new file mode 100644 index 00000000..7fc0c515 --- /dev/null +++ b/tests/sql_test_files/data/set_variable_to_sqlpage_function.sql @@ -0,0 +1,3 @@ +set my_var = sqlpage.url_encode(' '); +select '%20' as expected, + $my_var as actual; \ No newline at end of file diff --git a/tests/sql_test_files/data/set_variable_to_sqlpage_post_function.sql b/tests/sql_test_files/data/set_variable_to_sqlpage_post_function.sql new file mode 100644 index 00000000..56ee3578 --- /dev/null +++ b/tests/sql_test_files/data/set_variable_to_sqlpage_post_function.sql @@ -0,0 +1,3 @@ +set my_var = sqlpage.url_encode(UPPER('a')); +select 'A' as expected, + $my_var as actual; \ No newline at end of file diff --git a/tests/sql_test_files/data/sqlite_unicode_upper.sql b/tests/sql_test_files/data/sqlite_unicode_upper.sql new file mode 100644 index 00000000..a6fb751c --- /dev/null +++ b/tests/sql_test_files/data/sqlite_unicode_upper.sql @@ -0,0 +1,3 @@ +-- Checks that the UPPER function is working correctly with unicode characters. +select 'É' as expected, + UPPER('é') as actual; \ No newline at end of file diff --git a/tests/sql_test_files/data/sqrt.sql b/tests/sql_test_files/data/sqrt.sql new file mode 100644 index 00000000..921a46fc --- /dev/null +++ b/tests/sql_test_files/data/sqrt.sql @@ -0,0 +1,2 @@ +set result = sqrt(9.0); +select CAST(3.0 AS FLOAT) as expected, cast($result as FLOAT) as actual; diff --git a/tests/sql_test_files/data/uploaded_file_is_null.sql b/tests/sql_test_files/data/uploaded_file_is_null.sql new file mode 100644 index 00000000..86fcc53a --- /dev/null +++ b/tests/sql_test_files/data/uploaded_file_is_null.sql @@ -0,0 +1,2 @@ +set actual = sqlpage.uploaded_file_path('my_file'); +select null as expected, $actual as actual; diff --git a/tests/sql_test_files/data/url_encode.sql b/tests/sql_test_files/data/url_encode.sql new file mode 100644 index 00000000..9ced88b4 --- /dev/null +++ b/tests/sql_test_files/data/url_encode.sql @@ -0,0 +1,2 @@ +select '%2F' as expected, + sqlpage.url_encode('/') as actual; \ No newline at end of file diff --git a/tests/sql_test_files/it_works_varchar_nomysql.sql b/tests/sql_test_files/data/varchar_nomysql.sql similarity index 50% rename from tests/sql_test_files/it_works_varchar_nomysql.sql rename to tests/sql_test_files/data/varchar_nomysql.sql index 8bb4ba72..34716bf7 100644 --- a/tests/sql_test_files/it_works_varchar_nomysql.sql +++ b/tests/sql_test_files/data/varchar_nomysql.sql @@ -1,3 +1,4 @@ -- syntax is valid in SQLite, PostgreSQL and SQLServer -- no cast as varchar in MySQL -select 'text' as component, CAST('It works !' as varchar(100)) as contents; +select 'It works !' as expected, + CAST('It works !' as varchar(100)) as actual; diff --git a/tests/sql_test_files/data/variables_function.sql b/tests/sql_test_files/data/variables_function.sql new file mode 100644 index 00000000..36d9f48c --- /dev/null +++ b/tests/sql_test_files/data/variables_function.sql @@ -0,0 +1,2 @@ +select '{"x":"1"}' as expected, + sqlpage.variables('get') as actual; \ No newline at end of file diff --git a/tests/sql_test_files/data/variables_function_get_and_post.sql b/tests/sql_test_files/data/variables_function_get_and_post.sql new file mode 100644 index 00000000..b134c098 --- /dev/null +++ b/tests/sql_test_files/data/variables_function_get_and_post.sql @@ -0,0 +1,2 @@ +select '{"x":"1"}' as expected, + sqlpage.variables() as actual; \ No newline at end of file diff --git a/tests/sql_test_files/error_too_many_nested_inclusions.sql b/tests/sql_test_files/error_too_many_nested_inclusions.sql deleted file mode 100644 index a021bada..00000000 --- a/tests/sql_test_files/error_too_many_nested_inclusions.sql +++ /dev/null @@ -1,4 +0,0 @@ -select 'debug' as component, - sqlpage.run_sql( - 'tests/sql_test_files/error_too_many_nested_inclusions.sql' - ) as contents; \ No newline at end of file diff --git a/tests/sql_test_files/it_works_basic_auth_password.sql b/tests/sql_test_files/it_works_basic_auth_password.sql deleted file mode 100644 index 7397cdd0..00000000 --- a/tests/sql_test_files/it_works_basic_auth_password.sql +++ /dev/null @@ -1,5 +0,0 @@ -select 'text' as component, - case sqlpage.basic_auth_password() - when 'test' then 'It works !' - else 'error: ' || coalesce(sqlpage.basic_auth_password(), 'NULL') - end as contents; \ No newline at end of file diff --git a/tests/sql_test_files/it_works_basic_auth_username.sql b/tests/sql_test_files/it_works_basic_auth_username.sql deleted file mode 100644 index 6dd61057..00000000 --- a/tests/sql_test_files/it_works_basic_auth_username.sql +++ /dev/null @@ -1,5 +0,0 @@ -select 'text' as component, - case sqlpage.basic_auth_username() - when 'test' then 'It works !' - else 'error: ' || coalesce(sqlpage.basic_auth_username(), 'NULL') - end as contents; \ No newline at end of file diff --git a/tests/sql_test_files/it_works_client_ip.sql b/tests/sql_test_files/it_works_client_ip.sql deleted file mode 100644 index 78ba8f30..00000000 --- a/tests/sql_test_files/it_works_client_ip.sql +++ /dev/null @@ -1,4 +0,0 @@ -select 'text' as component, - case when sqlpage.client_ip() is null then 'It works !' - else 'It failed ! Got: ' || sqlpage.client_ip() - end as contents; \ No newline at end of file diff --git a/tests/sql_test_files/it_works_coalesce_eval.sql b/tests/sql_test_files/it_works_coalesce_eval.sql deleted file mode 100644 index 2870313f..00000000 --- a/tests/sql_test_files/it_works_coalesce_eval.sql +++ /dev/null @@ -1,5 +0,0 @@ -select 'text' as component, - case sqlpage.link(coalesce($i_do_not_exist, 'https://example.com')) - when 'https://example.com' then 'It works !' - else 'error: ' || coalesce(sqlpage.link(coalesce($i_do_not_exist, 'https://example.com')), 'NULL') - end AS contents; \ No newline at end of file diff --git a/tests/sql_test_files/it_works_concat_str_in_pseudofunction.sql b/tests/sql_test_files/it_works_concat_str_in_pseudofunction.sql deleted file mode 100644 index 1e1804a9..00000000 --- a/tests/sql_test_files/it_works_concat_str_in_pseudofunction.sql +++ /dev/null @@ -1,17 +0,0 @@ -select 'text' as component, - 'With "||": ' || - CASE sqlpage.url_encode('/' || $x) - WHEN '%2F1' THEN 'It works !' - ELSE 'Error: "/1" should be urlencoded to "%2F1"' - END - || ' | With CONCAT: ' || - CASE sqlpage.url_encode(CONCAT('/', $x)) -- $x is set to '1' in the test - WHEN '%2F1' THEN 'With CONCAT: It works !' - ELSE 'Error: "/1" should be urlencoded to "%2F1"' - END - || ' | With a null value: ' || - CASE COALESCE(sqlpage.url_encode(CONCAT('/', $thisisnull)), 'expected') - WHEN 'expected' THEN 'With a null value: It works !' - ELSE 'Error: a null value concatenated with "/" should be null, and urlencoded to NULL' - END - AS contents; \ No newline at end of file diff --git a/tests/sql_test_files/it_works_cookie.sql b/tests/sql_test_files/it_works_cookie.sql deleted file mode 100644 index 89ff3bda..00000000 --- a/tests/sql_test_files/it_works_cookie.sql +++ /dev/null @@ -1,5 +0,0 @@ -select 'text' as component, - case sqlpage.cookie('test_cook') - when '123' then 'It works !' - else 'error: ' || coalesce(sqlpage.cookie('test_cook'), 'NULL') - end AS contents; \ No newline at end of file diff --git a/tests/sql_test_files/it_works_decimal.sql b/tests/sql_test_files/it_works_decimal.sql deleted file mode 100644 index 6a1bd595..00000000 --- a/tests/sql_test_files/it_works_decimal.sql +++ /dev/null @@ -1,7 +0,0 @@ -set my_decimal = CAST(0.47 AS DECIMAL(3,2)); - -select 'text' as component, - case $my_decimal - when '0.47' then 'It works !' - else 'error: ' || coalesce($my_decimal, 'NULL') - end AS contents; \ No newline at end of file diff --git a/tests/sql_test_files/it_works_dynamic_run_sql_include.sql b/tests/sql_test_files/it_works_dynamic_run_sql_include.sql deleted file mode 100644 index d4c3679f..00000000 --- a/tests/sql_test_files/it_works_dynamic_run_sql_include.sql +++ /dev/null @@ -1 +0,0 @@ -select 'dynamic' as component, sqlpage.run_sql('tests/sql_test_files/it_works_dynamic_shell.sql') as properties; diff --git a/tests/sql_test_files/it_works_env_var_empty.sql b/tests/sql_test_files/it_works_env_var_empty.sql deleted file mode 100644 index c45c7ca2..00000000 --- a/tests/sql_test_files/it_works_env_var_empty.sql +++ /dev/null @@ -1 +0,0 @@ -select 'text' as component, coalesce(sqlpage.environment_variable('I_DO_NOT_EXIST'), 'It works !') as contents; \ No newline at end of file diff --git a/tests/sql_test_files/it_works_exec.sql b/tests/sql_test_files/it_works_exec.sql deleted file mode 100644 index 7a8ccfa5..00000000 --- a/tests/sql_test_files/it_works_exec.sql +++ /dev/null @@ -1 +0,0 @@ -select 'text' as component, sqlpage.exec('echo', 'It', $thisisnull, 'works', '!') as contents; \ No newline at end of file diff --git a/tests/sql_test_files/it_works_fetch_base64.sql b/tests/sql_test_files/it_works_fetch_base64.sql deleted file mode 100644 index f5127005..00000000 --- a/tests/sql_test_files/it_works_fetch_base64.sql +++ /dev/null @@ -1,9 +0,0 @@ -set res = sqlpage.fetch('{ - "url": "http://localhost:' || $echo_port || '/hello_world", - "response_encoding": "base64" -}'); -select 'text' as component, - case - when $res LIKE 'R0VUIC9oZWxsb193b3Js%' then 'It works !' - else 'It failed ! Got: ' || $res - end as contents; diff --git a/tests/sql_test_files/it_works_fetch_hex.sql b/tests/sql_test_files/it_works_fetch_hex.sql deleted file mode 100644 index ea300435..00000000 --- a/tests/sql_test_files/it_works_fetch_hex.sql +++ /dev/null @@ -1,9 +0,0 @@ -set res = sqlpage.fetch('{ - "url": "http://localhost:' || $echo_port || '/hello_world", - "response_encoding": "hex" -}'); -select 'text' as component, - case - when $res LIKE '474554202f68656c6c6f5f776f726c64%' then 'It works !' - else 'It failed ! Got: ' || $res - end as contents; diff --git a/tests/sql_test_files/it_works_fetch_simple.sql b/tests/sql_test_files/it_works_fetch_simple.sql deleted file mode 100644 index 1984e7a2..00000000 --- a/tests/sql_test_files/it_works_fetch_simple.sql +++ /dev/null @@ -1,7 +0,0 @@ -set url = 'http://localhost:' || $echo_port || '/hello_world'; -set res = sqlpage.fetch($url); -select 'text' as component, - case - when $res LIKE 'GET /hello_world%' then 'It works !' - else 'It failed ! Got: ' || $res - end as contents; \ No newline at end of file diff --git a/tests/sql_test_files/it_works_fetch_with_meta_error.sql b/tests/sql_test_files/it_works_fetch_with_meta_error.sql deleted file mode 100644 index 721797fb..00000000 --- a/tests/sql_test_files/it_works_fetch_with_meta_error.sql +++ /dev/null @@ -1,7 +0,0 @@ -set res = sqlpage.fetch_with_meta('http://not-a-real-url'); - -select 'text' as component, - case - when $res LIKE '%"error":"Request failed%' then 'It works !' - else CONCAT('Error! Got: ', $res) - end as contents; \ No newline at end of file diff --git a/tests/sql_test_files/it_works_hash_password.sql b/tests/sql_test_files/it_works_hash_password.sql deleted file mode 100644 index 4e431519..00000000 --- a/tests/sql_test_files/it_works_hash_password.sql +++ /dev/null @@ -1 +0,0 @@ -SELECT 'text' as component, 'It works ! The hashed password is: ' || sqlpage.hash_password($x) as contents; diff --git a/tests/sql_test_files/it_works_hash_password_null.sql b/tests/sql_test_files/it_works_hash_password_null.sql deleted file mode 100644 index 9c52f351..00000000 --- a/tests/sql_test_files/it_works_hash_password_null.sql +++ /dev/null @@ -1,3 +0,0 @@ -SELECT 'text' as component, - case when sqlpage.hash_password(null) is null then 'It works !' else 'Error !' end - as contents; diff --git a/tests/sql_test_files/it_works_header.sql b/tests/sql_test_files/it_works_header.sql deleted file mode 100644 index 987d5879..00000000 --- a/tests/sql_test_files/it_works_header.sql +++ /dev/null @@ -1,5 +0,0 @@ -select 'text' as component, - case sqlpage.header('cookie') - when 'test_cook=123' then 'It works !' - else 'error: ' || coalesce(sqlpage.header('cookie'), 'NULL') - end AS contents; \ No newline at end of file diff --git a/tests/sql_test_files/it_works_headers.sql b/tests/sql_test_files/it_works_headers.sql deleted file mode 100644 index c1984b1c..00000000 --- a/tests/sql_test_files/it_works_headers.sql +++ /dev/null @@ -1,4 +0,0 @@ -select 'text' as component, - case when sqlpage.headers() LIKE '%"cookie":"test_cook=123"%' then 'It works !' - else 'error: ' || sqlpage.headers() - end AS contents; \ No newline at end of file diff --git a/tests/sql_test_files/it_works_hmac_base64.sql b/tests/sql_test_files/it_works_hmac_base64.sql deleted file mode 100644 index 32132cb6..00000000 --- a/tests/sql_test_files/it_works_hmac_base64.sql +++ /dev/null @@ -1,6 +0,0 @@ --- Test HMAC with base64 output format --- Redirect if hash doesn't match expected value -SELECT 'redirect' as component, '/error.sql' as link -WHERE sqlpage.hmac('The quick brown fox jumps over the lazy dog', 'key', 'sha256-base64') != '97yD9DBThCSxMpjmqm+xQ+9NWaFJRhdZl0edvC0aPNg='; - -SELECT 'text' as component, 'It works ! HMAC SHA-256 base64 output is correct' as contents; \ No newline at end of file diff --git a/tests/sql_test_files/it_works_hmac_default.sql b/tests/sql_test_files/it_works_hmac_default.sql deleted file mode 100644 index df93da49..00000000 --- a/tests/sql_test_files/it_works_hmac_default.sql +++ /dev/null @@ -1,5 +0,0 @@ --- Redirect if default algorithm doesn't match sha256 -SELECT 'redirect' as component, '/error.sql' as link -WHERE sqlpage.hmac('test data', 'test key') != sqlpage.hmac('test data', 'test key', 'sha256'); - -SELECT 'text' as component, 'It works ! HMAC default algorithm is SHA-256' as contents; \ No newline at end of file diff --git a/tests/sql_test_files/it_works_hmac_sha256.sql b/tests/sql_test_files/it_works_hmac_sha256.sql deleted file mode 100644 index 35334387..00000000 --- a/tests/sql_test_files/it_works_hmac_sha256.sql +++ /dev/null @@ -1,5 +0,0 @@ --- Redirect if hash doesn't match expected value -SELECT 'redirect' as component, '/error.sql' as link -WHERE sqlpage.hmac('The quick brown fox jumps over the lazy dog', 'key', 'sha256') != 'f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8'; - -SELECT 'text' as component, 'It works ! HMAC SHA-256 hash is correct' as contents; \ No newline at end of file diff --git a/tests/sql_test_files/it_works_hmac_sha512.sql b/tests/sql_test_files/it_works_hmac_sha512.sql deleted file mode 100644 index 0b6ad9e1..00000000 --- a/tests/sql_test_files/it_works_hmac_sha512.sql +++ /dev/null @@ -1,5 +0,0 @@ --- Redirect if hash doesn't match expected value -SELECT 'redirect' as component, '/error.sql' as link -WHERE sqlpage.hmac('The quick brown fox jumps over the lazy dog', 'key', 'sha512') != 'b42af09057bac1e2d41708e48a902e09b5ff7f12ab428a4fe86653c73dd248fb82f948a549f7b791a5b41915ee4d1ec3935357e4e2317250d0372afa2ebeeb3a'; - -SELECT 'text' as component, 'It works ! HMAC SHA-512 hash is correct' as contents; \ No newline at end of file diff --git a/tests/sql_test_files/it_works_hmac_shopify_webhook.sql b/tests/sql_test_files/it_works_hmac_shopify_webhook.sql deleted file mode 100644 index 909ee8a2..00000000 --- a/tests/sql_test_files/it_works_hmac_shopify_webhook.sql +++ /dev/null @@ -1,15 +0,0 @@ --- Test Shopify webhook HMAC validation with base64 output --- Shopify sends webhook body and HMAC signature in X-Shopify-Hmac-SHA256 header (base64 format) - --- Redirect to error if signature doesn't match (proper pattern) -SELECT 'redirect' as component, - '/error.sql?msg=invalid_signature' as link -WHERE sqlpage.hmac( - '{"id":1234567890,"email":"customer@example.com","total_price":"123.45"}', - 'test-webhook-secret', - 'sha256-base64' -) != 'QNyObTlKbMx2qDlPF/ZOZcBqg5OgPg+2oky3zldc0Gw='; - --- If we reach here, signature is valid -SELECT 'text' as component, - 'It works ! Shopify webhook signature verified (base64 format)' as contents; \ No newline at end of file diff --git a/tests/sql_test_files/it_works_immutable_variables.sql b/tests/sql_test_files/it_works_immutable_variables.sql deleted file mode 100644 index 11b5d459..00000000 --- a/tests/sql_test_files/it_works_immutable_variables.sql +++ /dev/null @@ -1,31 +0,0 @@ -SET x = 'set_value'; -SET set_only = 'only_in_set'; - -SELECT 'text' AS component; - -SELECT CASE - WHEN $x = 'set_value' THEN 'It works !' - WHEN $x = '1' THEN 'FAIL: SET variable should shadow URL param' - ELSE 'FAIL: Unexpected value for $x: ' || COALESCE($x, 'NULL') -END AS contents; - -SELECT CASE - WHEN $set_only = 'only_in_set' THEN 'It works !' - ELSE 'FAIL: SET-only variable not found' -END AS contents; - -SELECT CASE - WHEN sqlpage.variables('get') = '{"x":"1"}' THEN 'It works !' - ELSE 'FAIL: variables(''get'') should return only URL parameters, got: ' || sqlpage.variables('get') -END AS contents; - -SELECT CASE - WHEN sqlpage.variables('set') = '{"x":"set_value","set_only":"only_in_set"}' THEN 'It works !' - ELSE 'FAIL: variables(''set'') should return only SET variables, got: ' || sqlpage.variables('set') -END AS contents; - -SELECT CASE - WHEN sqlpage.variables() = '{"x":"set_value","set_only":"only_in_set"}' THEN 'It works !' - ELSE 'FAIL: variables() should merge all with SET taking precedence, got: ' || sqlpage.variables() -END AS contents; - diff --git a/tests/sql_test_files/it_works_link.sql b/tests/sql_test_files/it_works_link.sql deleted file mode 100644 index fd4bbb27..00000000 --- a/tests/sql_test_files/it_works_link.sql +++ /dev/null @@ -1,5 +0,0 @@ -select 'text' as component, - case sqlpage.link('test.sql', json_object('x', 123)) - when 'test.sql?x=123' then 'It works !' - else 'error: ' || coalesce(sqlpage.link('test.sql', json_object('x', 123)), 'NULL') - end AS contents; \ No newline at end of file diff --git a/tests/sql_test_files/it_works_link_null.sql b/tests/sql_test_files/it_works_link_null.sql deleted file mode 100644 index 0b3a7de3..00000000 --- a/tests/sql_test_files/it_works_link_null.sql +++ /dev/null @@ -1,5 +0,0 @@ -select 'text' as component, - case sqlpage.link('test.sql', json_object('x', null)) - when 'test.sql' then 'It works !' - else 'error: ' || coalesce(sqlpage.link('test.sql', json_object('x', null)), 'NULL') - end AS contents; diff --git a/tests/sql_test_files/it_works_nested_sqlpage_functions.sql b/tests/sql_test_files/it_works_nested_sqlpage_functions.sql deleted file mode 100644 index a1e299ad..00000000 --- a/tests/sql_test_files/it_works_nested_sqlpage_functions.sql +++ /dev/null @@ -1,5 +0,0 @@ -select 'text' as component, - case sqlpage.url_encode(sqlpage.read_file_as_text('tests/it_works.txt')) - when 'It%20works%20%21' then 'It works !' - else 'Error! Nested sqlpage functions are not working as expected.' - end as contents; diff --git a/tests/sql_test_files/it_works_path.sql b/tests/sql_test_files/it_works_path.sql deleted file mode 100644 index 3bf81d68..00000000 --- a/tests/sql_test_files/it_works_path.sql +++ /dev/null @@ -1,6 +0,0 @@ -select 'text' as component, - CASE sqlpage.path() - WHEN '/tests/sql_test_files/it_works_path.sql' THEN 'It works !' - ELSE 'It failed ! Expected "/tests/sql_test_files/it_works_path.sql", got "' || sqlpage.path() || '"".' - END - AS contents; \ No newline at end of file diff --git a/tests/sql_test_files/it_works_postgres_cast_syntax.sql b/tests/sql_test_files/it_works_postgres_cast_syntax.sql deleted file mode 100644 index 6244aa9e..00000000 --- a/tests/sql_test_files/it_works_postgres_cast_syntax.sql +++ /dev/null @@ -1,7 +0,0 @@ --- the syntax $x::int is supported only in PostgreSQL --- but for consistency with other databases, sqlpage supports this syntax everywher () -SELECT 'text' as component, - case $x::decimal + 1 - when 2 then 'It works !' - else 'Error !' - end as contents; diff --git a/tests/sql_test_files/it_works_protocol.sql b/tests/sql_test_files/it_works_protocol.sql deleted file mode 100644 index 1355975b..00000000 --- a/tests/sql_test_files/it_works_protocol.sql +++ /dev/null @@ -1,6 +0,0 @@ -select 'text' as component, - CASE sqlpage.protocol() - WHEN 'http' THEN 'It works !' - ELSE 'It failed ! Expected "http", got "' || sqlpage.protocol() || '"".' - END - AS contents; \ No newline at end of file diff --git a/tests/sql_test_files/it_works_query_string.sql b/tests/sql_test_files/it_works_query_string.sql deleted file mode 100644 index cfe5f36b..00000000 --- a/tests/sql_test_files/it_works_query_string.sql +++ /dev/null @@ -1,11 +0,0 @@ -set actual = sqlpage.link('', sqlpage.variables('get')); -set expected = '?x=1'; -SELECT - 'text' AS component, - CASE $actual - WHEN $expected THEN - 'It works !' - ELSE - 'Expected ' || COALESCE($expected, 'null') || ' but got ' || COALESCE($actual, 'null') - END AS contents -; \ No newline at end of file diff --git a/tests/sql_test_files/it_works_random_string.sql b/tests/sql_test_files/it_works_random_string.sql deleted file mode 100644 index 54d7e09b..00000000 --- a/tests/sql_test_files/it_works_random_string.sql +++ /dev/null @@ -1,5 +0,0 @@ -select 'text' as component, - case when sqlpage.random_string(0) = '' -- with 0 as a parameter, the function becomes deterministic ;) - then 'It works !' - else 'Error ! sqlpage.random_string(5) = ' || sqlpage.random_string(5) - end as contents; \ No newline at end of file diff --git a/tests/sql_test_files/it_works_read_file_as_data_url.sql b/tests/sql_test_files/it_works_read_file_as_data_url.sql deleted file mode 100644 index 21985d7b..00000000 --- a/tests/sql_test_files/it_works_read_file_as_data_url.sql +++ /dev/null @@ -1,12 +0,0 @@ -set actual = sqlpage.read_file_as_data_url('tests/it_works.txt') -set expected = 'data:text/plain;base64,SXQgd29ya3MgIQ=='; - -select 'text' as component, - case $actual - when $expected - then 'It works !' - else - 'Failed. - Expected: ' || $expected || - 'Got: ' || $actual - end as contents; diff --git a/tests/sql_test_files/it_works_read_file_as_text.sql b/tests/sql_test_files/it_works_read_file_as_text.sql deleted file mode 100644 index 18c980e2..00000000 --- a/tests/sql_test_files/it_works_read_file_as_text.sql +++ /dev/null @@ -1 +0,0 @@ -select 'text' as component, sqlpage.read_file_as_text('tests/it_works.txt') as contents; diff --git a/tests/sql_test_files/it_works_request_method.sql b/tests/sql_test_files/it_works_request_method.sql deleted file mode 100644 index e798189b..00000000 --- a/tests/sql_test_files/it_works_request_method.sql +++ /dev/null @@ -1,12 +0,0 @@ -set actual = sqlpage.request_method() -set expected = 'GET'; - -select 'text' as component, - case $actual - when $expected - then 'It works !' - else - 'Failed. - Expected: ' || $expected || - 'Got: ' || $actual - end as contents; diff --git a/tests/sql_test_files/it_works_run_sql.sql b/tests/sql_test_files/it_works_run_sql.sql deleted file mode 100644 index d7c830d8..00000000 --- a/tests/sql_test_files/it_works_run_sql.sql +++ /dev/null @@ -1 +0,0 @@ -select 'dynamic' as component, sqlpage.run_sql('tests/sql_test_files/it_works_simple.sql') as properties; diff --git a/tests/sql_test_files/it_works_set_case.sql b/tests/sql_test_files/it_works_set_case.sql deleted file mode 100644 index c948de0d..00000000 --- a/tests/sql_test_files/it_works_set_case.sql +++ /dev/null @@ -1,2 +0,0 @@ -SET msg = case when 1=1 then 'It works !' else 'It failed !' end; -select 'text' as component, $msg AS contents; diff --git a/tests/sql_test_files/it_works_set_variable.sql b/tests/sql_test_files/it_works_set_variable.sql deleted file mode 100644 index e9ac8286..00000000 --- a/tests/sql_test_files/it_works_set_variable.sql +++ /dev/null @@ -1,2 +0,0 @@ -set what_does_it_do = 'wo' || 'rks'; -select 'text' as component, 'It ' || $what_does_it_do || ' !' as contents; diff --git a/tests/sql_test_files/it_works_set_variable_func.sql b/tests/sql_test_files/it_works_set_variable_func.sql deleted file mode 100644 index b3b2771a..00000000 --- a/tests/sql_test_files/it_works_set_variable_func.sql +++ /dev/null @@ -1,7 +0,0 @@ -set url = sqlpage.set_variable('y', '2'); - -select 'text' as component, - case $url - when '?x=1&y=2' THEN 'It works !' - else 'It failed ! Expected ?x=1&y=2 but got ' || coalesce($url, 'NULL') - end as contents; \ No newline at end of file diff --git a/tests/sql_test_files/it_works_set_variable_func_null.sql b/tests/sql_test_files/it_works_set_variable_func_null.sql deleted file mode 100644 index 21800dc4..00000000 --- a/tests/sql_test_files/it_works_set_variable_func_null.sql +++ /dev/null @@ -1,6 +0,0 @@ -set url = sqlpage.set_variable('x', null); -select 'text' as component, - case $url - when '?' THEN 'It works !' - else 'It failed ! Expected "?" but got ' || coalesce('"' || $url || '"', 'NULL') - end as contents; diff --git a/tests/sql_test_files/it_works_set_variable_func_replace.sql b/tests/sql_test_files/it_works_set_variable_func_replace.sql deleted file mode 100644 index 6d71a44b..00000000 --- a/tests/sql_test_files/it_works_set_variable_func_replace.sql +++ /dev/null @@ -1,6 +0,0 @@ -set url = sqlpage.set_variable('x', '2'); -select 'text' as component, - case $url - when '?x=2' THEN 'It works !' - else 'It failed ! Expected ?x=2 but got ' || $url - end as contents; diff --git a/tests/sql_test_files/it_works_set_variable_large_integer.sql b/tests/sql_test_files/it_works_set_variable_large_integer.sql deleted file mode 100644 index 859f89db..00000000 --- a/tests/sql_test_files/it_works_set_variable_large_integer.sql +++ /dev/null @@ -1,7 +0,0 @@ -SET test_stored_number = 123456789123456789123456789; -select 'text' as component, - case $test_stored_number - when '123456789123456789123456789' then 'It works !' - else 'It failed ! Expected 123456789123456789123456789 but got ' || COALESCE($test_stored_number, 'NULL') - end -AS contents; \ No newline at end of file diff --git a/tests/sql_test_files/it_works_set_variable_numeric.sql b/tests/sql_test_files/it_works_set_variable_numeric.sql deleted file mode 100644 index ae392824..00000000 --- a/tests/sql_test_files/it_works_set_variable_numeric.sql +++ /dev/null @@ -1,9 +0,0 @@ -set two = 2; -select 'text' as component, - CASE - WHEN $two = '2' -- All variables are strings - THEN - 'It works !' - ELSE - 'error: expected "2", got: ' || COALESCE($two, 'null') - END as contents; diff --git a/tests/sql_test_files/it_works_set_variable_to_null.sql b/tests/sql_test_files/it_works_set_variable_to_null.sql deleted file mode 100644 index e2435dfc..00000000 --- a/tests/sql_test_files/it_works_set_variable_to_null.sql +++ /dev/null @@ -1,9 +0,0 @@ -set i_am_null = NULL; -select 'text' as component, - CASE - WHEN $i_am_null IS NULL - THEN - 'It works !' - ELSE - 'error: expected null, got: ' || $i_am_null - END as contents; diff --git a/tests/sql_test_files/it_works_set_variable_to_other_variable.sql b/tests/sql_test_files/it_works_set_variable_to_other_variable.sql deleted file mode 100644 index 5c277a9e..00000000 --- a/tests/sql_test_files/it_works_set_variable_to_other_variable.sql +++ /dev/null @@ -1,9 +0,0 @@ -SET x = 42; -SET y = $x; -SET z = $y; -select 'text' as component, - case $z - when '42' then 'It works !' - else 'It failed ! Expected 42 but got ' || COALESCE($z, 'NULL') - end -AS contents; \ No newline at end of file diff --git a/tests/sql_test_files/it_works_set_variable_to_sqlpage_function.sql b/tests/sql_test_files/it_works_set_variable_to_sqlpage_function.sql deleted file mode 100644 index 96186502..00000000 --- a/tests/sql_test_files/it_works_set_variable_to_sqlpage_function.sql +++ /dev/null @@ -1,7 +0,0 @@ -set my_var = sqlpage.url_encode(' '); -select 'text' as component, - CASE $my_var - WHEN '%20' THEN 'It works !' - ELSE 'It failed !' - END - AS contents; \ No newline at end of file diff --git a/tests/sql_test_files/it_works_set_variable_to_sqlpage_post_function.sql b/tests/sql_test_files/it_works_set_variable_to_sqlpage_post_function.sql deleted file mode 100644 index 87f6d85f..00000000 --- a/tests/sql_test_files/it_works_set_variable_to_sqlpage_post_function.sql +++ /dev/null @@ -1,7 +0,0 @@ -set my_var = sqlpage.url_encode(UPPER('a')); -select 'text' as component, - CASE $my_var - WHEN 'A' THEN 'It works !' - ELSE 'It failed !' - END - AS contents; \ No newline at end of file diff --git a/tests/sql_test_files/it_works_sqlite_unicode_upper.sql b/tests/sql_test_files/it_works_sqlite_unicode_upper.sql deleted file mode 100644 index 182bbe23..00000000 --- a/tests/sql_test_files/it_works_sqlite_unicode_upper.sql +++ /dev/null @@ -1,6 +0,0 @@ --- Checks that the UPPER function is working correctly with unicode characters. -select 'text' as component, - case - when UPPER('é') = 'É' then 'It works !' - else 'It failed ! Expected É, got ' || UPPER('é') || '.' - end as contents; \ No newline at end of file diff --git a/tests/sql_test_files/it_works_sqrt.sql b/tests/sql_test_files/it_works_sqrt.sql deleted file mode 100644 index f13063e2..00000000 --- a/tests/sql_test_files/it_works_sqrt.sql +++ /dev/null @@ -1,8 +0,0 @@ -set number_three = sqrt(9.0); - -select 'text' as component, - case $number_three - when '3.0' then 'It works !' - when '3' then 'It works !' - else 'error: ' || coalesce($number_three, 'NULL') - end AS contents; diff --git a/tests/sql_test_files/it_works_uploaded_file_is_null.sql b/tests/sql_test_files/it_works_uploaded_file_is_null.sql deleted file mode 100644 index cf3ba9d5..00000000 --- a/tests/sql_test_files/it_works_uploaded_file_is_null.sql +++ /dev/null @@ -1,7 +0,0 @@ --- checks that sqlpage.uploaded_file_path returns null when there is no uploaded_file -set actual = sqlpage.uploaded_file_path('my_file'); -select 'text' as component, - case when $actual is null - then 'It works !' - else 'Failed. Expected: null. Got: ' || $actual - end as contents; diff --git a/tests/sql_test_files/it_works_url_encode.sql b/tests/sql_test_files/it_works_url_encode.sql deleted file mode 100644 index 679129e1..00000000 --- a/tests/sql_test_files/it_works_url_encode.sql +++ /dev/null @@ -1,6 +0,0 @@ -select 'text' as component, - CASE sqlpage.url_encode('/') - WHEN '%2F' THEN 'It works !' - ELSE 'It failed !' - END - AS contents; \ No newline at end of file diff --git a/tests/sql_test_files/it_works_variables_function.sql b/tests/sql_test_files/it_works_variables_function.sql deleted file mode 100644 index d7497205..00000000 --- a/tests/sql_test_files/it_works_variables_function.sql +++ /dev/null @@ -1,6 +0,0 @@ -select 'text' as component, - CASE sqlpage.variables('get') - WHEN '{"x":"1"}' THEN 'It works !' - ELSE 'It failed ! Expected {"x":"1"}, got ' || sqlpage.variables('get') - END - AS contents; \ No newline at end of file diff --git a/tests/sql_test_files/it_works_variables_function_get_and_post.sql b/tests/sql_test_files/it_works_variables_function_get_and_post.sql deleted file mode 100644 index 0217d9ef..00000000 --- a/tests/sql_test_files/it_works_variables_function_get_and_post.sql +++ /dev/null @@ -1,6 +0,0 @@ -select 'text' as component, - CASE sqlpage.variables() - WHEN '{"x":"1"}' THEN 'It works !' - ELSE 'It failed ! Expected {"x":"1"}, got ' || sqlpage.variables() - END - AS contents; \ No newline at end of file diff --git a/tests/sql_test_files/mod.rs b/tests/sql_test_files/mod.rs index 8635a20d..a3b21e34 100644 --- a/tests/sql_test_files/mod.rs +++ b/tests/sql_test_files/mod.rs @@ -7,179 +7,257 @@ use tokio::task::JoinHandle; #[actix_web::test] async fn run_all_sql_test_files() { let app_data = crate::common::make_app_data().await; - let test_files = get_sql_test_files(); + let test_files = get_sql_test_cases(); - // Create a shutdown channel for the echo server let (shutdown_tx, shutdown_rx) = oneshot::channel(); - // Start echo server once for all tests let (echo_handle, port) = crate::common::start_echo_server(shutdown_rx); - - // Wait for echo server to be ready wait_for_echo_server(port).await; for test_file in test_files { - let test_result = run_sql_test(&test_file, &app_data, &echo_handle, port).await; - assert_test_result(test_result, &test_file); + run_sql_test(&test_file, &app_data, &echo_handle, port).await; } - // Signal the echo server to shut down let _ = shutdown_tx.send(()); - // Wait for echo server to complete after all tests with a timeout - match tokio::time::timeout(Duration::from_secs(2), echo_handle).await { - Ok(_) => (), - Err(_) => panic!("Echo server did not shut down within 2 seconds"), - } + let _ = tokio::time::timeout(Duration::from_secs(2), echo_handle).await; } async fn wait_for_echo_server(port: u16) { let client = awc::Client::default(); let start = std::time::Instant::now(); - let timeout = Duration::from_secs(5); - - while start.elapsed() < timeout { - match client.get(format!("http://localhost:{port}/")).send().await { - Ok(_) => return, - Err(_) => { - tokio::time::sleep(Duration::from_millis(100)).await; - continue; - } + while start.elapsed() < Duration::from_secs(5) { + if client + .get(format!("http://localhost:{port}/")) + .send() + .await + .is_ok() + { + return; } + tokio::time::sleep(Duration::from_millis(100)).await; } - panic!("Echo server did not become ready within 5 seconds"); + panic!("Echo server did not become ready"); +} + +#[derive(Clone, Copy)] +enum SqlTestFormat { + Html, + Json, +} + +struct SqlTestCase { + path: std::path::PathBuf, + format: SqlTestFormat, } -fn get_sql_test_files() -> Vec { - let path = std::path::Path::new("tests/sql_test_files"); - std::fs::read_dir(path) +fn get_sql_test_cases() -> Vec { + let mut tests = Vec::new(); + tests.extend(read_sql_tests_in_dir( + "tests/sql_test_files/component_rendering", + SqlTestFormat::Html, + )); + tests.extend(read_sql_tests_in_dir( + "tests/sql_test_files/data", + SqlTestFormat::Json, + )); + tests +} + +fn read_sql_tests_in_dir(dir: &str, format: SqlTestFormat) -> Vec { + std::fs::read_dir(dir) .unwrap() - .filter_map(|entry| { - let entry = entry.ok()?; - let path = entry.path(); - if path.extension()? == "sql" { - Some(path) - } else { - None + .filter_map(|e| { + let path = e.ok()?.path(); + if path.is_dir() || path.extension()? != "sql" { + return None; } + Some(SqlTestCase { path, format }) }) .collect() } -use std::fmt::Write; - -#[derive(Debug)] -enum TestResult { - Success(String), - Skipped(String), -} - async fn run_sql_test( - test_file: &std::path::Path, + test_case: &SqlTestCase, app_data: &actix_web::web::Data, _echo_handle: &JoinHandle<()>, port: u16, -) -> anyhow::Result { +) { + let test_file = &test_case.path; let test_file_path = test_file.to_string_lossy().replace('\\', "/"); let stem = test_file.file_stem().unwrap().to_str().unwrap(); - let app_state = app_data.get_ref(); - let db = &app_state.db; - let db_type = format!("{:?}", db.info.database_type).to_lowercase(); - + let db_type = format!("{:?}", app_data.db.info.database_type).to_lowercase(); if stem.contains(&format!("_no{db_type}")) { - return Ok(TestResult::Skipped(format!( - "Test skipped for database type: {db_type}" - ))); + println!("Skipped {}: {}", test_file.display(), db_type); + return; } let mut query_params = "x=1".to_string(); if test_file_path.contains("fetch") { - write!(query_params, "&echo_port={port}").unwrap(); + query_params.push_str(&format!("&echo_port={port}")); } let req_str = format!("/{test_file_path}?{query_params}"); - let resp = tokio::time::timeout( - Duration::from_secs(5), - crate::common::req_path_with_app_data(&req_str, app_data.clone()), - ) + let use_json = matches!(test_case.format, SqlTestFormat::Json); + + let resp = tokio::time::timeout(Duration::from_secs(5), async { + if use_json { + crate::common::req_path_with_app_data_json(&req_str, app_data.clone()).await + } else { + crate::common::req_path_with_app_data(&req_str, app_data.clone()).await + } + }) .await - .map_err(|e| anyhow::anyhow!("Test request timed out after 5 seconds: {}", e))??; + .unwrap_or_else(|_| panic!("Test timeout: {}", test_file.display())) + .unwrap_or_else(|e| panic!("Request failed: {}: {}", test_file.display(), e)); + + let body = String::from_utf8(test::read_body(resp).await.to_vec()) + .unwrap_or_else(|_| panic!("Invalid UTF-8: {}", test_file.display())); - let body = test::read_body(resp).await; - Ok(TestResult::Success(String::from_utf8(body.to_vec())?)) + if use_json { + assert_json_test(&body, test_file); + } else { + assert_html_test(&body, test_file, stem); + } } -fn assert_test_result(result: anyhow::Result, test_file: &std::path::Path) { - match result { - Ok(TestResult::Skipped(reason)) => { - println!("⏭️ Skipped {}: {}", test_file.display(), reason); +fn format_error(obj: &serde_json::Map) -> Option { + if obj.get("component").and_then(|v| v.as_str()) != Some("error") { + return None; + } + let mut msg = String::new(); + if let Some(desc) = obj.get("description").and_then(|v| v.as_str()) { + msg.push_str(desc); + } + if let Some(bt) = obj.get("backtrace").and_then(|v| v.as_array()) { + for frame in bt { + if let Some(s) = frame.as_str() { + msg.push_str(&format!("\n {}", s)); + } } - Ok(TestResult::Success(body)) => { - assert_html_response(&body, test_file); - let lowercase_body = body.to_lowercase(); - let stem = test_file.file_stem().unwrap().to_str().unwrap().to_string(); - - if stem.starts_with("it_works") { - assert_it_works_tests(&body, &lowercase_body, test_file); - } else if stem.starts_with("error_") { - assert_error_tests(&stem, &lowercase_body, test_file); + } + Some(msg) +} + +fn assert_json_test(body: &str, test_file: &std::path::Path) { + let rows: Vec = serde_json::from_str(body) + .unwrap_or_else(|_| panic!("Invalid JSON: {}", test_file.display())); + + assert!( + !rows.is_empty(), + "No rows returned: {}", + test_file.display() + ); + + for row in rows { + let obj = match row.as_object() { + Some(o) => o, + None => continue, + }; + + if let Some(err) = format_error(obj) { + panic!("Error in {}:\n{}", test_file.display(), err); + } + + let actual = obj + .get("actual") + .cloned() + .unwrap_or(serde_json::Value::Null); + let actual_str = json_to_string(&actual); + + let expected: Vec = obj + .get("expected") + .map(|v| match v { + serde_json::Value::Array(arr) => arr.clone(), + _ => vec![v.clone()], + }) + .unwrap_or_default(); + + let expected_contains: Vec = obj + .get("expected_contains") + .map(|v| match v { + serde_json::Value::Array(arr) => arr.iter().map(json_to_string).collect(), + _ => vec![json_to_string(v)], + }) + .unwrap_or_default(); + + if expected.is_empty() && expected_contains.is_empty() { + panic!( + "No expected values found in {}: {}", + test_file.display(), + row + ); + } + + let exact_ok = expected.is_empty() || expected.iter().any(|e| e == &actual); + let contains_ok = expected_contains.is_empty() + || expected_contains.iter().all(|e| actual_str.contains(e)); + + if !exact_ok || !contains_ok { + let mut msg = format!("Test failed: {}\n", test_file.display()); + if !expected.is_empty() { + let expected_strs: Vec = expected.iter().map(|d| d.to_string()).collect(); + msg.push_str(&format!("Expected: {}\n", expected_strs.join(" or "))); } + if !expected_contains.is_empty() { + msg.push_str(&format!( + "Expected to contain: {}\n", + expected_contains.join(", ") + )); + } + msg.push_str(&format!("Actual: {}\n", actual)); + panic!("{}", msg); } - Err(e) => panic!("Failed to get response for {}: {}", test_file.display(), e), } } -fn assert_html_response(body: &str, test_file: &std::path::Path) { +fn assert_html_test(body: &str, test_file: &std::path::Path, stem: &str) { assert!( body.starts_with(""), - "Response to {} is not HTML", + "Not HTML: {}", test_file.display() ); -} -fn assert_it_works_tests(body: &str, lowercase_body: &str, test_file: &std::path::Path) { - if body.contains("") { - let error_desc = body - .split("") - .nth(1) - .and_then(|s| s.split("").next()) - .unwrap_or("Unknown error"); - panic!( - "\n\n❌ TEST FAILED: {} ❌\n\nFull Response:\n{}\n\nError Description: {}\n", - test_file.display(), - error_desc, - body + if stem.starts_with("error_") { + let expected = stem.strip_prefix("error_").unwrap().replace('_', " "); + assert!( + body.to_lowercase().contains(&expected.to_lowercase()), + "Should contain '{}': {}", + expected, + test_file.display() + ); + } else { + if let Some(error) = extract_error(body) { + panic!("Error in {}: {}", test_file.display(), error); + } + assert!( + body.contains("It works !"), + "Should contain 'It works !': {}", + test_file.display() + ); + assert!( + !body.to_lowercase().contains("error"), + "Unexpected error: {}", + test_file.display() ); } +} - assert!( - body.contains("It works !"), - "{body}\n❌ Error in file {test_file:?} ❌\nShould contain: 'It works !'", - ); - assert!( - !lowercase_body.contains("error"), - "{}\n{}\nexpected to not contain: error", - test_file.display(), - body - ); +fn extract_error(body: &str) -> Option { + body.split("") + .nth(1)? + .split("") + .next() + .map(str::trim) + .filter(|s| !s.is_empty()) + .map(String::from) } -fn assert_error_tests(stem: &str, lowercase_body: &str, test_file: &std::path::Path) { - let expected_error = stem - .strip_prefix("error_") - .unwrap() - .replace('_', " ") - .to_lowercase(); - assert!( - lowercase_body.contains(&expected_error), - "{}\n{}\nexpected to contain: {}", - test_file.display(), - lowercase_body, - expected_error - ); - assert!( - lowercase_body.contains("error"), - "{}\n{}\nexpected to contain: error", - test_file.display(), - lowercase_body - ); +fn json_to_string(v: &serde_json::Value) -> String { + match v { + serde_json::Value::Null => "NULL".to_string(), + serde_json::Value::String(s) => s.clone(), + serde_json::Value::Number(n) => n.to_string(), + serde_json::Value::Bool(b) => b.to_string(), + _ => v.to_string(), + } } diff --git a/tests/sql_test_files/select_temp_t.sql b/tests/sql_test_files/select_temp_t.sql index 3e8f2d90..e94287b7 100644 --- a/tests/sql_test_files/select_temp_t.sql +++ b/tests/sql_test_files/select_temp_t.sql @@ -1,2 +1,2 @@ --- see tests/sql_test_files/it_works_temp_table_accessible_in_run_sql.sql +-- see tests/sql_test_files/component_rendering/temp_table_accessible_in_run_sql_nomssql.sql select 'text' as component, x as contents from temp_t; \ No newline at end of file diff --git a/tests/transactions/mod.rs b/tests/transactions/mod.rs index 835df0d6..dc9e7417 100644 --- a/tests/transactions/mod.rs +++ b/tests/transactions/mod.rs @@ -46,7 +46,7 @@ async fn test_failed_copy_followed_by_query() -> actix_web::Result<()> { let app_data = make_app_data().await; let big_csv = "col1,col2\nval1,val2\n".repeat(1000); let req = get_request_to_with_data( - "/tests/sql_test_files/error_failed_to_import_the_csv.sql", + "/tests/sql_test_files/component_rendering/error_failed_to_import_the_csv.sql", app_data.clone(), ) .await? @@ -79,9 +79,9 @@ async fn test_failed_copy_followed_by_query() -> actix_web::Result<()> { } // Now make other requests to verify the connection is still usable for path in [ - "/tests/sql_test_files/it_works_lower.sql", - "/tests/sql_test_files/it_works_simple.sql", - "/tests/sql_test_files/it_works_path.sql", + "/tests/sql_test_files/component_rendering/simple.sql", + "/tests/sql_test_files/component_rendering/text_markdown.sql", + "/tests/sql_test_files/component_rendering/text_unsafe_markdown.sql", ] { let req = get_request_to_with_data(path, app_data.clone()) .await?