code wiki / (root) / nx_phred_test.nx

nx_phred_test.nx source

↩ module page · 123 lines · 4725 B

1// nx_phred_test.nx -- KAT for Phred+33 and Phred+64 encode/decode. 2// 3// expect_exit: 0 4// 5// license_tier: ORIGINAL 6 7import "nx_syscalls.nx" 8import "nx_const.nx" 9import "nx_phred.nx" 10 11func main() -> i64 { 12 13 // ============================================================ 14 // Section A -- Phred+33 single-value boundary + canonical values. 15 // Q 0 -> '!' 0x21 16 // Q 20 -> '5' 0x35 (variant-calling threshold) 17 // Q 30 -> '?' 0x3F (Illumina target) 18 // Q 40 -> 'I' 0x49 (PacBio HiFi typical) 19 // Q 60 -> ']' 0x5D 20 // Q 93 -> '~' 0x7E (upper cap) 21 // ============================================================ 22 23 if nx_phred33_encode(0) != 0x21 { return 1 } 24 if nx_phred33_encode(20) != 0x35 { return 2 } 25 if nx_phred33_encode(30) != 0x3F { return 3 } 26 if nx_phred33_encode(40) != 0x49 { return 4 } 27 if nx_phred33_encode(60) != 0x5D { return 5 } 28 if nx_phred33_encode(93) != 0x7E { return 6 } 29 30 // Out-of-range refusal. 31 if nx_phred33_encode(-1) != -1 { return 7 } 32 if nx_phred33_encode(94) != -1 { return 8 } 33 if nx_phred33_encode(1000) != -1 { return 9 } 34 35 // ============================================================ 36 // Section B -- Phred+33 decode boundary + round-trip. 37 // ============================================================ 38 39 if nx_phred33_decode(0x21) != 0 { return 10 } 40 if nx_phred33_decode(0x35) != 20 { return 11 } 41 if nx_phred33_decode(0x49) != 40 { return 12 } 42 if nx_phred33_decode(0x7E) != 93 { return 13 } 43 44 // Out-of-range refusal. 45 if nx_phred33_decode(0x20) != -1 { return 14 } // ' ' below 33 46 if nx_phred33_decode(0x7F) != -1 { return 15 } // DEL above 126 47 if nx_phred33_decode(0x00) != -1 { return 16 } 48 49 // Round-trip Q=0..93. 50 var q: i64 = 0 51 while q <= 93 { 52 let a: i64 = nx_phred33_encode(q) 53 let qr: i64 = nx_phred33_decode(a) 54 if qr != q { return 20 + q } 55 q = q + 1 56 } 57 58 // ============================================================ 59 // Section C -- Phred+64 single-value boundary + canonical. 60 // Q 0 -> '@' 0x40 61 // Q 20 -> 'T' 0x54 62 // Q 40 -> 'h' 0x68 63 // Q 62 -> '~' 0x7E (legacy upper cap) 64 // ============================================================ 65 66 if nx_phred64_encode(0) != 0x40 { return 200 } 67 if nx_phred64_encode(20) != 0x54 { return 201 } 68 if nx_phred64_encode(40) != 0x68 { return 202 } 69 if nx_phred64_encode(62) != 0x7E { return 203 } 70 71 if nx_phred64_encode(-1) != -1 { return 204 } 72 if nx_phred64_encode(63) != -1 { return 205 } // cap at 62 73 74 if nx_phred64_decode(0x40) != 0 { return 210 } 75 if nx_phred64_decode(0x7E) != 62 { return 211 } 76 if nx_phred64_decode(0x3F) != -1 { return 212 } // below 64 77 if nx_phred64_decode(0x7F) != -1 { return 213 } // above 126 78 79 // ============================================================ 80 // Section D -- bulk encode / decode on a realistic FASTQ snippet. 81 // 8-base read with descending quality (typical of Illumina cycle drop): 82 // Q values: 40 38 35 33 30 25 20 15 83 // ASCII: I G D B ? : 5 0 84 // ============================================================ 85 86 let qs: *i64 = sys_mmap(128) as *i64 87 let ascii: *u8 = sys_mmap(64) 88 qs[0]=40; qs[1]=38; qs[2]=35; qs[3]=33; qs[4]=30; qs[5]=25; qs[6]=20; qs[7]=15 89 90 if nx_phred33_encode_string(qs, 8, ascii) != 0 { return 220 } 91 if (ascii[0] & 0xff) != 0x49 { return 221 } // I 92 if (ascii[1] & 0xff) != 0x47 { return 222 } // G 93 if (ascii[2] & 0xff) != 0x44 { return 223 } // D 94 if (ascii[3] & 0xff) != 0x42 { return 224 } // B 95 if (ascii[4] & 0xff) != 0x3F { return 225 } // ? 96 if (ascii[5] & 0xff) != 0x3A { return 226 } // : 97 if (ascii[6] & 0xff) != 0x35 { return 227 } // 5 98 if (ascii[7] & 0xff) != 0x30 { return 228 } // 0 99 100 // Round-trip via decode. 101 let qs_rt: *i64 = sys_mmap(128) as *i64 102 if nx_phred33_decode_string(ascii, 8, qs_rt) != 0 { return 230 } 103 var i: i64 = 0 104 while i < 8 { 105 if qs_rt[i] != qs[i] { return 240 + i } 106 i = i + 1 107 } 108 109 // ============================================================ 110 // Section E -- bulk operations refuse bad input. 111 // ============================================================ 112 113 qs[0] = 100 // out of range for Phred+33 114 if nx_phred33_encode_string(qs, 1, ascii) != -1 { return 250 } 115 116 ascii[0] = 0x20 // below Phred+33 range 117 if nx_phred33_decode_string(ascii, 1, qs_rt) != -1 { return 251 } 118 119 if nx_phred33_encode_string(qs, -1, ascii) != -1 { return 252 } 120 if nx_phred33_decode_string(ascii, -1, qs_rt) != -1 { return 253 } 121 122 return 0 123}