github.com/google/yamlfmt@v0.12.2-0.20240514121411-7f77800e2681/formatters/basic/formatter_test.go (about) 1 // Copyright 2022 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package basic_test 16 17 import ( 18 "strings" 19 "testing" 20 21 "github.com/google/yamlfmt" 22 "github.com/google/yamlfmt/formatters/basic" 23 ) 24 25 func newFormatter(config *basic.Config) *basic.BasicFormatter { 26 return &basic.BasicFormatter{ 27 Config: config, 28 Features: basic.ConfigureFeaturesFromConfig(config), 29 } 30 } 31 32 func TestFormatterRetainsComments(t *testing.T) { 33 f := newFormatter(basic.DefaultConfig()) 34 35 yaml := `x: "y" # foo comment` 36 37 s, err := f.Format([]byte(yaml)) 38 if err != nil { 39 t.Fatalf("expected formatting to pass, returned error: %v", err) 40 } 41 if !strings.Contains(string(s), "#") { 42 t.Fatal("comment was stripped away") 43 } 44 } 45 46 func TestFormatterPreservesKeyOrder(t *testing.T) { 47 f := &basic.BasicFormatter{Config: basic.DefaultConfig()} 48 49 yaml := ` 50 b: 51 a:` 52 53 s, err := f.Format([]byte(yaml)) 54 if err != nil { 55 t.Fatalf("expected formatting to pass, returned error: %v", err) 56 } 57 unmarshalledStr := string(s) 58 bPos := strings.Index(unmarshalledStr, "b") 59 aPos := strings.Index(unmarshalledStr, "a") 60 if bPos > aPos { 61 t.Fatalf("keys were reordered:\n%s", s) 62 } 63 } 64 65 func TestFormatterParsesMultipleDocuments(t *testing.T) { 66 f := &basic.BasicFormatter{Config: basic.DefaultConfig()} 67 68 yaml := `b: 69 --- 70 a: 71 ` 72 s, err := f.Format([]byte(yaml)) 73 if err != nil { 74 t.Fatalf("expected formatting to pass, returned error: %v", err) 75 } 76 if len(s) != len([]byte(yaml)) { 77 t.Fatalf("expected yaml not to change, result: %s", string(s)) 78 } 79 } 80 81 func TestWithDocumentStart(t *testing.T) { 82 config := basic.DefaultConfig() 83 config.IncludeDocumentStart = true 84 f := newFormatter(config) 85 86 yaml := "a:" 87 s, err := f.Format([]byte(yaml)) 88 if err != nil { 89 t.Fatalf("expected formatting to pass, returned error: %v", err) 90 } 91 if strings.Index(string(s), "---\n") != 0 { 92 t.Fatalf("expected document start to be included, result was: %s", string(s)) 93 } 94 } 95 96 func TestCRLFLineEnding(t *testing.T) { 97 config := basic.DefaultConfig() 98 config.LineEnding = yamlfmt.LineBreakStyleCRLF 99 f := newFormatter(config) 100 101 yaml := "# comment\r\na:\r\n" 102 result, err := f.Format([]byte(yaml)) 103 if err != nil { 104 t.Fatalf("expected formatting to pass, returned error: %v", err) 105 } 106 if string(yaml) != string(result) { 107 t.Fatalf("didn't write CRLF properly in result: %v", result) 108 } 109 } 110 111 func TestEmojiSupport(t *testing.T) { 112 config := basic.DefaultConfig() 113 f := newFormatter(config) 114 115 yaml := "a: 😊" 116 result, err := f.Format([]byte(yaml)) 117 if err != nil { 118 t.Fatalf("expected formatting to pass, returned error: %v", err) 119 } 120 resultStr := string(result) 121 if !strings.Contains(resultStr, "😊") { 122 t.Fatalf("expected string to contain 😊, got: %s", resultStr) 123 } 124 } 125 126 func TestRetainLineBreaks(t *testing.T) { 127 testCases := []struct { 128 name string 129 input string 130 expect string 131 single bool 132 }{ 133 { 134 name: "basic", 135 input: `a: 1 136 137 b: 2`, 138 expect: `a: 1 139 140 b: 2 141 `, 142 }, 143 { 144 name: "multi-doc", 145 input: `a: 1 146 147 # tail comment 148 --- 149 b: 2`, 150 expect: `a: 1 151 152 # tail comment 153 --- 154 b: 2 155 `, 156 }, 157 { 158 name: "literal string", 159 input: `a: 1 160 161 shell: | 162 #!/usr/bin/env bash 163 164 # hello, world 165 # bye 166 echo "hello, world" 167 `, 168 expect: `a: 1 169 170 shell: | 171 #!/usr/bin/env bash 172 173 # hello, world 174 # bye 175 echo "hello, world" 176 `, 177 }, 178 { 179 name: "multi level nested literal string", 180 input: `a: 1 181 x: 182 y: 183 shell: | 184 #!/usr/bin/env bash 185 186 # bye 187 echo "hello, world"`, 188 expect: `a: 1 189 x: 190 y: 191 shell: | 192 #!/usr/bin/env bash 193 194 # bye 195 echo "hello, world" 196 `, 197 }, 198 { 199 name: "retain single line break", 200 single: true, 201 input: `a: 1 202 203 204 205 206 b: 2 207 208 209 c: 3 210 `, 211 expect: `a: 1 212 213 b: 2 214 215 c: 3 216 `, 217 }, 218 } 219 for _, tc := range testCases { 220 t.Run(tc.name, func(t *testing.T) { 221 config := basic.DefaultConfig() 222 config.RetainLineBreaks = true 223 config.RetainLineBreaksSingle = tc.single 224 f := newFormatter(config) 225 got, err := f.Format([]byte(tc.input)) 226 if err != nil { 227 t.Fatalf("expected formatting to pass, returned error: %v", err) 228 } 229 if string(got) != tc.expect { 230 t.Fatalf("didn't retain line breaks\nresult: %v\nexpect %s", string(got), tc.expect) 231 } 232 }) 233 } 234 } 235 236 func TestScanFoldedAsLiteral(t *testing.T) { 237 config := basic.DefaultConfig() 238 config.ScanFoldedAsLiteral = true 239 f := newFormatter(config) 240 241 yml := `a: > 242 multiline 243 folded 244 scalar` 245 lines := len(strings.Split(yml, "\n")) 246 result, err := f.Format([]byte(yml)) 247 if err != nil { 248 t.Fatalf("expected formatting to pass, returned error: %v", err) 249 } 250 resultStr := string(result) 251 resultLines := len(strings.Split(resultStr, "\n")) 252 if resultLines == lines { 253 t.Fatalf("expected string to be %d lines, was %d", lines, resultLines) 254 } 255 } 256 257 func TestIndentlessArrays(t *testing.T) { 258 config := basic.DefaultConfig() 259 config.IndentlessArrays = true 260 f := newFormatter(config) 261 262 yml := `a: 263 - 1 264 - 2 265 ` 266 result, err := f.Format([]byte(yml)) 267 if err != nil { 268 t.Fatalf("expected formatting to pass, returned error: %v", err) 269 } 270 resultStr := string(result) 271 if resultStr != yml { 272 t.Fatalf("expected:\n%s\ngot:\n%s", yml, resultStr) 273 } 274 } 275 276 func TestDropMergeTag(t *testing.T) { 277 config := basic.DefaultConfig() 278 config.DropMergeTag = true 279 f := newFormatter(config) 280 281 yml := `a: &a 282 b: 283 <<: *a` 284 285 result, err := f.Format([]byte(yml)) 286 if err != nil { 287 t.Fatalf("expected formatting to pass, returned error: %v", err) 288 } 289 resultStr := string(result) 290 if strings.Contains(resultStr, "!!merge") { 291 t.Fatalf("expected formatted result to drop merge tag, was found:\n%s", resultStr) 292 } 293 } 294 295 func TestPadLineComments(t *testing.T) { 296 config := basic.DefaultConfig() 297 config.PadLineComments = 2 298 f := newFormatter(config) 299 300 yml := "a: 1 # line comment" 301 expectedStr := "a: 1 # line comment" 302 303 result, err := f.Format([]byte(yml)) 304 if err != nil { 305 t.Fatalf("expected formatting to pass, returned error: %v", err) 306 } 307 resultStr := strings.TrimSuffix(string(result), "\n") 308 if resultStr != expectedStr { 309 t.Fatalf("expected: '%s', got: '%s'", expectedStr, resultStr) 310 } 311 }