Skip to content

Commit 1bdf24b

Browse files
committed
Add test cases
1 parent 90a8ace commit 1bdf24b

File tree

2 files changed

+242
-2
lines changed

2 files changed

+242
-2
lines changed

crates/ty/tests/cli/main.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -762,6 +762,7 @@ pub(crate) struct CliTest {
762762
_temp_dir: TempDir,
763763
_settings_scope: SettingsBindDropGuard,
764764
project_dir: PathBuf,
765+
ty_binary_path: PathBuf,
765766
}
766767

767768
impl CliTest {
@@ -795,6 +796,7 @@ impl CliTest {
795796
project_dir,
796797
_temp_dir: temp_dir,
797798
_settings_scope: settings_scope,
799+
ty_binary_path: get_cargo_bin("ty"),
798800
})
799801
}
800802

@@ -823,6 +825,19 @@ impl CliTest {
823825
Ok(())
824826
}
825827

828+
/// Return [`Self`] with the ty binary copied to the specified path instead.
829+
pub(crate) fn with_ty_at(mut self, dest_path: impl AsRef<Path>) -> anyhow::Result<Self> {
830+
let dest_path = dest_path.as_ref();
831+
let dest_path = self.project_dir.join(dest_path);
832+
833+
Self::ensure_parent_directory(&dest_path)?;
834+
std::fs::copy(&self.ty_binary_path, &dest_path)
835+
.with_context(|| format!("Failed to copy ty binary to `{}`", dest_path.display()))?;
836+
837+
self.ty_binary_path = dest_path;
838+
Ok(self)
839+
}
840+
826841
fn ensure_parent_directory(path: &Path) -> anyhow::Result<()> {
827842
if let Some(parent) = path.parent() {
828843
std::fs::create_dir_all(parent)
@@ -868,7 +883,7 @@ impl CliTest {
868883
}
869884

870885
pub(crate) fn command(&self) -> Command {
871-
let mut command = Command::new(get_cargo_bin("ty"));
886+
let mut command = Command::new(&self.ty_binary_path);
872887
command.current_dir(&self.project_dir).arg("check");
873888

874889
// Unset all environment variables because they can affect test behavior.

crates/ty/tests/cli/python_environment.rs

Lines changed: 226 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -510,7 +510,6 @@ fn many_search_paths() -> anyhow::Result<()> {
510510
Found 1 diagnostic
511511
512512
----- stderr -----
513-
INFO Using ty's environment for site-packages
514513
INFO Python version: Python 3.14, platform: linux
515514
INFO Indexed 7 file(s) in 0.000s
516515
");
@@ -1655,6 +1654,232 @@ home = ./
16551654
Ok(())
16561655
}
16571656

1657+
/// Test that ty can discover site-packages from the environment it's installed in.
1658+
///
1659+
/// This simulates installing ty into a virtual environment (ty-venv) and running it
1660+
/// from there with a local `.venv` present. Since `LocalVenv` origin allows self-environment
1661+
/// extension, ty should discover site-packages from both locations.
1662+
#[test]
1663+
fn discovers_site_packages_from_ty_environment() -> anyhow::Result<()> {
1664+
let ty_venv_site_packages = if cfg!(windows) {
1665+
"ty-venv/Lib/site-packages"
1666+
} else {
1667+
"ty-venv/lib/python3.13/site-packages"
1668+
};
1669+
1670+
let ty_executable_path = if cfg!(windows) {
1671+
"ty-venv/Scripts/ty.exe"
1672+
} else {
1673+
"ty-venv/bin/ty"
1674+
};
1675+
1676+
let local_venv_site_packages = if cfg!(windows) {
1677+
".venv/Lib/site-packages"
1678+
} else {
1679+
".venv/lib/python3.13/site-packages"
1680+
};
1681+
1682+
let ty_package_path = format!("{}/ty_package/__init__.py", ty_venv_site_packages);
1683+
let local_package_path = format!("{}/local_package/__init__.py", local_venv_site_packages);
1684+
1685+
let case = CliTest::with_files([
1686+
(ty_package_path.as_str(), "class TyEnvClass: ..."),
1687+
(
1688+
"ty-venv/pyvenv.cfg",
1689+
r"
1690+
home = ./
1691+
version = 3.13
1692+
",
1693+
),
1694+
(local_package_path.as_str(), "class LocalClass: ..."),
1695+
(
1696+
".venv/pyvenv.cfg",
1697+
r"
1698+
home = ./
1699+
version = 3.13
1700+
",
1701+
),
1702+
(
1703+
"test.py",
1704+
r"
1705+
from ty_package import TyEnvClass
1706+
from local_package import LocalClass
1707+
",
1708+
),
1709+
])?;
1710+
1711+
// Both imports should succeed because ty discovers site-packages from both environments
1712+
let case = case.with_ty_at(ty_executable_path)?;
1713+
assert_cmd_snapshot!(case.command(), @r###"
1714+
success: true
1715+
exit_code: 0
1716+
----- stdout -----
1717+
All checks passed!
1718+
1719+
----- stderr -----
1720+
"###);
1721+
1722+
Ok(())
1723+
}
1724+
1725+
/// When `VIRTUAL_ENV` is set, ty should **not** discover its own environment's site-packages.
1726+
#[test]
1727+
fn virtual_env_set_does_not_discover_ty_environment() -> anyhow::Result<()> {
1728+
let ty_venv_site_packages = if cfg!(windows) {
1729+
"ty-venv/Lib/site-packages"
1730+
} else {
1731+
"ty-venv/lib/python3.13/site-packages"
1732+
};
1733+
1734+
let ty_executable_path = if cfg!(windows) {
1735+
"ty-venv/Scripts/ty.exe"
1736+
} else {
1737+
"ty-venv/bin/ty"
1738+
};
1739+
1740+
let active_venv_site_packages = if cfg!(windows) {
1741+
"active-venv/Lib/site-packages"
1742+
} else {
1743+
"active-venv/lib/python3.13/site-packages"
1744+
};
1745+
1746+
let ty_package_path = format!("{}/ty_package/__init__.py", ty_venv_site_packages);
1747+
let active_package_path = format!("{}/active_package/__init__.py", active_venv_site_packages);
1748+
1749+
let case = CliTest::with_files([
1750+
(ty_package_path.as_str(), "class TyEnvClass: ..."),
1751+
(
1752+
"ty-venv/pyvenv.cfg",
1753+
r"
1754+
home = ./
1755+
version = 3.13
1756+
",
1757+
),
1758+
(active_package_path.as_str(), "class ActiveClass: ..."),
1759+
(
1760+
"active-venv/pyvenv.cfg",
1761+
r"
1762+
home = ./
1763+
version = 3.13
1764+
",
1765+
),
1766+
(
1767+
"test.py",
1768+
r"
1769+
from ty_package import TyEnvClass
1770+
from active_package import ActiveClass
1771+
",
1772+
),
1773+
])?;
1774+
1775+
// ty_package should not be found because VIRTUAL_ENV is set
1776+
let case = case.with_ty_at(ty_executable_path)?;
1777+
assert_cmd_snapshot!(
1778+
case.command()
1779+
.env("VIRTUAL_ENV", case.root().join("active-venv")),
1780+
@r###"
1781+
success: false
1782+
exit_code: 1
1783+
----- stdout -----
1784+
error[unresolved-import]: Cannot resolve imported module `ty_package`
1785+
--> test.py:2:6
1786+
|
1787+
2 | from ty_package import TyEnvClass
1788+
| ^^^^^^^^^^
1789+
3 | from active_package import ActiveClass
1790+
|
1791+
info: Searched in the following paths during module resolution:
1792+
info: 1. <temp_dir>/ (first-party code)
1793+
info: 2. vendored://stdlib (stdlib typeshed stubs vendored by ty)
1794+
info: 3. <temp_dir>/active-venv/lib/python3.13/site-packages (site-packages)
1795+
info: make sure your Python environment is properly configured: https://docs.astral.sh/ty/modules/#python-environment
1796+
info: rule `unresolved-import` is enabled by default
1797+
1798+
Found 1 diagnostic
1799+
1800+
----- stderr -----
1801+
"###
1802+
);
1803+
1804+
Ok(())
1805+
}
1806+
1807+
/// When a `.venv` is present, ty's environment site-packages are prepended to the search path and
1808+
/// take precedence.
1809+
#[test]
1810+
fn ty_environment_takes_precedence_over_local_venv() -> anyhow::Result<()> {
1811+
let ty_venv_site_packages = if cfg!(windows) {
1812+
"ty-venv/Lib/site-packages"
1813+
} else {
1814+
"ty-venv/lib/python3.13/site-packages"
1815+
};
1816+
1817+
let ty_executable_path = if cfg!(windows) {
1818+
"ty-venv/Scripts/ty.exe"
1819+
} else {
1820+
"ty-venv/bin/ty"
1821+
};
1822+
1823+
let local_venv_site_packages = if cfg!(windows) {
1824+
".venv/Lib/site-packages"
1825+
} else {
1826+
".venv/lib/python3.13/site-packages"
1827+
};
1828+
1829+
let ty_package_path = format!("{}/conflicting_package/__init__.py", ty_venv_site_packages);
1830+
let local_package_path = format!(
1831+
"{}/conflicting_package/__init__.py",
1832+
local_venv_site_packages
1833+
);
1834+
1835+
let case = CliTest::with_files([
1836+
(ty_package_path.as_str(), "class FromTyEnv: ..."),
1837+
(
1838+
"ty-venv/pyvenv.cfg",
1839+
r"
1840+
home = ./
1841+
version = 3.13
1842+
",
1843+
),
1844+
(local_package_path.as_str(), "class FromLocalVenv: ..."),
1845+
(
1846+
".venv/pyvenv.cfg",
1847+
r"
1848+
home = ./
1849+
version = 3.13
1850+
",
1851+
),
1852+
(
1853+
"test.py",
1854+
r"
1855+
from conflicting_package import FromTyEnv
1856+
from conflicting_package import FromLocalVenv
1857+
",
1858+
),
1859+
])?;
1860+
1861+
let case = case.with_ty_at(ty_executable_path)?;
1862+
assert_cmd_snapshot!(case.command(), @r"
1863+
success: false
1864+
exit_code: 1
1865+
----- stdout -----
1866+
error[unresolved-import]: Module `conflicting_package` has no member `FromLocalVenv`
1867+
--> test.py:3:33
1868+
|
1869+
2 | from conflicting_package import FromTyEnv
1870+
3 | from conflicting_package import FromLocalVenv
1871+
| ^^^^^^^^^^^^^
1872+
|
1873+
info: rule `unresolved-import` is enabled by default
1874+
1875+
Found 1 diagnostic
1876+
1877+
----- stderr -----
1878+
");
1879+
1880+
Ok(())
1881+
}
1882+
16581883
#[test]
16591884
fn src_root_deprecation_warning() -> anyhow::Result<()> {
16601885
let case = CliTest::with_files([

0 commit comments

Comments
 (0)