code wiki / (root) / nx_moonraker_telemetry_parse_test.nx

nx_moonraker_telemetry_parse_test.nx source

↩ module page · 99 lines · 4794 B

1// nx_moonraker_telemetry_parse_test.nx -- parse canonical 2// Moonraker JSON responses into NxPrintTelemetry thermal fields. 3// 4// Closed-form invariants: 5// (a) Empty/null body -> BAD_INPUT 6// (b) JSON with no extruder/heater_bed -> NO_OBJECT 7// (c) Canonical extruder+heater_bed body -> OK, fields populated 8// (d) Missing target -> setpoint = -1 (skip axis), actual still set 9// (e) Negative temperature (e.g. ambient probe) handled 10// (f) Nested objects don't confuse the brace matcher 11// (g) Same-key inside different scope: "temperature" inside the 12// extruder scope picks the extruder one, not heater_bed's 13// (h) has_thermal flag set when any value found 14// 15// expect_exit: 0 16// license_tier: ORIGINAL 17 18import "nx_syscalls.nx" 19import "nx_print_telemetry.nx" 20import "nx_moonraker_telemetry_parse.nx" 21 22func cstr_len(s: *u8) -> i64 { 23 var n: i64 = 0 24 while s[n] != 0 { n = n + 1 } 25 return n 26} 27 28func main() -> i64 { 29 let ev: *NxPrintTelemetry = nx_print_telemetry_new() 30 if (ev as i64) == 0 { return 5 } 31 32 // ===== (a) Bad inputs ===== 33 if nx_moonraker_parse_thermal(0 as *u8, 100, ev) != NX_MR_PARSE_BAD_INPUT { return 10 } 34 if nx_moonraker_parse_thermal("dummy", 5, 0 as *NxPrintTelemetry) != NX_MR_PARSE_BAD_INPUT { return 11 } 35 if nx_moonraker_parse_thermal("dummy", 0, ev) != NX_MR_PARSE_BAD_INPUT { return 12 } 36 37 // ===== (b) JSON without extruder/heater_bed -> NO_OBJECT ===== 38 let body_a: *u8 = "{\"result\":{\"status\":{\"other\":{\"foo\":1}}}}" 39 if nx_moonraker_parse_thermal(body_a, cstr_len(body_a), ev) != NX_MR_PARSE_NO_OBJECT { return 20 } 40 41 // ===== (c) Canonical response ===== 42 let ev2: *NxPrintTelemetry = nx_print_telemetry_new() 43 let body_c: *u8 = 44"{\"result\":{\"status\":{\"extruder\":{\"temperature\":209.8,\"target\":210.0,\"power\":0.45},\"heater_bed\":{\"temperature\":59.7,\"target\":60.0}},\"eventtime\":12345.6}}" 45 let vc: i64 = nx_moonraker_parse_thermal(body_c, cstr_len(body_c), ev2) 46 if vc != NX_MR_PARSE_OK { return 30 } 47 if ev2.hotend_actual_c != 209 { return 31 } 48 if ev2.hotend_setpoint_c != 210 { return 32 } 49 if ev2.bed_actual_c != 59 { return 33 } 50 if ev2.bed_setpoint_c != 60 { return 34 } 51 if ev2.has_thermal != 1 { return 35 } 52 53 // ===== (d) Missing target -> setpoint -1, actual still set ===== 54 let ev3: *NxPrintTelemetry = nx_print_telemetry_new() 55 let body_d: *u8 = 56"{\"result\":{\"status\":{\"extruder\":{\"temperature\":25.0,\"power\":0.0},\"heater_bed\":{\"temperature\":24.0}}}}" 57 if nx_moonraker_parse_thermal(body_d, cstr_len(body_d), ev3) != NX_MR_PARSE_OK { return 40 } 58 if ev3.hotend_actual_c != 25 { return 41 } 59 if ev3.hotend_setpoint_c != -1 { return 42 } 60 if ev3.bed_actual_c != 24 { return 43 } 61 if ev3.bed_setpoint_c != -1 { return 44 } 62 63 // ===== (e) Negative temperature ===== 64 let ev4: *NxPrintTelemetry = nx_print_telemetry_new() 65 let body_e: *u8 = 66"{\"result\":{\"status\":{\"extruder\":{\"temperature\":-12.5,\"target\":-10.0}}}}" 67 if nx_moonraker_parse_thermal(body_e, cstr_len(body_e), ev4) != NX_MR_PARSE_OK { return 50 } 68 if ev4.hotend_actual_c != -12 { return 51 } 69 if ev4.hotend_setpoint_c != -10 { return 52 } 70 71 // ===== (f) Nested object in extruder scope doesn't break matcher ===== 72 let ev5: *NxPrintTelemetry = nx_print_telemetry_new() 73 let body_f: *u8 = 74"{\"result\":{\"status\":{\"extruder\":{\"temperature\":200.0,\"target\":210.0,\"smoothed\":{\"value\":199.8,\"target\":210.0}},\"heater_bed\":{\"temperature\":60.0,\"target\":65.0}}}}" 75 if nx_moonraker_parse_thermal(body_f, cstr_len(body_f), ev5) != NX_MR_PARSE_OK { return 60 } 76 if ev5.hotend_actual_c != 200 { return 61 } 77 if ev5.hotend_setpoint_c != 210 { return 62 } 78 if ev5.bed_actual_c != 60 { return 63 } 79 if ev5.bed_setpoint_c != 65 { return 64 } 80 81 // ===== (g) Scope isolation: heater_bed's temperature is not picked 82 // when extracting extruder's temperature ===== 83 // Test by putting heater_bed BEFORE extruder in the response. 84 let ev6: *NxPrintTelemetry = nx_print_telemetry_new() 85 let body_g: *u8 = 86"{\"result\":{\"status\":{\"heater_bed\":{\"temperature\":50.0,\"target\":55.0},\"extruder\":{\"temperature\":190.0,\"target\":200.0}}}}" 87 if nx_moonraker_parse_thermal(body_g, cstr_len(body_g), ev6) != NX_MR_PARSE_OK { return 70 } 88 if ev6.hotend_actual_c != 190 { return 71 } // NOT 50 89 if ev6.bed_actual_c != 50 { return 72 } 90 91 // ===== (h) has_thermal flag set ===== 92 if ev6.has_thermal != 1 { return 80 } 93 94 // Empty pass-through: ev with no parse run has has_thermal = 0 95 let ev7: *NxPrintTelemetry = nx_print_telemetry_new() 96 if ev7.has_thermal != 0 { return 81 } 97 98 return 0 99}