github.com/prebid/prebid-server/v2@v2.18.0/privacy/ccpa/parsedpolicy_test.go (about) 1 package ccpa 2 3 import ( 4 "testing" 5 6 "github.com/stretchr/testify/assert" 7 ) 8 9 func TestValidateConsent(t *testing.T) { 10 testCases := []struct { 11 description string 12 consent string 13 expected bool 14 }{ 15 { 16 description: "Empty String", 17 consent: "", 18 expected: true, 19 }, 20 { 21 description: "Valid Consent With Opt Out", 22 consent: "1NYN", 23 expected: true, 24 }, 25 { 26 description: "Valid Consent Without Opt Out", 27 consent: "1NNN", 28 expected: true, 29 }, 30 { 31 description: "Invalid", 32 consent: "malformed", 33 expected: false, 34 }, 35 } 36 37 for _, test := range testCases { 38 result := ValidateConsent(test.consent) 39 assert.Equal(t, test.expected, result, test.description) 40 } 41 } 42 43 func TestParse(t *testing.T) { 44 validBidders := map[string]struct{}{"a": {}} 45 46 testCases := []struct { 47 description string 48 consent string 49 noSaleBidders []string 50 expectedPolicy ParsedPolicy 51 expectedError string 52 }{ 53 { 54 description: "Consent Error", 55 consent: "malformed", 56 noSaleBidders: []string{}, 57 expectedPolicy: ParsedPolicy{}, 58 expectedError: "request.regs.ext.us_privacy must contain 4 characters", 59 }, 60 { 61 description: "No Sale Error", 62 consent: "1NYN", 63 noSaleBidders: []string{"b"}, 64 expectedPolicy: ParsedPolicy{}, 65 expectedError: "request.ext.prebid.nosale is invalid: unrecognized bidder 'b'", 66 }, 67 { 68 description: "Success", 69 consent: "1NYN", 70 noSaleBidders: []string{"a"}, 71 expectedPolicy: ParsedPolicy{ 72 consentSpecified: true, 73 consentOptOutSale: true, 74 noSaleForAllBidders: false, 75 noSaleSpecificBidders: map[string]struct{}{"a": {}}, 76 }, 77 }, 78 } 79 80 for _, test := range testCases { 81 policy := Policy{test.consent, test.noSaleBidders} 82 83 result, err := policy.Parse(validBidders) 84 85 if test.expectedError == "" { 86 assert.NoError(t, err, test.description) 87 } else { 88 assert.EqualError(t, err, test.expectedError, test.description) 89 } 90 91 assert.Equal(t, test.expectedPolicy, result, test.description) 92 } 93 } 94 95 func TestParseConsent(t *testing.T) { 96 testCases := []struct { 97 description string 98 consent string 99 expectedResult bool 100 expectedError string 101 }{ 102 { 103 description: "Valid", 104 consent: "1NYN", 105 expectedResult: true, 106 }, 107 { 108 description: "Valid - Not Sale", 109 consent: "1NNN", 110 expectedResult: false, 111 }, 112 { 113 description: "Valid - Not Applicable", 114 consent: "1---", 115 expectedResult: false, 116 }, 117 { 118 description: "Valid - Empty", 119 consent: "", 120 expectedResult: false, 121 }, 122 { 123 description: "Wrong Length", 124 consent: "1NY", 125 expectedResult: false, 126 expectedError: "must contain 4 characters", 127 }, 128 { 129 description: "Wrong Version", 130 consent: "2---", 131 expectedResult: false, 132 expectedError: "must specify version 1", 133 }, 134 { 135 description: "Explicit Notice Char", 136 consent: "1X--", 137 expectedResult: false, 138 expectedError: "must specify 'N', 'Y', or '-' for the explicit notice", 139 }, 140 { 141 description: "Invalid Explicit Notice Case", 142 consent: "1y--", 143 expectedResult: false, 144 expectedError: "must specify 'N', 'Y', or '-' for the explicit notice", 145 }, 146 { 147 description: "Invalid Opt-Out Sale Char", 148 consent: "1-X-", 149 expectedResult: false, 150 expectedError: "must specify 'N', 'Y', or '-' for the opt-out sale", 151 }, 152 { 153 description: "Invalid Opt-Out Sale Case", 154 consent: "1-y-", 155 expectedResult: false, 156 expectedError: "must specify 'N', 'Y', or '-' for the opt-out sale", 157 }, 158 { 159 description: "Invalid LSPA Char", 160 consent: "1--X", 161 expectedResult: false, 162 expectedError: "must specify 'N', 'Y', or '-' for the limited service provider agreement", 163 }, 164 { 165 description: "Invalid LSPA Case", 166 consent: "1--y", 167 expectedResult: false, 168 expectedError: "must specify 'N', 'Y', or '-' for the limited service provider agreement", 169 }, 170 } 171 172 for _, test := range testCases { 173 result, err := parseConsent(test.consent) 174 175 if test.expectedError == "" { 176 assert.NoError(t, err, test.description) 177 } else { 178 assert.EqualError(t, err, test.expectedError, test.description) 179 } 180 181 assert.Equal(t, test.expectedResult, result, test.description) 182 } 183 } 184 185 func TestParseNoSaleBidders(t *testing.T) { 186 testCases := []struct { 187 description string 188 noSaleBidders []string 189 validBidders []string 190 expectedNoSaleForAllBidders bool 191 expectedNoSaleSpecificBidders map[string]struct{} 192 expectedError string 193 }{ 194 { 195 description: "Valid - No Bidders", 196 noSaleBidders: []string{}, 197 validBidders: []string{"a"}, 198 expectedNoSaleForAllBidders: false, 199 expectedNoSaleSpecificBidders: map[string]struct{}{}, 200 }, 201 { 202 description: "Valid - 1 Bidder", 203 noSaleBidders: []string{"a"}, 204 validBidders: []string{"a"}, 205 expectedNoSaleForAllBidders: false, 206 expectedNoSaleSpecificBidders: map[string]struct{}{"a": {}}, 207 }, 208 { 209 description: "Valid - 1+ Bidders", 210 noSaleBidders: []string{"a", "b"}, 211 validBidders: []string{"a", "b"}, 212 expectedNoSaleForAllBidders: false, 213 expectedNoSaleSpecificBidders: map[string]struct{}{"a": {}, "b": {}}, 214 }, 215 { 216 description: "Valid - All Bidders", 217 noSaleBidders: []string{"*"}, 218 validBidders: []string{"a"}, 219 expectedNoSaleForAllBidders: true, 220 expectedNoSaleSpecificBidders: map[string]struct{}{}, 221 }, 222 { 223 description: "Bidder Not Valid", 224 noSaleBidders: []string{"b"}, 225 validBidders: []string{"a"}, 226 expectedError: "unrecognized bidder 'b'", 227 expectedNoSaleForAllBidders: false, 228 expectedNoSaleSpecificBidders: map[string]struct{}{}, 229 }, 230 { 231 description: "All Bidder Mixed With Other Bidders Is Invalid", 232 noSaleBidders: []string{"*", "a"}, 233 validBidders: []string{"a"}, 234 expectedError: "can only specify all bidders if no other bidders are provided", 235 expectedNoSaleForAllBidders: false, 236 expectedNoSaleSpecificBidders: map[string]struct{}{}, 237 }, 238 { 239 description: "Valid Bidders Case Sensitive", 240 noSaleBidders: []string{"a"}, 241 validBidders: []string{"A"}, 242 expectedError: "unrecognized bidder 'a'", 243 expectedNoSaleForAllBidders: false, 244 expectedNoSaleSpecificBidders: map[string]struct{}{}, 245 }, 246 } 247 248 for _, test := range testCases { 249 validBiddersMap := make(map[string]struct{}) 250 for _, v := range test.validBidders { 251 validBiddersMap[v] = struct{}{} 252 } 253 254 resultNoSaleForAllBidders, resultNoSaleSpecificBidders, err := parseNoSaleBidders(test.noSaleBidders, validBiddersMap) 255 256 if test.expectedError == "" { 257 assert.NoError(t, err, test.description+":err") 258 } else { 259 assert.EqualError(t, err, test.expectedError, test.description+":err") 260 } 261 262 assert.Equal(t, test.expectedNoSaleForAllBidders, resultNoSaleForAllBidders, test.description+":allBidders") 263 assert.Equal(t, test.expectedNoSaleSpecificBidders, resultNoSaleSpecificBidders, test.description+":specificBidders") 264 } 265 } 266 267 func TestCanEnforce(t *testing.T) { 268 testCases := []struct { 269 description string 270 policy ParsedPolicy 271 expected bool 272 }{ 273 { 274 description: "Specified", 275 policy: ParsedPolicy{ 276 consentSpecified: true, 277 consentOptOutSale: false, 278 noSaleForAllBidders: false, 279 noSaleSpecificBidders: map[string]struct{}{}, 280 }, 281 expected: true, 282 }, 283 { 284 description: "Not Specified", 285 policy: ParsedPolicy{ 286 consentSpecified: false, 287 consentOptOutSale: false, 288 noSaleForAllBidders: false, 289 noSaleSpecificBidders: map[string]struct{}{}, 290 }, 291 expected: false, 292 }, 293 } 294 295 for _, test := range testCases { 296 result := test.policy.CanEnforce() 297 assert.Equal(t, test.expected, result, test.description) 298 } 299 } 300 301 func TestShouldEnforce(t *testing.T) { 302 testCases := []struct { 303 description string 304 policy ParsedPolicy 305 bidder string 306 expected bool 307 }{ 308 { 309 description: "Not Enforced - All Bidders No Sale", 310 policy: ParsedPolicy{ 311 consentSpecified: true, 312 consentOptOutSale: true, 313 noSaleForAllBidders: true, 314 noSaleSpecificBidders: map[string]struct{}{}, 315 }, 316 bidder: "a", 317 expected: false, 318 }, 319 { 320 description: "Not Enforced - Specific Bidders No Sale", 321 policy: ParsedPolicy{ 322 consentSpecified: true, 323 consentOptOutSale: true, 324 noSaleForAllBidders: false, 325 noSaleSpecificBidders: map[string]struct{}{"a": {}}, 326 }, 327 bidder: "a", 328 expected: false, 329 }, 330 { 331 description: "Not Enforced - No Bidder No Sale", 332 policy: ParsedPolicy{ 333 consentSpecified: true, 334 consentOptOutSale: false, 335 noSaleForAllBidders: false, 336 noSaleSpecificBidders: map[string]struct{}{}, 337 }, 338 bidder: "a", 339 expected: false, 340 }, 341 { 342 description: "Not Enforced - No Sale Case Sensitive", 343 policy: ParsedPolicy{ 344 consentSpecified: true, 345 consentOptOutSale: false, 346 noSaleForAllBidders: false, 347 noSaleSpecificBidders: map[string]struct{}{"A": {}}, 348 }, 349 bidder: "a", 350 expected: false, 351 }, 352 { 353 description: "Enforced - No Bidder No Sale", 354 policy: ParsedPolicy{ 355 consentSpecified: true, 356 consentOptOutSale: true, 357 noSaleForAllBidders: false, 358 noSaleSpecificBidders: map[string]struct{}{}, 359 }, 360 bidder: "a", 361 expected: true, 362 }, 363 { 364 description: "Enforced - No Sale Case Sensitive", 365 policy: ParsedPolicy{ 366 consentSpecified: true, 367 consentOptOutSale: true, 368 noSaleForAllBidders: false, 369 noSaleSpecificBidders: map[string]struct{}{"A": {}}, 370 }, 371 bidder: "a", 372 expected: true, 373 }, 374 } 375 376 for _, test := range testCases { 377 result := test.policy.ShouldEnforce(test.bidder) 378 assert.Equal(t, test.expected, result, test.description) 379 } 380 }