php-lsp 0.12.0

A PHP Language Server Protocol implementation
Documentation
//! Generate code action transformation tests.
//! Tests verify that constructors and getters/setters are generated from properties.

use super::*;
use expect_test::expect;

#[tokio::test]
async fn generate_constructor_from_properties() {
    let mut s = TestServer::new().await;
    s.validate_syntax(false);
    let out = s
        .check_code_action_apply(
            r#"<?php
class U$0ser$0 {
    public string $name = '';
    public int $age = 0;
}
"#,
            "Generate constructor",
        )
        .await;
    expect![[r#"
        <?php
        class User {
            public string $name = '';
            public int $age = 0;
            public function __construct(
                string $name,
                int $age,
            ) {
                $this->name = $name;
                $this->age = $age;
            }

        }
    "#]]
    .assert_eq(&out);
}

#[tokio::test]
async fn generate_constructor_with_nullable_types() {
    let mut s = TestServer::new().await;
    s.validate_syntax(false);
    let out = s
        .check_code_action_apply(
            r#"<?php
class P$0roduct$0 {
    public string $title;
    public ?string $description = null;
}
"#,
            "Generate constructor",
        )
        .await;
    expect![[r#"
        <?php
        class Product {
            public string $title;
            public ?string $description = null;
            public function __construct(
                string $title,
                ?string $description,
            ) {
                $this->title = $title;
                $this->description = $description;
            }

        }
    "#]]
    .assert_eq(&out);
}

#[tokio::test]
async fn generate_getters_and_setters() {
    let mut s = TestServer::new().await;
    s.validate_syntax(false);
    let out = s
        .check_code_action_apply(
            r#"<?php
class A$0ccount$0 {
    private string $email = '';
    private int $balance = 0;
}
"#,
            "Generate 2 getters/setters",
        )
        .await;
    expect![[r#"
        <?php
        class Account {
            private string $email = '';
            private int $balance = 0;
            public function getEmail(): string
            {
                return $this->email;
            }

            public function setEmail(string $email): void
            {
                $this->email = $email;
            }

            public function getBalance(): int
            {
                return $this->balance;
            }

            public function setBalance(int $balance): void
            {
                $this->balance = $balance;
            }

        }
    "#]]
    .assert_eq(&out);
}

#[tokio::test]
async fn generate_getters_single_property() {
    let mut s = TestServer::new().await;
    s.validate_syntax(false);
    let out = s
        .check_code_action_apply(
            r#"<?php
class C$0onfig$0 {
    private string $apiKey = '';
}
"#,
            "Generate getter/setter",
        )
        .await;
    expect![[r#"
        <?php
        class Config {
            private string $apiKey = '';
            public function getApiKey(): string
            {
                return $this->apiKey;
            }

            public function setApiKey(string $apiKey): void
            {
                $this->apiKey = $apiKey;
            }

        }
    "#]]
    .assert_eq(&out);
}

#[tokio::test]
async fn generate_no_action_when_constructor_exists() {
    let mut s = TestServer::new().await;
    s.validate_syntax(false);
    let out = s
        .check_code_action_apply(
            r#"<?php
class U$0ser$0 {
    public string $name = '';
    public function __construct(string $name) { $this->name = $name; }
}
"#,
            "Generate constructor",
        )
        .await;
    expect!["<action not found: Generate constructor>"].assert_eq(&out);
}

#[tokio::test]
async fn generate_constructor_no_properties() {
    let mut s = TestServer::new().await;
    s.validate_syntax(false);
    let out = s
        .check_code_action_apply(
            r#"<?php
class E$0mpty$0 {
}
"#,
            "Generate constructor",
        )
        .await;
    expect!["<action not found: Generate constructor>"].assert_eq(&out);
}

#[tokio::test]
async fn generate_constructor_with_property_defaults() {
    let mut s = TestServer::new().await;
    s.validate_syntax(false);
    let out = s
        .check_code_action_apply(
            r#"<?php
class U$0ser$0 {
    public string $name = 'John';
    public int $age = 0;
}
"#,
            "Generate constructor",
        )
        .await;
    // Constructor should include default values from property initialization
    expect![[r#"
        <?php
        class User {
            public string $name = 'John';
            public int $age = 0;
            public function __construct(
                string $name,
                int $age,
            ) {
                $this->name = $name;
                $this->age = $age;
            }

        }
    "#]]
    .assert_eq(&out);
}

#[tokio::test]
async fn generate_getters_with_boolean_properties() {
    let mut s = TestServer::new().await;
    s.validate_syntax(false);
    let out = s
        .check_code_action_apply(
            r#"<?php
class S$0ettings$0 {
    private bool $isEnabled = false;
}
"#,
            "Generate getter/setter",
        )
        .await;
    expect![[r#"
        <?php
        class Settings {
            private bool $isEnabled = false;
            public function getIsEnabled(): bool
            {
                return $this->isEnabled;
            }

            public function setIsEnabled(bool $isEnabled): void
            {
                $this->isEnabled = $isEnabled;
            }

        }
    "#]]
    .assert_eq(&out);
}