├── LICENSE ├── doc.go ├── fmtc.go ├── README.md ├── decorator.go └── fmtc_test.go /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Pronin S.V. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Pronin S.V. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | /* 6 | The fmtc overrides the print functions of the fmt package, but with the ability to color output in bash using HTML tags 7 | 8 | Available text decoration tags: 9 | - make font Bold 10 | - make font Bold 11 | - make text Underlined 12 | - make font Dim 13 | - Reverse background anf font color 14 | - make text Blink (not working on Mint/Ubuntu) 15 | - set font color Black (Dark) 16 | - set font color Red 17 | - set font color Green 18 | - set font color Yellow 19 | - set font color Blue 20 | - set font color Magenta 21 | - set font color Cyan 22 | - set font color Grey (Smokey) 23 | - set font color White 24 | 25 | Available background colors tags: 26 | - black background color 27 | - red background color 28 | - green background color 29 | - yellow background color 30 | - blue background color 31 | - magenta background color 32 | - cyan background color 33 | - grey background color 34 | - white background color 35 | 36 | - black background color 37 | - red background color 38 | - green background color 39 | - yellow background color 40 | - blue background color 41 | - magenta background color 42 | - cyan background color 43 | - grey background color 44 | - white background color 45 | 46 | Examples: 47 | 48 | fmtc.Print("HELLO WORLD") 49 | fmtc.Println("HELLO WORLD") 50 | fmtc.Printf("%v: %v", name, result) 51 | */ 52 | 53 | package fmtc 54 | -------------------------------------------------------------------------------- /fmtc.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Pronin S.V. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package fmtc 6 | 7 | import ( 8 | "fmt" 9 | "io" 10 | ) 11 | 12 | // Fprint formats using the default formats for its operands and writes to w. 13 | // Spaces are added between operands when neither is a string. 14 | // It returns the number of bytes written and any write error encountered. 15 | func Fprint(w io.Writer, a ...interface{}) (n int, err error) { 16 | decorateIface(&a) 17 | return fmt.Fprint(w, a...) 18 | } 19 | 20 | // Fprintln formats using the default formats for its operands and writes to w. 21 | // Spaces are always added between operands and a newline is appended. 22 | // It returns the number of bytes written and any write error encountered. 23 | func Fprintln(w io.Writer, a ...interface{}) (n int, err error) { 24 | decorateIface(&a) 25 | return fmt.Fprintln(w, a...) 26 | } 27 | 28 | // Fprintf formats according to a format specifier and writes to w. 29 | // It returns the number of bytes written and any write error encountered. 30 | func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { 31 | return fmt.Fprintf(w, decorate(format), a...) 32 | } 33 | 34 | // Print formats using the default formats for its operands and writes to standard output. 35 | // Spaces are added between operands when neither is a string. 36 | // It returns the number of bytes written and any write error encountered. 37 | func Print(a ...interface{}) (n int, err error) { 38 | decorateIface(&a) 39 | return fmt.Print(a...) 40 | } 41 | 42 | // Printf formats according to a format specifier and writes to standard output. 43 | // It returns the number of bytes written and any write error encountered. 44 | func Printf(format string, a ...interface{}) (n int, err error) { 45 | return fmt.Printf(decorate(format), a...) 46 | } 47 | 48 | // Println formats using the default formats for its operands and writes to standard output. 49 | // Spaces are always added between operands and a newline is appended. 50 | // It returns the number of bytes written and any write error encountered. 51 | func Println(a ...interface{}) (n int, err error) { 52 | decorateIface(&a) 53 | return fmt.Println(a...) 54 | } 55 | 56 | // Sprint formats using the default formats for its operands and returns the resulting string. 57 | // Spaces are added between operands when neither is a string. 58 | func Sprint(a ...interface{}) string { 59 | decorateIface(&a) 60 | return fmt.Sprint(a...) 61 | } 62 | 63 | // Sprintf formats according to a format specifier and returns the resulting string. 64 | func Sprintf(format string, a ...interface{}) string { 65 | return fmt.Sprintf(decorate(format), a...) 66 | } 67 | 68 | // Sprintln formats using the default formats for its operands and returns the resulting string. 69 | // Spaces are always added between operands and a newline is appended. 70 | func Sprintln(a ...interface{}) string { 71 | decorateIface(&a) 72 | return fmt.Sprintln(a...) 73 | } 74 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # fmtc 2 | The fmtc overrides the print functions of the fmt package, but with the ability to color output in bash using HTML tags 3 | 4 | ### Available text decoration tags 5 | 6 | ``` 7 | - make font Bold 8 | - make font Bold 9 | - make text Underlined 10 | - make font Dim 11 | - Reverse background and font color 12 | - make text Blink (not working on Mint/Ubuntu) 13 | - set font color Black (Dark) 14 | - set font color Red 15 | - set font color Green 16 | - set font color Yellow 17 | - set font color Blue 18 | - set font color Magenta 19 | - set font color Cyan 20 | - set font color Grey (Smokey) 21 | - set font color White 22 | ``` 23 | ### Available background colors tags: 24 | ``` 25 | - black background color 26 | - red background color 27 | - green background color 28 | - yellow background color 29 | - blue background color 30 | - magenta background color 31 | - cyan background color 32 | - grey background color 33 | - white background color 34 | 35 | - black background color 36 | - red background color 37 | - green background color 38 | - yellow background color 39 | - blue background color 40 | - magenta background color 41 | - cyan background color 42 | - grey background color 43 | - white background color 44 | ``` 45 | 46 | ### Install: 47 | ```bash 48 | go get github.com/Pronin1986/fmtc 49 | ``` 50 | 51 | ### Usage: 52 | ```golang 53 | fmtc.Print(`HELLO BLUE TEXT`) 54 | fmtc.Println(`HELLO BLUE TEXT`) 55 | fmtc.Printf(`%v %v %v`, "HELLO", "BLUE", "TEXT") 56 | ``` 57 | 58 | ```golang 59 | got: = fmtc.Sprint(`HELLO BLUE TEXT`) 60 | got = fmtc.Sprintln(`HELLO BLUE TEXT`) 61 | got = fmtc.Sprintf(`%v %v %v`, "HELLO", "BLUE", "TEXT") 62 | ``` 63 | 64 | ```golang 65 | buf := new(bytes.Buffer) 66 | fmtc.Fprint(buf, `HELLO BLUE TEXT`) 67 | fmtc.Fprintln(buf, `HELLO BLUE TEXT`) 68 | fmtc.Fprintf(buf, `%v %v %v`, "HELLO", "BLUE", "TEXT") 69 | ``` 70 | 71 | You have already decorated text for console output like a picture above: 72 | 73 | ![UsageExampleResult](http://www.pronin86.ru/git/fmtc/example.png) 74 | 75 | ### Example: 76 | 77 | ```golang 78 | package main 79 | 80 | import ( 81 | "fmt" 82 | 83 | "github.com/Pronin1986/fmtc" 84 | ) 85 | 86 | func main() { 87 | fmt.Println("HELLO WORLD") 88 | fmtc.Println("HELLO WORLD") 89 | } 90 | ``` 91 | 92 | ![ExampleResult](http://www.pronin86.ru/git/fmtc/example2.png) 93 | 94 | -------------------------------------------------------------------------------- /decorator.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Pronin S.V. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package fmtc 6 | 7 | import ( 8 | "regexp" 9 | "strings" 10 | "unicode/utf8" 11 | 12 | "golang.org/x/net/html" 13 | ) 14 | 15 | const ( 16 | //CODERESET reset style after this code 17 | CODERESET = "\033[0m" 18 | ) 19 | 20 | // An array of tag and ASCI code matches for text 21 | var fontStyle = map[string]string{ 22 | "b": "1", // - Bold 23 | "strong": "1", // - Bold 24 | "u": "4", // - Underline 25 | "dim": "2", // - Dim 26 | "reverse": "7", // - Reverse 27 | "blink": "5", // - Blink 28 | "black": "30", // - Black (Dark) 29 | "red": "31", // - Red 30 | "green": "32", // - Green 31 | "yellow": "33", // - Yellow 32 | "blue": "34", // - Blue 33 | "magenta": "35", // - Magenta 34 | "cyan": "36", // - Cyan 35 | "grey": "37", // - Grey (Smokey) 36 | "white": "97", // - White 37 | } 38 | 39 | // An array of tag and ASCI code matches for background colors 40 | var background = map[string]string{ 41 | "black": "40", // Black (Dark) 42 | "red": "41", // Red 43 | "green": "42", // Green 44 | "yellow": "43", // Yellow 45 | "blue": "44", // Blue 46 | "magenta": "45", // Magenta 47 | "cyan": "46", // Cyan 48 | "grey": "47", // Grey (Smokey) 49 | "white": "107", // White 50 | } 51 | 52 | // LIFO stack struct fir HTML tags 53 | type stack struct { 54 | items []tag 55 | } 56 | 57 | // push add element to stack 58 | func (stack *stack) push(value tag) { 59 | stack.items = append(stack.items, value) 60 | } 61 | 62 | // pop delete element from stack 63 | func (stack *stack) pop(tag tag) bool { 64 | if len(stack.items) > 0 { 65 | i := len(stack.items) - 1 66 | if stack.items[i].name == tag.name { 67 | stack.items = stack.items[:i] 68 | return true 69 | } 70 | } 71 | return false 72 | } 73 | 74 | // tag in this struct we store html-tag name and map of tag attributes 75 | type tag struct { 76 | name string 77 | attr map[string]string 78 | } 79 | 80 | // decorate string using HTML tags from her 81 | // It returns decorated string 82 | func decorate(str string) string { 83 | //get io.Reader from string 84 | reader := strings.NewReader(str) 85 | //get HTML Tokenizer from io.Reader 86 | d := html.NewTokenizer(reader) 87 | //Stack of unclosed HTML tags 88 | tagsStack := stack{} 89 | //Result string 90 | finalString := "" 91 | for { 92 | tokenType := d.Next() 93 | 94 | //if str is end, or if error 95 | if tokenType == html.ErrorToken { 96 | 97 | finalString += CODERESET 98 | return finalString 99 | } 100 | 101 | //get current token of str 102 | token := d.Token() 103 | switch tokenType { 104 | //if token type is StartTag (like ) 105 | case html.StartTagToken: 106 | oneTag := tag{name: token.Data} 107 | //try to get tag attributes 108 | if len(token.Attr) > 0 { 109 | tagAttr := make(map[string]string) 110 | for _, attr := range token.Attr { 111 | tagAttr[attr.Key] = attr.Val 112 | } 113 | oneTag.attr = tagAttr 114 | } 115 | //try to get tag ANSI code 116 | tagCode := getASCICode(oneTag) 117 | if utf8.RuneCountInString(tagCode) > 0 { 118 | //if ANSI code exists, then we add them to string 119 | finalString += tagCode 120 | //and add current tag in stack of opened tags 121 | tagsStack.push(oneTag) 122 | } else { 123 | //if tag ANSI code not exists, then add to final string tag 124 | finalString += token.String() 125 | } 126 | //if curent token is text 127 | case html.TextToken: 128 | //then add this text to final string 129 | finalString += token.Data 130 | //if current token is SelfClosingTag (like
) 131 | case html.SelfClosingTagToken: 132 | //add tag to string 133 | finalString += token.String() 134 | //if current token is EndTag (like
) 135 | case html.EndTagToken: 136 | oneTag := tag{name: token.Data} 137 | //try to pop last tag from stack (Success if the last stack tag matches the current closing tag) 138 | if tagsStack.pop(oneTag) == true { 139 | finalString += CODERESET 140 | finalString += applyOpenedTags(tagsStack) 141 | } else { 142 | finalString += token.String() 143 | } 144 | } 145 | } 146 | } 147 | 148 | // decorateIface decorator for an empty interface 149 | func decorateIface(a *[]interface{}) { 150 | for i, x := range *a { 151 | if s, ok := x.(string); ok { 152 | (*a)[i] = decorate(s) 153 | } 154 | } 155 | } 156 | 157 | // applyOpenedTags apply to string not closed tagsArr 158 | // It returns string with ASCI codes of not closet tags 159 | func applyOpenedTags(tagsStack stack) string { 160 | if len(tagsStack.items) == 0 { 161 | return "" 162 | } 163 | tagsStr := "" 164 | for _, tag := range tagsStack.items { 165 | tagCode := getASCICode(tag) 166 | if utf8.RuneCountInString(tagCode) > 0 { 167 | tagsStr += tagCode 168 | } 169 | } 170 | return tagsStr 171 | } 172 | 173 | // getASCICode get ASCI code of font style or background color 174 | // It returns the code of current tag 175 | func getASCICode(tag tag) string { 176 | code := "" 177 | var validShortBG = regexp.MustCompile(`^b_([A-Za-z]+)$`) 178 | 179 | if tag.name == "bg" { 180 | if color, ok := tag.attr["color"]; ok { 181 | code = background[color] 182 | } 183 | } else if validShortBG.MatchString(tag.name) { 184 | bgColor := validShortBG.FindStringSubmatch(tag.name) 185 | code = background[bgColor[1]] 186 | } else { 187 | code = fontStyle[tag.name] 188 | } 189 | if utf8.RuneCountInString(code) > 0 { 190 | code = "\033[" + code + "m" 191 | } 192 | return code 193 | } 194 | -------------------------------------------------------------------------------- /fmtc_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Pronin S.V. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package fmtc 6 | 7 | import ( 8 | "bytes" 9 | "testing" 10 | ) 11 | 12 | func TestStackSuccessDelete(t *testing.T) { 13 | oneTag := tag{name: "b"} 14 | tagStack := stack{} 15 | tagStack.push(oneTag) 16 | 17 | if tagStack.pop(oneTag) == false { 18 | t.Error("tagStack.pop(oneTag) == false - сould not delete existing text") 19 | } 20 | } 21 | 22 | func TestStackFalseDelete(t *testing.T) { 23 | oneTag := tag{name: "b"} 24 | tagStack := stack{} 25 | tagStack.push(oneTag) 26 | 27 | oneTag2 := tag{name: "u"} 28 | if tagStack.pop(oneTag2) == true { 29 | t.Error("tagStack.pop(oneTag2) == true - error deleting") 30 | } 31 | } 32 | 33 | func TestStackFalseDeleteEmptyStack(t *testing.T) { 34 | tagStack := stack{} 35 | oneTag2 := tag{name: "u"} 36 | if tagStack.pop(oneTag2) == true { 37 | t.Error("tagStack.pop(oneTag2) == true - error deleting") 38 | } 39 | } 40 | 41 | func TestGetASCICode(t *testing.T) { 42 | var tests = []struct { 43 | input tag 44 | want string 45 | }{ 46 | {tag{name: "b"}, "\033[1m"}, 47 | {tag{name: "strong"}, "\033[1m"}, 48 | {tag{name: "u"}, "\033[4m"}, 49 | {tag{name: "dim"}, "\033[2m"}, 50 | {tag{name: "reverse"}, "\033[7m"}, 51 | {tag{name: "blink"}, "\033[5m"}, 52 | {tag{name: "black"}, "\033[30m"}, 53 | {tag{name: "red"}, "\033[31m"}, 54 | {tag{name: "green"}, "\033[32m"}, 55 | {tag{name: "yellow"}, "\033[33m"}, 56 | {tag{name: "blue"}, "\033[34m"}, 57 | {tag{name: "magenta"}, "\033[35m"}, 58 | {tag{name: "cyan"}, "\033[36m"}, 59 | {tag{name: "grey"}, "\033[37m"}, 60 | {tag{name: "white"}, "\033[97m"}, 61 | {tag{name: "bg", attr: map[string]string{"color": "red"}}, "\033[41m"}, 62 | {tag{name: "bg", attr: map[string]string{"color": "blue"}}, "\033[44m"}, 63 | {tag{name: "bg", attr: map[string]string{"color": "wrong"}}, ""}, 64 | {tag{name: "b_blue"}, "\033[44m"}, 65 | {tag{name: "b_red"}, "\033[41m"}, 66 | {tag{name: "bred"}, ""}, 67 | {tag{name: "b_rred"}, ""}, 68 | {tag{name: "wrong"}, ""}, 69 | {tag{name: "wrong wrong"}, ""}, 70 | {tag{name: "hui"}, ""}, 71 | {tag{name: " "}, ""}, 72 | {tag{name: "****"}, ""}, 73 | {tag{name: "\033[1m"}, ""}, 74 | {tag{name: "\033[1m;;;;;"}, ""}, 75 | {tag{name: "\\\\\\////\\"}, ""}, 76 | } 77 | 78 | for _, test := range tests { 79 | if got := getASCICode(test.input); got != test.want { 80 | t.Errorf("getASCICode(%v) = '%v' (SUCCEESS: %v)", test.input.name, got, test.want) 81 | } 82 | } 83 | } 84 | 85 | func TestDecorate(t *testing.T) { 86 | someVar := "SOME TEXT" 87 | var tests = []struct { 88 | want string 89 | got string 90 | }{ 91 | {"BOLD", "\033[1mBOLD\033[0m\033[0m"}, 92 | {"" + someVar + "", "\033[1m" + someVar + "\033[0m\033[0m"}, 93 | {"BOLD BLUE", "\033[1mBOLD \033[34mBLUE\033[0m\033[1m\033[0m\033[0m"}, 94 | {"HELLO BLUE TEXT", "\033[1mHELLO \033[34mBLUE\033[0m\033[1m \033[42mTEXT\033[0m\033[1m\033[0m\033[0m"}, 95 | } 96 | 97 | for _, test := range tests { 98 | if decorate(test.want) != test.got { 99 | t.Errorf("decorate(\"%v\") != ' %v '", test.want, test.got) 100 | } 101 | } 102 | } 103 | 104 | func TestPrint(t *testing.T) { 105 | _, err := Print("BOLD BLUE TEXT") 106 | if err != nil { 107 | t.Error("Print failed") 108 | } 109 | } 110 | 111 | func TestPrintln(t *testing.T) { 112 | _, err := Println("BOLD BLUE TEXT") 113 | if err != nil { 114 | t.Error("Println failed") 115 | } 116 | } 117 | 118 | func TestPrintf(t *testing.T) { 119 | bold := "BOLD" 120 | blue := "BLUE" 121 | txt := "TEXT" 122 | 123 | _, err := Printf("%v %v %v", bold, blue, txt) 124 | if err != nil { 125 | t.Error("Printf failed") 126 | } 127 | } 128 | 129 | func TestSprint(t *testing.T) { 130 | someVar := "SOME TEXT" 131 | var tests = []struct { 132 | want string 133 | got string 134 | }{ 135 | {"BOLD", "\033[1mBOLD\033[0m\033[0m"}, 136 | {"" + someVar + "", "\033[1m" + someVar + "\033[0m\033[0m"}, 137 | {"BOLD BLUE", "\033[1mBOLD \033[34mBLUE\033[0m\033[1m\033[0m\033[0m"}, 138 | {"HELLO BLUE TEXT", "\033[1mHELLO \033[34mBLUE\033[0m\033[1m \033[42mTEXT\033[0m\033[1m\033[0m\033[0m"}, 139 | } 140 | 141 | for _, test := range tests { 142 | if Sprint(test.want) != test.got { 143 | t.Errorf("Sprint(\"%v\") != '%v'", test.want, test.got) 144 | } 145 | } 146 | } 147 | 148 | func TestSprintln(t *testing.T) { 149 | someVar := "SOME TEXT" 150 | var tests = []struct { 151 | want string 152 | got string 153 | }{ 154 | {"BOLD", "\033[1mBOLD\033[0m\033[0m\n"}, 155 | {"" + someVar + "", "\033[1m" + someVar + "\033[0m\033[0m\n"}, 156 | {"BOLD BLUE", "\033[1mBOLD \033[34mBLUE\033[0m\033[1m\033[0m\033[0m\n"}, 157 | {"HELLO BLUE TEXT", "\033[1mHELLO \033[34mBLUE\033[0m\033[1m \033[42mTEXT\033[0m\033[1m\033[0m\033[0m\n"}, 158 | } 159 | 160 | for _, test := range tests { 161 | if Sprintln(test.want) != test.got { 162 | t.Errorf("Sprintln(\"%v\") != '%v'", test.want, test.got) 163 | } 164 | } 165 | } 166 | 167 | func TestSprintf(t *testing.T) { 168 | if Sprintf("%v", "BOLD") != "\033[1mBOLD\033[0m\033[0m" { 169 | t.Errorf("Sprintf(\"%v\") != '%v'", "BOLD", "\033[1mBOLD\033[0m\033[0m") 170 | } 171 | 172 | if Sprintf("%v %v", "BOLD", "BLUE") != "\033[1mBOLD \033[34mBLUE\033[0m\033[1m\033[0m\033[0m" { 173 | t.Errorf("Sprintf(\"%v %v\") != '%v'", "BOLD", "BLUE", "\033[1mBOLD\033[0m\033[0m") 174 | } 175 | } 176 | 177 | func TestFprint(t *testing.T) { 178 | someVar := "SOME TEXT" 179 | var tests = []struct { 180 | want string 181 | got string 182 | }{ 183 | {"HELLO", "HELLO\033[0m"}, 184 | {"BOLD", "\033[1mBOLD\033[0m\033[0m"}, 185 | {"" + someVar + "", "\033[1m" + someVar + "\033[0m\033[0m"}, 186 | {"BOLD BLUE", "\033[1mBOLD \033[34mBLUE\033[0m\033[1m\033[0m\033[0m"}, 187 | {"HELLO BLUE TEXT", "\033[1mHELLO \033[34mBLUE\033[0m\033[1m \033[42mTEXT\033[0m\033[1m\033[0m\033[0m"}, 188 | } 189 | 190 | for _, test := range tests { 191 | buf := new(bytes.Buffer) 192 | Fprint(buf, test.want) 193 | if buf.String() != test.got { 194 | t.Errorf("Fprint(buf, \"%v\") != '%v'", test.want, test.got) 195 | } 196 | } 197 | } 198 | 199 | func TestFprintln(t *testing.T) { 200 | someVar := "SOME TEXT" 201 | var tests = []struct { 202 | want string 203 | got string 204 | }{ 205 | {"HELLO", "HELLO\033[0m\n"}, 206 | {"BOLD", "\033[1mBOLD\033[0m\033[0m\n"}, 207 | {"" + someVar + "", "\033[1m" + someVar + "\033[0m\033[0m\n"}, 208 | {"BOLD BLUE", "\033[1mBOLD \033[34mBLUE\033[0m\033[1m\033[0m\033[0m\n"}, 209 | {"HELLO BLUE TEXT", "\033[1mHELLO \033[34mBLUE\033[0m\033[1m \033[42mTEXT\033[0m\033[1m\033[0m\033[0m\n"}, 210 | } 211 | 212 | for _, test := range tests { 213 | buf := new(bytes.Buffer) 214 | Fprintln(buf, test.want) 215 | if buf.String() != test.got { 216 | t.Errorf("Fprintln(buf, \"%v\") != '%v'", test.want, test.got) 217 | } 218 | } 219 | } 220 | 221 | func TestFprintf(t *testing.T) { 222 | buf := new(bytes.Buffer) 223 | Fprintf(buf, "%v", "BOLD") 224 | if buf.String() != "\033[1mBOLD\033[0m\033[0m" { 225 | t.Errorf("Fprintf(buf, \"%v\") != '%v'", "BOLD", "\033[1mBOLD\033[0m\033[0m") 226 | } 227 | 228 | buf2 := new(bytes.Buffer) 229 | Fprintf(buf2, "%v %v", "BOLD", "BLUE") 230 | if buf2.String() != "\033[1mBOLD \033[34mBLUE\033[0m\033[1m\033[0m\033[0m" { 231 | t.Errorf("Fprintf(buf2, \"%v %v\") != '%v'", "BOLD", "BLUE", "\033[1mBOLD\033[0m\033[0m") 232 | } 233 | } 234 | --------------------------------------------------------------------------------