github.com/SuCicada/su-hugo@v1.0.0/parser/metadecoders/decoder_test.go (about)

     1  // Copyright 2018 The Hugo Authors. All rights reserved.
     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  // http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package metadecoders
    15  
    16  import (
    17  	"reflect"
    18  	"testing"
    19  
    20  	qt "github.com/frankban/quicktest"
    21  )
    22  
    23  func TestUnmarshalXML(t *testing.T) {
    24  	c := qt.New(t)
    25  
    26  	xmlDoc := `<?xml version="1.0" encoding="utf-8" standalone="yes"?>
    27  	<rss version="2.0"
    28  		xmlns:atom="http://www.w3.org/2005/Atom">
    29  		<channel>
    30  			<title>Example feed</title>
    31  			<link>https://example.com/</link>
    32  			<description>Example feed</description>
    33  			<generator>Hugo -- gohugo.io</generator>
    34  			<language>en-us</language>
    35  			<copyright>Example</copyright>
    36  			<lastBuildDate>Fri, 08 Jan 2021 14:44:10 +0000</lastBuildDate>
    37  			<atom:link href="https://example.com/feed.xml" rel="self" type="application/rss+xml"/>
    38  			<item>
    39  				<title>Example title</title>
    40  				<link>https://example.com/2021/11/30/example-title/</link>
    41  				<pubDate>Tue, 30 Nov 2021 15:00:00 +0000</pubDate>
    42  				<guid>https://example.com/2021/11/30/example-title/</guid>
    43  				<description>Example description</description>
    44  			</item>
    45  		</channel>
    46  	</rss>`
    47  
    48  	expect := map[string]any{
    49  		"-atom": "http://www.w3.org/2005/Atom", "-version": "2.0",
    50  		"channel": map[string]any{
    51  			"copyright":   "Example",
    52  			"description": "Example feed",
    53  			"generator":   "Hugo -- gohugo.io",
    54  			"item": map[string]any{
    55  				"description": "Example description",
    56  				"guid":        "https://example.com/2021/11/30/example-title/",
    57  				"link":        "https://example.com/2021/11/30/example-title/",
    58  				"pubDate":     "Tue, 30 Nov 2021 15:00:00 +0000",
    59  				"title":       "Example title"},
    60  			"language":      "en-us",
    61  			"lastBuildDate": "Fri, 08 Jan 2021 14:44:10 +0000",
    62  			"link": []any{"https://example.com/", map[string]any{
    63  				"-href": "https://example.com/feed.xml",
    64  				"-rel":  "self",
    65  				"-type": "application/rss+xml"}},
    66  			"title": "Example feed",
    67  		}}
    68  
    69  	d := Default
    70  
    71  	m, err := d.Unmarshal([]byte(xmlDoc), XML)
    72  	c.Assert(err, qt.IsNil)
    73  	c.Assert(m, qt.DeepEquals, expect)
    74  
    75  }
    76  func TestUnmarshalToMap(t *testing.T) {
    77  	c := qt.New(t)
    78  
    79  	expect := map[string]any{"a": "b"}
    80  
    81  	d := Default
    82  
    83  	for i, test := range []struct {
    84  		data   string
    85  		format Format
    86  		expect any
    87  	}{
    88  		{`a = "b"`, TOML, expect},
    89  		{`a: "b"`, YAML, expect},
    90  		// Make sure we get all string keys, even for YAML
    91  		{"a: Easy!\nb:\n  c: 2\n  d: [3, 4]", YAML, map[string]any{"a": "Easy!", "b": map[string]any{"c": 2, "d": []any{3, 4}}}},
    92  		{"a:\n  true: 1\n  false: 2", YAML, map[string]any{"a": map[string]any{"true": 1, "false": 2}}},
    93  		{`{ "a": "b" }`, JSON, expect},
    94  		{`<root><a>b</a></root>`, XML, expect},
    95  		{`#+a: b`, ORG, expect},
    96  		// errors
    97  		{`a = b`, TOML, false},
    98  		{`a,b,c`, CSV, false}, // Use Unmarshal for CSV
    99  	} {
   100  		msg := qt.Commentf("%d: %s", i, test.format)
   101  		m, err := d.UnmarshalToMap([]byte(test.data), test.format)
   102  		if b, ok := test.expect.(bool); ok && !b {
   103  			c.Assert(err, qt.Not(qt.IsNil), msg)
   104  		} else {
   105  			c.Assert(err, qt.IsNil, msg)
   106  			c.Assert(m, qt.DeepEquals, test.expect, msg)
   107  		}
   108  	}
   109  }
   110  
   111  func TestUnmarshalToInterface(t *testing.T) {
   112  	c := qt.New(t)
   113  
   114  	expect := map[string]any{"a": "b"}
   115  
   116  	d := Default
   117  
   118  	for i, test := range []struct {
   119  		data   string
   120  		format Format
   121  		expect any
   122  	}{
   123  		{`[ "Brecker", "Blake", "Redman" ]`, JSON, []any{"Brecker", "Blake", "Redman"}},
   124  		{`{ "a": "b" }`, JSON, expect},
   125  		{`#+a: b`, ORG, expect},
   126  		{`#+DATE: <2020-06-26 Fri>`, ORG, map[string]any{"date": "2020-06-26"}},
   127  		{`a = "b"`, TOML, expect},
   128  		{`a: "b"`, YAML, expect},
   129  		{`<root><a>b</a></root>`, XML, expect},
   130  		{`a,b,c`, CSV, [][]string{{"a", "b", "c"}}},
   131  		{"a: Easy!\nb:\n  c: 2\n  d: [3, 4]", YAML, map[string]any{"a": "Easy!", "b": map[string]any{"c": 2, "d": []any{3, 4}}}},
   132  		// errors
   133  		{`a = "`, TOML, false},
   134  	} {
   135  		msg := qt.Commentf("%d: %s", i, test.format)
   136  		m, err := d.Unmarshal([]byte(test.data), test.format)
   137  		if b, ok := test.expect.(bool); ok && !b {
   138  			c.Assert(err, qt.Not(qt.IsNil), msg)
   139  		} else {
   140  			c.Assert(err, qt.IsNil, msg)
   141  			c.Assert(m, qt.DeepEquals, test.expect, msg)
   142  		}
   143  
   144  	}
   145  }
   146  
   147  func TestUnmarshalStringTo(t *testing.T) {
   148  	c := qt.New(t)
   149  
   150  	d := Default
   151  
   152  	expectMap := map[string]any{"a": "b"}
   153  
   154  	for i, test := range []struct {
   155  		data   string
   156  		to     any
   157  		expect any
   158  	}{
   159  		{"a string", "string", "a string"},
   160  		{`{ "a": "b" }`, make(map[string]any), expectMap},
   161  		{"32", int64(1234), int64(32)},
   162  		{"32", int(1234), int(32)},
   163  		{"3.14159", float64(1), float64(3.14159)},
   164  		{"[3,7,9]", []any{}, []any{3, 7, 9}},
   165  		{"[3.1,7.2,9.3]", []any{}, []any{3.1, 7.2, 9.3}},
   166  	} {
   167  		msg := qt.Commentf("%d: %T", i, test.to)
   168  		m, err := d.UnmarshalStringTo(test.data, test.to)
   169  		if b, ok := test.expect.(bool); ok && !b {
   170  			c.Assert(err, qt.Not(qt.IsNil), msg)
   171  		} else {
   172  			c.Assert(err, qt.IsNil, msg)
   173  			c.Assert(m, qt.DeepEquals, test.expect, msg)
   174  		}
   175  
   176  	}
   177  }
   178  
   179  func TestStringifyYAMLMapKeys(t *testing.T) {
   180  	cases := []struct {
   181  		input    any
   182  		want     any
   183  		replaced bool
   184  	}{
   185  		{
   186  			map[any]any{"a": 1, "b": 2},
   187  			map[string]any{"a": 1, "b": 2},
   188  			true,
   189  		},
   190  		{
   191  			map[any]any{"a": []any{1, map[any]any{"b": 2}}},
   192  			map[string]any{"a": []any{1, map[string]any{"b": 2}}},
   193  			true,
   194  		},
   195  		{
   196  			map[any]any{true: 1, "b": false},
   197  			map[string]any{"true": 1, "b": false},
   198  			true,
   199  		},
   200  		{
   201  			map[any]any{1: "a", 2: "b"},
   202  			map[string]any{"1": "a", "2": "b"},
   203  			true,
   204  		},
   205  		{
   206  			map[any]any{"a": map[any]any{"b": 1}},
   207  			map[string]any{"a": map[string]any{"b": 1}},
   208  			true,
   209  		},
   210  		{
   211  			map[string]any{"a": map[string]any{"b": 1}},
   212  			map[string]any{"a": map[string]any{"b": 1}},
   213  			false,
   214  		},
   215  		{
   216  			[]any{map[any]any{1: "a", 2: "b"}},
   217  			[]any{map[string]any{"1": "a", "2": "b"}},
   218  			false,
   219  		},
   220  	}
   221  
   222  	for i, c := range cases {
   223  		res, replaced := stringifyMapKeys(c.input)
   224  
   225  		if c.replaced != replaced {
   226  			t.Fatalf("[%d] Replaced mismatch: %t", i, replaced)
   227  		}
   228  		if !c.replaced {
   229  			res = c.input
   230  		}
   231  		if !reflect.DeepEqual(res, c.want) {
   232  			t.Errorf("[%d] given %q\nwant: %q\n got: %q", i, c.input, c.want, res)
   233  		}
   234  	}
   235  }
   236  
   237  func BenchmarkStringifyMapKeysStringsOnlyInterfaceMaps(b *testing.B) {
   238  	maps := make([]map[any]any, b.N)
   239  	for i := 0; i < b.N; i++ {
   240  		maps[i] = map[any]any{
   241  			"a": map[any]any{
   242  				"b": 32,
   243  				"c": 43,
   244  				"d": map[any]any{
   245  					"b": 32,
   246  					"c": 43,
   247  				},
   248  			},
   249  			"b": []any{"a", "b"},
   250  			"c": "d",
   251  		}
   252  	}
   253  	b.ResetTimer()
   254  	for i := 0; i < b.N; i++ {
   255  		stringifyMapKeys(maps[i])
   256  	}
   257  }
   258  
   259  func BenchmarkStringifyMapKeysStringsOnlyStringMaps(b *testing.B) {
   260  	m := map[string]any{
   261  		"a": map[string]any{
   262  			"b": 32,
   263  			"c": 43,
   264  			"d": map[string]any{
   265  				"b": 32,
   266  				"c": 43,
   267  			},
   268  		},
   269  		"b": []any{"a", "b"},
   270  		"c": "d",
   271  	}
   272  
   273  	b.ResetTimer()
   274  	for i := 0; i < b.N; i++ {
   275  		stringifyMapKeys(m)
   276  	}
   277  }
   278  
   279  func BenchmarkStringifyMapKeysIntegers(b *testing.B) {
   280  	maps := make([]map[any]any, b.N)
   281  	for i := 0; i < b.N; i++ {
   282  		maps[i] = map[any]any{
   283  			1: map[any]any{
   284  				4: 32,
   285  				5: 43,
   286  				6: map[any]any{
   287  					7: 32,
   288  					8: 43,
   289  				},
   290  			},
   291  			2: []any{"a", "b"},
   292  			3: "d",
   293  		}
   294  	}
   295  	b.ResetTimer()
   296  	for i := 0; i < b.N; i++ {
   297  		stringifyMapKeys(maps[i])
   298  	}
   299  }