Skip to content

Commit 419b185

Browse files
author
Eric Wheeler
committed
test: add comprehensive Rust Tree-sitter tests
Add test suite for Rust language support in Tree-sitter: - Verify parsing of struct definitions - Verify parsing of method definitions within impl blocks - Verify parsing of standalone function definitions - Add tests for complex Rust structures - Include skipped debug test for future diagnostics These tests confirm the existing Rust support in Tree-sitter is working correctly and provide a foundation for future enhancements to the Rust parser. Signed-off-by: Eric Wheeler <[email protected]>
1 parent 7661ef9 commit 419b185

File tree

1 file changed

+271
-0
lines changed

1 file changed

+271
-0
lines changed
Lines changed: 271 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
1+
import { describe, expect, it, jest, beforeEach } from "@jest/globals"
2+
import { parseSourceCodeDefinitionsForFile } from ".."
3+
import * as fs from "fs/promises"
4+
import * as path from "path"
5+
import Parser from "web-tree-sitter"
6+
import { fileExistsAtPath } from "../../../utils/fs"
7+
import { loadRequiredLanguageParsers } from "../languageParser"
8+
import { rustQuery } from "../queries"
9+
import { initializeTreeSitter, testParseSourceCodeDefinitions, inspectTreeStructure, debugLog } from "./helpers"
10+
11+
// Sample Rust content for tests covering all supported structures:
12+
// - struct definitions
13+
// - method definitions (functions within a declaration list)
14+
// - function definitions
15+
const sampleRustContent = `
16+
// Basic struct definition
17+
struct Point {
18+
x: f64,
19+
y: f64,
20+
}
21+
22+
// Struct with implementation (methods)
23+
struct Rectangle {
24+
width: u32,
25+
height: u32,
26+
}
27+
28+
impl Rectangle {
29+
// Method definition
30+
fn area(&self) -> u32 {
31+
self.width * self.height
32+
}
33+
34+
// Another method
35+
fn can_hold(&self, other: &Rectangle) -> bool {
36+
self.width > other.width && self.height > other.height
37+
}
38+
39+
// Associated function (not a method, but still part of impl)
40+
fn square(size: u32) -> Rectangle {
41+
Rectangle {
42+
width: size,
43+
height: size,
44+
}
45+
}
46+
}
47+
48+
// A standalone function
49+
fn calculate_distance(p1: &Point, p2: &Point) -> f64 {
50+
let dx = p2.x - p1.x;
51+
let dy = p2.y - p1.y;
52+
(dx * dx + dy * dy).sqrt()
53+
}
54+
55+
// A more complex struct
56+
struct Vehicle {
57+
make: String,
58+
model: String,
59+
year: u32,
60+
}
61+
62+
impl Vehicle {
63+
// Constructor-like method
64+
fn new(make: String, model: String, year: u32) -> Vehicle {
65+
Vehicle {
66+
make,
67+
model,
68+
year,
69+
}
70+
}
71+
72+
// Regular method
73+
fn description(&self) -> String {
74+
format!("{} {} ({})", self.make, self.model, self.year)
75+
}
76+
}
77+
78+
// Another standalone function
79+
fn process_data(input: &str) -> String {
80+
format!("Processed: {}", input)
81+
}
82+
83+
// More complex Rust structures for advanced testing
84+
enum Status {
85+
Active,
86+
Inactive,
87+
Pending(String),
88+
Error { code: i32, message: String },
89+
}
90+
91+
trait Drawable {
92+
fn draw(&self);
93+
fn get_dimensions(&self) -> (u32, u32);
94+
}
95+
96+
impl Drawable for Rectangle {
97+
fn draw(&self) {
98+
println!("Drawing rectangle: {}x{}", self.width, self.height);
99+
}
100+
101+
fn get_dimensions(&self) -> (u32, u32) {
102+
(self.width, self.height)
103+
}
104+
}
105+
106+
// Generic struct with lifetime parameters
107+
struct Container<'a, T> {
108+
data: &'a T,
109+
count: usize,
110+
}
111+
112+
impl<'a, T> Container<'a, T> {
113+
fn new(data: &'a T) -> Container<'a, T> {
114+
Container {
115+
data,
116+
count: 1,
117+
}
118+
}
119+
}
120+
`
121+
122+
// Rust test options
123+
const rustOptions = {
124+
language: "rust",
125+
wasmFile: "tree-sitter-rust.wasm",
126+
queryString: rustQuery,
127+
extKey: "rs",
128+
content: sampleRustContent,
129+
}
130+
131+
// Mock file system operations
132+
jest.mock("fs/promises")
133+
const mockedFs = jest.mocked(fs)
134+
135+
// Mock loadRequiredLanguageParsers
136+
jest.mock("../languageParser", () => ({
137+
loadRequiredLanguageParsers: jest.fn(),
138+
}))
139+
140+
// Mock fileExistsAtPath to return true for our test paths
141+
jest.mock("../../../utils/fs", () => ({
142+
fileExistsAtPath: jest.fn().mockImplementation(() => Promise.resolve(true)),
143+
}))
144+
145+
describe("parseSourceCodeDefinitionsForFile with Rust", () => {
146+
beforeEach(() => {
147+
jest.clearAllMocks()
148+
})
149+
150+
it("should parse Rust struct definitions", async () => {
151+
const result = await testParseSourceCodeDefinitions("/test/file.rs", sampleRustContent, rustOptions)
152+
153+
// Check for struct definitions
154+
expect(result).toContain("struct Point")
155+
expect(result).toContain("struct Rectangle")
156+
expect(result).toContain("struct Vehicle")
157+
})
158+
159+
it("should parse Rust method definitions within impl blocks", async () => {
160+
const result = await testParseSourceCodeDefinitions("/test/file.rs", sampleRustContent, rustOptions)
161+
162+
// Check for function definitions within implementations
163+
expect(result).toContain("fn square")
164+
expect(result).toContain("fn new")
165+
})
166+
167+
it("should parse Rust standalone function definitions", async () => {
168+
const result = await testParseSourceCodeDefinitions("/test/file.rs", sampleRustContent, rustOptions)
169+
170+
// Check for standalone function definitions
171+
// Based on the actual output we've seen
172+
expect(result).toContain("fn calculate_distance")
173+
})
174+
175+
it("should correctly identify structs and functions", async () => {
176+
const result = await testParseSourceCodeDefinitions("/test/file.rs", sampleRustContent, rustOptions)
177+
178+
// Verify that structs and functions are being identified
179+
const resultLines = result?.split("\n") || []
180+
181+
// Check that struct Point is found
182+
const pointStructLine = resultLines.find((line) => line.includes("struct Point"))
183+
expect(pointStructLine).toBeTruthy()
184+
185+
// Check that fn calculate_distance is found
186+
const distanceFuncLine = resultLines.find((line) => line.includes("fn calculate_distance"))
187+
expect(distanceFuncLine).toBeTruthy()
188+
189+
// Check that fn square is found (method in impl block)
190+
const squareFuncLine = resultLines.find((line) => line.includes("fn square"))
191+
expect(squareFuncLine).toBeTruthy()
192+
})
193+
194+
it("should parse all supported Rust structures comprehensively", async () => {
195+
const result = await testParseSourceCodeDefinitions("/test/file.rs", sampleRustContent, rustOptions)
196+
const resultLines = result?.split("\n") || []
197+
198+
// Verify all struct definitions are captured
199+
expect(resultLines.some((line) => line.includes("struct Point"))).toBe(true)
200+
expect(resultLines.some((line) => line.includes("struct Rectangle"))).toBe(true)
201+
expect(resultLines.some((line) => line.includes("struct Vehicle"))).toBe(true)
202+
203+
// Verify impl block functions are captured
204+
expect(resultLines.some((line) => line.includes("fn square"))).toBe(true)
205+
expect(resultLines.some((line) => line.includes("fn new"))).toBe(true)
206+
207+
// Verify standalone functions are captured
208+
expect(resultLines.some((line) => line.includes("fn calculate_distance"))).toBe(true)
209+
210+
// Verify the output format includes line numbers
211+
expect(resultLines.some((line) => /\d+--\d+ \|/.test(line))).toBe(true)
212+
213+
// Verify the output includes the file name
214+
expect(result).toContain("# file.rs")
215+
})
216+
217+
it("should handle complex Rust structures", async () => {
218+
const result = await testParseSourceCodeDefinitions("/test/file.rs", sampleRustContent, rustOptions)
219+
const resultLines = result?.split("\n") || []
220+
221+
// We're not testing specific captures here since the current query might not capture all these structures
222+
// Instead, we're verifying that the parser doesn't crash with more complex Rust code
223+
224+
// The test passes if parsing completes without errors
225+
expect(result).toBeTruthy()
226+
227+
// If the parser is enhanced in the future to capture these structures,
228+
// we can add more specific assertions here:
229+
// - enum definitions
230+
// - trait definitions
231+
// - impl trait for struct
232+
// - generic structs with lifetime parameters
233+
})
234+
235+
// Debug test that can be enabled for diagnosing issues
236+
it.skip("should debug Rust tree structure directly", async () => {
237+
jest.unmock("fs/promises")
238+
239+
// Initialize tree-sitter
240+
const TreeSitter = await initializeTreeSitter()
241+
242+
// Create parser and load Rust language
243+
const parser = new TreeSitter()
244+
const wasmPath = path.join(process.cwd(), "dist/tree-sitter-rust.wasm")
245+
const rustLang = await TreeSitter.Language.load(wasmPath)
246+
parser.setLanguage(rustLang)
247+
248+
// Parse the content
249+
const tree = parser.parse(sampleRustContent)
250+
251+
// Create the query
252+
const query = rustLang.query(rustQuery)
253+
254+
// Execute the query
255+
const captures = query.captures(tree.rootNode)
256+
257+
// Log the results for debugging
258+
console.log(
259+
"Captures:",
260+
captures.map((c: { node: Parser.SyntaxNode; name: string }) => ({
261+
name: c.name,
262+
text: c.node.text,
263+
type: c.node.type,
264+
startRow: c.node.startPosition.row,
265+
startCol: c.node.startPosition.column,
266+
endRow: c.node.endPosition.row,
267+
endCol: c.node.endPosition.column,
268+
})),
269+
)
270+
})
271+
})

0 commit comments

Comments
 (0)