nx_printer_waste_test.nx source
↩ module page · 130 lines · 6125 B
1// nx_printer_waste_test.nx -- offline gate for the supply/waste auditor (R4).
2// Unique exit codes per invariant:
3// 1x Brother-like: BK level 0 / low 10 / high 100, duplex-capable but one-sided default
4// -> worst=EMPTY, count 1, min%=0, duplex=WASTE
5// 2x healthy 80% + duplex default -> OK, 80%, duplex=OK
6// 3x low 5% -> LOW, 5%
7// 4x 4-color KCMY {90,5,50,0} -> worst=EMPTY, count 4, min%=0
8// 5x level -1 (unknown) -> UNKNOWN, %=-1 (not a false 0%)
9// 6x no markers / no sides -> count 0 UNKNOWN, duplex=UNKNOWN
10// 7x one-sided-only printer -> duplex=UNSUPPORTED
11// expect_exit: 0 license_tier: ORIGINAL
12
13import "nx_syscalls.nx"
14import "nx_ipp_codec.nx"
15import "nx_printer_waste.nx"
16
17func t_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
18
19func base(buf: *u8) -> i64 {
20 var o: i64 = nx_ipp_begin(buf, 1, 1, NX_IPP_STATUS_OK, 1)
21 o = nx_ipp_group(buf, o, NX_IPP_GRP_PRINTER)
22 o = nx_ipp_attr_int(buf, o, NX_IPP_VT_ENUM, "printer-state", 13, NX_IPP_PSTATE_IDLE)
23 return o
24}
25
26// add sides-supported [one-sided, two-sided-long-edge, two-sided-short-edge] + sides-default.
27// def_one=1 -> default one-sided (waste); else default two-sided-long-edge.
28func add_sides(buf: *u8, off: i64, def_one: i64) -> i64 {
29 var o: i64 = off
30 let SS: *u8 = "sides-supported"
31 o = nx_ipp_attr(buf, o, NX_IPP_VT_KEYWORD, SS, nx_ipp_strlen(SS), "one-sided", 9)
32 o = nx_ipp_attr_add(buf, o, NX_IPP_VT_KEYWORD, "two-sided-long-edge", 19)
33 o = nx_ipp_attr_add(buf, o, NX_IPP_VT_KEYWORD, "two-sided-short-edge", 20)
34 let SD: *u8 = "sides-default"
35 if def_one == 1 { o = nx_ipp_attr(buf, o, NX_IPP_VT_KEYWORD, SD, nx_ipp_strlen(SD), "one-sided", 9) }
36 else { o = nx_ipp_attr(buf, o, NX_IPP_VT_KEYWORD, SD, nx_ipp_strlen(SD), "two-sided-long-edge", 19) }
37 return o
38}
39
40func main() -> i64 {
41 let sc: *i64 = sys_mmap(64) as *i64
42 let cnt: *i64 = sys_mmap(16) as *i64
43 let pct: *i64 = sys_mmap(16) as *i64
44 let dup: *i64 = sys_mmap(16) as *i64
45 let ML: *u8 = "marker-levels"
46 let MLO: *u8 = "marker-low-levels"
47 let MHI: *u8 = "marker-high-levels"
48
49 // ===== KAT 1: Brother-like (BK 0/10/100, duplex but one-sided default) =====
50 let a: *u8 = sys_mmap(2048)
51 var oa: i64 = base(a)
52 oa = nx_ipp_attr_int(a, oa, NX_IPP_VT_INTEGER, ML, nx_ipp_strlen(ML), 0)
53 oa = nx_ipp_attr_int(a, oa, NX_IPP_VT_INTEGER, MLO, nx_ipp_strlen(MLO), 10)
54 oa = nx_ipp_attr_int(a, oa, NX_IPP_VT_INTEGER, MHI, nx_ipp_strlen(MHI), 100)
55 oa = add_sides(a, oa, 1)
56 oa = nx_ipp_end(a, oa)
57 if nx_printer_waste(a, oa, sc, cnt, pct, dup) != NX_SUP_EMPTY { return 1 }
58 if cnt[0] != 1 { return 2 }
59 if pct[0] != 0 { return 3 }
60 if dup[0] != NX_DUP_WASTE { return 4 }
61
62 // ===== KAT 2: healthy 80% + duplex default =====
63 let b: *u8 = sys_mmap(2048)
64 var ob: i64 = base(b)
65 ob = nx_ipp_attr_int(b, ob, NX_IPP_VT_INTEGER, ML, nx_ipp_strlen(ML), 80)
66 ob = nx_ipp_attr_int(b, ob, NX_IPP_VT_INTEGER, MLO, nx_ipp_strlen(MLO), 10)
67 ob = nx_ipp_attr_int(b, ob, NX_IPP_VT_INTEGER, MHI, nx_ipp_strlen(MHI), 100)
68 ob = add_sides(b, ob, 0)
69 ob = nx_ipp_end(b, ob)
70 if nx_printer_waste(b, ob, sc, cnt, pct, dup) != NX_SUP_OK { return 10 }
71 if pct[0] != 80 { return 11 }
72 if dup[0] != NX_DUP_OK { return 12 }
73
74 // ===== KAT 3: low 5% =====
75 let c: *u8 = sys_mmap(2048)
76 var oc: i64 = base(c)
77 oc = nx_ipp_attr_int(c, oc, NX_IPP_VT_INTEGER, ML, nx_ipp_strlen(ML), 5)
78 oc = nx_ipp_attr_int(c, oc, NX_IPP_VT_INTEGER, MLO, nx_ipp_strlen(MLO), 10)
79 oc = nx_ipp_attr_int(c, oc, NX_IPP_VT_INTEGER, MHI, nx_ipp_strlen(MHI), 100)
80 oc = nx_ipp_end(c, oc)
81 if nx_printer_waste(c, oc, sc, cnt, pct, dup) != NX_SUP_LOW { return 20 }
82 if pct[0] != 5 { return 21 }
83
84 // ===== KAT 4: 4-color KCMY {90,5,50,0} =====
85 let d: *u8 = sys_mmap(2048)
86 var od: i64 = base(d)
87 od = nx_ipp_attr_int(d, od, NX_IPP_VT_INTEGER, ML, nx_ipp_strlen(ML), 90)
88 od = nx_ipp_attr_add_int(d, od, NX_IPP_VT_INTEGER, 5)
89 od = nx_ipp_attr_add_int(d, od, NX_IPP_VT_INTEGER, 50)
90 od = nx_ipp_attr_add_int(d, od, NX_IPP_VT_INTEGER, 0)
91 od = nx_ipp_attr_int(d, od, NX_IPP_VT_INTEGER, MLO, nx_ipp_strlen(MLO), 10)
92 od = nx_ipp_attr_add_int(d, od, NX_IPP_VT_INTEGER, 10)
93 od = nx_ipp_attr_add_int(d, od, NX_IPP_VT_INTEGER, 10)
94 od = nx_ipp_attr_add_int(d, od, NX_IPP_VT_INTEGER, 10)
95 od = nx_ipp_attr_int(d, od, NX_IPP_VT_INTEGER, MHI, nx_ipp_strlen(MHI), 100)
96 od = nx_ipp_attr_add_int(d, od, NX_IPP_VT_INTEGER, 100)
97 od = nx_ipp_attr_add_int(d, od, NX_IPP_VT_INTEGER, 100)
98 od = nx_ipp_attr_add_int(d, od, NX_IPP_VT_INTEGER, 100)
99 od = nx_ipp_end(d, od)
100 if nx_printer_waste(d, od, sc, cnt, pct, dup) != NX_SUP_EMPTY { return 30 }
101 if cnt[0] != 4 { return 31 }
102 if pct[0] != 0 { return 32 }
103
104 // ===== KAT 5: unknown level -1 -> not a false 0% =====
105 let e: *u8 = sys_mmap(2048)
106 var oe: i64 = base(e)
107 oe = nx_ipp_attr_int(e, oe, NX_IPP_VT_INTEGER, ML, nx_ipp_strlen(ML), 0 - 1)
108 oe = nx_ipp_end(e, oe)
109 if nx_printer_waste(e, oe, sc, cnt, pct, dup) != NX_SUP_UNKNOWN { return 40 }
110 if cnt[0] != 1 { return 41 }
111 if pct[0] != (0 - 1) { return 42 }
112
113 // ===== KAT 6: no markers, no sides =====
114 let f: *u8 = sys_mmap(2048)
115 var of: i64 = base(f)
116 of = nx_ipp_end(f, of)
117 if nx_printer_waste(f, of, sc, cnt, pct, dup) != NX_SUP_UNKNOWN { return 50 }
118 if cnt[0] != 0 { return 51 }
119 if dup[0] != NX_DUP_UNKNOWN { return 52 }
120
121 // ===== KAT 7: one-sided-only printer -> duplex unsupported =====
122 let g: *u8 = sys_mmap(2048)
123 var og: i64 = base(g)
124 og = nx_ipp_attr(g, og, NX_IPP_VT_KEYWORD, "sides-supported", 15, "one-sided", 9)
125 og = nx_ipp_end(g, og)
126 if nx_pw_duplex(g, og) != NX_DUP_UNSUPPORTED { return 60 }
127
128 t_puts("nx_printer_waste: 7/7 KAT groups PASS (supply OK/LOW/EMPTY/UNKNOWN + multi-supply + duplex-waste/unsupported)\n")
129 return 0
130}