diff --git a/saferune.go b/saferune.go new file mode 100644 index 0000000..9d5c27c --- /dev/null +++ b/saferune.go @@ -0,0 +1,180 @@ +package htmlescape + +var escaped00 []byte = []byte("�") +var escaped01 []byte = []byte("") +var escaped02 []byte = []byte("") +var escaped03 []byte = []byte("") +var escaped04 []byte = []byte("") +var escaped05 []byte = []byte("") +var escaped06 []byte = []byte("") +var escaped07 []byte = []byte("") +var escaped08 []byte = []byte("") +var escaped09 []byte = []byte(" ") +var escaped0A []byte = []byte(" ") +var escaped0B []byte = []byte(" ") +var escaped0C []byte = []byte(" ") +var escaped0D []byte = []byte(" ") +var escaped0E []byte = []byte("") +var escaped0F []byte = []byte("") + +var escaped10 []byte = []byte("") +var escaped11 []byte = []byte("") +var escaped12 []byte = []byte("") +var escaped13 []byte = []byte("") +var escaped14 []byte = []byte("") +var escaped15 []byte = []byte("") +var escaped16 []byte = []byte("") +var escaped17 []byte = []byte("") +var escaped18 []byte = []byte("") +var escaped19 []byte = []byte("") +var escaped1A []byte = []byte("") +var escaped1B []byte = []byte("") +var escaped1C []byte = []byte("") +var escaped1D []byte = []byte("") +var escaped1E []byte = []byte("") +var escaped1F []byte = []byte("") + +const minCtrlBlock1 = 0x7F + +var escaped7F []byte = []byte("") +var escaped80 []byte = []byte("€") +var escaped81 []byte = []byte("") +var escaped82 []byte = []byte("‚") +var escaped83 []byte = []byte("ƒ") +var escaped84 []byte = []byte("„") +var escaped85 []byte = []byte("…") +var escaped86 []byte = []byte("†") +var escaped87 []byte = []byte("‡") +var escaped88 []byte = []byte("ˆ") +var escaped89 []byte = []byte("‰") +var escaped8A []byte = []byte("Š") +var escaped8B []byte = []byte("‹") +var escaped8C []byte = []byte("Œ") +var escaped8D []byte = []byte("") +var escaped8E []byte = []byte("Ž") +var escaped8F []byte = []byte("") +var escaped90 []byte = []byte("") +var escaped91 []byte = []byte("‘") +var escaped92 []byte = []byte("’") +var escaped93 []byte = []byte("“") +var escaped94 []byte = []byte("”") +var escaped95 []byte = []byte("•") +var escaped96 []byte = []byte("–") +var escaped97 []byte = []byte("—") +var escaped98 []byte = []byte("˜") +var escaped99 []byte = []byte("™") +var escaped9A []byte = []byte("š") +var escaped9B []byte = []byte("›") +var escaped9C []byte = []byte("œ") +var escaped9D []byte = []byte("") +var escaped9E []byte = []byte("ž") +var escaped9F []byte = []byte("Ÿ") + +var ctrlBlock0 [][]byte = [][]byte{ + escaped00, + escaped01, + escaped02, + escaped03, + escaped04, + escaped05, + escaped06, + escaped07, + escaped08, + escaped09, + escaped0A, + escaped0B, + escaped0C, + escaped0D, + escaped0E, + escaped0F, + + escaped10, + escaped11, + escaped12, + escaped13, + escaped14, + escaped15, + escaped16, + escaped17, + escaped18, + escaped19, + escaped1A, + escaped1B, + escaped1C, + escaped1D, + escaped1E, + escaped1F, +} + +var ctrlBlock1 [][]byte = [][]byte{ + escaped7F, + + escaped80, + escaped81, + escaped82, + escaped83, + escaped84, + escaped85, + escaped86, + escaped87, + escaped88, + escaped89, + escaped8A, + escaped8B, + escaped8C, + escaped8D, + escaped8E, + escaped8F, + + escaped90, + escaped91, + escaped92, + escaped93, + escaped94, + escaped95, + escaped96, + escaped97, + escaped98, + escaped99, + escaped9A, + escaped9B, + escaped9C, + escaped9D, + escaped9E, + escaped9F, +} + +var escapedQuotationMark []byte = []byte(""") // """ """ +var escapedApostrophe []byte = []byte("'") // "'" "'" +var escapedAmpersand []byte = []byte("&") // "&" "&" +var escapedLessThanSign []byte = []byte("<") // "<" "<" +var escapedGreaterThanSign []byte = []byte(">") // ">" ">" + +// safeRune will only escape the rune 'r' if it is necessary or wise to do so. +// The returned []byte is in UTF-8 — although all the values returned are in the sub-set of Unicode that is also ASCII. +// So it is both valid UTF-8 and ASCII. +func safeRune(r rune) (escapedRune []byte, wasEscaped bool) { + switch r { + case '"': + return escapedQuotationMark, true + case '\'': + return escapedApostrophe, true + case '&': + return escapedAmpersand, true + case '<': + return escapedLessThanSign, true + case '>': + return escapedGreaterThanSign, true + default: + } + + if int64(0) <= int64(r) && int64(r) < int64(len(ctrlBlock0)) { + return ctrlBlock0[int(r)], true + } + + if minCtrlBlock1 <= int64(r) && int64(r) < (minCtrlBlock1 + int64(len(ctrlBlock1))) { + return ctrlBlock1[int(r) - minCtrlBlock1], true + } + + return nil, false +} diff --git a/saferune_test.go b/saferune_test.go new file mode 100644 index 0000000..4960ebe --- /dev/null +++ b/saferune_test.go @@ -0,0 +1,1013 @@ +package htmlescape + +import ( + "testing" + + "bytes" +) + +func TestSafeRune(t *testing.T) { + + tests := []struct{ + Rune rune + ExpectedEscaped []byte + ExpectedWasEscaped bool + }{ + { + Rune: '\x00', // NUL + ExpectedEscaped: []byte("�"), + ExpectedWasEscaped: true, + }, + { + Rune: '\x01', // SOH + ExpectedEscaped: []byte(""), + ExpectedWasEscaped: true, + }, + { + Rune: '\x02', // STX + ExpectedEscaped: []byte(""), + ExpectedWasEscaped: true, + }, + { + Rune: '\x03', // ETX + ExpectedEscaped: []byte(""), + ExpectedWasEscaped: true, + }, + { + Rune: '\x04', // EOT + ExpectedEscaped: []byte(""), + ExpectedWasEscaped: true, + }, + { + Rune: '\x05', // ENQ + ExpectedEscaped: []byte(""), + ExpectedWasEscaped: true, + }, + { + Rune: '\x06', // ACK + ExpectedEscaped: []byte(""), + ExpectedWasEscaped: true, + }, + { + Rune: '\x07', // BEL + ExpectedEscaped: []byte(""), + ExpectedWasEscaped: true, + }, + { + Rune: '\x08', // BS + ExpectedEscaped: []byte(""), + ExpectedWasEscaped: true, + }, + { + Rune: '\x09', // HT + ExpectedEscaped: []byte(" "), + ExpectedWasEscaped: true, + }, + { + Rune: '\x0A', // LF + ExpectedEscaped: []byte(" "), + ExpectedWasEscaped: true, + }, + { + Rune: '\x0B', // VT + ExpectedEscaped: []byte(" "), + ExpectedWasEscaped: true, + }, + { + Rune: '\x0C', // FF + ExpectedEscaped: []byte(" "), + ExpectedWasEscaped: true, + }, + { + Rune: '\x0D', // CR + ExpectedEscaped: []byte(" "), + ExpectedWasEscaped: true, + }, + { + Rune: '\x0E', // SO + ExpectedEscaped: []byte(""), + ExpectedWasEscaped: true, + }, + { + Rune: '\x0F', // SI + ExpectedEscaped: []byte(""), + ExpectedWasEscaped: true, + }, + { + Rune: '\x10', // DLE + ExpectedEscaped: []byte(""), + ExpectedWasEscaped: true, + }, + { + Rune: '\x11', // DC1 + ExpectedEscaped: []byte(""), + ExpectedWasEscaped: true, + }, + { + Rune: '\x12', // DC2 + ExpectedEscaped: []byte(""), + ExpectedWasEscaped: true, + }, + { + Rune: '\x13', // DC3 + ExpectedEscaped: []byte(""), + ExpectedWasEscaped: true, + }, + { + Rune: '\x14', // DC4 + ExpectedEscaped: []byte(""), + ExpectedWasEscaped: true, + }, + { + Rune: '\x15', // NAK + ExpectedEscaped: []byte(""), + ExpectedWasEscaped: true, + }, + { + Rune: '\x16', // SYN + ExpectedEscaped: []byte(""), + ExpectedWasEscaped: true, + }, + { + Rune: '\x17', // ETB + ExpectedEscaped: []byte(""), + ExpectedWasEscaped: true, + }, + { + Rune: '\x18', // CAN + ExpectedEscaped: []byte(""), + ExpectedWasEscaped: true, + }, + { + Rune: '\x19', // EM + ExpectedEscaped: []byte(""), + ExpectedWasEscaped: true, + }, + { + Rune: '\x1A', // SUB + ExpectedEscaped: []byte(""), + ExpectedWasEscaped: true, + }, + { + Rune: '\x1B', // ESC + ExpectedEscaped: []byte(""), + ExpectedWasEscaped: true, + }, + { + Rune: '\x1C', // FS + ExpectedEscaped: []byte(""), + ExpectedWasEscaped: true, + }, + { + Rune: '\x1D', // GS + ExpectedEscaped: []byte(""), + ExpectedWasEscaped: true, + }, + { + Rune: '\x1E', // RS + ExpectedEscaped: []byte(""), + ExpectedWasEscaped: true, + }, + { + Rune: '\x1F', // US + ExpectedEscaped: []byte(""), + ExpectedWasEscaped: true, + }, + { + Rune: ' ', // 0x20 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '!', // 0x21 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '"', // 0x22 == 34 + ExpectedEscaped: []byte("""), // """ + ExpectedWasEscaped: true, + }, + { + Rune: '#', // 0x23 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '$', // 0x24 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '%', // 0x25 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '&', // 0x26 + ExpectedEscaped: []byte("&"), + ExpectedWasEscaped: true, + }, + { + Rune: '\'', // 0x27 + ExpectedEscaped: []byte("'"), + ExpectedWasEscaped: true, + }, + { + Rune: '(', // 0x28 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: ')', // 0x29 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '*', // 0x2A + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '+', // 0x2B + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: ',', // 0x2C + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '-', // 0x2D + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '.', // 0x2E + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '/', // 0x2F + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '0', // 0x30 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '1', // 0x31 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '2', // 0x32 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '3', // 0x33 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '4', // 0x34 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '5', // 0x35 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '6', // 0x36 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '7', // 0x37 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '8', // 0x38 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '9', // 0x39 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: ':', // 0x3A + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: ';', // 0x3B + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '<', // 0x3C + ExpectedEscaped: []byte("<"), + ExpectedWasEscaped: true, + }, + { + Rune: '=', // 0x3D + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '>', // 0x3E + ExpectedEscaped: []byte(">"), + ExpectedWasEscaped: true, + }, + { + Rune: '?', // 0x3F + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '@', // 0x40 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'A', // 0x41 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'B', // 0x42 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'C', // 0x43 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'D', // 0x44 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'E', // 0x45 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'F', // 0x46 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'G', // 0x47 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'H', // 0x48 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'I', // 0x49 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'J', // 0x4A + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'K', // 0x4B + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'L', // 0x4C + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'M', // 0x4D + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'N', // 0x4E + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'O', // 0x4F + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'P', // 0x5 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'Q', // 0x51 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'R', // 0x52 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'S', // 0x53 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'T', // 0x54 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'U', // 0x55 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'V', // 0x56 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'W', // 0x57 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'X', // 0x58 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'Y', // 0x59 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'Z', // 0x5A + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '[', // 0x5B + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '\\', // 0x5C + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: ']', // 0x5D + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '^', // 0x5E + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '_', // 0x5F + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '`', // 0x60 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'a', // 0x61 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'b', // 0x62 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'c', // 0x63 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'd', // 0x64 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'e', // 0x65 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'f', // 0x66 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'g', // 0x67 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'h', // 0x68 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'i', // 0x69 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'j', // 0x6A + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'k', // 0x6B + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'l', // 0x6C + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'm', // 0x6D + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'n', // 0x6E + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'o', // 0x6F + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'p', // 0x70 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'q', // 0x71 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'r', // 0x72 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 's', // 0x73 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 't', // 0x74 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'u', // 0x75 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'v', // 0x76 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'w', // 0x77 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'x', // 0x78 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'y', // 0x79 + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: 'z', // 0x7A + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '{', // 0x7B + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '|', // 0x7C + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '}', // 0x7D + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '~', // 0x7E + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '\x7F', // DEL + ExpectedEscaped: []byte(""), + ExpectedWasEscaped: true, + }, + { + Rune: '\x80', // PAD + ExpectedEscaped: []byte("€"), + ExpectedWasEscaped: true, + }, + { + Rune: '\x81', // HOP + ExpectedEscaped: []byte(""), + ExpectedWasEscaped: true, + }, + { + Rune: '\x82', // BPH + ExpectedEscaped: []byte("‚"), + ExpectedWasEscaped: true, + }, + { + Rune: '\x83', // NBH + ExpectedEscaped: []byte("ƒ"), + ExpectedWasEscaped: true, + }, + { + Rune: '\x84', // IND + ExpectedEscaped: []byte("„"), + ExpectedWasEscaped: true, + }, + { + Rune: '\x85', // NEL + ExpectedEscaped: []byte("…"), + ExpectedWasEscaped: true, + }, + { + Rune: '\x86', // SSA + ExpectedEscaped: []byte("†"), + ExpectedWasEscaped: true, + }, + { + Rune: '\x87', // ESA + ExpectedEscaped: []byte("‡"), + ExpectedWasEscaped: true, + }, + { + Rune: '\x88', // HTS + ExpectedEscaped: []byte("ˆ"), + ExpectedWasEscaped: true, + }, + { + Rune: '\x89', // HTJ + ExpectedEscaped: []byte("‰"), + ExpectedWasEscaped: true, + }, + { + Rune: '\x8A', // VTS + ExpectedEscaped: []byte("Š"), + ExpectedWasEscaped: true, + }, + { + Rune: '\x8B', // PLD + ExpectedEscaped: []byte("‹"), + ExpectedWasEscaped: true, + }, + { + Rune: '\x8C', // PLU + ExpectedEscaped: []byte("Œ"), + ExpectedWasEscaped: true, + }, + { + Rune: '\x8D', // RI + ExpectedEscaped: []byte(""), + ExpectedWasEscaped: true, + }, + { + Rune: '\x8E', // SS2 + ExpectedEscaped: []byte("Ž"), + ExpectedWasEscaped: true, + }, + { + Rune: '\x8F', // SS3 + ExpectedEscaped: []byte(""), + ExpectedWasEscaped: true, + }, + { + Rune: '\x90', // DCS + ExpectedEscaped: []byte(""), + ExpectedWasEscaped: true, + }, + { + Rune: '\x91', // PU1 + ExpectedEscaped: []byte("‘"), + ExpectedWasEscaped: true, + }, + { + Rune: '\x92', // PU2 + ExpectedEscaped: []byte("’"), + ExpectedWasEscaped: true, + }, + { + Rune: '\x93', // STS + ExpectedEscaped: []byte("“"), + ExpectedWasEscaped: true, + }, + { + Rune: '\x94', // CCH + ExpectedEscaped: []byte("”"), + ExpectedWasEscaped: true, + }, + { + Rune: '\x95', // MW + ExpectedEscaped: []byte("•"), + ExpectedWasEscaped: true, + }, + { + Rune: '\x96', // SPA + ExpectedEscaped: []byte("–"), + ExpectedWasEscaped: true, + }, + { + Rune: '\x97', // EPA + ExpectedEscaped: []byte("—"), + ExpectedWasEscaped: true, + }, + { + Rune: '\x98', // SOS + ExpectedEscaped: []byte("˜"), + ExpectedWasEscaped: true, + }, + { + Rune: '\x99', // SGC (SGCI) + ExpectedEscaped: []byte("™"), + ExpectedWasEscaped: true, + }, + { + Rune: '\x9A', // SCI + ExpectedEscaped: []byte("š"), + ExpectedWasEscaped: true, + }, + { + Rune: '\x9B', // CSI + ExpectedEscaped: []byte("›"), + ExpectedWasEscaped: true, + }, + { + Rune: '\x9C', // ST + ExpectedEscaped: []byte("œ"), + ExpectedWasEscaped: true, + }, + { + Rune: '\x9D', // OSC + ExpectedEscaped: []byte(""), + ExpectedWasEscaped: true, + }, + { + Rune: '\x9E', // PM + ExpectedEscaped: []byte("ž"), + ExpectedWasEscaped: true, + }, + { + Rune: '\x9F', // APC + ExpectedEscaped: []byte("Ÿ"), + ExpectedWasEscaped: true, + }, + { + Rune: '\u00A0', + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '\u00A1', + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '\u00A2', + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '\u00A3', + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '\u00A4', + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '\u00A5', + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '\u00A6', + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '\u00A7', + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '\u00A8', + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '\u00A9', + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '\u00AA', + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '\u00AB', + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '\u00AC', + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '\u00AD', + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '\u00AE', + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '\u00AF', + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '\u00B0', + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '\u00B1', + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '\u00B2', + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '\u00B3', + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '\u00B4', + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '\u00B5', + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '\u00B6', + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '\u00B7', + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '\u00B8', + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '\u00B9', + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '\u00BA', + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '\u00BB', + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '\u00BC', + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '\u00BD', + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '\u00BE', + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '\u00BF', + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + { + Rune: '\u00C0', + ExpectedEscaped: nil, + ExpectedWasEscaped: false, + }, + } + + for testNumber, test := range tests { + + actualEscaped, actuallyWasEscaped := safeRune(test.Rune) + + { + expected := test.ExpectedWasEscaped + actual := actuallyWasEscaped + + if expected != actual { + t.Errorf("For test #%d, the actual value for was-escaped is not what was expected." , testNumber) + t.Logf("EXPECTED: %t", expected) + t.Logf("ACTUAL: %t", actual) + t.Logf("RUNE: %q (%U)", test.Rune, test.Rune) + continue + } + } + + { + expected := test.ExpectedEscaped + actual := actualEscaped + + if !bytes.Equal(expected, actual) { + t.Errorf("For test #%d, the actual escaped-rune is not what was expected.", testNumber) + t.Logf("EXPECTED: %q", expected) + t.Logf("ACTUAL: %q", actual) + t.Logf("RUNE: %q (%U)", test.Rune, test.Rune) + continue + } + } + } +}