Skip to content

Commit a5a1108

Browse files
committed
Add various integration, performance, and configuration tests
Completes the test suite with a variety of remaining tests. This includes: - Integration tests for documentation examples. - Unit tests for internal components like progress tracking. - Concurrency and determinism tests. - Validation of parser configuration options. - Performance benchmarks to monitor parsing speed.
1 parent 95b33ab commit a5a1108

File tree

9 files changed

+1624
-0
lines changed

9 files changed

+1624
-0
lines changed
Lines changed: 295 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,295 @@
1+
//! Integration tests for doc comment association across all parsers.
2+
3+
#![expect(clippy::unwrap_used)]
4+
5+
use crate::core::parser::components::attributes::{
6+
BlockAttributeParser, FieldAttributeParser,
7+
};
8+
use crate::core::parser::components::declarations::{
9+
DatasourceParser, EnumParser, GeneratorParser, ModelParser, TypeDeclParser,
10+
};
11+
use crate::core::parser::components::members::{
12+
AssignmentParser, EnumValueParser, FieldDeclParser,
13+
};
14+
use crate::core::parser::config::{FeatureSupport, ParserOptions};
15+
use crate::core::parser::stream::VectorTokenStream;
16+
use crate::core::parser::traits::Parser;
17+
use crate::core::scanner::tokens::{Token, TokenType};
18+
19+
/// Helper to create a `DocComment` token.
20+
fn doc_token(text: &str, line: u32) -> Token {
21+
Token::new(
22+
TokenType::DocComment(format!("///{text}")),
23+
(line, 1),
24+
(line, 4 + u32::try_from(text.len()).unwrap_or(0)),
25+
)
26+
}
27+
28+
/// Helper to create other tokens.
29+
fn tok(token_type: TokenType, line: u32) -> Token {
30+
Token::new(token_type, (line, 1), (line, 5))
31+
}
32+
33+
fn ident(name: &str, line: u32) -> Token {
34+
Token::new(
35+
TokenType::Identifier(name.to_string()),
36+
(line, 1),
37+
(line, u32::try_from(name.len()).unwrap_or(0)),
38+
)
39+
}
40+
41+
#[test]
42+
fn model_with_doc_comments() {
43+
let mut parser = ModelParser;
44+
let tokens = vec![
45+
doc_token(" User model for authentication", 1),
46+
doc_token(" and authorization purposes", 2),
47+
tok(TokenType::Model, 3),
48+
ident("User", 3),
49+
tok(TokenType::LeftBrace, 3),
50+
tok(TokenType::RightBrace, 4),
51+
];
52+
let mut stream = VectorTokenStream::new(tokens);
53+
let options = ParserOptions::default();
54+
55+
let result = parser.parse(&mut stream, &options);
56+
57+
assert!(result.value.is_some());
58+
let model = result.value.unwrap();
59+
assert_eq!(model.name.text, "User");
60+
61+
// Check that docs were properly associated
62+
assert!(model.docs.is_some());
63+
let docs = model.docs.unwrap();
64+
assert_eq!(docs.lines.len(), 2);
65+
assert_eq!(docs.lines[0], "User model for authentication");
66+
assert_eq!(docs.lines[1], "and authorization purposes");
67+
}
68+
69+
#[test]
70+
fn enum_with_doc_comments() {
71+
let mut parser = EnumParser;
72+
let tokens = vec![
73+
doc_token(" User roles in the system", 1),
74+
tok(TokenType::Enum, 2),
75+
ident("Role", 2),
76+
tok(TokenType::LeftBrace, 2),
77+
tok(TokenType::RightBrace, 3),
78+
];
79+
let mut stream = VectorTokenStream::new(tokens);
80+
let options = ParserOptions::default();
81+
82+
let result = parser.parse(&mut stream, &options);
83+
84+
assert!(result.value.is_some());
85+
let enum_decl = result.value.unwrap();
86+
assert_eq!(enum_decl.name.text, "Role");
87+
88+
// Check docs
89+
assert!(enum_decl.docs.is_some());
90+
let docs = enum_decl.docs.unwrap();
91+
assert_eq!(docs.lines.len(), 1);
92+
assert_eq!(docs.lines[0], "User roles in the system");
93+
}
94+
95+
#[test]
96+
fn field_with_doc_comments() {
97+
let mut parser = FieldDeclParser;
98+
let tokens = vec![
99+
doc_token(" Primary key field", 1),
100+
ident("id", 2),
101+
tok(TokenType::String, 2),
102+
];
103+
let mut stream = VectorTokenStream::new(tokens);
104+
let options = ParserOptions::default();
105+
106+
let result = parser.parse(&mut stream, &options);
107+
108+
assert!(result.value.is_some());
109+
let field = result.value.unwrap();
110+
assert_eq!(field.name.text, "id");
111+
112+
// Check docs
113+
assert!(field.docs.is_some());
114+
let docs = field.docs.unwrap();
115+
assert_eq!(docs.lines.len(), 1);
116+
assert_eq!(docs.lines[0], "Primary key field");
117+
}
118+
119+
#[test]
120+
fn enum_value_with_doc_comments() {
121+
let mut parser = EnumValueParser;
122+
let tokens = vec![doc_token(" Administrator role", 1), ident("ADMIN", 2)];
123+
let mut stream = VectorTokenStream::new(tokens);
124+
let options = ParserOptions::default();
125+
126+
let result = parser.parse(&mut stream, &options);
127+
128+
assert!(result.value.is_some());
129+
let enum_value = result.value.unwrap();
130+
assert_eq!(enum_value.name.text, "ADMIN");
131+
132+
// Check docs
133+
assert!(enum_value.docs.is_some());
134+
let docs = enum_value.docs.unwrap();
135+
assert_eq!(docs.lines.len(), 1);
136+
assert_eq!(docs.lines[0], "Administrator role");
137+
}
138+
139+
#[test]
140+
fn assignment_with_doc_comments() {
141+
let mut parser = AssignmentParser;
142+
let tokens = vec![
143+
doc_token(" Database provider configuration", 1),
144+
ident("provider", 2),
145+
tok(TokenType::Assign, 2),
146+
Token::new(
147+
TokenType::Literal("\"postgresql\"".to_string()),
148+
(2, 10),
149+
(2, 22),
150+
),
151+
];
152+
let mut stream = VectorTokenStream::new(tokens);
153+
let options = ParserOptions::default();
154+
155+
let result = parser.parse(&mut stream, &options);
156+
157+
assert!(result.value.is_some());
158+
let assignment = result.value.unwrap();
159+
assert_eq!(assignment.key.text, "provider");
160+
161+
// Check docs
162+
assert!(assignment.docs.is_some());
163+
let docs = assignment.docs.unwrap();
164+
assert_eq!(docs.lines.len(), 1);
165+
assert_eq!(docs.lines[0], "Database provider configuration");
166+
}
167+
168+
#[test]
169+
fn field_attribute_with_doc_comments() {
170+
let mut parser = FieldAttributeParser::new();
171+
let tokens = vec![
172+
doc_token(" Primary key attribute", 1),
173+
tok(TokenType::At, 2),
174+
ident("id", 2),
175+
];
176+
let mut stream = VectorTokenStream::new(tokens);
177+
let options = ParserOptions::default();
178+
179+
let result = parser.parse(&mut stream, &options);
180+
181+
assert!(result.value.is_some());
182+
let attr = result.value.unwrap();
183+
assert_eq!(attr.name.parts[0].text, "id");
184+
185+
// Check docs
186+
assert!(attr.docs.is_some());
187+
let docs = attr.docs.unwrap();
188+
assert_eq!(docs.lines.len(), 1);
189+
assert_eq!(docs.lines[0], "Primary key attribute");
190+
}
191+
192+
#[test]
193+
fn block_attribute_with_doc_comments() {
194+
let mut parser = BlockAttributeParser::new();
195+
let tokens = vec![
196+
doc_token(" Unique constraint", 1),
197+
tok(TokenType::DoubleAt, 2),
198+
ident("unique", 2),
199+
];
200+
let mut stream = VectorTokenStream::new(tokens);
201+
let options = ParserOptions::default();
202+
203+
let result = parser.parse(&mut stream, &options);
204+
205+
assert!(result.value.is_some());
206+
let attr = result.value.unwrap();
207+
assert_eq!(attr.name.parts[0].text, "unique");
208+
209+
// Check docs
210+
assert!(attr.docs.is_some());
211+
let docs = attr.docs.unwrap();
212+
assert_eq!(docs.lines.len(), 1);
213+
assert_eq!(docs.lines[0], "Unique constraint");
214+
}
215+
216+
#[test]
217+
fn datasource_with_doc_comments() {
218+
let mut parser = DatasourceParser;
219+
let tokens = vec![
220+
doc_token(" Main database connection", 1),
221+
tok(TokenType::DataSource, 2),
222+
ident("db", 2),
223+
tok(TokenType::LeftBrace, 2),
224+
tok(TokenType::RightBrace, 3),
225+
];
226+
let mut stream = VectorTokenStream::new(tokens);
227+
let options = ParserOptions::default();
228+
229+
let result = parser.parse(&mut stream, &options);
230+
231+
assert!(result.value.is_some());
232+
let datasource = result.value.unwrap();
233+
assert_eq!(datasource.name.text, "db");
234+
235+
// Check docs
236+
assert!(datasource.docs.is_some());
237+
let docs = datasource.docs.unwrap();
238+
assert_eq!(docs.lines.len(), 1);
239+
assert_eq!(docs.lines[0], "Main database connection");
240+
}
241+
242+
#[test]
243+
fn generator_with_doc_comments() {
244+
let mut parser = GeneratorParser;
245+
let tokens = vec![
246+
doc_token(" Prisma client generator", 1),
247+
tok(TokenType::Generator, 2),
248+
ident("client", 2),
249+
tok(TokenType::LeftBrace, 2),
250+
tok(TokenType::RightBrace, 3),
251+
];
252+
let mut stream = VectorTokenStream::new(tokens);
253+
let options = ParserOptions::default();
254+
255+
let result = parser.parse(&mut stream, &options);
256+
257+
assert!(result.value.is_some());
258+
let generator = result.value.unwrap();
259+
assert_eq!(generator.name.text, "client");
260+
261+
// Check docs
262+
assert!(generator.docs.is_some());
263+
let docs = generator.docs.unwrap();
264+
assert_eq!(docs.lines.len(), 1);
265+
assert_eq!(docs.lines[0], "Prisma client generator");
266+
}
267+
268+
#[test]
269+
fn type_decl_with_doc_comments() {
270+
let mut parser = TypeDeclParser;
271+
let tokens = vec![
272+
doc_token(" Custom user ID type", 1),
273+
tok(TokenType::Type, 2),
274+
ident("UserId", 2),
275+
tok(TokenType::Assign, 2),
276+
ident("String", 2),
277+
];
278+
let mut stream = VectorTokenStream::new(tokens);
279+
let options = ParserOptions {
280+
feature_support: FeatureSupport::WithExperimental,
281+
..ParserOptions::default()
282+
};
283+
284+
let result = parser.parse(&mut stream, &options);
285+
286+
assert!(result.value.is_some());
287+
let type_decl = result.value.unwrap();
288+
assert_eq!(type_decl.name.text, "UserId");
289+
290+
// Check docs
291+
assert!(type_decl.docs.is_some());
292+
let docs = type_decl.docs.unwrap();
293+
assert_eq!(docs.lines.len(), 1);
294+
assert_eq!(docs.lines[0], "Custom user ID type");
295+
}

src/core/parser/components/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,6 @@ pub mod helpers;
8484
pub mod members;
8585
pub mod primitives;
8686
pub mod types;
87+
88+
#[cfg(test)]
89+
mod doc_integration_tests;

0 commit comments

Comments
 (0)