github.com/graemephi/kahugo@v0.62.3-0.20211121071557-d78c0423784d/tpl/data/data_test.go (about)

     1  // Copyright 2017 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 data
    15  
    16  import (
    17  	"bytes"
    18  	"html/template"
    19  	"net/http"
    20  	"net/http/httptest"
    21  	"path/filepath"
    22  	"strings"
    23  	"testing"
    24  
    25  	"github.com/gohugoio/hugo/common/maps"
    26  
    27  	qt "github.com/frankban/quicktest"
    28  )
    29  
    30  func TestGetCSV(t *testing.T) {
    31  	t.Parallel()
    32  	c := qt.New(t)
    33  
    34  	for i, test := range []struct {
    35  		sep     string
    36  		url     string
    37  		content string
    38  		expect  interface{}
    39  	}{
    40  		// Remotes
    41  		{
    42  			",",
    43  			`http://success/`,
    44  			"gomeetup,city\nyes,Sydney\nyes,San Francisco\nyes,Stockholm\n",
    45  			[][]string{{"gomeetup", "city"}, {"yes", "Sydney"}, {"yes", "San Francisco"}, {"yes", "Stockholm"}},
    46  		},
    47  		{
    48  			",",
    49  			`http://error.extra.field/`,
    50  			"gomeetup,city\nyes,Sydney\nyes,San Francisco\nyes,Stockholm,EXTRA\n",
    51  			false,
    52  		},
    53  		{
    54  			",",
    55  			`http://nofound/404`,
    56  			``,
    57  			false,
    58  		},
    59  
    60  		// Locals
    61  		{
    62  			";",
    63  			"pass/semi",
    64  			"gomeetup;city\nyes;Sydney\nyes;San Francisco\nyes;Stockholm\n",
    65  			[][]string{{"gomeetup", "city"}, {"yes", "Sydney"}, {"yes", "San Francisco"}, {"yes", "Stockholm"}},
    66  		},
    67  		{
    68  			";",
    69  			"fail/no-file",
    70  			"",
    71  			false,
    72  		},
    73  	} {
    74  
    75  		c.Run(test.url, func(c *qt.C) {
    76  			msg := qt.Commentf("Test %d", i)
    77  
    78  			ns := newTestNs()
    79  
    80  			// Setup HTTP test server
    81  			var srv *httptest.Server
    82  			srv, ns.client = getTestServer(func(w http.ResponseWriter, r *http.Request) {
    83  				if !hasHeaderValue(r.Header, "Accept", "text/csv") && !hasHeaderValue(r.Header, "Accept", "text/plain") {
    84  					http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
    85  					return
    86  				}
    87  
    88  				if r.URL.Path == "/404" {
    89  					http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
    90  					return
    91  				}
    92  
    93  				w.Header().Add("Content-type", "text/csv")
    94  
    95  				w.Write([]byte(test.content))
    96  			})
    97  			defer func() { srv.Close() }()
    98  
    99  			// Setup local test file for schema-less URLs
   100  			if !strings.Contains(test.url, ":") && !strings.HasPrefix(test.url, "fail/") {
   101  				f, err := ns.deps.Fs.Source.Create(filepath.Join(ns.deps.Cfg.GetString("workingDir"), test.url))
   102  				c.Assert(err, qt.IsNil, msg)
   103  				f.WriteString(test.content)
   104  				f.Close()
   105  			}
   106  
   107  			// Get on with it
   108  			got, err := ns.GetCSV(test.sep, test.url)
   109  
   110  			if _, ok := test.expect.(bool); ok {
   111  				c.Assert(int(ns.deps.Log.LogCounters().ErrorCounter.Count()), qt.Equals, 1)
   112  				c.Assert(got, qt.IsNil)
   113  				return
   114  			}
   115  
   116  			c.Assert(err, qt.IsNil, msg)
   117  			c.Assert(int(ns.deps.Log.LogCounters().ErrorCounter.Count()), qt.Equals, 0)
   118  			c.Assert(got, qt.Not(qt.IsNil), msg)
   119  			c.Assert(got, qt.DeepEquals, test.expect, msg)
   120  		})
   121  
   122  	}
   123  }
   124  
   125  func TestGetJSON(t *testing.T) {
   126  	t.Parallel()
   127  	c := qt.New(t)
   128  
   129  	for i, test := range []struct {
   130  		url     string
   131  		content string
   132  		expect  interface{}
   133  	}{
   134  		{
   135  			`http://success/`,
   136  			`{"gomeetup":["Sydney","San Francisco","Stockholm"]}`,
   137  			map[string]interface{}{"gomeetup": []interface{}{"Sydney", "San Francisco", "Stockholm"}},
   138  		},
   139  		{
   140  			`http://malformed/`,
   141  			`{gomeetup:["Sydney","San Francisco","Stockholm"]}`,
   142  			false,
   143  		},
   144  		{
   145  			`http://nofound/404`,
   146  			``,
   147  			false,
   148  		},
   149  		// Locals
   150  		{
   151  			"pass/semi",
   152  			`{"gomeetup":["Sydney","San Francisco","Stockholm"]}`,
   153  			map[string]interface{}{"gomeetup": []interface{}{"Sydney", "San Francisco", "Stockholm"}},
   154  		},
   155  		{
   156  			"fail/no-file",
   157  			"",
   158  			false,
   159  		},
   160  		{
   161  			`pass/üńīçøðê-url.json`,
   162  			`{"gomeetup":["Sydney","San Francisco","Stockholm"]}`,
   163  			map[string]interface{}{"gomeetup": []interface{}{"Sydney", "San Francisco", "Stockholm"}},
   164  		},
   165  	} {
   166  
   167  		c.Run(test.url, func(c *qt.C) {
   168  
   169  			msg := qt.Commentf("Test %d", i)
   170  			ns := newTestNs()
   171  
   172  			// Setup HTTP test server
   173  			var srv *httptest.Server
   174  			srv, ns.client = getTestServer(func(w http.ResponseWriter, r *http.Request) {
   175  				if !hasHeaderValue(r.Header, "Accept", "application/json") {
   176  					http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
   177  					return
   178  				}
   179  
   180  				if r.URL.Path == "/404" {
   181  					http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
   182  					return
   183  				}
   184  
   185  				w.Header().Add("Content-type", "application/json")
   186  
   187  				w.Write([]byte(test.content))
   188  			})
   189  			defer func() { srv.Close() }()
   190  
   191  			// Setup local test file for schema-less URLs
   192  			if !strings.Contains(test.url, ":") && !strings.HasPrefix(test.url, "fail/") {
   193  				f, err := ns.deps.Fs.Source.Create(filepath.Join(ns.deps.Cfg.GetString("workingDir"), test.url))
   194  				c.Assert(err, qt.IsNil, msg)
   195  				f.WriteString(test.content)
   196  				f.Close()
   197  			}
   198  
   199  			// Get on with it
   200  			got, _ := ns.GetJSON(test.url)
   201  
   202  			if _, ok := test.expect.(bool); ok {
   203  				c.Assert(int(ns.deps.Log.LogCounters().ErrorCounter.Count()), qt.Equals, 1)
   204  				return
   205  			}
   206  
   207  			c.Assert(int(ns.deps.Log.LogCounters().ErrorCounter.Count()), qt.Equals, 0, msg)
   208  			c.Assert(got, qt.Not(qt.IsNil), msg)
   209  			c.Assert(got, qt.DeepEquals, test.expect)
   210  
   211  		})
   212  	}
   213  }
   214  
   215  func TestHeaders(t *testing.T) {
   216  	t.Parallel()
   217  	c := qt.New(t)
   218  
   219  	for _, test := range []struct {
   220  		name    string
   221  		headers interface{}
   222  		assert  func(c *qt.C, headers string)
   223  	}{
   224  		{
   225  			`Misc header variants`,
   226  			map[string]interface{}{
   227  				"Accept-Charset": "utf-8",
   228  				"Max-forwards":   "10",
   229  				"X-Int":          32,
   230  				"X-Templ":        template.HTML("a"),
   231  				"X-Multiple":     []string{"a", "b"},
   232  				"X-MultipleInt":  []int{3, 4},
   233  			},
   234  			func(c *qt.C, headers string) {
   235  				c.Assert(headers, qt.Contains, "Accept-Charset: utf-8")
   236  				c.Assert(headers, qt.Contains, "Max-Forwards: 10")
   237  				c.Assert(headers, qt.Contains, "X-Int: 32")
   238  				c.Assert(headers, qt.Contains, "X-Templ: a")
   239  				c.Assert(headers, qt.Contains, "X-Multiple: a")
   240  				c.Assert(headers, qt.Contains, "X-Multiple: b")
   241  				c.Assert(headers, qt.Contains, "X-Multipleint: 3")
   242  				c.Assert(headers, qt.Contains, "X-Multipleint: 4")
   243  				c.Assert(headers, qt.Contains, "User-Agent: Hugo Static Site Generator")
   244  			},
   245  		},
   246  		{
   247  			`Params`,
   248  			maps.Params{
   249  				"Accept-Charset": "utf-8",
   250  			},
   251  			func(c *qt.C, headers string) {
   252  				c.Assert(headers, qt.Contains, "Accept-Charset: utf-8")
   253  			},
   254  		},
   255  		{
   256  			`Override User-Agent`,
   257  			map[string]interface{}{
   258  				"User-Agent": "007",
   259  			},
   260  			func(c *qt.C, headers string) {
   261  				c.Assert(headers, qt.Contains, "User-Agent: 007")
   262  			},
   263  		},
   264  	} {
   265  
   266  		c.Run(test.name, func(c *qt.C) {
   267  
   268  			ns := newTestNs()
   269  
   270  			// Setup HTTP test server
   271  			var srv *httptest.Server
   272  			var headers bytes.Buffer
   273  			srv, ns.client = getTestServer(func(w http.ResponseWriter, r *http.Request) {
   274  				c.Assert(r.URL.String(), qt.Equals, "http://gohugo.io/api?foo")
   275  				w.Write([]byte("{}"))
   276  				r.Header.Write(&headers)
   277  
   278  			})
   279  			defer func() { srv.Close() }()
   280  
   281  			testFunc := func(fn func(args ...interface{}) error) {
   282  				defer headers.Reset()
   283  				err := fn("http://example.org/api", "?foo", test.headers)
   284  
   285  				c.Assert(err, qt.IsNil)
   286  				c.Assert(int(ns.deps.Log.LogCounters().ErrorCounter.Count()), qt.Equals, 0)
   287  				test.assert(c, headers.String())
   288  			}
   289  
   290  			testFunc(func(args ...interface{}) error {
   291  				_, err := ns.GetJSON(args...)
   292  				return err
   293  			})
   294  			testFunc(func(args ...interface{}) error {
   295  				_, err := ns.GetCSV(",", args...)
   296  				return err
   297  			})
   298  
   299  		})
   300  
   301  	}
   302  }
   303  
   304  func TestToURLAndHeaders(t *testing.T) {
   305  	t.Parallel()
   306  	c := qt.New(t)
   307  	url, headers := toURLAndHeaders([]interface{}{"https://foo?id=", 32})
   308  	c.Assert(url, qt.Equals, "https://foo?id=32")
   309  	c.Assert(headers, qt.IsNil)
   310  
   311  	url, headers = toURLAndHeaders([]interface{}{"https://foo?id=", 32, map[string]interface{}{"a": "b"}})
   312  	c.Assert(url, qt.Equals, "https://foo?id=32")
   313  	c.Assert(headers, qt.DeepEquals, map[string]interface{}{"a": "b"})
   314  }
   315  
   316  func TestParseCSV(t *testing.T) {
   317  	t.Parallel()
   318  	c := qt.New(t)
   319  
   320  	for i, test := range []struct {
   321  		csv []byte
   322  		sep string
   323  		exp string
   324  		err bool
   325  	}{
   326  		{[]byte("a,b,c\nd,e,f\n"), "", "", true},
   327  		{[]byte("a,b,c\nd,e,f\n"), "~/", "", true},
   328  		{[]byte("a,b,c\nd,e,f"), "|", "a,b,cd,e,f", false},
   329  		{[]byte("q,w,e\nd,e,f"), ",", "qwedef", false},
   330  		{[]byte("a|b|c\nd|e|f|g"), "|", "abcdefg", true},
   331  		{[]byte("z|y|c\nd|e|f"), "|", "zycdef", false},
   332  	} {
   333  		msg := qt.Commentf("Test %d: %v", i, test)
   334  
   335  		csv, err := parseCSV(test.csv, test.sep)
   336  		if test.err {
   337  			c.Assert(err, qt.Not(qt.IsNil), msg)
   338  			continue
   339  		}
   340  		c.Assert(err, qt.IsNil, msg)
   341  
   342  		act := ""
   343  		for _, v := range csv {
   344  			act = act + strings.Join(v, "")
   345  		}
   346  
   347  		c.Assert(act, qt.Equals, test.exp, msg)
   348  	}
   349  }