github.com/kyma-incubator/compass/components/director@v0.0.0-20230623144113-d764f56ff805/pkg/graphql/app_template_validation_test.go (about)

     1  package graphql_test
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  
     7  	"github.com/kyma-incubator/compass/components/director/pkg/inputvalidation/inputvalidationtest"
     8  
     9  	"github.com/kyma-incubator/compass/components/director/pkg/str"
    10  
    11  	"github.com/kyma-incubator/compass/components/director/pkg/graphql"
    12  	"github.com/stretchr/testify/require"
    13  )
    14  
    15  // ApplicationTemplateInput
    16  
    17  func TestApplicationTemplateInput_Validate_Rule_ValidPlaceholders(t *testing.T) {
    18  	testPlaceholderName := "test"
    19  
    20  	testCases := []struct {
    21  		Name  string
    22  		Value []*graphql.PlaceholderDefinitionInput
    23  		Valid bool
    24  	}{
    25  		{
    26  			Name: "Valid",
    27  			Value: []*graphql.PlaceholderDefinitionInput{
    28  				{Name: testPlaceholderName, Description: str.Ptr("Test description"), JSONPath: str.Ptr("displayName")},
    29  			},
    30  			Valid: true,
    31  		},
    32  		{
    33  			Name:  "Valid - no placeholders",
    34  			Value: []*graphql.PlaceholderDefinitionInput{},
    35  			Valid: true,
    36  		},
    37  		{
    38  			Name: "Invalid - not unique",
    39  			Value: []*graphql.PlaceholderDefinitionInput{
    40  				{Name: testPlaceholderName, Description: str.Ptr("Test description"), JSONPath: str.Ptr("displayName")},
    41  				{Name: testPlaceholderName, Description: str.Ptr("Different description"), JSONPath: str.Ptr("displayName2")},
    42  			},
    43  			Valid: false,
    44  		},
    45  		{
    46  			Name: "Invalid - not used",
    47  			Value: []*graphql.PlaceholderDefinitionInput{
    48  				{Name: "notused", Description: str.Ptr("Test description"), JSONPath: str.Ptr("displayName")},
    49  			},
    50  			Valid: false,
    51  		},
    52  	}
    53  
    54  	for _, testCase := range testCases {
    55  		t.Run(testCase.Name, func(t *testing.T) {
    56  			//GIVEN
    57  			sut := fixValidApplicationTemplateInput()
    58  			sut.ApplicationInput.Description = str.Ptr(fmt.Sprintf("{{%s}}", testPlaceholderName))
    59  			sut.Placeholders = testCase.Value
    60  			// WHEN
    61  			err := sut.Validate()
    62  			// THEN
    63  			if testCase.Valid {
    64  				require.NoError(t, err)
    65  			} else {
    66  				require.Error(t, err)
    67  			}
    68  		})
    69  	}
    70  }
    71  
    72  func TestApplicationTemplateInput_Validate_Name(t *testing.T) {
    73  	testCases := []struct {
    74  		Name          string
    75  		Value         string
    76  		ExpectedValid bool
    77  	}{
    78  		{
    79  			Name:          "ExpectedValid",
    80  			Value:         "name-123.com",
    81  			ExpectedValid: true,
    82  		},
    83  		{
    84  			Name:          "Valid Printable ASCII",
    85  			Value:         "V1 +=_-)(*&^%$#@!?/>.<,|\\\"':;}{][",
    86  			ExpectedValid: true,
    87  		},
    88  		{
    89  			Name:          "Empty string",
    90  			Value:         inputvalidationtest.EmptyString,
    91  			ExpectedValid: false,
    92  		},
    93  		{
    94  			Name:          "String longer than 100 chars",
    95  			Value:         inputvalidationtest.String129Long,
    96  			ExpectedValid: false,
    97  		},
    98  		{
    99  			Name:          "String contains invalid ASCII",
   100  			Value:         "ąćńłóęǖǘǚǜ",
   101  			ExpectedValid: false,
   102  		},
   103  	}
   104  
   105  	for _, testCase := range testCases {
   106  		t.Run(testCase.Name, func(t *testing.T) {
   107  			//GIVEN
   108  			sut := fixValidApplicationTemplateInput()
   109  			sut.Name = testCase.Value
   110  			// WHEN
   111  			err := sut.Validate()
   112  			// THEN
   113  			if testCase.ExpectedValid {
   114  				require.NoError(t, err)
   115  			} else {
   116  				require.Error(t, err)
   117  			}
   118  		})
   119  	}
   120  }
   121  
   122  func TestApplicationTemplateInput_Validate_Description(t *testing.T) {
   123  	testCases := []struct {
   124  		Name  string
   125  		Value *string
   126  		Valid bool
   127  	}{
   128  		{
   129  			Name: "Valid",
   130  			Value: str.Ptr("valid	valid"),
   131  			Valid: true,
   132  		},
   133  		{
   134  			Name:  "Valid - Nil",
   135  			Value: (*string)(nil),
   136  			Valid: true,
   137  		},
   138  		{
   139  			Name:  "Valid - Empty",
   140  			Value: str.Ptr(inputvalidationtest.EmptyString),
   141  			Valid: true,
   142  		},
   143  		{
   144  			Name:  "Invalid - Too long",
   145  			Value: str.Ptr(inputvalidationtest.String2001Long),
   146  			Valid: false,
   147  		},
   148  	}
   149  
   150  	for _, testCase := range testCases {
   151  		t.Run(testCase.Name, func(t *testing.T) {
   152  			//GIVEN
   153  			sut := fixValidApplicationTemplateInput()
   154  			sut.Description = testCase.Value
   155  			// WHEN
   156  			err := sut.Validate()
   157  			// THEN
   158  			if testCase.Valid {
   159  				require.NoError(t, err)
   160  			} else {
   161  				require.Error(t, err)
   162  			}
   163  		})
   164  	}
   165  }
   166  
   167  func TestApplicationTemplateInput_Validate_ApplicationNamespace(t *testing.T) {
   168  	testCases := []struct {
   169  		Name  string
   170  		Value *string
   171  		Valid bool
   172  	}{
   173  		{
   174  			Name:  "Valid",
   175  			Value: str.Ptr("valid"),
   176  			Valid: true,
   177  		},
   178  		{
   179  			Name:  "Valid - Nil",
   180  			Value: (*string)(nil),
   181  			Valid: true,
   182  		},
   183  		{
   184  			Name:  "Valid - Empty",
   185  			Value: str.Ptr(inputvalidationtest.EmptyString),
   186  			Valid: true,
   187  		},
   188  		{
   189  			Name:  "Invalid - Too long",
   190  			Value: str.Ptr(inputvalidationtest.String257Long),
   191  			Valid: false,
   192  		},
   193  	}
   194  
   195  	for _, testCase := range testCases {
   196  		t.Run(testCase.Name, func(t *testing.T) {
   197  			//GIVEN
   198  			sut := fixValidApplicationTemplateInput()
   199  			sut.ApplicationNamespace = testCase.Value
   200  			// WHEN
   201  			err := sut.Validate()
   202  			// THEN
   203  			if testCase.Valid {
   204  				require.NoError(t, err)
   205  			} else {
   206  				require.Error(t, err)
   207  			}
   208  		})
   209  	}
   210  }
   211  
   212  func TestApplicationTemplateInput_Validate_Placeholders(t *testing.T) {
   213  	testPlaceholderName := "test"
   214  	testCases := []struct {
   215  		Name  string
   216  		Value []*graphql.PlaceholderDefinitionInput
   217  		Valid bool
   218  	}{
   219  		{
   220  			Name: "Valid",
   221  			Value: []*graphql.PlaceholderDefinitionInput{
   222  				{Name: testPlaceholderName, Description: str.Ptr("Test description"), JSONPath: str.Ptr("displayName")},
   223  			},
   224  			Valid: true,
   225  		},
   226  		{
   227  			Name:  "Valid - Empty",
   228  			Value: []*graphql.PlaceholderDefinitionInput{},
   229  			Valid: true,
   230  		},
   231  		{
   232  			Name:  "Valid - Nil",
   233  			Value: nil,
   234  			Valid: true,
   235  		},
   236  		{
   237  			Name: "Invalid - Nil in slice",
   238  			Value: []*graphql.PlaceholderDefinitionInput{
   239  				nil,
   240  			},
   241  			Valid: false,
   242  		},
   243  		{
   244  			Name: "Invalid - Nested validation error",
   245  			Value: []*graphql.PlaceholderDefinitionInput{
   246  				{},
   247  			},
   248  			Valid: false,
   249  		},
   250  	}
   251  
   252  	for _, testCase := range testCases {
   253  		t.Run(testCase.Name, func(t *testing.T) {
   254  			//GIVEN
   255  			sut := fixValidApplicationTemplateInput()
   256  			sut.ApplicationInput.Description = str.Ptr(fmt.Sprintf("{{%s}}", testPlaceholderName))
   257  			sut.Placeholders = testCase.Value
   258  			// WHEN
   259  			err := sut.Validate()
   260  			// THEN
   261  			if testCase.Valid {
   262  				require.NoError(t, err)
   263  			} else {
   264  				require.Error(t, err)
   265  			}
   266  		})
   267  	}
   268  }
   269  
   270  func TestApplicationTemplateInput_Validate_AccessLevel(t *testing.T) {
   271  	testCases := []struct {
   272  		Name  string
   273  		Value graphql.ApplicationTemplateAccessLevel
   274  		Valid bool
   275  	}{
   276  		{
   277  			Name:  "Valid",
   278  			Value: graphql.ApplicationTemplateAccessLevelGlobal,
   279  			Valid: true,
   280  		},
   281  		{
   282  			Name:  "Invalid - Empty",
   283  			Value: inputvalidationtest.EmptyString,
   284  			Valid: false,
   285  		},
   286  		{
   287  			Name:  "Invalid - Not in enum",
   288  			Value: "invalid",
   289  			Valid: false,
   290  		},
   291  	}
   292  
   293  	for _, testCase := range testCases {
   294  		t.Run(testCase.Name, func(t *testing.T) {
   295  			//GIVEN
   296  			sut := fixValidApplicationTemplateInput()
   297  			sut.AccessLevel = testCase.Value
   298  			// WHEN
   299  			err := sut.Validate()
   300  			// THEN
   301  			if testCase.Valid {
   302  				require.NoError(t, err)
   303  			} else {
   304  				require.Error(t, err)
   305  			}
   306  		})
   307  	}
   308  }
   309  
   310  func TestApplicationTemplateInput_Validate_Webhooks(t *testing.T) {
   311  	webhookInput := fixValidWebhookInput(inputvalidationtest.ValidURL)
   312  	webhookInputWithInvalidOutputTemplate := fixValidWebhookInput(inputvalidationtest.ValidURL)
   313  	webhookInputWithInvalidOutputTemplate.OutputTemplate = stringPtr(`{ "gone_status_code": 404, "success_status_code": 200}`)
   314  	webhookInputwithInvalidURL := fixValidWebhookInput(inputvalidationtest.ValidURL)
   315  	webhookInputwithInvalidURL.URL = nil
   316  	testCases := []struct {
   317  		Name  string
   318  		Value []*graphql.WebhookInput
   319  		Valid bool
   320  	}{
   321  		{
   322  			Name:  "Valid",
   323  			Value: []*graphql.WebhookInput{&webhookInput},
   324  			Valid: true,
   325  		},
   326  		{
   327  			Name:  "Valid - Empty",
   328  			Value: []*graphql.WebhookInput{},
   329  			Valid: true,
   330  		},
   331  		{
   332  			Name:  "Valid - nil",
   333  			Value: nil,
   334  			Valid: true,
   335  		},
   336  		{
   337  			Name:  "Invalid - some of the webhooks are in invalid state - invalid output template",
   338  			Value: []*graphql.WebhookInput{&webhookInputWithInvalidOutputTemplate},
   339  			Valid: false,
   340  		},
   341  		{
   342  			Name:  "Invalid - some of the webhooks are in invalid state - invalid URL",
   343  			Value: []*graphql.WebhookInput{&webhookInputwithInvalidURL},
   344  			Valid: false,
   345  		},
   346  	}
   347  
   348  	for _, testCase := range testCases {
   349  		t.Run(testCase.Name, func(t *testing.T) {
   350  			//GIVEN
   351  			sut := fixValidApplicationTemplateInput()
   352  			sut.Webhooks = testCase.Value
   353  			// WHEN
   354  			err := sut.Validate()
   355  			// THEN
   356  			if testCase.Valid {
   357  				require.NoError(t, err)
   358  			} else {
   359  				require.Error(t, err)
   360  			}
   361  		})
   362  	}
   363  }
   364  
   365  // ApplicationTemplateUpdateInput
   366  
   367  func TestApplicationTemplateUpdateInput_Validate_Rule_ValidPlaceholders(t *testing.T) {
   368  	testPlaceholderName := "test"
   369  
   370  	testCases := []struct {
   371  		Name  string
   372  		Value []*graphql.PlaceholderDefinitionInput
   373  		Valid bool
   374  	}{
   375  		{
   376  			Name: "Valid",
   377  			Value: []*graphql.PlaceholderDefinitionInput{
   378  				{Name: testPlaceholderName, Description: str.Ptr("Test description"), JSONPath: str.Ptr("displayName")},
   379  			},
   380  			Valid: true,
   381  		},
   382  		{
   383  			Name:  "Valid - no placeholders",
   384  			Value: []*graphql.PlaceholderDefinitionInput{},
   385  			Valid: true,
   386  		},
   387  		{
   388  			Name: "Invalid - not unique",
   389  			Value: []*graphql.PlaceholderDefinitionInput{
   390  				{Name: testPlaceholderName, Description: str.Ptr("Test description"), JSONPath: str.Ptr("displayName")},
   391  				{Name: testPlaceholderName, Description: str.Ptr("Different description"), JSONPath: str.Ptr("displayName2")},
   392  			},
   393  			Valid: false,
   394  		},
   395  		{
   396  			Name: "Invalid - not used",
   397  			Value: []*graphql.PlaceholderDefinitionInput{
   398  				{Name: "notused", Description: str.Ptr("Test description"), JSONPath: str.Ptr("displayName")},
   399  			},
   400  			Valid: false,
   401  		},
   402  	}
   403  
   404  	for _, testCase := range testCases {
   405  		t.Run(testCase.Name, func(t *testing.T) {
   406  			//GIVEN
   407  			sut := fixValidApplicationTemplateUpdateInput()
   408  			sut.ApplicationInput.Description = str.Ptr(fmt.Sprintf("{{%s}}", testPlaceholderName))
   409  			sut.Placeholders = testCase.Value
   410  			// WHEN
   411  			err := sut.Validate()
   412  			// THEN
   413  			if testCase.Valid {
   414  				require.NoError(t, err)
   415  			} else {
   416  				require.Error(t, err)
   417  			}
   418  		})
   419  	}
   420  }
   421  
   422  func TestApplicationTemplateUpdateInput_Validate_Name(t *testing.T) {
   423  	testCases := []struct {
   424  		Name          string
   425  		Value         string
   426  		ExpectedValid bool
   427  	}{
   428  		{
   429  			Name:          "ExpectedValid",
   430  			Value:         "name-123.com",
   431  			ExpectedValid: true,
   432  		},
   433  		{
   434  			Name:          "Valid Printable ASCII",
   435  			Value:         "V1 +=_-)(*&^%$#@!?/>.<,|\\\"':;}{][",
   436  			ExpectedValid: true,
   437  		},
   438  		{
   439  			Name:          "Empty string",
   440  			Value:         inputvalidationtest.EmptyString,
   441  			ExpectedValid: false,
   442  		},
   443  		{
   444  			Name:          "String longer than 100 chars",
   445  			Value:         inputvalidationtest.String129Long,
   446  			ExpectedValid: false,
   447  		},
   448  		{
   449  			Name:          "String contains invalid ASCII",
   450  			Value:         "ąćńłóęǖǘǚǜ",
   451  			ExpectedValid: false,
   452  		},
   453  	}
   454  
   455  	for _, testCase := range testCases {
   456  		t.Run(testCase.Name, func(t *testing.T) {
   457  			//GIVEN
   458  			sut := fixValidApplicationTemplateUpdateInput()
   459  			sut.Name = testCase.Value
   460  			// WHEN
   461  			err := sut.Validate()
   462  			// THEN
   463  			if testCase.ExpectedValid {
   464  				require.NoError(t, err)
   465  			} else {
   466  				require.Error(t, err)
   467  			}
   468  		})
   469  	}
   470  }
   471  
   472  func TestApplicationTemplateUpdateInput_Validate_Description(t *testing.T) {
   473  	testCases := []struct {
   474  		Name  string
   475  		Value *string
   476  		Valid bool
   477  	}{
   478  		{
   479  			Name: "Valid",
   480  			Value: str.Ptr("valid	valid"),
   481  			Valid: true,
   482  		},
   483  		{
   484  			Name:  "Valid - Nil",
   485  			Value: (*string)(nil),
   486  			Valid: true,
   487  		},
   488  		{
   489  			Name:  "Valid - Empty",
   490  			Value: str.Ptr(inputvalidationtest.EmptyString),
   491  			Valid: true,
   492  		},
   493  		{
   494  			Name:  "Invalid - Too long",
   495  			Value: str.Ptr(inputvalidationtest.String2001Long),
   496  			Valid: false,
   497  		},
   498  	}
   499  
   500  	for _, testCase := range testCases {
   501  		t.Run(testCase.Name, func(t *testing.T) {
   502  			//GIVEN
   503  			sut := fixValidApplicationTemplateUpdateInput()
   504  			sut.Description = testCase.Value
   505  			// WHEN
   506  			err := sut.Validate()
   507  			// THEN
   508  			if testCase.Valid {
   509  				require.NoError(t, err)
   510  			} else {
   511  				require.Error(t, err)
   512  			}
   513  		})
   514  	}
   515  }
   516  
   517  func TestApplicationTemplateUpdateInput_Validate_Placeholders(t *testing.T) {
   518  	testPlaceholderName := "test"
   519  	testCases := []struct {
   520  		Name  string
   521  		Value []*graphql.PlaceholderDefinitionInput
   522  		Valid bool
   523  	}{
   524  		{
   525  			Name: "Valid",
   526  			Value: []*graphql.PlaceholderDefinitionInput{
   527  				{Name: testPlaceholderName, Description: str.Ptr("Test description"), JSONPath: str.Ptr("displayName")},
   528  			},
   529  			Valid: true,
   530  		},
   531  		{
   532  			Name:  "Valid - Empty",
   533  			Value: []*graphql.PlaceholderDefinitionInput{},
   534  			Valid: true,
   535  		},
   536  		{
   537  			Name:  "Valid - Nil",
   538  			Value: nil,
   539  			Valid: true,
   540  		},
   541  		{
   542  			Name: "Invalid - Nil in slice",
   543  			Value: []*graphql.PlaceholderDefinitionInput{
   544  				nil,
   545  			},
   546  			Valid: false,
   547  		},
   548  		{
   549  			Name: "Invalid - Nested validation error",
   550  			Value: []*graphql.PlaceholderDefinitionInput{
   551  				{},
   552  			},
   553  			Valid: false,
   554  		},
   555  	}
   556  
   557  	for _, testCase := range testCases {
   558  		t.Run(testCase.Name, func(t *testing.T) {
   559  			//GIVEN
   560  			sut := fixValidApplicationTemplateUpdateInput()
   561  			sut.ApplicationInput.Description = str.Ptr(fmt.Sprintf("{{%s}}", testPlaceholderName))
   562  			sut.Placeholders = testCase.Value
   563  			// WHEN
   564  			err := sut.Validate()
   565  			// THEN
   566  			if testCase.Valid {
   567  				require.NoError(t, err)
   568  			} else {
   569  				require.Error(t, err)
   570  			}
   571  		})
   572  	}
   573  }
   574  
   575  func TestApplicationTemplateUpdateInput_Validate_AccessLevel(t *testing.T) {
   576  	testCases := []struct {
   577  		Name  string
   578  		Value graphql.ApplicationTemplateAccessLevel
   579  		Valid bool
   580  	}{
   581  		{
   582  			Name:  "Valid",
   583  			Value: graphql.ApplicationTemplateAccessLevelGlobal,
   584  			Valid: true,
   585  		},
   586  		{
   587  			Name:  "Invalid - Empty",
   588  			Value: inputvalidationtest.EmptyString,
   589  			Valid: false,
   590  		},
   591  		{
   592  			Name:  "Invalid - Not in enum",
   593  			Value: "invalid",
   594  			Valid: false,
   595  		},
   596  	}
   597  
   598  	for _, testCase := range testCases {
   599  		t.Run(testCase.Name, func(t *testing.T) {
   600  			//GIVEN
   601  			sut := fixValidApplicationTemplateUpdateInput()
   602  			sut.AccessLevel = testCase.Value
   603  			// WHEN
   604  			err := sut.Validate()
   605  			// THEN
   606  			if testCase.Valid {
   607  				require.NoError(t, err)
   608  			} else {
   609  				require.Error(t, err)
   610  			}
   611  		})
   612  	}
   613  }
   614  
   615  func TestApplicationTemplateUpdateInput_Validate_Webhooks(t *testing.T) {
   616  	webhookInput := fixValidWebhookInput(inputvalidationtest.ValidURL)
   617  	webhookInputWithInvalidOutputTemplate := fixValidWebhookInput(inputvalidationtest.ValidURL)
   618  	webhookInputWithInvalidOutputTemplate.OutputTemplate = stringPtr(`{ "gone_status_code": 404, "success_status_code": 200}`)
   619  	webhookInputWithInvalidURL := fixValidWebhookInput(inputvalidationtest.ValidURL)
   620  	webhookInputWithInvalidURL.URL = nil
   621  	testCases := []struct {
   622  		Name  string
   623  		Value []*graphql.WebhookInput
   624  		Valid bool
   625  	}{
   626  		{
   627  			Name:  "Valid",
   628  			Value: []*graphql.WebhookInput{&webhookInput},
   629  			Valid: true,
   630  		},
   631  		{
   632  			Name:  "Valid - Empty",
   633  			Value: []*graphql.WebhookInput{},
   634  			Valid: true,
   635  		},
   636  		{
   637  			Name:  "Valid - nil",
   638  			Value: nil,
   639  			Valid: true,
   640  		},
   641  		{
   642  			Name:  "Invalid - some of the webhooks are in invalid state - invalid output template",
   643  			Value: []*graphql.WebhookInput{&webhookInputWithInvalidOutputTemplate},
   644  			Valid: false,
   645  		},
   646  		{
   647  			Name:  "Invalid - some of the webhooks are in invalid state - invalid URL",
   648  			Value: []*graphql.WebhookInput{&webhookInputWithInvalidURL},
   649  			Valid: false,
   650  		},
   651  	}
   652  
   653  	for _, testCase := range testCases {
   654  		t.Run(testCase.Name, func(t *testing.T) {
   655  			//GIVEN
   656  			sut := fixValidApplicationTemplateUpdateInput()
   657  			sut.ApplicationInput.Webhooks = testCase.Value
   658  			// WHEN
   659  			err := sut.Validate()
   660  			// THEN
   661  			if testCase.Valid {
   662  				require.NoError(t, err)
   663  			} else {
   664  				require.Error(t, err)
   665  			}
   666  		})
   667  	}
   668  }
   669  
   670  // PlaceholderDefinitionInput
   671  
   672  func TestPlaceholderDefinitionInput_Validate_Name(t *testing.T) {
   673  	testCases := []struct {
   674  		Name  string
   675  		Value string
   676  		Valid bool
   677  	}{
   678  		{
   679  			Name:  "Valid",
   680  			Value: inputvalidationtest.ValidName,
   681  			Valid: true,
   682  		},
   683  		{
   684  			Name:  "Invalid - Empty",
   685  			Value: inputvalidationtest.EmptyString,
   686  			Valid: false,
   687  		},
   688  		{
   689  			Name:  "Invalid - Invalid Name",
   690  			Value: inputvalidationtest.InvalidName,
   691  			Valid: false,
   692  		},
   693  	}
   694  
   695  	for _, testCase := range testCases {
   696  		t.Run(testCase.Name, func(t *testing.T) {
   697  			//GIVEN
   698  			sut := fixValidPlaceholderDefintionInput()
   699  			sut.Name = testCase.Value
   700  			// WHEN
   701  			err := sut.Validate()
   702  			// THEN
   703  			if testCase.Valid {
   704  				require.NoError(t, err)
   705  			} else {
   706  				require.Error(t, err)
   707  			}
   708  		})
   709  	}
   710  }
   711  
   712  func TestPlaceholderDefinitionInput_Validate_Description(t *testing.T) {
   713  	testCases := []struct {
   714  		Name  string
   715  		Value *string
   716  		Valid bool
   717  	}{
   718  		{
   719  			Name: "Valid",
   720  			Value: str.Ptr("valid	valid"),
   721  			Valid: true,
   722  		},
   723  		{
   724  			Name:  "Valid - Nil",
   725  			Value: (*string)(nil),
   726  			Valid: true,
   727  		},
   728  		{
   729  			Name:  "Valid - Empty",
   730  			Value: str.Ptr(inputvalidationtest.EmptyString),
   731  			Valid: true,
   732  		},
   733  		{
   734  			Name:  "Invalid - Too long",
   735  			Value: str.Ptr(inputvalidationtest.String2001Long),
   736  			Valid: false,
   737  		},
   738  	}
   739  
   740  	for _, testCase := range testCases {
   741  		t.Run(testCase.Name, func(t *testing.T) {
   742  			//GIVEN
   743  			sut := fixValidPlaceholderDefintionInput()
   744  			sut.Description = testCase.Value
   745  			// WHEN
   746  			err := sut.Validate()
   747  			// THEN
   748  			if testCase.Valid {
   749  				require.NoError(t, err)
   750  			} else {
   751  				require.Error(t, err)
   752  			}
   753  		})
   754  	}
   755  }
   756  
   757  func TestApplicationFromTemplateInput_Validate_Rule_EitherPlaceholdersOrPlaceholdersPayloadExists(t *testing.T) {
   758  	testPlaceholderName := "test"
   759  	testPlacehoderPayload := "{\"a\":\"b\"}"
   760  
   761  	testCases := []struct {
   762  		Name                string
   763  		Value               []*graphql.TemplateValueInput
   764  		PlaceholdersPayload *string
   765  		Valid               bool
   766  	}{
   767  		{
   768  			Name: "Valid - only Value",
   769  			Value: []*graphql.TemplateValueInput{
   770  				{Placeholder: testPlaceholderName, Value: "abc"},
   771  			},
   772  			Valid: true,
   773  		},
   774  		{
   775  			Name:                "Valid - only PlaceholdersPayload",
   776  			PlaceholdersPayload: &testPlacehoderPayload,
   777  			Valid:               true,
   778  		},
   779  		{
   780  			Name: "Invalid - both Value and PlaceholdersPayload",
   781  			Value: []*graphql.TemplateValueInput{
   782  				{Placeholder: testPlaceholderName, Value: "abc"},
   783  			},
   784  			PlaceholdersPayload: &testPlacehoderPayload,
   785  			Valid:               false,
   786  		},
   787  		{
   788  			Name:  "Invalid - neither Value nor PlaceholdersPayload",
   789  			Valid: false,
   790  		},
   791  	}
   792  
   793  	for _, testCase := range testCases {
   794  		t.Run(testCase.Name, func(t *testing.T) {
   795  			//GIVEN
   796  			sut := fixValidApplicationFromTemplateInput()
   797  			sut.Values = testCase.Value
   798  			sut.PlaceholdersPayload = testCase.PlaceholdersPayload
   799  			// WHEN
   800  			err := sut.Validate()
   801  			// THEN
   802  			if testCase.Valid {
   803  				require.NoError(t, err)
   804  			} else {
   805  				require.Error(t, err)
   806  			}
   807  		})
   808  	}
   809  }
   810  
   811  // ApplicationFromTemplateInput
   812  
   813  func TestApplicationFromTemplateInput_Validate_Rule_UniquePlaceholders(t *testing.T) {
   814  	testPlaceholderName := "test"
   815  
   816  	testCases := []struct {
   817  		Name  string
   818  		Value []*graphql.TemplateValueInput
   819  		Valid bool
   820  	}{
   821  		{
   822  			Name: "Valid",
   823  			Value: []*graphql.TemplateValueInput{
   824  				{Placeholder: testPlaceholderName, Value: ""},
   825  			},
   826  			Valid: true,
   827  		},
   828  		{
   829  			Name: "Invalid - not unique",
   830  			Value: []*graphql.TemplateValueInput{
   831  				{Placeholder: testPlaceholderName, Value: "one"},
   832  				{Placeholder: testPlaceholderName, Value: "two"},
   833  			},
   834  			Valid: false,
   835  		},
   836  	}
   837  
   838  	for _, testCase := range testCases {
   839  		t.Run(testCase.Name, func(t *testing.T) {
   840  			//GIVEN
   841  			sut := fixValidApplicationFromTemplateInput()
   842  			sut.Values = testCase.Value
   843  			// WHEN
   844  			err := sut.Validate()
   845  			// THEN
   846  			if testCase.Valid {
   847  				require.NoError(t, err)
   848  			} else {
   849  				require.Error(t, err)
   850  			}
   851  		})
   852  	}
   853  }
   854  
   855  func TestApplicationFromTemplateInput_Validate_TemplateName(t *testing.T) {
   856  	testPlacehoderPayload := "{\"a\":\"b\"}"
   857  	testCases := []struct {
   858  		Name          string
   859  		Value         string
   860  		ExpectedValid bool
   861  	}{
   862  		{
   863  			Name:          "ExpectedValid",
   864  			Value:         "name-123.com",
   865  			ExpectedValid: true,
   866  		},
   867  		{
   868  			Name:          "Valid Printable ASCII",
   869  			Value:         "V1 +=_-)(*&^%$#@!?/>.<,|\\\"':;}{][",
   870  			ExpectedValid: true,
   871  		},
   872  		{
   873  			Name:          "Empty string",
   874  			Value:         inputvalidationtest.EmptyString,
   875  			ExpectedValid: false,
   876  		},
   877  		{
   878  			Name:          "String longer than 100 chars",
   879  			Value:         inputvalidationtest.String129Long,
   880  			ExpectedValid: false,
   881  		},
   882  		{
   883  			Name:          "String contains invalid ASCII",
   884  			Value:         "ąćńłóęǖǘǚǜ",
   885  			ExpectedValid: false,
   886  		},
   887  	}
   888  
   889  	for _, testCase := range testCases {
   890  		t.Run(testCase.Name, func(t *testing.T) {
   891  			//GIVEN
   892  			sut := fixValidApplicationFromTemplateInput()
   893  			sut.TemplateName = testCase.Value
   894  			sut.PlaceholdersPayload = &testPlacehoderPayload
   895  			// WHEN
   896  			err := sut.Validate()
   897  			// THEN
   898  			if testCase.ExpectedValid {
   899  				require.NoError(t, err)
   900  			} else {
   901  				require.Error(t, err)
   902  			}
   903  		})
   904  	}
   905  }
   906  
   907  func TestApplicationTemplateInput_Validate_Value(t *testing.T) {
   908  	testPlaceholderName := "test"
   909  	testCases := []struct {
   910  		Name  string
   911  		Value []*graphql.TemplateValueInput
   912  		Valid bool
   913  	}{
   914  		{
   915  			Name: "Valid",
   916  			Value: []*graphql.TemplateValueInput{
   917  				{Placeholder: testPlaceholderName, Value: "valid"},
   918  			},
   919  			Valid: true,
   920  		},
   921  		{
   922  			Name: "Invalid - Nil in slice",
   923  			Value: []*graphql.TemplateValueInput{
   924  				nil,
   925  			},
   926  			Valid: false,
   927  		},
   928  		{
   929  			Name: "Invalid - Nested validation error",
   930  			Value: []*graphql.TemplateValueInput{
   931  				{},
   932  			},
   933  			Valid: false,
   934  		},
   935  	}
   936  
   937  	for _, testCase := range testCases {
   938  		t.Run(testCase.Name, func(t *testing.T) {
   939  			//GIVEN
   940  			sut := fixValidApplicationFromTemplateInput()
   941  			sut.Values = testCase.Value
   942  			// WHEN
   943  			err := sut.Validate()
   944  			// THEN
   945  			if testCase.Valid {
   946  				require.NoError(t, err)
   947  			} else {
   948  				require.Error(t, err)
   949  			}
   950  		})
   951  	}
   952  }
   953  
   954  // TemplateValueInput
   955  
   956  func TestTemplateValueInput_Validate_Name(t *testing.T) {
   957  	testCases := []struct {
   958  		Name  string
   959  		Value string
   960  		Valid bool
   961  	}{
   962  		{
   963  			Name:  "Valid",
   964  			Value: inputvalidationtest.ValidName,
   965  			Valid: true,
   966  		},
   967  		{
   968  			Name:  "Invalid - Empty",
   969  			Value: inputvalidationtest.EmptyString,
   970  			Valid: false,
   971  		},
   972  		{
   973  			Name:  "Invalid - Invalid Name",
   974  			Value: inputvalidationtest.InvalidName,
   975  			Valid: false,
   976  		},
   977  	}
   978  
   979  	for _, testCase := range testCases {
   980  		t.Run(testCase.Name, func(t *testing.T) {
   981  			//GIVEN
   982  			sut := fixValidTemplateValueInput()
   983  			sut.Placeholder = testCase.Value
   984  			// WHEN
   985  			err := sut.Validate()
   986  			// THEN
   987  			if testCase.Valid {
   988  				require.NoError(t, err)
   989  			} else {
   990  				require.Error(t, err)
   991  			}
   992  		})
   993  	}
   994  }
   995  
   996  func TestTemplateValueInput_Validate_Description(t *testing.T) {
   997  	testCases := []struct {
   998  		Name  string
   999  		Value string
  1000  		Valid bool
  1001  	}{
  1002  		{
  1003  			Name:  "Valid",
  1004  			Value: "valid",
  1005  			Valid: true,
  1006  		},
  1007  		{
  1008  			Name:  "Valid - Empty",
  1009  			Value: inputvalidationtest.EmptyString,
  1010  			Valid: true,
  1011  		},
  1012  		{
  1013  			Name:  "Invalid - Too long",
  1014  			Value: inputvalidationtest.String129Long,
  1015  			Valid: false,
  1016  		},
  1017  	}
  1018  
  1019  	for _, testCase := range testCases {
  1020  		t.Run(testCase.Name, func(t *testing.T) {
  1021  			//GIVEN
  1022  			sut := fixValidTemplateValueInput()
  1023  			sut.Value = testCase.Value
  1024  			// WHEN
  1025  			err := sut.Validate()
  1026  			// THEN
  1027  			if testCase.Valid {
  1028  				require.NoError(t, err)
  1029  			} else {
  1030  				require.Error(t, err)
  1031  			}
  1032  		})
  1033  	}
  1034  }
  1035  
  1036  // fixtures
  1037  
  1038  func fixValidApplicationTemplateInput() graphql.ApplicationTemplateInput {
  1039  	return graphql.ApplicationTemplateInput{
  1040  		Name: "valid",
  1041  		ApplicationInput: &graphql.ApplicationJSONInput{
  1042  			Name: "valid",
  1043  		},
  1044  		AccessLevel: graphql.ApplicationTemplateAccessLevelGlobal,
  1045  		Webhooks:    []*graphql.WebhookInput{},
  1046  	}
  1047  }
  1048  func fixValidApplicationTemplateUpdateInput() graphql.ApplicationTemplateUpdateInput {
  1049  	return graphql.ApplicationTemplateUpdateInput{
  1050  		Name: "valid",
  1051  		ApplicationInput: &graphql.ApplicationJSONInput{
  1052  			Name: "valid",
  1053  		},
  1054  		AccessLevel: graphql.ApplicationTemplateAccessLevelGlobal,
  1055  	}
  1056  }
  1057  
  1058  func fixValidPlaceholderDefintionInput() graphql.PlaceholderDefinitionInput {
  1059  	return graphql.PlaceholderDefinitionInput{
  1060  		Name: "valid",
  1061  	}
  1062  }
  1063  
  1064  func fixValidApplicationFromTemplateInput() graphql.ApplicationFromTemplateInput {
  1065  	return graphql.ApplicationFromTemplateInput{
  1066  		TemplateName: "valid",
  1067  	}
  1068  }
  1069  
  1070  func fixValidTemplateValueInput() graphql.TemplateValueInput {
  1071  	return graphql.TemplateValueInput{
  1072  		Placeholder: "test",
  1073  		Value:       "",
  1074  	}
  1075  }