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  }