github.com/prebid/prebid-server/v2@v2.18.0/amp/parse_test.go (about)

     1  package amp
     2  
     3  import (
     4  	"net/http"
     5  	"testing"
     6  
     7  	"github.com/prebid/openrtb/v20/openrtb2"
     8  	"github.com/prebid/prebid-server/v2/errortypes"
     9  	"github.com/prebid/prebid-server/v2/privacy"
    10  	"github.com/prebid/prebid-server/v2/privacy/ccpa"
    11  	"github.com/prebid/prebid-server/v2/privacy/gdpr"
    12  	"github.com/stretchr/testify/assert"
    13  )
    14  
    15  func TestParseParams(t *testing.T) {
    16  	var expectedTimeout uint64 = 42
    17  
    18  	testCases := []struct {
    19  		description    string
    20  		query          string
    21  		expectedParams Params
    22  		expectedError  string
    23  	}{
    24  		{
    25  			description:   "Empty",
    26  			query:         "",
    27  			expectedError: "AMP requests require an AMP tag_id",
    28  		},
    29  		{
    30  			description: "All Fields",
    31  			// targeting data is encoded string that looks like this: {"gam-key1":"val1","gam-key2":"val2"}
    32  			query: "tag_id=anyTagID&account=anyAccount&curl=anyCurl&consent_string=anyConsent&debug=1&__amp_source_origin=anyOrigin" +
    33  				"&slot=anySlot&timeout=42&h=1&w=2&oh=3&ow=4&ms=10x11,12x13&targeting=%7B%22gam-key1%22%3A%22val1%22%2C%22gam-key2%22%3A%22val2%22%7D&trace=basic",
    34  			expectedParams: Params{
    35  				Account:         "anyAccount",
    36  				CanonicalURL:    "anyCurl",
    37  				Consent:         "anyConsent",
    38  				Debug:           true,
    39  				Origin:          "anyOrigin",
    40  				Slot:            "anySlot",
    41  				StoredRequestID: "anyTagID",
    42  				Timeout:         &expectedTimeout,
    43  				Size: Size{
    44  					Height:         1,
    45  					OverrideHeight: 3,
    46  					OverrideWidth:  4,
    47  					Width:          2,
    48  					Multisize: []openrtb2.Format{
    49  						{W: 10, H: 11}, {W: 12, H: 13},
    50  					},
    51  				},
    52  				Targeting: `{"gam-key1":"val1","gam-key2":"val2"}`,
    53  				Trace:     "basic",
    54  			},
    55  		},
    56  		{
    57  			description:    "Integer Values Ignored If Invalid",
    58  			query:          "tag_id=anyTagID&h=invalid&w=invalid&oh=invalid&ow=invalid&ms=invalid",
    59  			expectedParams: Params{StoredRequestID: "anyTagID"},
    60  		},
    61  		{
    62  			description:    "consent_string Preferred Over gdpr_consent",
    63  			query:          "tag_id=anyTagID&consent_string=consent1&gdpr_consent=consent2",
    64  			expectedParams: Params{StoredRequestID: "anyTagID", Consent: "consent1"},
    65  		},
    66  		{
    67  			description:    "consent_string Preferred Over gdpr_consent - Order Doesn't Matter",
    68  			query:          "tag_id=anyTagID&gdpr_consent=consent2&consent_string=consent1",
    69  			expectedParams: Params{StoredRequestID: "anyTagID", Consent: "consent1"},
    70  		},
    71  		{
    72  			description:    "Just gdpr_consent",
    73  			query:          "tag_id=anyTagID&gdpr_consent=consent2",
    74  			expectedParams: Params{StoredRequestID: "anyTagID", Consent: "consent2"},
    75  		},
    76  		{
    77  			description:    "Debug 0",
    78  			query:          "tag_id=anyTagID&debug=0",
    79  			expectedParams: Params{StoredRequestID: "anyTagID", Debug: false},
    80  		},
    81  		{
    82  			description:    "Debug Ignored If Invalid",
    83  			query:          "tag_id=anyTagID&debug=invalid",
    84  			expectedParams: Params{StoredRequestID: "anyTagID", Debug: false},
    85  		},
    86  	}
    87  
    88  	for _, test := range testCases {
    89  		httpRequest, err := http.NewRequest("GET", "http://any.url/anypage?"+test.query, nil)
    90  		assert.NoError(t, err, test.description+":request")
    91  
    92  		params, err := ParseParams(httpRequest)
    93  		assert.Equal(t, test.expectedParams, params, test.description+":params")
    94  		if test.expectedError == "" {
    95  			assert.NoError(t, err, test.description+":err")
    96  		} else {
    97  			assert.EqualError(t, err, test.expectedError)
    98  		}
    99  	}
   100  }
   101  
   102  func TestParseIntPtr(t *testing.T) {
   103  	var boolZero uint64 = 0
   104  	var boolOne uint64 = 1
   105  
   106  	type testResults struct {
   107  		intPtr *uint64
   108  		err    bool
   109  	}
   110  
   111  	testCases := []struct {
   112  		desc     string
   113  		input    string
   114  		expected testResults
   115  	}{
   116  		{
   117  			desc:  "Input is an empty string: expect nil pointer and error",
   118  			input: "",
   119  			expected: testResults{
   120  				intPtr: nil,
   121  				err:    true,
   122  			},
   123  		},
   124  		{
   125  			desc:  "Input is negative number: expect a nil pointer and error",
   126  			input: "-1",
   127  			expected: testResults{
   128  				intPtr: nil,
   129  				err:    true,
   130  			},
   131  		},
   132  		{
   133  			desc:  "Input is a string depicting a zero value: expect a reference pointing to zero value, no error",
   134  			input: "0",
   135  			expected: testResults{
   136  				intPtr: &boolZero,
   137  				err:    false,
   138  			},
   139  		},
   140  		{
   141  			desc:  "Input is a string depicting a value of 1: expect a reference pointing to the value of 1 and no error",
   142  			input: "1",
   143  			expected: testResults{
   144  				intPtr: &boolOne,
   145  				err:    false,
   146  			},
   147  		},
   148  	}
   149  	for _, tc := range testCases {
   150  		resultingIntPtr, resultingErr := parseIntPtr(tc.input)
   151  
   152  		assert.Equal(t, tc.expected.intPtr, resultingIntPtr, tc.desc)
   153  		if tc.expected.err {
   154  			assert.Error(t, resultingErr, tc.desc)
   155  		} else {
   156  			assert.NoError(t, resultingErr, tc.desc)
   157  		}
   158  	}
   159  }
   160  
   161  func TestParseBoolPtr(t *testing.T) {
   162  	boolTrue := true
   163  	boolFalse := false
   164  
   165  	type testResults struct {
   166  		boolPtr *bool
   167  		err     bool
   168  	}
   169  
   170  	testCases := []struct {
   171  		desc     string
   172  		input    string
   173  		expected testResults
   174  	}{
   175  		{
   176  			desc:  "Input is an empty string: expect nil pointer and error",
   177  			input: "",
   178  			expected: testResults{
   179  				boolPtr: nil,
   180  				err:     true,
   181  			},
   182  		},
   183  		{
   184  			desc:  "Input is neither true nor false: expect a nil pointer and error",
   185  			input: "other",
   186  			expected: testResults{
   187  				boolPtr: nil,
   188  				err:     true,
   189  			},
   190  		},
   191  		{
   192  			desc:  "Input is the word 'false', expect a reference pointing to false value",
   193  			input: "false",
   194  			expected: testResults{
   195  				boolPtr: &boolFalse,
   196  				err:     false,
   197  			},
   198  		},
   199  		{
   200  			desc:  "Input is the word 'true', expect a reference pointing to true value",
   201  			input: "true",
   202  			expected: testResults{
   203  				boolPtr: &boolTrue,
   204  				err:     false,
   205  			},
   206  		},
   207  	}
   208  	for _, tc := range testCases {
   209  		resultingBoolPtr, resultingErr := parseBoolPtr(tc.input)
   210  
   211  		assert.Equal(t, tc.expected.boolPtr, resultingBoolPtr, tc.desc)
   212  		if tc.expected.err {
   213  			assert.Error(t, resultingErr, tc.desc)
   214  		} else {
   215  			assert.NoError(t, resultingErr, tc.desc)
   216  		}
   217  	}
   218  }
   219  
   220  // TestPrivacyReader asserts the ReadPolicy scenarios
   221  func TestPrivacyReader(t *testing.T) {
   222  	int8Zero := int8(0)
   223  	int8One := int8(1)
   224  	boolTrue := true
   225  	boolFalse := false
   226  
   227  	type testInput struct {
   228  		ampParams Params
   229  	}
   230  	type expectedResults struct {
   231  		policyWriter privacy.PolicyWriter
   232  		warning      error
   233  	}
   234  	type testCase struct {
   235  		desc     string
   236  		in       testInput
   237  		expected expectedResults
   238  	}
   239  
   240  	testGroups := []struct {
   241  		groupDesc string
   242  		tests     []testCase
   243  	}{
   244  		{
   245  			groupDesc: "No consent string",
   246  			tests: []testCase{
   247  				{
   248  					desc:     "Params comes with an empty consent string, expect nil policy writer. No warning returned",
   249  					expected: expectedResults{policyWriter: privacy.NilPolicyWriter{}, warning: nil},
   250  				},
   251  			},
   252  		},
   253  		{
   254  			groupDesc: "TCF1",
   255  			tests: []testCase{
   256  				{
   257  					desc: "Consent type TCF1: expect nil policy writer. Warning is returned",
   258  					in: testInput{
   259  						ampParams: Params{Consent: "VALID_TCF1_CONSENT", ConsentType: ConsentTCF1},
   260  					},
   261  					expected: expectedResults{
   262  						policyWriter: privacy.NilPolicyWriter{},
   263  						warning:      &errortypes.Warning{Message: "TCF1 consent is deprecated and no longer supported.", WarningCode: errortypes.InvalidPrivacyConsentWarningCode},
   264  					},
   265  				},
   266  			},
   267  		},
   268  		{
   269  			groupDesc: "ConsentNone. In order to be backwards compatible, we'll guess what consent string this is",
   270  			tests: []testCase{
   271  				{
   272  					desc: "No consent type was specified and invalid consent string provided: expect nil policy writer and a warning",
   273  					in: testInput{
   274  						ampParams: Params{Consent: "NOT_CCPA_NOR_GDPR_TCF2"},
   275  					},
   276  					expected: expectedResults{
   277  						policyWriter: privacy.NilPolicyWriter{},
   278  						warning:      &errortypes.Warning{Message: "Consent string 'NOT_CCPA_NOR_GDPR_TCF2' is not recognized as one of the supported formats CCPA or TCF2.", WarningCode: errortypes.InvalidPrivacyConsentWarningCode},
   279  					},
   280  				},
   281  				{
   282  					desc: "No consent type specified but query params come with a valid CCPA consent string: expect a CCPA consent writer and no error nor warning",
   283  					in: testInput{
   284  						ampParams: Params{Consent: "1YYY"},
   285  					},
   286  					expected: expectedResults{
   287  						policyWriter: ccpa.ConsentWriter{Consent: "1YYY"},
   288  						warning:      nil,
   289  					},
   290  				},
   291  				{
   292  					desc: "No consent type, valid CCPA consent string and gdpr_applies set to true: expect a CCPA consent writer and a warning",
   293  					in: testInput{
   294  						ampParams: Params{
   295  							Consent:     "1YYY",
   296  							GdprApplies: &boolTrue,
   297  						},
   298  					},
   299  					expected: expectedResults{
   300  						policyWriter: ccpa.ConsentWriter{Consent: "1YYY"},
   301  						warning: &errortypes.Warning{
   302  							Message:     "AMP request gdpr_applies value was ignored because provided consent string is a CCPA consent string",
   303  							WarningCode: errortypes.InvalidPrivacyConsentWarningCode,
   304  						},
   305  					},
   306  				},
   307  				{
   308  					desc: "No consent type, valid GDPR consent string and gdpr_applies not set: expect a GDPR consent writer and no error nor warning",
   309  					in: testInput{
   310  						ampParams: Params{Consent: "CPdiPIJPdiPIJACABBENAzCv_____3___wAAAQNd_X9cAAAAAAAA"},
   311  					},
   312  					expected: expectedResults{
   313  						policyWriter: gdpr.ConsentWriter{
   314  							Consent:    "CPdiPIJPdiPIJACABBENAzCv_____3___wAAAQNd_X9cAAAAAAAA",
   315  							RegExtGDPR: &int8One,
   316  						},
   317  						warning: nil,
   318  					},
   319  				},
   320  			},
   321  		},
   322  		{
   323  			groupDesc: "Unrecognized consent type. In order to be backwards compatible, we'll guess what consent string type it is",
   324  			tests: []testCase{
   325  				{
   326  					desc: "Unrecognized consent type was specified and invalid consent string provided: expect nil policy writer and a warning",
   327  					in: testInput{
   328  						ampParams: Params{
   329  							ConsentType: 101,
   330  							Consent:     "NOT_CCPA_NOR_GDPR_TCF2",
   331  						},
   332  					},
   333  					expected: expectedResults{
   334  						policyWriter: privacy.NilPolicyWriter{},
   335  						warning: &errortypes.Warning{
   336  							Message:     "Consent string 'NOT_CCPA_NOR_GDPR_TCF2' is not recognized as one of the supported formats CCPA or TCF2.",
   337  							WarningCode: errortypes.InvalidPrivacyConsentWarningCode,
   338  						},
   339  					},
   340  				},
   341  				{
   342  					desc: "Unrecognized consent type specified but query params come with a valid CCPA consent string: expect a CCPA consent writer and no error nor warning",
   343  					in: testInput{
   344  						ampParams: Params{
   345  							ConsentType: 101,
   346  							Consent:     "1YYY",
   347  						},
   348  					},
   349  					expected: expectedResults{
   350  						policyWriter: ccpa.ConsentWriter{Consent: "1YYY"},
   351  						warning:      nil,
   352  					},
   353  				},
   354  				{
   355  					desc: "Unrecognized consent type, valid CCPA consent string and gdpr_applies set to true: expect a CCPA consent writer and a warning",
   356  					in: testInput{
   357  						ampParams: Params{
   358  							ConsentType: 101,
   359  							Consent:     "1YYY",
   360  							GdprApplies: &boolTrue,
   361  						},
   362  					},
   363  					expected: expectedResults{
   364  						policyWriter: ccpa.ConsentWriter{Consent: "1YYY"},
   365  						warning: &errortypes.Warning{
   366  							Message:     "AMP request gdpr_applies value was ignored because provided consent string is a CCPA consent string",
   367  							WarningCode: errortypes.InvalidPrivacyConsentWarningCode,
   368  						},
   369  					},
   370  				},
   371  				{
   372  					desc: "Unrecognized consent type, valid TCF2 consent string and gdpr_applies not set: expect GDPR consent writer and no error nor warning",
   373  					in: testInput{
   374  						ampParams: Params{
   375  							ConsentType: 101,
   376  							Consent:     "CPdiPIJPdiPIJACABBENAzCv_____3___wAAAQNd_X9cAAAAAAAA",
   377  						},
   378  					},
   379  					expected: expectedResults{
   380  						policyWriter: gdpr.ConsentWriter{
   381  							Consent:    "CPdiPIJPdiPIJACABBENAzCv_____3___wAAAQNd_X9cAAAAAAAA",
   382  							RegExtGDPR: &int8One,
   383  						},
   384  						warning: nil,
   385  					},
   386  				},
   387  			},
   388  		},
   389  		{
   390  			groupDesc: "consent type TCF2. Return a valid GDPR consent writer in all scenarios.",
   391  			tests: []testCase{
   392  				{
   393  					desc: "GDPR consent string is invalid, but consent type is TCF2: return a valid GDPR writer and warn about the GDPR string being invalid",
   394  					in: testInput{
   395  						ampParams: Params{
   396  							Consent:     "INVALID_GDPR",
   397  							ConsentType: ConsentTCF2,
   398  							GdprApplies: nil,
   399  						},
   400  					},
   401  					expected: expectedResults{
   402  						policyWriter: gdpr.ConsentWriter{
   403  							Consent:    "INVALID_GDPR",
   404  							RegExtGDPR: &int8One,
   405  						},
   406  						warning: &errortypes.Warning{
   407  							Message:     "Consent string 'INVALID_GDPR' is not a valid TCF2 consent string.",
   408  							WarningCode: errortypes.InvalidPrivacyConsentWarningCode,
   409  						},
   410  					},
   411  				},
   412  				{
   413  					desc: "GDPR consent string is invalid, consent type is TCF2, gdpr_applies is set to true: return a valid GDPR writer and warn about the GDPR string being invalid",
   414  					in: testInput{
   415  						ampParams: Params{
   416  							Consent:     "INVALID_GDPR",
   417  							ConsentType: ConsentTCF2,
   418  							GdprApplies: &boolFalse,
   419  						},
   420  					},
   421  					expected: expectedResults{
   422  						policyWriter: gdpr.ConsentWriter{
   423  							Consent:    "INVALID_GDPR",
   424  							RegExtGDPR: &int8Zero,
   425  						},
   426  						warning: &errortypes.Warning{
   427  							Message:     "Consent string 'INVALID_GDPR' is not a valid TCF2 consent string.",
   428  							WarningCode: errortypes.InvalidPrivacyConsentWarningCode,
   429  						},
   430  					},
   431  				},
   432  				{
   433  					desc: "Valid GDPR consent string, gdpr_applies is set to false, return a valid GDPR writer, no warning",
   434  					in: testInput{
   435  						ampParams: Params{
   436  							Consent:     "CPdiPIJPdiPIJACABBENAzCv_____3___wAAAQNd_X9cAAAAAAAA",
   437  							ConsentType: ConsentTCF2,
   438  							GdprApplies: &boolFalse,
   439  						},
   440  					},
   441  					expected: expectedResults{
   442  						policyWriter: gdpr.ConsentWriter{
   443  							Consent:    "CPdiPIJPdiPIJACABBENAzCv_____3___wAAAQNd_X9cAAAAAAAA",
   444  							RegExtGDPR: &int8Zero,
   445  						},
   446  						warning: nil,
   447  					},
   448  				},
   449  				{
   450  					desc: "Valid GDPR consent string, gdpr_applies is set to true, return a valid GDPR writer and no warning",
   451  					in: testInput{
   452  						ampParams: Params{
   453  							Consent:     "CPdiPIJPdiPIJACABBENAzCv_____3___wAAAQNd_X9cAAAAAAAA",
   454  							ConsentType: ConsentTCF2,
   455  							GdprApplies: &boolTrue,
   456  						},
   457  					},
   458  					expected: expectedResults{
   459  						policyWriter: gdpr.ConsentWriter{
   460  							Consent:    "CPdiPIJPdiPIJACABBENAzCv_____3___wAAAQNd_X9cAAAAAAAA",
   461  							RegExtGDPR: &int8One,
   462  						},
   463  						warning: nil,
   464  					},
   465  				},
   466  				{
   467  					desc: "Valid GDPR consent string, return a valid GDPR writer and no warning",
   468  					in: testInput{
   469  						ampParams: Params{
   470  							Consent:     "CPdiPIJPdiPIJACABBENAzCv_____3___wAAAQNd_X9cAAAAAAAA",
   471  							ConsentType: ConsentTCF2,
   472  						},
   473  					},
   474  					expected: expectedResults{
   475  						policyWriter: gdpr.ConsentWriter{
   476  							Consent:    "CPdiPIJPdiPIJACABBENAzCv_____3___wAAAQNd_X9cAAAAAAAA",
   477  							RegExtGDPR: &int8One,
   478  						},
   479  						warning: nil,
   480  					},
   481  				},
   482  			},
   483  		},
   484  		{
   485  			groupDesc: "consent type CCPA. Return a valid CCPA consent writer in all scenarios.",
   486  			tests: []testCase{
   487  				{
   488  					desc: "CCPA consent string is invalid: return a valid writer a warning about the string being invalid",
   489  					in: testInput{
   490  						ampParams: Params{
   491  							Consent:     "XXXX",
   492  							ConsentType: ConsentUSPrivacy,
   493  						},
   494  					},
   495  					expected: expectedResults{
   496  						policyWriter: ccpa.ConsentWriter{Consent: "XXXX"},
   497  						warning: &errortypes.Warning{
   498  							Message:     "Consent string 'XXXX' is not a valid CCPA consent string.",
   499  							WarningCode: errortypes.InvalidPrivacyConsentWarningCode,
   500  						},
   501  					},
   502  				},
   503  				{
   504  					desc: "Valid CCPA consent string, gdpr_applies is set to true: return a valid GDPR writer and warn about the gdpr_applies value.",
   505  					in: testInput{
   506  						ampParams: Params{
   507  							Consent:     "1YYY",
   508  							ConsentType: ConsentUSPrivacy,
   509  							GdprApplies: &boolTrue,
   510  						},
   511  					},
   512  					expected: expectedResults{
   513  						policyWriter: ccpa.ConsentWriter{Consent: "1YYY"},
   514  						warning: &errortypes.Warning{
   515  							Message:     "AMP request gdpr_applies value was ignored because provided consent string is a CCPA consent string",
   516  							WarningCode: errortypes.InvalidPrivacyConsentWarningCode,
   517  						},
   518  					},
   519  				},
   520  				{
   521  					desc: "Valid CCPA consent string, return a valid GDPR writer and no warning",
   522  					in: testInput{
   523  						ampParams: Params{
   524  							Consent:     "1YYY",
   525  							ConsentType: ConsentUSPrivacy,
   526  						},
   527  					},
   528  					expected: expectedResults{
   529  						policyWriter: ccpa.ConsentWriter{Consent: "1YYY"},
   530  						warning:      nil,
   531  					},
   532  				},
   533  			},
   534  		},
   535  	}
   536  	for _, group := range testGroups {
   537  		for _, tc := range group.tests {
   538  			actualPolicyWriter, actualErr := ReadPolicy(tc.in.ampParams, true)
   539  
   540  			assert.Equal(t, tc.expected.policyWriter, actualPolicyWriter, tc.desc)
   541  			assert.Equal(t, tc.expected.warning, actualErr, tc.desc)
   542  		}
   543  	}
   544  }
   545  
   546  func TestBuildGdprTCF2ConsentWriter(t *testing.T) {
   547  	int8Zero := int8(0)
   548  	int8One := int8(1)
   549  	boolTrue := true
   550  	boolFalse := false
   551  	consentString := "CONSENT"
   552  
   553  	testCases := []struct {
   554  		desc           string
   555  		inParams       Params
   556  		expectedWriter gdpr.ConsentWriter
   557  	}{
   558  		{
   559  			desc:     "gdpr_applies not set",
   560  			inParams: Params{Consent: consentString},
   561  			expectedWriter: gdpr.ConsentWriter{
   562  				Consent:    consentString,
   563  				RegExtGDPR: &int8One,
   564  			},
   565  		},
   566  		{
   567  			desc: "gdpr_applies set to false",
   568  			inParams: Params{
   569  				Consent:     consentString,
   570  				GdprApplies: &boolFalse,
   571  			},
   572  			expectedWriter: gdpr.ConsentWriter{
   573  				Consent:    consentString,
   574  				RegExtGDPR: &int8Zero,
   575  			},
   576  		},
   577  		{
   578  			desc: "gdpr_applies set to true",
   579  			inParams: Params{
   580  				Consent:     consentString,
   581  				GdprApplies: &boolTrue,
   582  			},
   583  			expectedWriter: gdpr.ConsentWriter{
   584  				Consent:    consentString,
   585  				RegExtGDPR: &int8One,
   586  			},
   587  		},
   588  	}
   589  	for _, tc := range testCases {
   590  		actualPolicyWriter := buildGdprTCF2ConsentWriter(tc.inParams)
   591  		assert.Equal(t, tc.expectedWriter, actualPolicyWriter, tc.desc)
   592  	}
   593  }
   594  
   595  func TestParseMultisize(t *testing.T) {
   596  	testCases := []struct {
   597  		description     string
   598  		multisize       string
   599  		expectedFormats []openrtb2.Format
   600  	}{
   601  		{
   602  			description:     "Empty",
   603  			multisize:       "",
   604  			expectedFormats: nil,
   605  		},
   606  		{
   607  			description:     "One",
   608  			multisize:       "1x2",
   609  			expectedFormats: []openrtb2.Format{{W: 1, H: 2}},
   610  		},
   611  		{
   612  			description:     "Many",
   613  			multisize:       "1x2,3x4",
   614  			expectedFormats: []openrtb2.Format{{W: 1, H: 2}, {W: 3, H: 4}},
   615  		},
   616  		{
   617  			// Existing Behavior: The " 3" token in the second size is parsed as 0.
   618  			description:     "Many With Space - Quirky Result",
   619  			multisize:       "1x2, 3x4",
   620  			expectedFormats: []openrtb2.Format{{W: 1, H: 2}, {W: 0, H: 4}},
   621  		},
   622  		{
   623  			description:     "One - Zero Size - Ignored",
   624  			multisize:       "0x0",
   625  			expectedFormats: nil,
   626  		},
   627  		{
   628  			description:     "Many - Zero Size - All Ignored",
   629  			multisize:       "0x0,3x4",
   630  			expectedFormats: nil,
   631  		},
   632  		{
   633  			description:     "One - Extra Dimension - Ignored",
   634  			multisize:       "1x2x3",
   635  			expectedFormats: nil,
   636  		},
   637  		{
   638  			description:     "Many - Extra Dimension - All Ignored",
   639  			multisize:       "1x2x3,4x5",
   640  			expectedFormats: nil,
   641  		},
   642  		{
   643  			description:     "One - Invalid Values - Ignored",
   644  			multisize:       "INVALIDxINVALID",
   645  			expectedFormats: nil,
   646  		},
   647  		{
   648  			description:     "Many - Invalid Values - All Ignored",
   649  			multisize:       "1x2,INVALIDxINVALID",
   650  			expectedFormats: nil,
   651  		},
   652  		{
   653  			description:     "One - No Pair - Ignored",
   654  			multisize:       "INVALID",
   655  			expectedFormats: nil,
   656  		},
   657  		{
   658  			description:     "Many - No Pair - All Ignored",
   659  			multisize:       "1x2,INVALID",
   660  			expectedFormats: nil,
   661  		},
   662  	}
   663  
   664  	for _, test := range testCases {
   665  		result := parseMultisize(test.multisize)
   666  		assert.ElementsMatch(t, test.expectedFormats, result, test.description)
   667  	}
   668  }
   669  
   670  func TestParseGdprApplies(t *testing.T) {
   671  	gdprAppliesFalse := false
   672  	gdprAppliesTrue := true
   673  
   674  	testCases := []struct {
   675  		desc              string
   676  		inGdprApplies     *bool
   677  		expectRegsExtGdpr int8
   678  	}{
   679  		{
   680  			desc:              "gdprApplies was not set and defaulted to nil, expect 0",
   681  			inGdprApplies:     nil,
   682  			expectRegsExtGdpr: int8(0),
   683  		},
   684  		{
   685  			desc:              "gdprApplies isn't nil and is set to false, expect a value of 0",
   686  			inGdprApplies:     &gdprAppliesFalse,
   687  			expectRegsExtGdpr: int8(0),
   688  		},
   689  		{
   690  			desc:              "gdprApplies isn't nil and is set to true, expect a value of 1",
   691  			inGdprApplies:     &gdprAppliesTrue,
   692  			expectRegsExtGdpr: int8(1),
   693  		},
   694  	}
   695  	for _, tc := range testCases {
   696  		assert.Equal(t, tc.expectRegsExtGdpr, parseGdprApplies(tc.inGdprApplies), tc.desc)
   697  	}
   698  }