test(lsp): smoke-test everyday code intelligence per language with real servers (#1299)

* test(lsp): smoke-test everyday code intelligence per language with real servers

A new ide-host integration test drives completion, go to definition, Find
Usages, hover, diagnostics with a quick fix, an intention, formatting and
rename on each language's fixtures/ project, through the ops the app's
commands call and the language server the app starts by default:
TypeScript (vtsls), Python (basedpyright + Ruff), Rust (rust-analyzer),
Go (gopls), Java (jdtls) and Kotlin (kotlin-lsp). A failure names the
language and the operation.

The tests are ignored by default; a Language smoke workflow installs pinned
server versions and runs one language per job on changes to crates/,
languages/ and fixtures/. Adds fixtures/java-app (Maven, JDK 21) for Java.

* test(lsp): rename TypeScript from a usage and check Rust errors while typing

Covers the fixes the smoke test turned up: a TypeScript rename started at a
call site in another file renames the declaration (#1301), and rust-analyzer's
own diagnostics and fixes arrive without saving (#1306).
Цей коміт міститься в:
l0ng-ai authored and GitHub committed 2026-11-04 23:35:53 +08:00
1 джерело 1789dbb98e
коміт 1e4eee27c4
10 files changed
+963

No files matched your search

+1
Переглянути файл
@@ -0,0 +1 @@
target/
+50
Переглянути файл
@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>openidea-fixture-orders</artifactId>
<version>0.1.0</version>
<description>OpenIDEA QA fixture: a tiny order book</description>
<properties>
<maven.compiler.release>21</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- `mvn test -DopenideaFail=true` runs the intentionally failing test. -->
<openideaFail>false</openideaFail>
</properties>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.11.3</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.5.2</version>
<configuration>
<systemPropertyVariables>
<openidea.fail>${openideaFail}</openidea.fail>
</systemPropertyVariables>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.5.0</version>
<configuration>
<mainClass>com.example.orders.App</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
+16
Переглянути файл
@@ -0,0 +1,16 @@
package com.example.orders;
public class App {
public static void main(String[] args) {
OrderBook book = new OrderBook();
book.place("alice", "Mechanical keyboard", 1, 8999);
book.place("bob", "Wireless mouse", 2, 2999);
book.place("alice", "USB-C hub", 1, 3999);
int unused = 42; // intentional warning: unused variable
// Set a breakpoint here (QA: debugger) and inspect `book`.
long revenue = book.revenueCents();
System.out.printf("%d orders, revenue %.2f%n", book.size(), revenue / 100.0);
book.largest().ifPresent(o -> System.out.println("Largest: " + o.product()));
}
}
+14
Переглянути файл
@@ -0,0 +1,14 @@
package com.example.orders;
/** A customer order: a product, how many and the unit price in cents. */
public record Order(String customer, String product, int quantity, long unitPriceCents) {
public Order {
if (quantity <= 0) throw new IllegalArgumentException("quantity must be positive");
}
/** The order's total in cents. */
public long totalCents() {
return unitPriceCents * quantity;
}
}
+35
Переглянути файл
@@ -0,0 +1,35 @@
package com.example.orders;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
/** Keeps the orders placed so far, in the order they were placed. */
public class OrderBook {
private final List<Order> orders = new ArrayList<>();
/** Places an order and returns it. */
public Order place(String customer, String product, int quantity, long unitPriceCents) {
Order order = new Order(customer, product, quantity, unitPriceCents);
orders.add(order);
return order;
}
public List<Order> byCustomer(String customer) {
return orders.stream().filter(o -> o.customer().equals(customer)).toList();
}
public Optional<Order> largest() {
return orders.stream().max(Comparator.comparingLong(Order::totalCents));
}
// TODO: discounts for repeat customers
public long revenueCents() {
return orders.stream().mapToLong(Order::totalCents).sum();
}
public int size() {
return orders.size();
}
}
+29
Переглянути файл
@@ -0,0 +1,29 @@
package com.example.orders;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledIfSystemProperty;
class OrderBookTest {
@Test
void sumsRevenueOverAllOrders() {
OrderBook book = new OrderBook();
book.place("alice", "Keyboard", 2, 1000);
book.place("bob", "Mouse", 1, 500);
assertEquals(2500, book.revenueCents());
assertEquals(1, book.byCustomer("bob").size());
}
@Test
void rejectsEmptyOrders() {
assertThrows(IllegalArgumentException.class, () -> new Order("alice", "Keyboard", 0, 1000));
}
@Test
@EnabledIfSystemProperty(named = "openidea.fail", matches = "true")
void intentionallyFails() {
assertEquals(1, new OrderBook().size(), "QA: an intentionally failing test");
}
}