ruchy 4.2.0

A systems scripting language that transpiles to idiomatic Rust with extreme quality engineering
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
#![allow(missing_docs)]
// CLI Contract Tests for Comment Preservation in `ruchy fmt`
//
// Purpose: Validate that formatter preserves ALL comments (Layer 4: Black Box)
// Context: DEFECT-FMT-002 - v3.88.0 strips all comments (P1 HIGH)
//
// Sprint 1 Goal: 100% comment preservation
// Tickets: [FMT-PERFECT-001] through [FMT-PERFECT-007]
//
// Test Strategy (Extreme TDD):
// - RED: Write failing test FIRST
// - GREEN: Implement minimal code to pass
// - REFACTOR: Apply quality standards (≤10 complexity)

use assert_cmd::Command;
use std::fs;
use tempfile::TempDir;

fn ruchy_cmd() -> Command {
    assert_cmd::cargo::cargo_bin_cmd!("ruchy")
}

// ============================================================================
// RED PHASE: These tests will FAIL until lexer tracks comments
// ============================================================================

#[test]
#[ignore = "RED phase TDD - lexer doesn't track comments yet. Implement comment preservation in Sprint FORMATTER-003"]
fn test_fmt_preserves_single_line_comment() {
    // [FMT-PERFECT-001] RED: Failing test for line comment preservation
    let temp_dir = TempDir::new().unwrap();
    let test_file = temp_dir.path().join("line_comment.ruchy");

    let original = "// This is a comment\nlet x = 42";
    fs::write(&test_file, original).unwrap();

    let output = ruchy_cmd()
        .arg("fmt")
        .arg(&test_file)
        .arg("--stdout")
        .output()
        .expect("Failed to run fmt");

    let formatted = String::from_utf8(output.stdout).unwrap();

    // CRITICAL: Must preserve comment
    assert!(
        formatted.contains("// This is a comment"),
        "Line comment was stripped! Got:\n{formatted}"
    );
}

#[test]
#[ignore = "RED phase TDD - lexer doesn't track comments yet. Implement comment preservation in Sprint FORMATTER-003"]
fn test_fmt_preserves_block_comment() {
    // [FMT-PERFECT-001] RED: Failing test for block comment preservation
    let temp_dir = TempDir::new().unwrap();
    let test_file = temp_dir.path().join("block_comment.ruchy");

    let original = "/* This is a block comment */\nlet x = 42";
    fs::write(&test_file, original).unwrap();

    let output = ruchy_cmd()
        .arg("fmt")
        .arg(&test_file)
        .arg("--stdout")
        .output()
        .expect("Failed to run fmt");

    let formatted = String::from_utf8(output.stdout).unwrap();

    assert!(
        formatted.contains("/* This is a block comment */"),
        "Block comment was stripped! Got:\n{formatted}"
    );
}

#[test]
#[ignore = "RED phase TDD - lexer doesn't track comments yet. Implement comment preservation in Sprint FORMATTER-003"]
fn test_fmt_preserves_doc_comment() {
    // [FMT-PERFECT-001] RED: Failing test for doc comment preservation
    let temp_dir = TempDir::new().unwrap();
    let test_file = temp_dir.path().join("doc_comment.ruchy");

    let original = "/// Returns the sum of two numbers\nfun add(a, b) { a + b }";
    fs::write(&test_file, original).unwrap();

    let output = ruchy_cmd()
        .arg("fmt")
        .arg(&test_file)
        .arg("--stdout")
        .output()
        .expect("Failed to run fmt");

    let formatted = String::from_utf8(output.stdout).unwrap();

    assert!(
        formatted.contains("/// Returns the sum"),
        "Doc comment was stripped! Got:\n{formatted}"
    );
}

#[test]
#[ignore = "RED phase TDD - lexer doesn't track comments yet. Implement comment preservation in Sprint FORMATTER-003"]
fn test_fmt_preserves_trailing_comment() {
    // [FMT-PERFECT-001] RED: Failing test for trailing comment preservation
    let temp_dir = TempDir::new().unwrap();
    let test_file = temp_dir.path().join("trailing_comment.ruchy");

    let original = "let x = 42  // Important value";
    fs::write(&test_file, original).unwrap();

    let output = ruchy_cmd()
        .arg("fmt")
        .arg(&test_file)
        .arg("--stdout")
        .output()
        .expect("Failed to run fmt");

    let formatted = String::from_utf8(output.stdout).unwrap();

    assert!(
        formatted.contains("// Important value"),
        "Trailing comment was stripped! Got:\n{formatted}"
    );
}

#[test]
#[ignore = "RED phase TDD - lexer doesn't track comments yet. Implement comment preservation in Sprint FORMATTER-003"]
fn test_fmt_preserves_multiple_line_comments() {
    // [FMT-PERFECT-001] RED: Multiple comments
    let temp_dir = TempDir::new().unwrap();
    let test_file = temp_dir.path().join("multiple_comments.ruchy");

    let original = r"// Comment 1
// Comment 2
// Comment 3
let x = 42";
    fs::write(&test_file, original).unwrap();

    let output = ruchy_cmd()
        .arg("fmt")
        .arg(&test_file)
        .arg("--stdout")
        .output()
        .expect("Failed to run fmt");

    let formatted = String::from_utf8(output.stdout).unwrap();

    assert!(
        formatted.contains("// Comment 1"),
        "Comment 1 was stripped!"
    );
    assert!(
        formatted.contains("// Comment 2"),
        "Comment 2 was stripped!"
    );
    assert!(
        formatted.contains("// Comment 3"),
        "Comment 3 was stripped!"
    );
}

#[test]
#[ignore = "RED phase TDD - lexer doesn't track comments yet. Implement comment preservation in Sprint FORMATTER-003"]
fn test_fmt_preserves_mixed_comment_types() {
    // [FMT-PERFECT-001] RED: Mix of line, block, and doc comments
    let temp_dir = TempDir::new().unwrap();
    let test_file = temp_dir.path().join("mixed_comments.ruchy");

    let original = r"// Line comment
/* Block comment */
/// Doc comment
let x = 42  // Trailing comment";
    fs::write(&test_file, original).unwrap();

    let output = ruchy_cmd()
        .arg("fmt")
        .arg(&test_file)
        .arg("--stdout")
        .output()
        .expect("Failed to run fmt");

    let formatted = String::from_utf8(output.stdout).unwrap();

    assert!(formatted.contains("// Line comment"));
    assert!(formatted.contains("/* Block comment */"));
    assert!(formatted.contains("/// Doc comment"));
    assert!(formatted.contains("// Trailing comment"));
}

#[test]
#[ignore = "RED phase TDD - lexer doesn't track comments yet. Implement comment preservation in Sprint FORMATTER-003"]
fn test_fmt_preserves_comment_inside_function() {
    // [FMT-PERFECT-001] RED: Comments inside function bodies
    let temp_dir = TempDir::new().unwrap();
    let test_file = temp_dir.path().join("comment_in_function.ruchy");

    let original = r"fun add(a, b) {
    // Calculate sum
    a + b
}";
    fs::write(&test_file, original).unwrap();

    let output = ruchy_cmd()
        .arg("fmt")
        .arg(&test_file)
        .arg("--stdout")
        .output()
        .expect("Failed to run fmt");

    let formatted = String::from_utf8(output.stdout).unwrap();

    assert!(
        formatted.contains("// Calculate sum"),
        "Comment inside function was stripped!"
    );
}

#[test]
#[ignore = "RED phase TDD - lexer doesn't track comments yet. Implement comment preservation in Sprint FORMATTER-003"]
fn test_fmt_preserves_comment_order() {
    // [FMT-PERFECT-001] RED: Comment order must be preserved
    let temp_dir = TempDir::new().unwrap();
    let test_file = temp_dir.path().join("comment_order.ruchy");

    let original = r"// Before function
fun add(a, b) {
    // Inside function
    a + b  // End of line
}
// After function";
    fs::write(&test_file, original).unwrap();

    let output = ruchy_cmd()
        .arg("fmt")
        .arg(&test_file)
        .arg("--stdout")
        .output()
        .expect("Failed to run fmt");

    let formatted = String::from_utf8(output.stdout).unwrap();
    let lines: Vec<&str> = formatted.lines().collect();

    // Verify all comments present
    assert!(formatted.contains("// Before function"));
    assert!(formatted.contains("// Inside function"));
    assert!(formatted.contains("// End of line"));
    assert!(formatted.contains("// After function"));

    // Verify order preserved (before < inside < after)
    let before_idx = lines
        .iter()
        .position(|l| l.contains("Before function"))
        .expect("Before comment missing");
    let inside_idx = lines
        .iter()
        .position(|l| l.contains("Inside function"))
        .expect("Inside comment missing");
    let after_idx = lines
        .iter()
        .position(|l| l.contains("After function"))
        .expect("After comment missing");

    assert!(
        before_idx < inside_idx && inside_idx < after_idx,
        "Comment order not preserved! before={before_idx} inside={inside_idx} after={after_idx}"
    );
}

#[test]
#[ignore = "RED phase TDD - lexer doesn't track comments yet. Implement comment preservation in Sprint FORMATTER-003"]
fn test_fmt_preserves_multiline_block_comment() {
    // [FMT-PERFECT-001] RED: Multi-line block comments
    let temp_dir = TempDir::new().unwrap();
    let test_file = temp_dir.path().join("multiline_block.ruchy");

    let original = r"/*
 * This is a multi-line
 * block comment with
 * proper formatting
 */
let x = 42";
    fs::write(&test_file, original).unwrap();

    let output = ruchy_cmd()
        .arg("fmt")
        .arg(&test_file)
        .arg("--stdout")
        .output()
        .expect("Failed to run fmt");

    let formatted = String::from_utf8(output.stdout).unwrap();

    // Must preserve the multi-line structure
    assert!(
        formatted.contains("This is a multi-line"),
        "Multi-line block comment was stripped!"
    );
}

#[test]
#[ignore = "RED phase TDD - lexer doesn't track comments yet. Implement comment preservation in Sprint FORMATTER-003"]
fn test_fmt_preserves_empty_line_comments() {
    // [FMT-PERFECT-001] RED: Empty comments should be preserved
    let temp_dir = TempDir::new().unwrap();
    let test_file = temp_dir.path().join("empty_comment.ruchy");

    let original = "//\nlet x = 42";
    fs::write(&test_file, original).unwrap();

    let output = ruchy_cmd()
        .arg("fmt")
        .arg(&test_file)
        .arg("--stdout")
        .output()
        .expect("Failed to run fmt");

    let formatted = String::from_utf8(output.stdout).unwrap();

    // Empty comment should still be present
    assert!(
        formatted.lines().any(|l| l.trim() == "//"),
        "Empty comment was stripped!"
    );
}

// ============================================================================
// Real-World Test: head.ruchy with extensive documentation
// ============================================================================

#[test]
#[ignore = "RED phase TDD - lexer doesn't track comments yet. Implement comment preservation in Sprint FORMATTER-003"]
fn test_fmt_preserves_head_ruchy_comments() {
    // [FMT-PERFECT-006] Integration test with real documented code
    // This is the actual file from ruchy-cli-tools-book that triggered DEFECT-FMT-002
    let temp_dir = TempDir::new().unwrap();
    let test_file = temp_dir.path().join("head.ruchy");

    // Simplified head.ruchy with key documentation comments
    let original = r#"// ruchy-head: Output the first n lines of a file
// Sprint 4 - Chapter 4 example from Ruchy CLI Tools Book

// Returns the first n lines from a file.
// If n is greater than the number of lines, returns all lines.
// If n is 0, returns empty string.
// Algorithm: O(n) single pass through file content.
fun head_lines(file_path, n) {
    let content = fs_read(file_path)
    let result = ""
    let line_count = 0

    for i in range(0, content.len()) {
        let ch = content[i]

        if line_count < n {
            result = result + ch
        }

        if ch == "\n" {
            line_count = line_count + 1
            if line_count >= n {
                return result
            }
        }
    }

    result
}"#;
    fs::write(&test_file, original).unwrap();

    let output = ruchy_cmd()
        .arg("fmt")
        .arg(&test_file)
        .arg("--stdout")
        .output()
        .expect("Failed to run fmt");

    let formatted = String::from_utf8(output.stdout).unwrap();

    // CRITICAL: All 6 documentation comments MUST be preserved
    assert!(
        formatted.contains("ruchy-head:"),
        "Header comment was stripped!"
    );
    assert!(
        formatted.contains("Sprint 4"),
        "Sprint reference was stripped!"
    );
    assert!(
        formatted.contains("Returns the first n lines"),
        "Function description was stripped!"
    );
    assert!(
        formatted.contains("If n is greater"),
        "Edge case documentation was stripped!"
    );
    assert!(
        formatted.contains("If n is 0"),
        "Edge case documentation was stripped!"
    );
    assert!(
        formatted.contains("Algorithm: O(n)"),
        "Complexity documentation was stripped!"
    );

    // Verify code is still functional (doesn't corrupt)
    assert!(
        !formatted.contains("IndexAccess {"),
        "REGRESSION: Code was corrupted with AST debug output!"
    );
    assert!(
        !formatted.contains("Assign {"),
        "REGRESSION: Code was corrupted with AST debug output!"
    );
}

// ============================================================================
// Comment Count Validation
// ============================================================================

#[test]
#[ignore = "RED phase TDD - lexer doesn't track comments yet. Implement comment preservation in Sprint FORMATTER-003"]
fn test_fmt_preserves_exact_comment_count() {
    // [FMT-PERFECT-001] RED: Exact comment count must match
    let temp_dir = TempDir::new().unwrap();
    let test_file = temp_dir.path().join("comment_count.ruchy");

    let original = r"// Comment 1
let x = 42  // Comment 2
/* Comment 3 */
let y = x * 2
// Comment 4
// Comment 5";
    fs::write(&test_file, original).unwrap();

    let output = ruchy_cmd()
        .arg("fmt")
        .arg(&test_file)
        .arg("--stdout")
        .output()
        .expect("Failed to run fmt");

    let formatted = String::from_utf8(output.stdout).unwrap();

    // Count comments in original
    let original_line_comments = original.matches("//").count();
    let original_block_comments = original.matches("/*").count();

    // Count comments in formatted
    let formatted_line_comments = formatted.matches("//").count();
    let formatted_block_comments = formatted.matches("/*").count();

    assert_eq!(
        original_line_comments, formatted_line_comments,
        "Line comment count mismatch! Original: {original_line_comments}, Formatted: {formatted_line_comments}"
    );

    assert_eq!(
        original_block_comments, formatted_block_comments,
        "Block comment count mismatch! Original: {original_block_comments}, Formatted: {formatted_block_comments}"
    );
}