From cb88f405d8a43c0a62d4ecf64e66c2194ce989e6 Mon Sep 17 00:00:00 2001 From: Charles Iliya Krempeaux Date: Mon, 25 Mar 2024 23:05:26 -0700 Subject: [PATCH] vertical-tab --- README.md | 1 + circumstance.go | 2 + notfound.go | 7 ++ readeol.go | 4 + readeol_test.go | 11 +++ readvt.go | 24 ++++++ readvt_test.go | 209 ++++++++++++++++++++++++++++++++++++++++++++++++ vt/byte.go | 3 + vt/rune.go | 3 + vt/string.go | 3 + 10 files changed, 267 insertions(+) create mode 100644 readvt.go create mode 100644 readvt_test.go create mode 100644 vt/byte.go create mode 100644 vt/rune.go create mode 100644 vt/string.go diff --git a/README.md b/README.md index ecf6e88..cf70303 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ Package **eol** implements tools for working with end-of-line, for the Go progra The end-of-line sequences it supports is: * `"\n" // line-feed (LF)` +* `"\v" // vertical-tab (VT)` * `"\n\r" // line-feed (LF), carriage-return (CR)` * `"\r" // carriage-return (CR)` * `"\r\n" // carriage-return (CR), line-feed (LF)` diff --git a/circumstance.go b/circumstance.go index 9a03e1d..ee87b3d 100644 --- a/circumstance.go +++ b/circumstance.go @@ -28,6 +28,8 @@ import ( // // var circumstance internalCircumstance = specifyCircumstance(opt.Something]("\n"), 1) // +// var circumstance internalCircumstance = specifyCircumstance(opt.Something]("\v"), 1) +// // var circumstance internalCircumstance = specifyCircumstance(opt.Something]("\r"), 1) // // var circumstance internalCircumstance = specifyCircumstance(opt.Something]("\r\n"), 1) diff --git a/notfound.go b/notfound.go index 863bc97..abb8a79 100644 --- a/notfound.go +++ b/notfound.go @@ -9,6 +9,7 @@ import ( "sourcecode.social/reiver/go-eol/lf" "sourcecode.social/reiver/go-eol/ls" "sourcecode.social/reiver/go-eol/nel" + "sourcecode.social/reiver/go-eol/vt" ) var _ error = internalNotFoundError{} @@ -46,6 +47,12 @@ func (receiver internalNotFoundError) Error() string { s = fmt.Sprintf(`eol: line-feed (LF) character ('\n') (U+000A) not found for end-of-line sequence %q character №%d — instead found %q (%U)`, sequence, characterNumber, actual, actual) }) p = append(p, s...) + case vt.Rune: + var s string = fmt.Sprintf(`eol: vertical-tab (VT) character ('\v') (U+000B) not found for end-of-line sequence character №%d — instead found %q (%U)`, characterNumber, actual, actual) + eolSequence.WhenSomething(func(sequence string){ + s = fmt.Sprintf(`eol: vertical-tab (VT) character ('\v') (U+000B) not found for end-of-line sequence %q character №%d — instead found %q (%U)`, sequence, characterNumber, actual, actual) + }) + p = append(p, s...) case cr.Rune: var s string = fmt.Sprintf(`eol: carriage-return (CR) character ('\r') (U+000D) not found for end-of-line sequence character №%d — instead found %q (%U)`, characterNumber, actual, actual) eolSequence.WhenSomething(func(sequence string){ diff --git a/readeol.go b/readeol.go index c1226c9..ef2924b 100644 --- a/readeol.go +++ b/readeol.go @@ -11,6 +11,7 @@ import ( "sourcecode.social/reiver/go-eol/lfcr" "sourcecode.social/reiver/go-eol/ls" "sourcecode.social/reiver/go-eol/nel" + "sourcecode.social/reiver/go-eol/vt" ) // ReadEOL tries to read an end-of-line sequence. @@ -18,6 +19,7 @@ import ( // The end-of-line sequences it supports are: // // line-feed (LF) (U+000A) ('\n') +// vertical-tab (VT) (U+000B) ('\v') // line-feed, carriage-return ("\n\r") // carriage-return (CR) (U+000D) ('\r') // carriage-return, line-feed ("\r\n") @@ -52,6 +54,8 @@ func ReadEOL(runescanner io.RuneScanner) (endofline string, size int, err error) switch r0 { case lf.Rune: // Nothing here. + case vt.Rune: + return vt.String, size0, nil case cr.Rune: // Nothing here. case nel.Rune: diff --git a/readeol_test.go b/readeol_test.go index c3d2282..25e91e5 100644 --- a/readeol_test.go +++ b/readeol_test.go @@ -15,6 +15,7 @@ import ( "sourcecode.social/reiver/go-eol/lfcr" "sourcecode.social/reiver/go-eol/ls" "sourcecode.social/reiver/go-eol/nel" + "sourcecode.social/reiver/go-eol/vt" ) func TestReadEOL(t *testing.T) { @@ -29,6 +30,11 @@ func TestReadEOL(t *testing.T) { ExpectedEOL: lf.String, ExpectedSize: 1, }, + { + Value: "\v", + ExpectedEOL: vt.String, + ExpectedSize: 1, + }, { Value: "\n\r", ExpectedEOL: lfcr.String, @@ -62,6 +68,11 @@ func TestReadEOL(t *testing.T) { ExpectedEOL: lf.String, ExpectedSize: 1, }, + { + Value: "\vapple banana cherry", + ExpectedEOL: vt.String, + ExpectedSize: 1, + }, { Value: "\n\rapple banana cherr", ExpectedEOL: lfcr.String, diff --git a/readvt.go b/readvt.go new file mode 100644 index 0000000..3274729 --- /dev/null +++ b/readvt.go @@ -0,0 +1,24 @@ +package eol + +import ( + "io" + + "sourcecode.social/reiver/go-opt" + + "sourcecode.social/reiver/go-eol/vt" +) + +// ReadVT tries to read the "\r" (i.e., carriage-return) end-of-line sequence. +// +// If successful, it returns the number-of-bytes read (to read in end-of-line sequence "\r"). +// +// If the character read is not a '\r', then ReadVT will try to unread the character. +// +// Example usage: +// +// size, err := eol.ReadVT(runescanner) +func ReadVT(runescanner io.RuneScanner) (size int, err error) { + const characterNumber uint64 = 1 + var circumstance internalCircumstance = specifyCircumstance(opt.Something(vt.String), characterNumber) + return readthisrune(circumstance, runescanner, vt.Rune) +} diff --git a/readvt_test.go b/readvt_test.go new file mode 100644 index 0000000..c2b75f9 --- /dev/null +++ b/readvt_test.go @@ -0,0 +1,209 @@ +package eol_test + +import ( + "testing" + + "io" + "strings" + + "sourcecode.social/reiver/go-utf8" + + "sourcecode.social/reiver/go-eol" +) + +func TestReadVT(t *testing.T) { + + tests := []struct{ + Value string + ExpectedSize int + }{ + { + Value: "\v", + ExpectedSize: 1, + }, + + + + { + Value: "\vapple banana cherry", + ExpectedSize: 1, + }, + } + + for testNumber, test := range tests { + + var reader io.Reader = strings.NewReader(test.Value) + var runescanner io.RuneScanner = utf8.NewRuneScanner(reader) + + actualSize, err := eol.ReadVT(runescanner) + if nil != err { + t.Errorf("For test #%d, did not expect an error but actually got one.", testNumber) + t.Logf("ERROR: (%T) %s", err, err) + t.Logf("VALUE: %q", test.Value) + continue + } + + { + expected := test.ExpectedSize + actual := actualSize + + if expected != actual { + t.Errorf("For test #%d, the actual size is not what was expected.", testNumber) + t.Logf("EXPECTED: %d", expected) + t.Logf("ACTUAL: %d", actual) + t.Logf("VALUE: %q", test.Value) + continue + } + } + + } +} + +func TestReadVT_fail(t *testing.T) { + + tests := []struct{ + Value string + ExpectedError string + }{ + { + Value: "", + ExpectedError: `eol: problem reading character №1 of end-of-line sequence "\v": EOF`, + }, + + + + { + Value: "\n", + ExpectedError: `eol: vertical-tab (VT) character ('\v') (U+000B) not found for end-of-line sequence "\v" character №1 — instead found '\n' (U+000A)`, + }, + { + Value: "\u0085", + ExpectedError: `eol: vertical-tab (VT) character ('\v') (U+000B) not found for end-of-line sequence "\v" character №1 — instead found '\u0085' (U+0085)`, + }, + { + Value: "\u2028", + ExpectedError: `eol: vertical-tab (VT) character ('\v') (U+000B) not found for end-of-line sequence "\v" character №1 — instead found '\u2028' (U+2028)`, + }, + + + + { + Value: "😈", + ExpectedError: `eol: vertical-tab (VT) character ('\v') (U+000B) not found for end-of-line sequence "\v" character №1 — instead found '😈' (U+1F608)`, + }, + + + + { + Value: "\napple banana cherry", + ExpectedError: `eol: vertical-tab (VT) character ('\v') (U+000B) not found for end-of-line sequence "\v" character №1 — instead found '\n' (U+000A)`, + }, + { + Value: "\u0085apple banana cherry", + ExpectedError: `eol: vertical-tab (VT) character ('\v') (U+000B) not found for end-of-line sequence "\v" character №1 — instead found '\u0085' (U+0085)`, + }, + { + Value: "\u2028apple banana cherry", + ExpectedError: `eol: vertical-tab (VT) character ('\v') (U+000B) not found for end-of-line sequence "\v" character №1 — instead found '\u2028' (U+2028)`, + }, + + + + { + Value: "😈apple banana cherry", + ExpectedError: `eol: vertical-tab (VT) character ('\v') (U+000B) not found for end-of-line sequence "\v" character №1 — instead found '😈' (U+1F608)`, + }, + + + + { + Value: " \n", + ExpectedError: `eol: vertical-tab (VT) character ('\v') (U+000B) not found for end-of-line sequence "\v" character №1 — instead found ' ' (U+0020)`, + }, + { + Value: " \r", + ExpectedError: `eol: vertical-tab (VT) character ('\v') (U+000B) not found for end-of-line sequence "\v" character №1 — instead found ' ' (U+0020)`, + }, + { + Value: " \u0085", + ExpectedError: `eol: vertical-tab (VT) character ('\v') (U+000B) not found for end-of-line sequence "\v" character №1 — instead found ' ' (U+0020)`, + }, + { + Value: " \u2028", + ExpectedError: `eol: vertical-tab (VT) character ('\v') (U+000B) not found for end-of-line sequence "\v" character №1 — instead found ' ' (U+0020)`, + }, + + + + { + Value: " 😈", + ExpectedError: `eol: vertical-tab (VT) character ('\v') (U+000B) not found for end-of-line sequence "\v" character №1 — instead found ' ' (U+0020)`, + }, + + + + { + Value: ".\n", + ExpectedError: `eol: vertical-tab (VT) character ('\v') (U+000B) not found for end-of-line sequence "\v" character №1 — instead found '.' (U+002E)`, + }, + { + Value: ".\r", + ExpectedError: `eol: vertical-tab (VT) character ('\v') (U+000B) not found for end-of-line sequence "\v" character №1 — instead found '.' (U+002E)`, + }, + { + Value: ".\u0085", + ExpectedError: `eol: vertical-tab (VT) character ('\v') (U+000B) not found for end-of-line sequence "\v" character №1 — instead found '.' (U+002E)`, + }, + { + Value: ".\u2028", + ExpectedError: `eol: vertical-tab (VT) character ('\v') (U+000B) not found for end-of-line sequence "\v" character №1 — instead found '.' (U+002E)`, + }, + + + + { + Value: ".😈", + ExpectedError: `eol: vertical-tab (VT) character ('\v') (U+000B) not found for end-of-line sequence "\v" character №1 — instead found '.' (U+002E)`, + }, + } + + for testNumber, test := range tests { + + var reader io.Reader = strings.NewReader(test.Value) + var runescanner io.RuneScanner = utf8.NewRuneScanner(reader) + + actualSize, err := eol.ReadVT(runescanner) + if nil == err { + t.Errorf("For test #%d, expected an error but did not actually get one.", testNumber) + t.Logf("EXPECTED-ERROR: %q", test.ExpectedError) + t.Logf("VALUE: %q", test.Value) + continue + } + + { + expected := test.ExpectedError + actual := err.Error() + + if expected != actual { + t.Errorf("For test #%d, the actual error is not what was expected.", testNumber) + t.Logf("EXPECTED: %q", expected) + t.Logf("ACTUAL: %q", actual) + t.Logf("VALUE: %q", test.Value) + continue + } + } + + { + expected := 0 + actual := actualSize + + if expected != actual { + t.Errorf("For test #%d, the actual size is not what was expected.", testNumber) + t.Logf("EXPECTED: %d", expected) + t.Logf("ACTUAL: %d", actual) + t.Logf("VALUE: %q", test.Value) + continue + } + } + } +} diff --git a/vt/byte.go b/vt/byte.go new file mode 100644 index 0000000..c11cada --- /dev/null +++ b/vt/byte.go @@ -0,0 +1,3 @@ +package vt + +const Byte byte = '\u000B' diff --git a/vt/rune.go b/vt/rune.go new file mode 100644 index 0000000..25fe4f4 --- /dev/null +++ b/vt/rune.go @@ -0,0 +1,3 @@ +package vt + +const Rune rune = '\u000B' diff --git a/vt/string.go b/vt/string.go new file mode 100644 index 0000000..dcad98f --- /dev/null +++ b/vt/string.go @@ -0,0 +1,3 @@ +package vt + +const String string = string(Rune)