diff --git a/pkg/govis/govis.go b/pkg/govis/govis.go index 9888c27..e8dfb3a 100644 --- a/pkg/govis/govis.go +++ b/pkg/govis/govis.go @@ -17,6 +17,11 @@ package govis +import ( + "strconv" + "strings" +) + // VisFlag manipulates how the characters are encoded/decoded type VisFlag uint @@ -37,3 +42,40 @@ const ( VisWhite VisFlag = (VisSpace | VisTab | VisNewline) ) + +// String pretty-prints VisFlag. +func (vflags VisFlag) String() string { + flagNames := []struct { + name string + bits VisFlag + }{ + {"VisOctal", VisOctal}, + {"VisCStyle", VisCStyle}, + {"VisSpace", VisSpace}, + {"VisTab", VisTab}, + {"VisNewline", VisNewline}, + {"VisSafe", VisSafe}, + {"VisNoSlash", VisNoSlash}, + {"VisHTTPStyle", VisHTTPStyle}, + {"VisGlob", VisGlob}, + } + var ( + flagSet = make([]string, 0, len(flagNames)) + seenBits VisFlag + ) + for _, flag := range flagNames { + if vflags&flag.bits == flag.bits { + seenBits |= flag.bits + flagSet = append(flagSet, flag.name) + } + } + // If there were any remaining flags specified we don't know the name of, + // just add them in an 0x... format. + if remaining := vflags &^ seenBits; remaining != 0 { + flagSet = append(flagSet, "0x"+strconv.FormatUint(uint64(remaining), 16)) + } + if len(flagSet) == 0 { + return "0" + } + return strings.Join(flagSet, "|") +} diff --git a/pkg/govis/govis_test.go b/pkg/govis/govis_test.go index 312cec3..eaab701 100644 --- a/pkg/govis/govis_test.go +++ b/pkg/govis/govis_test.go @@ -18,9 +18,11 @@ package govis import ( - "bytes" "crypto/rand" "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) const DefaultVisFlags = VisWhite | VisOctal | VisGlob @@ -31,31 +33,29 @@ func TestRandomVisUnvis(t *testing.T) { for i := 0; i < N; i++ { testBytes := make([]byte, 256) - if n, err := rand.Read(testBytes); n != cap(testBytes) || err != nil { - t.Fatalf("could not read enough bytes: err=%v n=%d", err, n) - } + + n, err := rand.Read(testBytes) + require.NoErrorf(t, err, "read %d random bytes", len(testBytes)) + require.Equal(t, len(testBytes), n, "read unexpected number of bytes") + test := string(testBytes) for flag := VisFlag(0); flag <= visMask; flag++ { - // VisNoSlash is frankly just a dumb flag, and it is impossible for us - // to actually preserve things in a round-trip. + // VisNoSlash is frankly just a dumb flag, and it is impossible + // for us to actually preserve things in a round-trip. if flag&VisNoSlash == VisNoSlash { continue } enc, err := Vis(test, flag) - if err != nil { - t.Errorf("unexpected error doing vis(%q, %b): %s", test, flag, err) - continue - } + require.NoErrorf(t, err, "vis(%q, %s)", test, flag) + dec, err := Unvis(enc, flag) - if err != nil { - t.Errorf("unexpected error doing unvis(%q, %b): %s", enc, flag, err) + require.NoErrorf(t, err, "unvis(%q, %s)", enc, flag) + + if !assert.Equalf(t, test, dec, "unvis(vis(%q, %b) = %q, %b) round-trip", test, flag, enc, flag) { continue } - if dec != test { - t.Errorf("roundtrip failed: unvis(vis(%q, %b) = %q, %b) = %q", test, flag, enc, flag, dec) - } } } } @@ -66,93 +66,88 @@ func TestRandomVisVisUnvisUnvis(t *testing.T) { for i := 0; i < N; i++ { testBytes := make([]byte, 256) - if n, err := rand.Read(testBytes); n != cap(testBytes) || err != nil { - t.Fatalf("could not read enough bytes: err=%v n=%d", err, n) - } + + n, err := rand.Read(testBytes) + require.NoErrorf(t, err, "read %d random bytes", len(testBytes)) + require.Equal(t, len(testBytes), n, "read unexpected number of bytes") + test := string(testBytes) for flag := VisFlag(0); flag <= visMask; flag++ { - // VisNoSlash is frankly just a dumb flag, and it is impossible for us - // to actually preserve things in a round-trip. + // VisNoSlash is frankly just a dumb flag, and it is impossible + // for us to actually preserve things in a round-trip. if flag&VisNoSlash == VisNoSlash { continue } enc, err := Vis(test, flag) - if err != nil { - t.Errorf("unexpected error doing vis(%q, %b): %s", test, flag, err) - continue - } + require.NoErrorf(t, err, "vis(%q, %s)", test, flag) + enc2, err := Vis(enc, flag) - if err != nil { - t.Errorf("unexpected error doing vis(%q, %b): %s", enc, flag, err) + require.NoErrorf(t, err, "vis(%q, %s)", enc, flag) + + dec2, err := Unvis(enc2, flag) + require.NoErrorf(t, err, "unvis(%q, %s)", enc2, flag) + + dec, err := Unvis(dec2, flag) + require.NoErrorf(t, err, "unvis(%q, %s)", dec2, flag) + + if !assert.Equalf(t, test, dec, "unvis(unvis(vis(vis(%q) = %q) = %q) = %q, %b) round-trip", test, enc, enc2, dec2, flag) { continue } - dec, err := Unvis(enc2, flag) - if err != nil { - t.Errorf("unexpected error doing unvis(%q, %b): %s", enc2, flag, err) - continue - } - dec2, err := Unvis(dec, flag) - if err != nil { - t.Errorf("unexpected error doing unvis(%q, %b): %s", dec, flag, err) - continue - } - if dec2 != test { - t.Errorf("roundtrip failed: unvis(unvis(vis(vis(%q) = %q) = %q) = %q, %b) = %q", test, enc, enc2, dec, flag, dec2) - } } } } func TestVisUnvis(t *testing.T) { - for flag := VisFlag(0); flag <= visMask; flag++ { - // VisNoSlash is frankly just a dumb flag, and it is impossible for us - // to actually preserve things in a round-trip. - if flag&VisNoSlash == VisNoSlash { - continue - } + // Round-trip testing. + for _, test := range []struct { + name string + input string + }{ + {"Empty", ""}, + {"Plain", "hello world"}, + {"Backslash", "THIS\\IS_A_TEST1234"}, + {"Punctuation", "this.is.a.normal_string"}, + {"Unicode1", "AC_Ra\u00edz_Certic\u00e1mara_S.A..pem"}, + {"Unicode2", "NetLock_Arany_=Class_Gold=_F\u0151tan\u00fas\u00edtv\u00e1ny.pem"}, + {"Unicode3", "T\u00dcB\u0130TAK_UEKAE_K\u00f6k_Sertifika_Hizmet_Sa\u011flay\u0131c\u0131s\u0131_-_S\u00fcr\u00fcm_3.pem"}, + {"ExtraPunctuation", "hello world [ this string needs=enco ding! ]"}, + {"Whitespace", "even \n more encoding necessary\a\a "}, + {"WeirdChars", "\024 <-- some more weird characters --> \u4f60\u597d\uff0c\u4e16\u754c"}, + {"DoubleEncoding", "\\xff\\n double encoding is also great fun \\x"}, + {"Unicode1-Encoded", "AC_Ra\\M-C\\M--z_Certic\\M-C\\M-!mara_S.A..pem"}, + {"Rand1", "z^i3i$\u00d3\u008anqgh5/t\u00e5<86>\u00b2kzla\\e^lv\u00df\u0093nv\u00df\u00aea|3}\u00d8\u0088\u00d6\u0084"}, + {"Rand2", `z^i3i$\M-C\M^S\M-B\M^Jnqgh5/t\M-C\M-%<86>\M-B\M-2kzla\\e^lv\M-C\M^_\M-B\M^Snv\M-C\M^_\M-B\M-.a|3}\M-C\M^X\M-B\M^H\M-C\M^V\M-B\M^D`}, + {"Rand3", "@?e1xs+.R_Kjo]7s8pgRP:*nXCE4{!c"}, + {"Rand4", "62_\u00c6\u00c62\u00ae\u00b7m\u00db\u00c3r^\u00bfp\u00c6u'q\u00fbc2\u00f0u\u00b8\u00dd\u00e8v\u00ff\u00b0\u00dc\u00c2\u00f53\u00db-k\u00f2sd4\\p\u00da\u00a6\u00d3\u00eea<\u00e6s{\u00a0p\u00f0\u00ffj\u00e0\u00e8\u00b8\u00b8\u00bc\u00fcb"}, + {"Rand4-Encoded", `62_\M-C\M^F\M-C\M^F2\M-B\M-.\M-B\M-7m\M-C\M^[\M-C\M^Cr^\M-B\M-?p\M-C\M^Fu'q\M-C\M-;c2\M-C\M-0u\M-B\M-8\M-C\M^]\M-C\M-(v\M-C\M-?\M-B\M-0\M-C\M^\\M-C\M^B\M-C\M-53\M-C\M^[-k\M-C\M-2sd4\\p\M-C\M^Z\M-B\M-&\M-C\M^S\M-C\M-.a<\M-C\M-&s{\M-B\240p\M-C\M-0\M-C\M-?j\M-C\240\M-C\M-(\M-B\M-8\M-B\M-8\M-B\M-<\M-C\M- \u4f60\u597d\uff0c\u4e16\u754c", - "\\xff\\n double encoding is also great fun \\x", - "AC_Ra\\M-C\\M--z_Certic\\M-C\\M-!mara_S.A..pem", - "z^i3i$\u00d3\u008anqgh5/t\u00e5<86>\u00b2kzla\\e^lv\u00df\u0093nv\u00df\u00aea|3}\u00d8\u0088\u00d6\u0084", - `z^i3i$\M-C\M^S\M-B\M^Jnqgh5/t\M-C\M-%<86>\M-B\M-2kzla\\e^lv\M-C\M^_\M-B\M^Snv\M-C\M^_\M-B\M-.a|3}\M-C\M^X\M-B\M^H\M-C\M^V\M-B\M^D`, - "@?e1xs+.R_Kjo]7s8pgRP:*nXCE4{!c", - "62_\u00c6\u00c62\u00ae\u00b7m\u00db\u00c3r^\u00bfp\u00c6u'q\u00fbc2\u00f0u\u00b8\u00dd\u00e8v\u00ff\u00b0\u00dc\u00c2\u00f53\u00db-k\u00f2sd4\\p\u00da\u00a6\u00d3\u00eea<\u00e6s{\u00a0p\u00f0\u00ffj\u00e0\u00e8\u00b8\u00b8\u00bc\u00fcb", - `62_\M-C\M^F\M-C\M^F2\M-B\M-.\M-B\M-7m\M-C\M^[\M-C\M^Cr^\M-B\M-?p\M-C\M^Fu'q\M-C\M-;c2\M-C\M-0u\M-B\M-8\M-C\M^]\M-C\M-(v\M-C\M-?\M-B\M-0\M-C\M^\\M-C\M^B\M-C\M-53\M-C\M^[-k\M-C\M-2sd4\\p\M-C\M^Z\M-B\M-&\M-C\M^S\M-C\M-.a<\M-C\M-&s{\M-B\240p\M-C\M-0\M-C\M-?j\M-C\240\M-C\M-(\M-B\M-8\M-B\M-8\M-B\M-<\M-C\M-