nx_klipper_gcode_validator_test.nx source
↩ module page · 109 lines · 3994 B
1// nx_klipper_gcode_validator_test.nx -- exercise the Klipper grammar
2// validator + verify the slicer's emitted G-code passes.
3//
4// Closed-form invariants:
5// (a) Empty input -> BAD_INPUT
6// (b) Single valid line "G1 X10 Y20 E0.5 F1500\n" -> OK
7// (c) Comment line ";LAYER 5\n" -> OK
8// (d) Line missing command number "G\n" -> BAD_LINE
9// (e) Line with control char "G1\x01X10\n" -> BAD_CONTROL_CHAR
10// (f) Line with negative feedrate "G1 F-100\n" -> BAD_FEEDRATE
11// (g) Line with zero feedrate "G1 F0\n" -> BAD_FEEDRATE
12// (h) Line with bad parameter "G1 q10\n" (lowercase letter) -> BAD_PARAM
13// (i) Real emitted G-code from the slicer passes
14//
15// expect_exit: 0
16// license_tier: ORIGINAL
17
18import "nx_syscalls.nx"
19import "nx_mesh.nx"
20import "nx_machine_graph.nx"
21import "nx_material_profile.nx"
22import "nx_gcode_emit.nx"
23import "nx_slice_pipeline.nx"
24import "nx_klipper_gcode_validator.nx"
25
26func put_str(dst: *u8, src: *u8) -> i64 {
27 var i: i64 = 0
28 while src[i] != 0 {
29 dst[i] = src[i]
30 i = i + 1
31 }
32 return i
33}
34
35func main() -> i64 {
36 let line_box: *i64 = sys_mmap(8) as *i64
37
38 // ===== (a) Empty input -> BAD_INPUT =====
39 let empty: *u8 = sys_mmap(4)
40 let r_empty: i64 = nx_klipper_gcode_validate(empty, 0, line_box)
41 if r_empty != NX_KGV_BAD_INPUT { return 10 }
42
43 // ===== (b) Valid line -> OK =====
44 let line_b: *u8 = sys_mmap(64)
45 let nb: i64 = put_str(line_b, "G1 X10 Y20 E0.5 F1500\n")
46 let r_b: i64 = nx_klipper_gcode_validate(line_b, nb, line_box)
47 if r_b != NX_KGV_OK { return 20 }
48
49 // ===== (c) Comment line -> OK =====
50 let line_c: *u8 = sys_mmap(64)
51 let nc: i64 = put_str(line_c, ";LAYER 5\n")
52 let r_c: i64 = nx_klipper_gcode_validate(line_c, nc, line_box)
53 if r_c != NX_KGV_OK { return 30 }
54
55 // ===== (d) Missing command number -> BAD_LINE =====
56 let line_d: *u8 = sys_mmap(16)
57 let nd: i64 = put_str(line_d, "G\n")
58 let r_d: i64 = nx_klipper_gcode_validate(line_d, nd, line_box)
59 if r_d != NX_KGV_BAD_LINE { return 40 }
60
61 // ===== (e) Control char -> BAD_CONTROL_CHAR =====
62 let line_e: *u8 = sys_mmap(32)
63 line_e[0] = 0x47 // 'G'
64 line_e[1] = 0x31 // '1'
65 line_e[2] = 0x01 // SOH control char
66 line_e[3] = 0x58 // 'X'
67 line_e[4] = 0x31 // '1'
68 line_e[5] = 0x30 // '0'
69 line_e[6] = 0x0A // \n
70 let r_e: i64 = nx_klipper_gcode_validate(line_e, 7, line_box)
71 if r_e != NX_KGV_BAD_CONTROL_CHAR { return 50 }
72
73 // ===== (f) Negative feedrate -> BAD_FEEDRATE =====
74 let line_f: *u8 = sys_mmap(32)
75 let nf: i64 = put_str(line_f, "G1 F-100\n")
76 let r_f: i64 = nx_klipper_gcode_validate(line_f, nf, line_box)
77 if r_f != NX_KGV_BAD_FEEDRATE { return 60 }
78
79 // ===== (g) Zero feedrate -> BAD_FEEDRATE =====
80 let line_g: *u8 = sys_mmap(32)
81 let ng: i64 = put_str(line_g, "G1 F0\n")
82 let r_g: i64 = nx_klipper_gcode_validate(line_g, ng, line_box)
83 if r_g != NX_KGV_BAD_FEEDRATE { return 70 }
84
85 // ===== (h) Lowercase parameter letter -> BAD_PARAM =====
86 let line_h: *u8 = sys_mmap(32)
87 let nh: i64 = put_str(line_h, "G1 q10\n")
88 let r_h: i64 = nx_klipper_gcode_validate(line_h, nh, line_box)
89 if r_h != NX_KGV_BAD_PARAM { return 80 }
90
91 // ===== (i) Real slicer-emitted G-code passes =====
92 let qidi: *NxMachineGraph = nx_machine_graph_qidi_xmax3()
93 let pla: *NxMaterialProfile = nx_material_profile_generic_pla()
94 let lh: i64 = 3277
95 let lw: i64 = 6554
96 let mesh: *NxMesh = nx_mesh_make_cube(5 * 16384, 0)
97 let e: *NxGcodeEmitter = nx_gemit_new(qidi, pla, lh, lw, 524288)
98 nx_gemit_preamble(e)
99 let n_layers: i64 = nx_slice_pipe_run_v2(e, mesh, 20, lh)
100 if n_layers <= 0 { return 90 }
101 let r_real: i64 = nx_klipper_gcode_validate(e.buf, e.len, line_box)
102 if r_real != NX_KGV_OK {
103 // Don't claim PASS if our own emitter outputs invalid Klipper
104 // G-code -- that's a real bug to fix.
105 return 91
106 }
107
108 return 0
109}