use super::*;
use expect_test::expect;
fn write_minimal_laravel_project(root: &std::path::Path) {
std::fs::write(root.join("artisan"), "#!/usr/bin/env php\n").unwrap();
}
#[tokio::test]
async fn completion_suggests_rule_names_in_pipe_form_first_rule() {
let tmp = tempfile::tempdir().unwrap();
write_minimal_laravel_project(tmp.path());
let php = "<?php\nclass Controller {\n public function store($request) {\n $request->validate(['email' => 'requ\n }\n}\n";
std::fs::write(tmp.path().join("app.php"), php).unwrap();
let mut s = TestServer::with_root(tmp.path()).await;
s.wait_for_index_ready().await;
s.open("app.php", php).await;
let resp = s.completion("app.php", 3, 44).await;
let out = render_completion(&resp);
assert!(
out.contains("Keyword required"),
"expected 'required' rule completion, got:\n{out}"
);
}
#[tokio::test]
async fn completion_suggests_rule_names_after_pipe() {
let tmp = tempfile::tempdir().unwrap();
write_minimal_laravel_project(tmp.path());
let php = "<?php\nclass Controller {\n public function store($request) {\n $request->validate(['email' => 'required|em\n }\n}\n";
std::fs::write(tmp.path().join("app.php"), php).unwrap();
let mut s = TestServer::with_root(tmp.path()).await;
s.wait_for_index_ready().await;
s.open("app.php", php).await;
let resp = s.completion("app.php", 3, 51).await;
let out = render_completion(&resp);
expect!["Keyword email"].assert_eq(&out);
}
#[tokio::test]
async fn completion_suggests_rule_names_in_array_form() {
let tmp = tempfile::tempdir().unwrap();
write_minimal_laravel_project(tmp.path());
let php = "<?php\nclass Controller {\n public function store($request) {\n $request->validate(['email' => ['required', 'em\n }\n}\n";
std::fs::write(tmp.path().join("app.php"), php).unwrap();
let mut s = TestServer::with_root(tmp.path()).await;
s.wait_for_index_ready().await;
s.open("app.php", php).await;
let resp = s.completion("app.php", 3, 55).await;
let out = render_completion(&resp);
expect!["Keyword email"].assert_eq(&out);
}
#[tokio::test]
async fn completion_suggests_rule_names_in_validator_make_second_argument() {
let tmp = tempfile::tempdir().unwrap();
write_minimal_laravel_project(tmp.path());
let php = "<?php\nValidator::make($data, ['email' => 'requ\n";
std::fs::write(tmp.path().join("app.php"), php).unwrap();
let mut s = TestServer::with_root(tmp.path()).await;
s.wait_for_index_ready().await;
s.open("app.php", php).await;
let resp = s.completion("app.php", 1, 40).await;
let out = render_completion(&resp);
assert!(
out.contains("Keyword required"),
"expected 'required' rule completion from Validator::make(), got:\n{out}"
);
}
#[tokio::test]
async fn completion_suggests_rule_names_in_rules_method_return() {
let tmp = tempfile::tempdir().unwrap();
write_minimal_laravel_project(tmp.path());
let php = "<?php\nclass StoreUserRequest {\n public function rules() {\n return ['email' => 'requ\n }\n}\n";
std::fs::write(tmp.path().join("app.php"), php).unwrap();
let mut s = TestServer::with_root(tmp.path()).await;
s.wait_for_index_ready().await;
s.open("app.php", php).await;
let resp = s.completion("app.php", 3, 32).await;
let out = render_completion(&resp);
assert!(
out.contains("Keyword required"),
"expected 'required' rule completion from a rules() method return, got:\n{out}"
);
}
#[tokio::test]
async fn completion_does_not_offer_rule_names_while_typing_the_field_key() {
let tmp = tempfile::tempdir().unwrap();
write_minimal_laravel_project(tmp.path());
let php = "<?php\nclass Controller {\n public function store($request) {\n $request->validate(['requ\n }\n}\n";
std::fs::write(tmp.path().join("app.php"), php).unwrap();
let mut s = TestServer::with_root(tmp.path()).await;
s.wait_for_index_ready().await;
s.open("app.php", php).await;
let resp = s.completion("app.php", 3, 33).await;
let out = render_completion(&resp);
assert!(
!out.contains("Keyword required"),
"must not offer rule completions while typing the field key, got:\n{out}"
);
}
#[tokio::test]
async fn completion_ignores_unrelated_array_literal() {
let tmp = tempfile::tempdir().unwrap();
write_minimal_laravel_project(tmp.path());
let php = "<?php\nclass Controller {\n public function store() {\n $x = ['email' => 'requ\n }\n}\n";
std::fs::write(tmp.path().join("app.php"), php).unwrap();
let mut s = TestServer::with_root(tmp.path()).await;
s.wait_for_index_ready().await;
s.open("app.php", php).await;
let resp = s.completion("app.php", 3, 30).await;
let out = render_completion(&resp);
assert!(
!out.contains("Keyword required"),
"a plain array unrelated to validate()/rules() must not get rule completions, got:\n{out}"
);
}
#[tokio::test]
async fn not_offered_in_non_laravel_workspace() {
let tmp = tempfile::tempdir().unwrap();
let php = "<?php\nclass Controller {\n public function store($request) {\n $request->validate(['email' => 'requ\n }\n}\n";
std::fs::write(tmp.path().join("app.php"), php).unwrap();
let mut s = TestServer::with_root(tmp.path()).await;
s.wait_for_index_ready().await;
s.open("app.php", php).await;
let resp = s.completion("app.php", 3, 44).await;
let out = render_completion(&resp);
assert!(
!out.contains("Keyword required"),
"non-Laravel workspaces must never offer validation rule completions, got:\n{out}"
);
}