github.com/hashicorp/vault/sdk@v0.13.0/helper/template/template_test.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  
     4  package template
     5  
     6  import (
     7  	"fmt"
     8  	"strings"
     9  	"testing"
    10  
    11  	"github.com/stretchr/testify/require"
    12  )
    13  
    14  func TestGenerate(t *testing.T) {
    15  	type testCase struct {
    16  		template       string
    17  		additionalOpts []Opt
    18  		data           interface{}
    19  
    20  		expected  string
    21  		expectErr bool
    22  	}
    23  
    24  	tests := map[string]testCase{
    25  		"template without arguments": {
    26  			template:  "this is a template",
    27  			data:      nil,
    28  			expected:  "this is a template",
    29  			expectErr: false,
    30  		},
    31  		"template with arguments but no data": {
    32  			template:  "this is a {{.String}}",
    33  			data:      nil,
    34  			expected:  "this is a <no value>",
    35  			expectErr: false,
    36  		},
    37  		"template with arguments": {
    38  			template: "this is a {{.String}}",
    39  			data: struct {
    40  				String string
    41  			}{
    42  				String: "foobar",
    43  			},
    44  			expected:  "this is a foobar",
    45  			expectErr: false,
    46  		},
    47  		"template with builtin functions": {
    48  			template: `{{.String | truncate 10}}
    49  {{.String | uppercase}}
    50  {{.String | lowercase}}
    51  {{.String | replace " " "."}}
    52  {{.String | sha256}}
    53  {{.String | base64}}
    54  {{.String | truncate_sha256 20}}`,
    55  			data: struct {
    56  				String string
    57  			}{
    58  				String: "Some string with Multiple Capitals LETTERS",
    59  			},
    60  			expected: `Some strin
    61  SOME STRING WITH MULTIPLE CAPITALS LETTERS
    62  some string with multiple capitals letters
    63  Some.string.with.Multiple.Capitals.LETTERS
    64  da9872dd96609c72897defa11fe81017a62c3f44339d9d3b43fe37540ede3601
    65  U29tZSBzdHJpbmcgd2l0aCBNdWx0aXBsZSBDYXBpdGFscyBMRVRURVJT
    66  Some string 6841cf80`,
    67  			expectErr: false,
    68  		},
    69  		"custom function": {
    70  			template: "{{foo}}",
    71  			additionalOpts: []Opt{
    72  				Function("foo", func() string {
    73  					return "custom-foo"
    74  				}),
    75  			},
    76  			expected:  "custom-foo",
    77  			expectErr: false,
    78  		},
    79  	}
    80  
    81  	for name, test := range tests {
    82  		t.Run(name, func(t *testing.T) {
    83  			opts := append(test.additionalOpts, Template(test.template))
    84  			st, err := NewTemplate(opts...)
    85  			require.NoError(t, err)
    86  
    87  			actual, err := st.Generate(test.data)
    88  			if test.expectErr && err == nil {
    89  				t.Fatalf("err expected, got nil")
    90  			}
    91  			if !test.expectErr && err != nil {
    92  				t.Fatalf("no error expected, got: %s", err)
    93  			}
    94  
    95  			require.Equal(t, test.expected, actual)
    96  		})
    97  	}
    98  
    99  	t.Run("random", func(t *testing.T) {
   100  		for i := 1; i < 100; i++ {
   101  			st, err := NewTemplate(
   102  				Template(fmt.Sprintf("{{random %d}}", i)),
   103  			)
   104  			require.NoError(t, err)
   105  
   106  			actual, err := st.Generate(nil)
   107  			require.NoError(t, err)
   108  
   109  			require.Regexp(t, fmt.Sprintf("^[a-zA-Z0-9]{%d}$", i), actual)
   110  		}
   111  	})
   112  
   113  	t.Run("unix_time", func(t *testing.T) {
   114  		for i := 0; i < 100; i++ {
   115  			st, err := NewTemplate(
   116  				Template("{{unix_time}}"),
   117  			)
   118  			require.NoError(t, err)
   119  
   120  			actual, err := st.Generate(nil)
   121  			require.NoError(t, err)
   122  
   123  			require.Regexp(t, "^[0-9]+$", actual)
   124  		}
   125  	})
   126  
   127  	t.Run("unix_time_millis", func(t *testing.T) {
   128  		for i := 0; i < 100; i++ {
   129  			st, err := NewTemplate(
   130  				Template("{{unix_time_millis}}"),
   131  			)
   132  			require.NoError(t, err)
   133  
   134  			actual, err := st.Generate(nil)
   135  			require.NoError(t, err)
   136  
   137  			require.Regexp(t, "^[0-9]+$", actual)
   138  		}
   139  	})
   140  
   141  	t.Run("timestamp", func(t *testing.T) {
   142  		for i := 0; i < 100; i++ {
   143  			st, err := NewTemplate(
   144  				Template(`{{timestamp "2006-01-02T15:04:05.000Z"}}`),
   145  			)
   146  			require.NoError(t, err)
   147  
   148  			actual, err := st.Generate(nil)
   149  			require.NoError(t, err)
   150  
   151  			require.Regexp(t, `^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$`, actual)
   152  		}
   153  	})
   154  
   155  	t.Run("too-large-overflow", func(t *testing.T) {
   156  		data := "{{" + strings.Repeat("(", 1000000)
   157  		_, err := NewTemplate(
   158  			Template(data),
   159  		)
   160  		// We expect an error due it being too large,
   161  		// this test should not fail with an overflow
   162  		require.Error(t, err)
   163  	})
   164  }
   165  
   166  func TestBadConstructorArguments(t *testing.T) {
   167  	type testCase struct {
   168  		opts []Opt
   169  	}
   170  
   171  	tests := map[string]testCase{
   172  		"missing template": {
   173  			opts: nil,
   174  		},
   175  		"missing custom function name": {
   176  			opts: []Opt{
   177  				Template("foo bar"),
   178  				Function("", func() string {
   179  					return "foo"
   180  				}),
   181  			},
   182  		},
   183  		"missing custom function": {
   184  			opts: []Opt{
   185  				Template("foo bar"),
   186  				Function("foo", nil),
   187  			},
   188  		},
   189  		"bad template": {
   190  			opts: []Opt{
   191  				Template("{{.String"),
   192  			},
   193  		},
   194  	}
   195  
   196  	for name, test := range tests {
   197  		t.Run(name, func(t *testing.T) {
   198  			st, err := NewTemplate(test.opts...)
   199  			require.Error(t, err)
   200  
   201  			str, err := st.Generate(nil)
   202  			require.Error(t, err)
   203  			require.Equal(t, "", str)
   204  		})
   205  	}
   206  
   207  	t.Run("erroring custom function", func(t *testing.T) {
   208  		st, err := NewTemplate(
   209  			Template("{{foo}}"),
   210  			Function("foo", func() (string, error) {
   211  				return "", fmt.Errorf("an error!")
   212  			}),
   213  		)
   214  		require.NoError(t, err)
   215  
   216  		str, err := st.Generate(nil)
   217  		require.Error(t, err)
   218  		require.Equal(t, "", str)
   219  	})
   220  }