diff --git a/README.md b/README.md index 5c6f166d..b82e09e6 100644 --- a/README.md +++ b/README.md @@ -161,12 +161,15 @@ CmpList cmpList = loader.cmpList(cmpListContent); |tcfcav1|5|PurposesImpliedConsent|Boolean list of size 24| |tcfcav1|5|VendorExpressConsent|Integer list of variable size| |tcfcav1|5|VendorImpliedConsent|Integer list of variable size| +|tcfcav1|5|PubRestrictions|RangeEntry list of variable size| |tcfcav1|5|PubPurposesSegmentType|3 bit int. Value is 3| |tcfcav1|5|PubPurposesExpressConsent|Boolean list of size 24| |tcfcav1|5|PubPurposesImpliedConsent|Boolean list of size 24| |tcfcav1|5|NumCustomPurposes|6 bit int| |tcfcav1|5|CustomPurposesExpressConsent|Boolean list where size is set by the NumCustomPurposes field| |tcfcav1|5|CustomPurposesImpliedConsent|Boolean list where size is set by the NumCustomPurposes field| +|tcfcav1|5|DisclosedVendorsSegmentType|3 bit int. Value is 1| +|tcfcav1|5|DisclosedVendors|Integer list of variable size| |uspv1|6|Version|6 bit int. Value is 1| |uspv1|6|Notice|2 bit int| |uspv1|6|OptOutSale|2 bit int| diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/GppModel.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/GppModel.java index 9877500a..b447d3a7 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/GppModel.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/GppModel.java @@ -1,6 +1,7 @@ package com.iab.gpp.encoder; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -8,6 +9,7 @@ import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.error.EncodingException; import com.iab.gpp.encoder.error.InvalidFieldException; +import com.iab.gpp.encoder.field.HeaderV1Field; import com.iab.gpp.encoder.section.EncodableSection; import com.iab.gpp.encoder.section.HeaderV1; import com.iab.gpp.encoder.section.Sections; @@ -18,27 +20,36 @@ import com.iab.gpp.encoder.section.UsCtV1; import com.iab.gpp.encoder.section.UsNatV1; import com.iab.gpp.encoder.section.UsUtV1; -import com.iab.gpp.encoder.section.UspV1; import com.iab.gpp.encoder.section.UsVaV1; +import com.iab.gpp.encoder.section.UspV1; public class GppModel { private Map sections = new HashMap<>(); + private String encodedString; + + private boolean dirty = false; + private boolean decoded = true; + public GppModel() { } - public GppModel(String encodedString) throws DecodingException { - if (encodedString != null && encodedString.length() > 0) { - this.decode(encodedString); - } + public GppModel(String encodedString) { + decode(encodedString); } - public void setFieldValue(int sectionId, String fieldName, Object value) throws InvalidFieldException { + public void setFieldValue(int sectionId, String fieldName, Object value) { setFieldValue(Sections.SECTION_ID_NAME_MAP.get(sectionId), fieldName, value); } - public void setFieldValue(String sectionName, String fieldName, Object value) throws InvalidFieldException { + public void setFieldValue(String sectionName, String fieldName, Object value) { + if (!this.decoded) { + this.sections = this.decodeModel(this.encodedString); + this.dirty = false; + this.decoded = true; + } + EncodableSection section = null; if (!this.sections.containsKey(sectionName)) { if (sectionName.equals(TcfCaV1.NAME)) { @@ -75,6 +86,7 @@ public void setFieldValue(String sectionName, String fieldName, Object value) th if (section != null) { section.setFieldValue(fieldName, value); + this.dirty = true; } else { throw new InvalidFieldException(sectionName + "." + fieldName + " not found"); } @@ -85,6 +97,12 @@ public Object getFieldValue(int sectionId, String fieldName) { } public Object getFieldValue(String sectionName, String fieldName) { + if (!this.decoded) { + this.sections = this.decodeModel(this.encodedString); + this.dirty = false; + this.decoded = true; + } + if (this.sections.containsKey(sectionName)) { return this.sections.get(sectionName).getFieldValue(fieldName); } else { @@ -97,6 +115,12 @@ public boolean hasField(int sectionId, String fieldName) { } public boolean hasField(String sectionName, String fieldName) { + if (!this.decoded) { + this.sections = this.decodeModel(this.encodedString); + this.dirty = false; + this.decoded = true; + } + if (this.sections.containsKey(sectionName)) { return this.sections.get(sectionName).hasField(fieldName); } else { @@ -109,10 +133,22 @@ public boolean hasSection(int sectionId) { } public boolean hasSection(String sectionName) { + if (!this.decoded) { + this.sections = this.decodeModel(this.encodedString); + this.dirty = false; + this.decoded = true; + } + return this.sections.containsKey(sectionName); } public HeaderV1 getHeader() { + if (!this.decoded) { + this.sections = this.decodeModel(this.encodedString); + this.dirty = false; + this.decoded = true; + } + HeaderV1 header = new HeaderV1(); try { header.setFieldValue("SectionIds", this.getSectionIds()); @@ -127,6 +163,12 @@ public EncodableSection getSection(int sectionId) { } public EncodableSection getSection(String sectionName) { + if (!this.decoded) { + this.sections = this.decodeModel(this.encodedString); + this.dirty = false; + this.decoded = true; + } + if (this.sections.containsKey(sectionName)) { return this.sections.get(sectionName); } else { @@ -139,13 +181,23 @@ public void deleteSection(int sectionId) { } public void deleteSection(String sectionName) { + if (!this.decoded) { + this.sections = this.decodeModel(this.encodedString); + this.dirty = false; + this.decoded = true; + } + if (this.sections.containsKey(sectionName)) { this.sections.remove(sectionName); + this.dirty = true; } } public void clear() { this.sections.clear(); + this.encodedString = null; + this.dirty = false; + this.decoded = true; } public TcfCaV1 getTcfCaV1Section() { @@ -185,6 +237,12 @@ public UsCtV1 getUsCtV1Section() { } public List getSectionIds() { + if (!this.decoded) { + this.sections = this.decodeModel(this.encodedString); + this.dirty = false; + this.decoded = true; + } + List sectionIds = new ArrayList<>(); for (int i = 0; i < Sections.SECTION_ORDER.size(); i++) { String sectionName = Sections.SECTION_ORDER.get(i); @@ -196,13 +254,13 @@ public List getSectionIds() { return sectionIds; } - public String encode() throws EncodingException { + protected String encodeModel(Map sections) { List encodedSections = new ArrayList<>(); List sectionIds = new ArrayList<>(); for (int i = 0; i < Sections.SECTION_ORDER.size(); i++) { String sectionName = Sections.SECTION_ORDER.get(i); - if (this.sections.containsKey(sectionName)) { - EncodableSection section = this.sections.get(sectionName); + if (sections.containsKey(sectionName)) { + EncodableSection section = sections.get(sectionName); encodedSections.add(section.encode()); sectionIds.add(section.getId()); } @@ -210,7 +268,7 @@ public String encode() throws EncodingException { HeaderV1 header = new HeaderV1(); try { - header.setFieldValue("SectionIds", this.getSectionIds()); + header.setFieldValue("SectionIds", getSectionIds()); } catch (InvalidFieldException e) { throw new EncodingException(e); } @@ -220,52 +278,87 @@ public String encode() throws EncodingException { return encodedString; } - public void decode(String str) throws DecodingException { - this.sections.clear(); + protected Map decodeModel(String str) { + if(str == null || str.isEmpty() || str.startsWith("DB")) { + Map sections = new HashMap<>(); + + if(str != null && !str.isEmpty()) { + String[] encodedSections = str.split("~"); + HeaderV1 header = new HeaderV1(encodedSections[0]); + sections.put(HeaderV1.NAME, header); + + @SuppressWarnings("unchecked") + List sectionIds = (List) header.getFieldValue("SectionIds"); + + if(sectionIds.size() != encodedSections.length-1) { + throw new DecodingException("Unable to decode '" + str + "'. The number of sections does not match the number of sections defined in the header."); + } + + for (int i = 0; i < sectionIds.size(); i++) { + String encodedSection = encodedSections[i + 1]; + if(encodedSection.trim().isEmpty()) { + throw new DecodingException("Unable to decode '" + str + "'. Section " + (i+1) + " is blank."); + } + if (sectionIds.get(i).equals(TcfEuV2.ID)) { + TcfEuV2 section = new TcfEuV2(encodedSection); + sections.put(TcfEuV2.NAME, section); + } else if (sectionIds.get(i).equals(TcfCaV1.ID)) { + TcfCaV1 section = new TcfCaV1(encodedSection); + sections.put(TcfCaV1.NAME, section); + } else if (sectionIds.get(i).equals(UspV1.ID)) { + UspV1 section = new UspV1(encodedSection); + sections.put(UspV1.NAME, section); + } else if (sectionIds.get(i).equals(UsCaV1.ID)) { + UsCaV1 section = new UsCaV1(encodedSection); + sections.put(UsCaV1.NAME, section); + } else if (sectionIds.get(i).equals(UsNatV1.ID)) { + UsNatV1 section = new UsNatV1(encodedSection); + sections.put(UsNatV1.NAME, section); + } else if (sectionIds.get(i).equals(UsVaV1.ID)) { + UsVaV1 section = new UsVaV1(encodedSection); + sections.put(UsVaV1.NAME, section); + } else if (sectionIds.get(i).equals(UsCoV1.ID)) { + UsCoV1 section = new UsCoV1(encodedSection); + sections.put(UsCoV1.NAME, section); + } else if (sectionIds.get(i).equals(UsUtV1.ID)) { + UsUtV1 section = new UsUtV1(encodedSection); + sections.put(UsUtV1.NAME, section); + } else if (sectionIds.get(i).equals(UsCtV1.ID)) { + UsCtV1 section = new UsCtV1(encodedSection); + sections.put(UsCtV1.NAME, section); + } + } + } + + return sections; + } else if(str.startsWith("C")) { + // old tcfeu only string + Map sections = new HashMap<>(); - String[] encodedSections = str.split("~"); - HeaderV1 header = new HeaderV1(encodedSections[0]); - this.sections.put(HeaderV1.NAME, header); + TcfEuV2 section = new TcfEuV2(str); + sections.put(TcfEuV2.NAME, section); - @SuppressWarnings("unchecked") - List sectionIds = (List) header.getFieldValue("SectionIds"); - for (int i = 0; i < sectionIds.size(); i++) { - if (sectionIds.get(i).equals(TcfEuV2.ID)) { - TcfEuV2 section = new TcfEuV2(encodedSections[i + 1]); - this.sections.put(TcfEuV2.NAME, section); - } else if (sectionIds.get(i).equals(TcfCaV1.ID)) { - TcfCaV1 section = new TcfCaV1(encodedSections[i + 1]); - this.sections.put(TcfCaV1.NAME, section); - } else if (sectionIds.get(i).equals(UspV1.ID)) { - UspV1 section = new UspV1(encodedSections[i + 1]); - this.sections.put(UspV1.NAME, section); - } else if (sectionIds.get(i).equals(UsCaV1.ID)) { - UsCaV1 section = new UsCaV1(encodedSections[i + 1]); - this.sections.put(UsCaV1.NAME, section); - } else if (sectionIds.get(i).equals(UsNatV1.ID)) { - UsNatV1 section = new UsNatV1(encodedSections[i + 1]); - this.sections.put(UsNatV1.NAME, section); - } else if (sectionIds.get(i).equals(UsVaV1.ID)) { - UsVaV1 section = new UsVaV1(encodedSections[i + 1]); - this.sections.put(UsVaV1.NAME, section); - } else if (sectionIds.get(i).equals(UsCoV1.ID)) { - UsCoV1 section = new UsCoV1(encodedSections[i + 1]); - this.sections.put(UsCoV1.NAME, section); - } else if (sectionIds.get(i).equals(UsUtV1.ID)) { - UsUtV1 section = new UsUtV1(encodedSections[i + 1]); - this.sections.put(UsUtV1.NAME, section); - } else if (sectionIds.get(i).equals(UsCtV1.ID)) { - UsCtV1 section = new UsCtV1(encodedSections[i + 1]); - this.sections.put(UsCtV1.NAME, section); - } + HeaderV1 header = new HeaderV1(); + header.setFieldValue(HeaderV1Field.SECTION_IDS, Arrays.asList(2)); + sections.put(HeaderV1.NAME, section); + + return sections; + } else { + throw new DecodingException("Unable to decode '" + str + "'"); } } - public String encodeSection(int sectionId) throws EncodingException { + public String encodeSection(int sectionId) { return encodeSection(Sections.SECTION_ID_NAME_MAP.get(sectionId)); } - public String encodeSection(String sectionName) throws EncodingException { + public String encodeSection(String sectionName) { + if (!this.decoded) { + this.sections = this.decodeModel(this.encodedString); + this.dirty = false; + this.decoded = true; + } + if (this.sections.containsKey(sectionName)) { return this.sections.get(sectionName).encode(); } else { @@ -273,11 +366,11 @@ public String encodeSection(String sectionName) throws EncodingException { } } - public void decodeSection(int sectionId, String encodedString) throws DecodingException { + public void decodeSection(int sectionId, String encodedString) { decodeSection(Sections.SECTION_ID_NAME_MAP.get(sectionId), encodedString); } - public void decodeSection(String sectionName, String encodedString) throws DecodingException { + public void decodeSection(String sectionName, String encodedString) { EncodableSection section = null; if (!this.sections.containsKey(sectionName)) { if (sectionName.equals(TcfEuV2.NAME)) { @@ -316,4 +409,22 @@ public void decodeSection(String sectionName, String encodedString) throws Decod section.decode(encodedString); } } -} + + public String encode() { + if (this.encodedString == null || this.encodedString.isEmpty() || this.dirty) { + this.encodedString = encodeModel(this.sections); + this.dirty = false; + this.decoded = true; + } + + return this.encodedString; + } + + public void decode(String encodedString) { + this.encodedString = encodedString; + this.dirty = false; + this.decoded = false; + } + + +} \ No newline at end of file diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/AbstractBase64UrlEncoder.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/base64/AbstractBase64UrlEncoder.java similarity index 94% rename from iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/AbstractBase64UrlEncoder.java rename to iabgpp-encoder/src/main/java/com/iab/gpp/encoder/base64/AbstractBase64UrlEncoder.java index 698a0994..a5434073 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/AbstractBase64UrlEncoder.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/base64/AbstractBase64UrlEncoder.java @@ -1,9 +1,10 @@ -package com.iab.gpp.encoder.datatype.encoder; +package com.iab.gpp.encoder.base64; import java.util.Map; import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; +import com.iab.gpp.encoder.datatype.encoder.FixedIntegerEncoder; import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.error.EncodingException; @@ -31,7 +32,7 @@ public abstract class AbstractBase64UrlEncoder { private static Pattern BASE64URL_VERIFICATION_PATTERN = Pattern.compile("^[A-Za-z0-9\\-_]*$", Pattern.CASE_INSENSITIVE); - public String encode(String bitString) throws EncodingException { + public String encode(String bitString) { // should only be 0 or 1 if (!BITSTRING_VERIFICATION_PATTERN.matcher(bitString).matches()) { throw new EncodingException("Unencodable Base64Url '" + bitString + "'"); @@ -58,7 +59,7 @@ public String encode(String bitString) throws EncodingException { return str; } - public String decode(String str) throws DecodingException { + public String decode(String str) { // should contain only characters from the base64url set if (!BASE64URL_VERIFICATION_PATTERN.matcher(str).matches()) { throw new DecodingException("Undecodable Base64URL string"); diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/base64/CompressedBase64UrlEncoder.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/base64/CompressedBase64UrlEncoder.java new file mode 100644 index 00000000..4ebd7be7 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/base64/CompressedBase64UrlEncoder.java @@ -0,0 +1,38 @@ +package com.iab.gpp.encoder.base64; + +import java.util.Arrays; + +public class CompressedBase64UrlEncoder extends AbstractBase64UrlEncoder { + + private static CompressedBase64UrlEncoder instance = new CompressedBase64UrlEncoder(); + + private CompressedBase64UrlEncoder() { + + } + + public static CompressedBase64UrlEncoder getInstance() { + return instance; + } + + @Override + protected String pad(String bitString) { + char[] chars1 = null; + if(bitString.length() % 8 > 0) { + chars1 = new char[8 - (bitString.length() % 8)]; + } else { + chars1 = new char[0]; + } + Arrays.fill(chars1, '0'); + + char[] chars2 = null; + if((bitString.length() + chars1.length) % 6 > 0) { + chars2 = new char[6 - ((bitString.length() + chars1.length) % 6)]; + } else { + chars2 = new char[0]; + } + Arrays.fill(chars2, '0'); + + return bitString + new String(chars1) + new String(chars2); + } + +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/base64/TraditionalBase64UrlEncoder.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/base64/TraditionalBase64UrlEncoder.java new file mode 100644 index 00000000..78ffe719 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/base64/TraditionalBase64UrlEncoder.java @@ -0,0 +1,28 @@ +package com.iab.gpp.encoder.base64; + +import java.util.Arrays; + +public class TraditionalBase64UrlEncoder extends AbstractBase64UrlEncoder { + + private static TraditionalBase64UrlEncoder instance = new TraditionalBase64UrlEncoder(); + + private TraditionalBase64UrlEncoder() { + + } + + public static TraditionalBase64UrlEncoder getInstance() { + return instance; + } + + @Override + protected String pad(String bitString) { + if(bitString.length() % 24 > 0) { + char[] chars = new char[24 - (bitString.length() % 24)]; + Arrays.fill(chars, '0'); + return bitString + new String(chars); + } else { + return bitString; + } + } + +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/bitstring/BitStringEncoder.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/bitstring/BitStringEncoder.java new file mode 100644 index 00000000..12bcb182 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/bitstring/BitStringEncoder.java @@ -0,0 +1,61 @@ +package com.iab.gpp.encoder.bitstring; + +import java.util.List; +import com.iab.gpp.encoder.datatype.AbstractEncodableBitStringDataType; +import com.iab.gpp.encoder.datatype.SubstringException; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.EncodingException; +import com.iab.gpp.encoder.field.EncodableBitStringFields; + +public class BitStringEncoder { + + private static BitStringEncoder instance = new BitStringEncoder(); + + private BitStringEncoder() { + + } + + public static BitStringEncoder getInstance() { + return instance; + } + + public String encode(EncodableBitStringFields fields, List fieldNames) { + String bitString = ""; + for (int i = 0; i < fieldNames.size(); i++) { + String fieldName = fieldNames.get(i); + if (fields.containsKey(fieldName)) { + AbstractEncodableBitStringDataType field = fields.get(fieldName); + bitString += field.encode(); + } else { + throw new EncodingException("Field not found: '" + fieldName + "'"); + } + } + + return bitString; + } + + public void decode(String bitString, List fieldNames, EncodableBitStringFields fields) { + int index = 0; + for (int i = 0; i < fieldNames.size(); i++) { + String fieldName = fieldNames.get(i); + if (fields.containsKey(fieldName)) { + AbstractEncodableBitStringDataType field = fields.get(fieldName); + try { + String substring = field.substring(bitString, index); + field.decode(substring); + index += substring.length(); + } catch (SubstringException e) { + if(field.getHardFailIfMissing()) { + throw new DecodingException("Unable to decode " + fieldName, e); + } else { + return; + } + } catch (Exception e) { + throw new DecodingException("Unable to decode " + fieldName, e); + } + } else { + throw new DecodingException("Field not found: '" + fieldName + "'"); + } + } + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/AbstractEncodableBitStringDataType.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/AbstractEncodableBitStringDataType.java index 27359760..07d9588c 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/AbstractEncodableBitStringDataType.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/AbstractEncodableBitStringDataType.java @@ -1,15 +1,25 @@ package com.iab.gpp.encoder.datatype; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; - -public abstract class AbstractEncodableBitStringDataType { +import java.util.Collection; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import com.iab.gpp.encoder.error.ValidationException; + +public abstract class AbstractEncodableBitStringDataType implements EncodableDataType { + //this if for backwards compatibility with the newer fields + protected boolean hardFailIfMissing = true; + protected Predicate validator = null; protected T value; - protected AbstractEncodableBitStringDataType() { - + protected AbstractEncodableBitStringDataType(boolean hardFailIfMissing) { + this.hardFailIfMissing = hardFailIfMissing; } - + + public AbstractEncodableBitStringDataType withValidator(Predicate validator) { + this.validator = validator; + return this; + } + public boolean hasValue() { return this.value != null; } @@ -20,12 +30,28 @@ public T getValue() { @SuppressWarnings("unchecked") public void setValue(Object value) { - this.value = (T) value; + T v = (T) value; + if (validator == null || validator.test(v)) { + this.value = v; + } else { + if (v instanceof Collection) { + throw new ValidationException("Invalid value '" + + ((Collection) v).stream().map(i -> i.toString()).collect(Collectors.joining(",")) + "'"); + } else { + throw new ValidationException("Invalid value '" + v + "'"); + } + } + + } + + public boolean getHardFailIfMissing() { + return this.hardFailIfMissing; } - public abstract String encode() throws EncodingException; + public abstract String encode(); + + public abstract void decode(String bitString); - public abstract void decode(String bitString) throws DecodingException; + public abstract String substring(String bitString, int fromIndex) throws SubstringException; - public abstract String substring(String bitString, int fromIndex) throws DecodingException; } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/DataType.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/DataType.java new file mode 100644 index 00000000..8a0d2c07 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/DataType.java @@ -0,0 +1,7 @@ +package com.iab.gpp.encoder.datatype; + +public interface DataType { + boolean hasValue(); + T getValue(); + void setValue(Object value); +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableArrayOfFixedIntegerRanges.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableArrayOfFixedIntegerRanges.java new file mode 100644 index 00000000..699e0d26 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableArrayOfFixedIntegerRanges.java @@ -0,0 +1,110 @@ +package com.iab.gpp.encoder.datatype; + +import java.util.ArrayList; +import java.util.List; +import com.iab.gpp.encoder.datatype.encoder.FixedIntegerEncoder; +import com.iab.gpp.encoder.datatype.encoder.FixedIntegerRangeEncoder; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.EncodingException; + +public class EncodableArrayOfFixedIntegerRanges extends AbstractEncodableBitStringDataType> { + + private int keyBitStringLength; + private int typeBitStringLength; + + protected EncodableArrayOfFixedIntegerRanges(int keyBitStringLength, int typeBitStringLength) { + super(true); + this.keyBitStringLength = keyBitStringLength; + this.typeBitStringLength = typeBitStringLength; + } + + public EncodableArrayOfFixedIntegerRanges(int keyBitStringLength, int typeBitStringLength, List value) { + super(true); + this.keyBitStringLength = keyBitStringLength; + this.typeBitStringLength = typeBitStringLength; + setValue(value); + } + + public EncodableArrayOfFixedIntegerRanges(int keyBitStringLength, int typeBitStringLength, List value, boolean hardFailIfMissing) { + super(hardFailIfMissing); + this.keyBitStringLength = keyBitStringLength; + this.typeBitStringLength = typeBitStringLength; + setValue(value); + } + + @Override + public String encode() { + try { + List entries = this.value; + + StringBuilder sb = new StringBuilder(); + sb.append(FixedIntegerEncoder.encode(entries.size(), 12)); + for (RangeEntry entry : entries) { + sb.append(FixedIntegerEncoder.encode(entry.getKey(), keyBitStringLength)) + .append(FixedIntegerEncoder.encode(entry.getType(), typeBitStringLength)) + .append(FixedIntegerRangeEncoder.encode(entry.getIds())); + } + + return sb.toString(); + } catch (Exception e) { + throw new EncodingException(e); + } + } + + @Override + public void decode(String bitString) { + try { + List entries = new ArrayList<>(); + + int size = FixedIntegerEncoder.decode(bitString.substring(0, 12)); + int index = 12; + for (int i = 0; i < size; i++) { + int key = FixedIntegerEncoder.decode(bitString.substring(index, index + keyBitStringLength)); + index += keyBitStringLength; + + int type = FixedIntegerEncoder.decode(bitString.substring(index, index + typeBitStringLength)); + index += typeBitStringLength; + + String substring = new EncodableFixedIntegerRange().substring(bitString, index); + List ids = FixedIntegerRangeEncoder.decode(substring); + index += substring.length(); + + entries.add(new RangeEntry(key, type, ids)); + } + + this.value = entries; + } catch (Exception e) { + throw new DecodingException(e); + } + } + + @Override + public String substring(String bitString, int fromIndex) throws SubstringException { + try { + StringBuilder sb = new StringBuilder(); + sb.append(bitString.substring(fromIndex, fromIndex + 12)); + + int size = FixedIntegerEncoder.decode(sb.toString()); + + int index = fromIndex + sb.length(); + for (int i = 0; i < size; i++) { + String keySubstring = bitString.substring(index, index + keyBitStringLength); + index += keySubstring.length(); + sb.append(keySubstring); + + String typeSubstring = bitString.substring(index, index + typeBitStringLength); + index += typeSubstring.length(); + sb.append(typeSubstring); + + String rangeSubstring = new EncodableFixedIntegerRange().substring(bitString, index); + index += rangeSubstring.length(); + sb.append(rangeSubstring); + } + + return sb.toString(); + } catch (Exception e) { + throw new SubstringException(e); + } + } + +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableBoolean.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableBoolean.java index 09d47ac7..340be3ab 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableBoolean.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableBoolean.java @@ -7,24 +7,40 @@ public class EncodableBoolean extends AbstractEncodableBitStringDataType { protected EncodableBoolean() { - super(); + super(true); } public EncodableBoolean(Boolean value) { - super(); + super(true); setValue(value); } - public String encode() throws EncodingException { - return BooleanEncoder.encode(this.value); + public EncodableBoolean(Boolean value, boolean hardFailIfMissing) { + super(hardFailIfMissing); + setValue(value); + } + + public String encode() { + try { + return BooleanEncoder.encode(this.value); + } catch (Exception e) { + throw new EncodingException(e); + } } - public void decode(String bitString) throws DecodingException { - this.value = BooleanEncoder.decode(bitString); + public void decode(String bitString) { + try { + this.value = BooleanEncoder.decode(bitString); + } catch (Exception e) { + throw new DecodingException(e); + } } - public String substring(String bitString, int fromIndex) { - // TODO: validate - return bitString.substring(fromIndex, fromIndex + 1); + public String substring(String bitString, int fromIndex) throws SubstringException { + try { + return bitString.substring(fromIndex, fromIndex + 1); + } catch (Exception e) { + throw new SubstringException(e); + } } } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableDataType.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableDataType.java new file mode 100644 index 00000000..94d416a6 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableDataType.java @@ -0,0 +1,7 @@ +package com.iab.gpp.encoder.datatype; + +public interface EncodableDataType extends DataType { + String encode(); + + void decode(String str); +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableDatetime.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableDatetime.java index f146d0aa..a96c46f4 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableDatetime.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableDatetime.java @@ -3,28 +3,45 @@ import java.time.ZonedDateTime; import com.iab.gpp.encoder.datatype.encoder.DatetimeEncoder; import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.EncodingException; public class EncodableDatetime extends AbstractEncodableBitStringDataType { protected EncodableDatetime() { - super(); + super(true); } public EncodableDatetime(ZonedDateTime value) { - super(); + super(true); + setValue(value); + } + + public EncodableDatetime(ZonedDateTime value, boolean hardFailIfMissing) { + super(hardFailIfMissing); setValue(value); } public String encode() { - return DatetimeEncoder.encode(this.value); + try { + return DatetimeEncoder.encode(this.value); + } catch (Exception e) { + throw new EncodingException(e); + } } - public void decode(String bitString) throws DecodingException { - this.value = DatetimeEncoder.decode(bitString); + public void decode(String bitString) { + try { + this.value = DatetimeEncoder.decode(bitString); + } catch (Exception e) { + throw new DecodingException(e); + } } - public String substring(String bitString, int fromIndex) { - // TODO: validate - return bitString.substring(fromIndex, fromIndex + 36); + public String substring(String bitString, int fromIndex) throws SubstringException { + try { + return bitString.substring(fromIndex, fromIndex + 36); + } catch (Exception e) { + throw new SubstringException(e); + } } } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFibonacciInteger.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFibonacciInteger.java index 5d4e1783..3da64a15 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFibonacciInteger.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFibonacciInteger.java @@ -2,32 +2,50 @@ import com.iab.gpp.encoder.datatype.encoder.FibonacciIntegerEncoder; import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.EncodingException; public class EncodableFibonacciInteger extends AbstractEncodableBitStringDataType { protected EncodableFibonacciInteger() { - super(); + super(true); } public EncodableFibonacciInteger(Integer value) { - super(); + super(true); + setValue(value); + } + + public EncodableFibonacciInteger(Integer value, boolean hardFailIfMissing) { + super(hardFailIfMissing); setValue(value); } public String encode() { - return FibonacciIntegerEncoder.encode(this.value); + try { + return FibonacciIntegerEncoder.encode(this.value); + } catch (Exception e) { + throw new EncodingException(e); + } } - public void decode(String bitString) throws DecodingException { - this.value = FibonacciIntegerEncoder.decode(bitString); + public void decode(String bitString) { + try { + this.value = FibonacciIntegerEncoder.decode(bitString); + } catch (Exception e) { + throw new DecodingException(e); + } } - public String substring(String bitString, int fromIndex) { - int index = bitString.indexOf("11", fromIndex); - if (index > 0) { - return bitString.substring(fromIndex, index + 2); - } else { - return bitString; + public String substring(String bitString, int fromIndex) throws SubstringException { + try { + int index = bitString.indexOf("11", fromIndex); + if (index > 0) { + return bitString.substring(fromIndex, index + 2); + } else { + return bitString; + } + } catch (Exception e) { + throw new SubstringException(e); } } } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFibonacciIntegerRange.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFibonacciIntegerRange.java index eaff0382..53ab2eb2 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFibonacciIntegerRange.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFibonacciIntegerRange.java @@ -6,38 +6,55 @@ import com.iab.gpp.encoder.datatype.encoder.FibonacciIntegerRangeEncoder; import com.iab.gpp.encoder.datatype.encoder.FixedIntegerEncoder; import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.EncodingException; public class EncodableFibonacciIntegerRange extends AbstractEncodableBitStringDataType> { protected EncodableFibonacciIntegerRange() { - super(); + super(true); } public EncodableFibonacciIntegerRange(List value) { - super(); + super(true); setValue(value); } + public EncodableFibonacciIntegerRange(List value, boolean hardFailIfMissing) { + super(hardFailIfMissing); + setValue(value); + } + public String encode() { - return FibonacciIntegerRangeEncoder.encode(this.value); + try { + return FibonacciIntegerRangeEncoder.encode(this.value); + } catch (Exception e) { + throw new EncodingException(e); + } } - public void decode(String bitString) throws DecodingException { - this.value = FibonacciIntegerRangeEncoder.decode(bitString); + public void decode(String bitString) { + try { + this.value = FibonacciIntegerRangeEncoder.decode(bitString); + } catch (Exception e) { + throw new DecodingException(e); + } } - public String substring(String bitString, int fromIndex) throws DecodingException { - // TODO: add some validation - int count = FixedIntegerEncoder.decode(bitString.substring(fromIndex, fromIndex + 12)); - int index = fromIndex + 12; - for (int i = 0; i < count; i++) { - if (bitString.charAt(index) == '1') { - index = bitString.indexOf("11", bitString.indexOf("11", index + 1) + 2) + 2; - } else { - index = bitString.indexOf("11", index + 1) + 2; + public String substring(String bitString, int fromIndex) throws SubstringException { + try { + int count = FixedIntegerEncoder.decode(bitString.substring(fromIndex, fromIndex + 12)); + int index = fromIndex + 12; + for (int i = 0; i < count; i++) { + if (bitString.charAt(index) == '1') { + index = bitString.indexOf("11", bitString.indexOf("11", index + 1) + 2) + 2; + } else { + index = bitString.indexOf("11", index + 1) + 2; + } } + return bitString.substring(fromIndex, index); + } catch (Exception e) { + throw new SubstringException(e); } - return bitString.substring(fromIndex, index); } @SuppressWarnings("unchecked") diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFixedBitfield.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFixedBitfield.java index e0ae9b8e..5e6890d9 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFixedBitfield.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFixedBitfield.java @@ -11,27 +11,49 @@ public class EncodableFixedBitfield extends AbstractEncodableBitStringDataType value) { - super(); + super(true); + this.numElements = value.size(); + setValue(value); + } + + public EncodableFixedBitfield(List value, boolean hardFailIfMissing) { + super(hardFailIfMissing); this.numElements = value.size(); setValue(value); } - public String encode() throws EncodingException { - return FixedBitfieldEncoder.encode(this.value, this.numElements); + public String encode() { + try { + return FixedBitfieldEncoder.encode(this.value, this.numElements); + } catch (Exception e) { + throw new EncodingException(e); + } } - public void decode(String bitString) throws DecodingException { - this.value = FixedBitfieldEncoder.decode(bitString); + public void decode(String bitString) { + try { + this.value = FixedBitfieldEncoder.decode(bitString); + } catch (Exception e) { + throw new DecodingException(e); + } } - public String substring(String bitString, int fromIndex) { - // TODO: validate - return bitString.substring(fromIndex, fromIndex + this.numElements); + public String substring(String bitString, int fromIndex) throws SubstringException { + try { + return bitString.substring(fromIndex, fromIndex + this.numElements); + } catch (Exception e) { + throw new SubstringException(e); + } } @SuppressWarnings("unchecked") diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFixedInteger.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFixedInteger.java index 8b0fcb7e..9fd25fb0 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFixedInteger.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFixedInteger.java @@ -2,32 +2,50 @@ import com.iab.gpp.encoder.datatype.encoder.FixedIntegerEncoder; import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.EncodingException; public class EncodableFixedInteger extends AbstractEncodableBitStringDataType { private int bitStringLength; protected EncodableFixedInteger(int bitStringLength) { - super(); + super(true); this.bitStringLength = bitStringLength; } public EncodableFixedInteger(int bitStringLength, Integer value) { - super(); + super(true); + this.bitStringLength = bitStringLength; + setValue(value); + } + + public EncodableFixedInteger(int bitStringLength, Integer value, boolean hardFailIfMissing) { + super(hardFailIfMissing); this.bitStringLength = bitStringLength; setValue(value); } public String encode() { - return FixedIntegerEncoder.encode(this.value, this.bitStringLength); + try { + return FixedIntegerEncoder.encode(this.value, this.bitStringLength); + } catch (Exception e) { + throw new EncodingException(e); + } } - public void decode(String bitString) throws DecodingException { - this.value = FixedIntegerEncoder.decode(bitString); + public void decode(String bitString) { + try { + this.value = FixedIntegerEncoder.decode(bitString); + } catch (Exception e) { + throw new DecodingException(e); + } } - public String substring(String bitString, int fromIndex) { - // TODO: validate - return bitString.substring(fromIndex, fromIndex + this.bitStringLength); + public String substring(String bitString, int fromIndex) throws SubstringException { + try { + return bitString.substring(fromIndex, fromIndex + this.bitStringLength); + } catch (Exception e) { + throw new SubstringException(e); + } } } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFixedIntegerList.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFixedIntegerList.java index ccaca886..f491e5ee 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFixedIntegerList.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFixedIntegerList.java @@ -12,29 +12,47 @@ public class EncodableFixedIntegerList extends AbstractEncodableBitStringDataTyp private int numElements; protected EncodableFixedIntegerList(int elementBitStringLength, int numElements) { - super(); + super(true); this.elementBitStringLength = elementBitStringLength; this.numElements = numElements; } public EncodableFixedIntegerList(int elementBitStringLength, List value) { - super(); + super(true); this.elementBitStringLength = elementBitStringLength; this.numElements = value.size(); setValue(value); } - public String encode() throws EncodingException { - return FixedIntegerListEncoder.encode(this.value, this.elementBitStringLength, this.numElements); + public EncodableFixedIntegerList(int elementBitStringLength, List value, boolean hardFailIfMissing) { + super(hardFailIfMissing); + this.elementBitStringLength = elementBitStringLength; + this.numElements = value.size(); + setValue(value); + } + + public String encode() { + try { + return FixedIntegerListEncoder.encode(this.value, this.elementBitStringLength, this.numElements); + } catch (Exception e) { + throw new EncodingException(e); + } } - public void decode(String bitString) throws DecodingException { - this.value = FixedIntegerListEncoder.decode(bitString, this.elementBitStringLength, this.numElements); + public void decode(String bitString) { + try { + this.value = FixedIntegerListEncoder.decode(bitString, this.elementBitStringLength, this.numElements); + } catch (Exception e) { + throw new DecodingException(e); + } } - public String substring(String bitString, int fromIndex) { - // TODO: validate - return bitString.substring(fromIndex, fromIndex + (this.elementBitStringLength * numElements)); + public String substring(String bitString, int fromIndex) throws SubstringException { + try { + return bitString.substring(fromIndex, fromIndex + (this.elementBitStringLength * numElements)); + } catch (Exception e) { + throw new SubstringException(e); + } } @SuppressWarnings("unchecked") diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFixedIntegerRange.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFixedIntegerRange.java index e43751af..7fdbd5a8 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFixedIntegerRange.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFixedIntegerRange.java @@ -6,38 +6,55 @@ import com.iab.gpp.encoder.datatype.encoder.FixedIntegerEncoder; import com.iab.gpp.encoder.datatype.encoder.FixedIntegerRangeEncoder; import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.EncodingException; public class EncodableFixedIntegerRange extends AbstractEncodableBitStringDataType> { protected EncodableFixedIntegerRange() { - super(); + super(true); } public EncodableFixedIntegerRange(List value) { - super(); + super(true); + setValue(value); + } + + public EncodableFixedIntegerRange(List value, boolean hardFailIfMissing) { + super(hardFailIfMissing); setValue(value); } public String encode() { - return FixedIntegerRangeEncoder.encode(this.value); + try { + return FixedIntegerRangeEncoder.encode(this.value); + } catch (Exception e) { + throw new EncodingException(e); + } } - public void decode(String bitString) throws DecodingException { - this.value = FixedIntegerRangeEncoder.decode(bitString); + public void decode(String bitString) { + try { + this.value = FixedIntegerRangeEncoder.decode(bitString); + } catch (Exception e) { + throw new DecodingException(e); + } } - public String substring(String bitString, int fromIndex) throws DecodingException { - // TODO: add some validation - int count = FixedIntegerEncoder.decode(bitString.substring(fromIndex, fromIndex + 12)); - int index = fromIndex + 12; - for (int i = 0; i < count; i++) { - if (bitString.charAt(index) == '1') { - index += 33; - } else { - index += 17; + public String substring(String bitString, int fromIndex) throws SubstringException { + try { + int count = FixedIntegerEncoder.decode(bitString.substring(fromIndex, fromIndex + 12)); + int index = fromIndex + 12; + for (int i = 0; i < count; i++) { + if (bitString.charAt(index) == '1') { + index += 33; + } else { + index += 17; + } } + return bitString.substring(fromIndex, index); + } catch (Exception e) { + throw new SubstringException(e); } - return bitString.substring(fromIndex, index); } @SuppressWarnings("unchecked") diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFixedString.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFixedString.java index ed736fc2..4cea9b48 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFixedString.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFixedString.java @@ -9,26 +9,43 @@ public class EncodableFixedString extends AbstractEncodableBitStringDataType value) { - super(); + super(true); this.getLengthSupplier = getLengthSupplier; this.setValue(value); } - public String encode() throws EncodingException { - return FixedBitfieldEncoder.encode(this.value, this.getLengthSupplier.getAsInt()); + public EncodableFlexibleBitfield(IntSupplier getLengthSupplier, List value, boolean hardFailIfMissing) { + super(hardFailIfMissing); + this.getLengthSupplier = getLengthSupplier; + this.setValue(value); } - public void decode(String bitString) throws DecodingException { - this.value = FixedBitfieldEncoder.decode(bitString); + public String encode() { + try { + return FixedBitfieldEncoder.encode(this.value, this.getLengthSupplier.getAsInt()); + } catch (Exception e) { + throw new EncodingException(e); + } } - public String substring(String bitString, int fromIndex) { - // TODO: validate - return bitString.substring(fromIndex, fromIndex + this.getLengthSupplier.getAsInt()); + public void decode(String bitString) { + try { + this.value = FixedBitfieldEncoder.decode(bitString); + } catch (Exception e) { + throw new DecodingException(e); + } + } + + public String substring(String bitString, int fromIndex) throws SubstringException { + try { + return bitString.substring(fromIndex, fromIndex + this.getLengthSupplier.getAsInt()); + } catch (Exception e) { + throw new SubstringException(e); + } } @SuppressWarnings("unchecked") diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableOptimizedFibonacciRange.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableOptimizedFibonacciRange.java index d32dcc49..2e49855f 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableOptimizedFibonacciRange.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableOptimizedFibonacciRange.java @@ -3,70 +3,54 @@ import java.util.ArrayList; import java.util.List; import java.util.TreeSet; -import com.iab.gpp.encoder.datatype.encoder.FibonacciIntegerRangeEncoder; -import com.iab.gpp.encoder.datatype.encoder.FixedBitfieldEncoder; import com.iab.gpp.encoder.datatype.encoder.FixedIntegerEncoder; +import com.iab.gpp.encoder.datatype.encoder.OptimizedFibonacciRangeEncoder; import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.error.EncodingException; public class EncodableOptimizedFibonacciRange extends AbstractEncodableBitStringDataType> { protected EncodableOptimizedFibonacciRange() { - super(); + super(true); } public EncodableOptimizedFibonacciRange(List value) { - super(); + super(true); setValue(value); } - public String encode() throws EncodingException { - // TODO: encoding the range before choosing the shortest is inefficient. There is probably a way - // to identify in advance which will be shorter based on the array length and values - int max = this.value.size() > 0 ? this.value.get(this.value.size() - 1) : 0; - String rangeBitString = FibonacciIntegerRangeEncoder.encode(this.value); - int rangeLength = rangeBitString.length(); - int bitFieldLength = max; + public EncodableOptimizedFibonacciRange(List value, boolean hardFailIfMissing) { + super(hardFailIfMissing); + setValue(value); + } - if (rangeLength <= bitFieldLength) { - return FixedIntegerEncoder.encode(max, 16) + "1" + rangeBitString; - } else { - List bits = new ArrayList<>(); - int index = 0; - for (int i = 0; i < max; i++) { - if (i == this.value.get(index) - 1) { - bits.add(true); - index++; - } else { - bits.add(false); - } - } - return FixedIntegerEncoder.encode(max, 16) + "0" + FixedBitfieldEncoder.encode(bits, bitFieldLength); + public String encode() { + try { + return OptimizedFibonacciRangeEncoder.encode(this.value); + } catch (Exception e) { + throw new EncodingException(e); } } - public void decode(String bitString) throws DecodingException { - if (bitString.charAt(16) == '1') { - this.value = FibonacciIntegerRangeEncoder.decode(bitString.substring(17)); - } else { - List value = new ArrayList<>(); - List bits = FixedBitfieldEncoder.decode(bitString.substring(17)); - for (int i = 0; i < bits.size(); i++) { - if (bits.get(i) == true) { - value.add(i + 1); - } - } - this.value = value; + public void decode(String bitString) { + try { + this.value = OptimizedFibonacciRangeEncoder.decode(bitString); + } catch (Exception e) { + throw new DecodingException(e); } } - public String substring(String bitString, int fromIndex) throws DecodingException { - int max = FixedIntegerEncoder.decode(bitString.substring(fromIndex, fromIndex + 16)); - if (bitString.charAt(fromIndex + 16) == '1') { - return (bitString.substring(fromIndex, fromIndex + 17) - + new EncodableFibonacciIntegerRange().substring(bitString, fromIndex + 17)); - } else { - return bitString.substring(fromIndex, fromIndex + 17 + max); + public String substring(String bitString, int fromIndex) throws SubstringException { + try { + int max = FixedIntegerEncoder.decode(bitString.substring(fromIndex, fromIndex + 16)); + if (bitString.charAt(fromIndex + 16) == '1') { + return (bitString.substring(fromIndex, fromIndex + 17) + + new EncodableFibonacciIntegerRange().substring(bitString, fromIndex + 17)); + } else { + return bitString.substring(fromIndex, fromIndex + 17 + max); + } + } catch (Exception e) { + throw new SubstringException(e); } } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableOptimizedFixedRange.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableOptimizedFixedRange.java index d3250f07..57f4b8e9 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableOptimizedFixedRange.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableOptimizedFixedRange.java @@ -3,71 +3,55 @@ import java.util.ArrayList; import java.util.List; import java.util.TreeSet; -import com.iab.gpp.encoder.datatype.encoder.FixedBitfieldEncoder; import com.iab.gpp.encoder.datatype.encoder.FixedIntegerEncoder; -import com.iab.gpp.encoder.datatype.encoder.FixedIntegerRangeEncoder; +import com.iab.gpp.encoder.datatype.encoder.OptimizedFixedRangeEncoder; import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.error.EncodingException; + public class EncodableOptimizedFixedRange extends AbstractEncodableBitStringDataType> { protected EncodableOptimizedFixedRange() { - super(); + super(true); } public EncodableOptimizedFixedRange(List value) { - super(); + super(true); setValue(value); } - public String encode() throws EncodingException { - // TODO: encoding the range before choosing the shortest is inefficient. There is probably a way - // to identify in advance which will be shorter based on the array length and values - int max = this.value.size() > 0 ? this.value.get(this.value.size() - 1) : 0; - String rangeBitString = FixedIntegerRangeEncoder.encode(this.value); - int rangeLength = rangeBitString.length(); - int bitFieldLength = max; - - if (rangeLength <= bitFieldLength) { - return FixedIntegerEncoder.encode(max, 16) + "1" + rangeBitString; - } else { - List bits = new ArrayList<>(); - int index = 0; - for (int i = 0; i < max; i++) { - if (i == this.value.get(index) - 1) { - bits.add(true); - index++; - } else { - bits.add(false); - } - } + public EncodableOptimizedFixedRange(List value, boolean hardFailIfMissing) { + super(hardFailIfMissing); + setValue(value); + } - return FixedIntegerEncoder.encode(max, 16) + "0" + FixedBitfieldEncoder.encode(bits, bitFieldLength); + public String encode() { + try { + return OptimizedFixedRangeEncoder.encode(this.value); + } catch (Exception e) { + throw new EncodingException(e); } } - public void decode(String bitString) throws DecodingException { - if (bitString.charAt(16) == '1') { - this.value = FixedIntegerRangeEncoder.decode(bitString.substring(17)); - } else { - List value = new ArrayList<>(); - List bits = FixedBitfieldEncoder.decode(bitString.substring(17)); - for (int i = 0; i < bits.size(); i++) { - if (bits.get(i) == true) { - value.add(i + 1); - } - } - this.value = value; + public void decode(String bitString) { + try { + this.value = OptimizedFixedRangeEncoder.decode(bitString); + } catch (Exception e) { + throw new DecodingException(e); } } - public String substring(String bitString, int fromIndex) throws DecodingException { - int max = FixedIntegerEncoder.decode(bitString.substring(fromIndex, fromIndex + 16)); - if (bitString.charAt(fromIndex + 16) == '1') { - return bitString.substring(fromIndex, fromIndex + 17) - + new EncodableFixedIntegerRange().substring(bitString, fromIndex + 17); - } else { - return bitString.substring(fromIndex, fromIndex + 17 + max); + public String substring(String bitString, int fromIndex) throws SubstringException { + try { + int max = FixedIntegerEncoder.decode(bitString.substring(fromIndex, fromIndex + 16)); + if (bitString.charAt(fromIndex + 16) == '1') { + return bitString.substring(fromIndex, fromIndex + 17) + + new EncodableFixedIntegerRange().substring(bitString, fromIndex + 17); + } else { + return bitString.substring(fromIndex, fromIndex + 17 + max); + } + } catch (Exception e) { + throw new SubstringException(e); } } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/RangeEntry.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/RangeEntry.java new file mode 100644 index 00000000..0237ed18 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/RangeEntry.java @@ -0,0 +1,42 @@ +package com.iab.gpp.encoder.datatype; + +import java.util.List; + +public class RangeEntry { + + private int key; + private int type; + private List ids; + + public RangeEntry(int key, int type, List ids) { + super(); + this.key = key; + this.type = type; + this.ids = ids; + } + + public int getKey() { + return key; + } + + public void setKey(int key) { + this.key = key; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public List getIds() { + return ids; + } + + public void setIds(List ids) { + this.ids = ids; + } + +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/SubstringException.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/SubstringException.java new file mode 100644 index 00000000..e9df8ca6 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/SubstringException.java @@ -0,0 +1,18 @@ +package com.iab.gpp.encoder.datatype; + +public class SubstringException extends Exception { + + private static final long serialVersionUID = 1825100490468259890L; + + public SubstringException(String msg) { + super(msg); + } + + public SubstringException(Exception e) { + super(e); + } + + public SubstringException(String msg, Exception e) { + super(msg, e); + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/UnencodableCharacter.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/UnencodableCharacter.java new file mode 100644 index 00000000..4ef9c256 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/UnencodableCharacter.java @@ -0,0 +1,49 @@ +package com.iab.gpp.encoder.datatype; + +import java.util.function.Predicate; +import com.iab.gpp.encoder.error.ValidationException; + +public class UnencodableCharacter implements DataType { + + private Predicate validator; + private Character value = null; + + public UnencodableCharacter() { + this.validator = v -> true; + } + + public UnencodableCharacter(Character value) { + this.validator = v -> true; + setValue(value); + } + + public UnencodableCharacter(Character value, Predicate validator) { + this.validator = validator; + setValue(value); + } + + public void setValidator(Predicate validator) { + this.validator = validator; + } + + @Override + public boolean hasValue() { + return this.value != null; + } + + @Override + public Character getValue() { + return this.value; + } + + @Override + public void setValue(Object value) { + Character c = (Character)value.toString().charAt(0); + if(validator.test(c)) { + this.value = c; + } else { + throw new ValidationException("Invalid value '" + c + "'"); + } + } + +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/UnencodableInteger.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/UnencodableInteger.java new file mode 100644 index 00000000..60dcddfd --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/UnencodableInteger.java @@ -0,0 +1,49 @@ +package com.iab.gpp.encoder.datatype; + +import java.util.function.Predicate; +import com.iab.gpp.encoder.error.ValidationException; + +public class UnencodableInteger implements DataType { + + private Predicate validator; + private Integer value = null; + + public UnencodableInteger() { + this.validator = v -> true; + } + + public UnencodableInteger(Integer value) { + this.validator = v -> true; + setValue(value); + } + + public UnencodableInteger(Integer value, Predicate validator) { + this.validator = validator; + setValue(value); + } + + public void setValidator(Predicate validator) { + this.validator = validator; + } + + @Override + public boolean hasValue() { + return this.value != null; + } + + @Override + public Integer getValue() { + return this.value; + } + + @Override + public void setValue(Object value) { + Integer i = (Integer)value; + if(validator.test(i)) { + this.value = i; + } else { + throw new ValidationException("Invalid value '" + i + "'"); + } + } + +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/ArrayOfRangesEntryEncoder.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/ArrayOfRangesEntryEncoder.java new file mode 100644 index 00000000..de1449b3 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/ArrayOfRangesEntryEncoder.java @@ -0,0 +1,43 @@ +package com.iab.gpp.encoder.datatype.encoder; + +import java.util.regex.Pattern; +import com.iab.gpp.encoder.error.DecodingException; + +public class ArrayOfRangesEntryEncoder { + + private static Pattern BITSTRING_VERIFICATION_PATTERN = Pattern.compile("^[0-1]*$", Pattern.CASE_INSENSITIVE); + + public static String encode(long value, int bitStringLength) { + String bitString = ""; + while (value > 0) { + if ((value & 1) == 1) { + bitString = "1" + bitString; + } else { + bitString = "0" + bitString; + } + value = value >> 1; + } + + while (bitString.length() < bitStringLength) { + bitString = "0" + bitString; + } + + return bitString; + } + + public static long decode(String bitString) throws DecodingException { + if (!BITSTRING_VERIFICATION_PATTERN.matcher(bitString).matches()) { + throw new DecodingException("Undecodable FixedLong '" + bitString + "'"); + } + + long value = 0; + + for (int i = 0; i < bitString.length(); i++) { + if (bitString.charAt(bitString.length() - (i + 1)) == '1') { + value += 1L << i; + } + } + + return value; + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/BooleanEncoder.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/BooleanEncoder.java index b49ff391..20e6cbd0 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/BooleanEncoder.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/BooleanEncoder.java @@ -4,7 +4,7 @@ import com.iab.gpp.encoder.error.EncodingException; public class BooleanEncoder { - public static String encode(Boolean value) throws EncodingException { + public static String encode(Boolean value) { if (value == true) { return "1"; } else if (value == false) { @@ -14,7 +14,7 @@ public static String encode(Boolean value) throws EncodingException { } } - public static boolean decode(String bitString) throws DecodingException { + public static boolean decode(String bitString) { if (bitString.equals("1")) { return true; } else if (bitString.equals("0")) { diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/CompressedBase64UrlEncoder.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/CompressedBase64UrlEncoder.java deleted file mode 100644 index c41e7465..00000000 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/CompressedBase64UrlEncoder.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.iab.gpp.encoder.datatype.encoder; - -public class CompressedBase64UrlEncoder extends AbstractBase64UrlEncoder { - - @Override - protected String pad(String bitString) { - while (bitString.length() % 8 > 0) { - bitString += "0"; - } - while (bitString.length() % 6 > 0) { - bitString += "0"; - } - - return bitString; - } - -} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FixedBitfieldEncoder.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FixedBitfieldEncoder.java index 20a71c13..6c922263 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FixedBitfieldEncoder.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FixedBitfieldEncoder.java @@ -10,7 +10,11 @@ public class FixedBitfieldEncoder { private static Pattern BITSTRING_VERIFICATION_PATTERN = Pattern.compile("^[0-1]*$", Pattern.CASE_INSENSITIVE); - public static String encode(List value, int bitStringLength) throws EncodingException { + public static String encode(List value, int bitStringLength) { + if (value.size() > bitStringLength) { + throw new EncodingException("Too many values '" + value.size() + "'"); + } + String bitString = ""; for (int i = 0; i < value.size(); i++) { bitString += BooleanEncoder.encode(value.get(i)); @@ -23,7 +27,7 @@ public static String encode(List value, int bitStringLength) throws Enc return bitString; } - public static List decode(String bitString) throws DecodingException { + public static List decode(String bitString) { if (!BITSTRING_VERIFICATION_PATTERN.matcher(bitString).matches()) { throw new DecodingException("Undecodable FixedBitfield '" + bitString + "'"); } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FixedIntegerEncoder.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FixedIntegerEncoder.java index 2870af60..dfc6802f 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FixedIntegerEncoder.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FixedIntegerEncoder.java @@ -2,6 +2,7 @@ import java.util.regex.Pattern; import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.EncodingException; public class FixedIntegerEncoder { @@ -20,6 +21,11 @@ public static String encode(int value, int bitStringLength) { value = value >> 1; } + if (bitString.length() > bitStringLength) { + throw new EncodingException( + "Numeric value '" + value + "' is too large for a bit string length of '" + bitStringLength + "'"); + } + while (bitString.length() < bitStringLength) { bitString = "0" + bitString; } @@ -31,9 +37,6 @@ public static int decode(String bitString) throws DecodingException { if (!BITSTRING_VERIFICATION_PATTERN.matcher(bitString).matches()) { throw new DecodingException("Undecodable FixedInteger '" + bitString + "'"); } - - // return parseInt(bitString, 2); - int value = 0; for (int i = 0; i < bitString.length(); i++) { diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FixedIntegerListEncoder.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FixedIntegerListEncoder.java index ba829322..044dfe26 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FixedIntegerListEncoder.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FixedIntegerListEncoder.java @@ -10,8 +10,11 @@ public class FixedIntegerListEncoder { private static Pattern BITSTRING_VERIFICATION_PATTERN = Pattern.compile("^[0-1]*$", Pattern.CASE_INSENSITIVE); - public static String encode(List value, int elementBitStringLength, int numElements) - throws EncodingException { + public static String encode(List value, int elementBitStringLength, int numElements) { + if(value.size() > numElements) { + throw new EncodingException("Too many values '" + value.size() + "'"); + } + String bitString = ""; for (int i = 0; i < value.size(); i++) { bitString += FixedIntegerEncoder.encode(value.get(i), elementBitStringLength); diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FixedLongEncoder.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FixedLongEncoder.java index 76ef8baf..c244a601 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FixedLongEncoder.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FixedLongEncoder.java @@ -2,6 +2,7 @@ import java.util.regex.Pattern; import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.EncodingException; public class FixedLongEncoder { @@ -18,6 +19,11 @@ public static String encode(long value, int bitStringLength) { value = value >> 1; } + if (bitString.length() > bitStringLength) { + throw new EncodingException( + "Numeric value '" + value + "' is too large for a bit string length of '" + bitStringLength + "'"); + } + while (bitString.length() < bitStringLength) { bitString = "0" + bitString; } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FixedStringEncoder.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FixedStringEncoder.java index 5cb8762a..38db681e 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FixedStringEncoder.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FixedStringEncoder.java @@ -8,7 +8,7 @@ public class FixedStringEncoder { private static Pattern BITSTRING_VERIFICATION_PATTERN = Pattern.compile("^[0-1]*$", Pattern.CASE_INSENSITIVE); - public static String encode(String value, int stringLength) throws EncodingException { + public static String encode(String value, int stringLength) { while (value.length() < stringLength) { value += " "; } @@ -29,7 +29,7 @@ public static String encode(String value, int stringLength) throws EncodingExcep return bitString; } - public static String decode(String bitString) throws DecodingException { + public static String decode(String bitString) { if (!BITSTRING_VERIFICATION_PATTERN.matcher(bitString).matches() || bitString.length() % 6 != 0) { throw new DecodingException("Undecodable FixedString '" + bitString + "'"); } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/OptimizedFibonacciRangeEncoder.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/OptimizedFibonacciRangeEncoder.java new file mode 100644 index 00000000..3492fbcc --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/OptimizedFibonacciRangeEncoder.java @@ -0,0 +1,56 @@ +package com.iab.gpp.encoder.datatype.encoder; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.EncodingException; + +public class OptimizedFibonacciRangeEncoder { + + private static Pattern BITSTRING_VERIFICATION_PATTERN = Pattern.compile("^[0-1]*$", Pattern.CASE_INSENSITIVE); + + public static String encode(List value) throws EncodingException { + // TODO: encoding the range before choosing the shortest is inefficient. There is probably a way + // to identify in advance which will be shorter based on the array length and values + int max = value.size() > 0 ? value.get(value.size() - 1) : 0; + String rangeBitString = FibonacciIntegerRangeEncoder.encode(value); + int rangeLength = rangeBitString.length(); + int bitFieldLength = max; + + if (rangeLength <= bitFieldLength) { + return FixedIntegerEncoder.encode(max, 16) + "1" + rangeBitString; + } else { + List bits = new ArrayList<>(); + int index = 0; + for (int i = 0; i < max; i++) { + if (i == value.get(index) - 1) { + bits.add(true); + index++; + } else { + bits.add(false); + } + } + return FixedIntegerEncoder.encode(max, 16) + "0" + FixedBitfieldEncoder.encode(bits, bitFieldLength); + } + } + + public static List decode(String bitString) throws DecodingException { + if (!BITSTRING_VERIFICATION_PATTERN.matcher(bitString).matches() || bitString.length() < 12) { + throw new DecodingException("Undecodable FibonacciIntegerRange '" + bitString + "'"); + } + + if (bitString.charAt(16) == '1') { + return FibonacciIntegerRangeEncoder.decode(bitString.substring(17)); + } else { + List value = new ArrayList<>(); + List bits = FixedBitfieldEncoder.decode(bitString.substring(17)); + for (int i = 0; i < bits.size(); i++) { + if (bits.get(i) == true) { + value.add(i + 1); + } + } + return value; + } + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/OptimizedFixedRangeEncoder.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/OptimizedFixedRangeEncoder.java new file mode 100644 index 00000000..73fb5e68 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/OptimizedFixedRangeEncoder.java @@ -0,0 +1,57 @@ +package com.iab.gpp.encoder.datatype.encoder; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.EncodingException; + +public class OptimizedFixedRangeEncoder { + + private static Pattern BITSTRING_VERIFICATION_PATTERN = Pattern.compile("^[0-1]*$", Pattern.CASE_INSENSITIVE); + + public static String encode(List value) throws EncodingException { + // TODO: encoding the range before choosing the shortest is inefficient. There is probably a way + // to identify in advance which will be shorter based on the array length and values + int max = value.size() > 0 ? value.get(value.size() - 1) : 0; + String rangeBitString = FixedIntegerRangeEncoder.encode(value); + int rangeLength = rangeBitString.length(); + int bitFieldLength = max; + + if (rangeLength <= bitFieldLength) { + return FixedIntegerEncoder.encode(max, 16) + "1" + rangeBitString; + } else { + List bits = new ArrayList<>(); + int index = 0; + for (int i = 0; i < max; i++) { + if (i == value.get(index) - 1) { + bits.add(true); + index++; + } else { + bits.add(false); + } + } + + return FixedIntegerEncoder.encode(max, 16) + "0" + FixedBitfieldEncoder.encode(bits, bitFieldLength); + } + } + + public static List decode(String bitString) throws DecodingException { + if (!BITSTRING_VERIFICATION_PATTERN.matcher(bitString).matches() || bitString.length() < 12) { + throw new DecodingException("Undecodable FixedIntegerRange '" + bitString + "'"); + } + + if (bitString.charAt(16) == '1') { + return FixedIntegerRangeEncoder.decode(bitString.substring(17)); + } else { + List value = new ArrayList<>(); + List bits = FixedBitfieldEncoder.decode(bitString.substring(17)); + for (int i = 0; i < bits.size(); i++) { + if (bits.get(i) == true) { + value.add(i + 1); + } + } + return value; + } + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/TraditionalBase64UrlEncoder.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/TraditionalBase64UrlEncoder.java deleted file mode 100644 index 848bbfe5..00000000 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/TraditionalBase64UrlEncoder.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.iab.gpp.encoder.datatype.encoder; - -public class TraditionalBase64UrlEncoder extends AbstractBase64UrlEncoder { - - @Override - protected String pad(String bitString) { - while (bitString.length() % 24 > 0) { - bitString += "0"; - } - return bitString; - } - -} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/error/DecodingException.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/error/DecodingException.java index 91c29b2f..d60c3459 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/error/DecodingException.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/error/DecodingException.java @@ -1,6 +1,6 @@ package com.iab.gpp.encoder.error; -public class DecodingException extends Exception { +public class DecodingException extends RuntimeException { private static final long serialVersionUID = 2098268445119981680L; diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/error/EncodingException.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/error/EncodingException.java index 2c7f80ad..a7f19355 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/error/EncodingException.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/error/EncodingException.java @@ -1,6 +1,6 @@ package com.iab.gpp.encoder.error; -public class EncodingException extends Exception { +public class EncodingException extends RuntimeException { private static final long serialVersionUID = 1161321945571871601L; diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/error/InvalidFieldException.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/error/InvalidFieldException.java index 5b1e1aa9..22113280 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/error/InvalidFieldException.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/error/InvalidFieldException.java @@ -1,6 +1,6 @@ package com.iab.gpp.encoder.error; -public class InvalidFieldException extends Exception { +public class InvalidFieldException extends RuntimeException { private static final long serialVersionUID = 2098268445119981680L; diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/error/LazyDecodingException.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/error/LazyDecodingException.java deleted file mode 100644 index 070a02d8..00000000 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/error/LazyDecodingException.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.iab.gpp.encoder.error; - -public class LazyDecodingException extends DecodingException { - - private static final long serialVersionUID = 2098268445119981680L; - - public LazyDecodingException(String msg) { - super(msg); - } - - public LazyDecodingException(Exception e) { - super(e); - } - - public LazyDecodingException(String msg, Exception e) { - super(msg, e); - } -} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/error/ValidationException.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/error/ValidationException.java new file mode 100644 index 00000000..733a740b --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/error/ValidationException.java @@ -0,0 +1,18 @@ +package com.iab.gpp.encoder.error; + +public class ValidationException extends DecodingException { + + private static final long serialVersionUID = 2098268445119981680L; + + public ValidationException(String msg) { + super(msg); + } + + public ValidationException(Exception e) { + super(e); + } + + public ValidationException(String msg, Exception e) { + super(msg, e); + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/EncodableBitStringFields.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/EncodableBitStringFields.java new file mode 100644 index 00000000..d2ac0f43 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/EncodableBitStringFields.java @@ -0,0 +1,31 @@ +package com.iab.gpp.encoder.field; + +import java.util.HashMap; +import java.util.Map; +import com.iab.gpp.encoder.datatype.AbstractEncodableBitStringDataType; + +public class EncodableBitStringFields implements Fields> { + + private Map> fields = new HashMap<>(); + + public boolean containsKey(String key) { + return this.fields.containsKey(key); + } + + public void put(String key, AbstractEncodableBitStringDataType value) { + this.fields.put(key, value); + } + + public AbstractEncodableBitStringDataType get(String key) { + return this.fields.get(key); + } + + public Map> getAll() { + return new HashMap<>(this.fields); + } + + public void reset(Fields> fields) { + this.fields.clear(); + this.fields.putAll(fields.getAll()); + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/Fields.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/Fields.java new file mode 100644 index 00000000..ca091e7f --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/Fields.java @@ -0,0 +1,14 @@ +package com.iab.gpp.encoder.field; + +import java.util.Map; +import com.iab.gpp.encoder.datatype.DataType; + +public interface Fields> { + + boolean containsKey(String key); + void put(String key, T value); + T get(String key); + Map getAll(); + void reset(Fields fields); + +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/GenericFields.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/GenericFields.java new file mode 100644 index 00000000..00263e55 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/GenericFields.java @@ -0,0 +1,31 @@ +package com.iab.gpp.encoder.field; + +import java.util.HashMap; +import java.util.Map; +import com.iab.gpp.encoder.datatype.DataType; + +public class GenericFields implements Fields> { + + private Map> fields = new HashMap<>(); + + public boolean containsKey(String key) { + return this.fields.containsKey(key); + } + + public void put(String key, DataType value) { + this.fields.put(key, value); + } + + public DataType get(String key) { + return this.fields.get(key); + } + + public Map> getAll() { + return new HashMap<>(this.fields); + } + + public void reset(Fields> fields) { + this.fields.clear(); + this.fields.putAll(fields.getAll()); + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/HeaderV1Field.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/HeaderV1Field.java index 384befab..17f1f5d9 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/HeaderV1Field.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/HeaderV1Field.java @@ -1,9 +1,21 @@ package com.iab.gpp.encoder.field; +import java.util.Arrays; +import java.util.List; + public class HeaderV1Field { public static String ID = "Id"; public static String VERSION = "Version"; public static String SECTION_IDS = "SectionIds"; + //@formatter:off + public static List HEADER_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + HeaderV1Field.ID, + HeaderV1Field.VERSION, + HeaderV1Field.SECTION_IDS + }); + //@formatter:on + + } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/TcfCaV1Field.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/TcfCaV1Field.java index 86c91dff..c87e886d 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/TcfCaV1Field.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/TcfCaV1Field.java @@ -1,5 +1,8 @@ package com.iab.gpp.encoder.field; +import java.util.Arrays; +import java.util.List; + public class TcfCaV1Field { public static String VERSION = "Version"; @@ -17,6 +20,7 @@ public class TcfCaV1Field { public static String PURPOSES_IMPLIED_CONSENT = "PurposesImpliedConsent"; public static String VENDOR_EXPRESS_CONSENT = "VendorExpressConsent"; public static String VENDOR_IMPLIED_CONSENT = "VendorImpliedConsent"; + public static String PUB_RESTRICTIONS = "PubRestrictions"; public static String PUB_PURPOSES_SEGMENT_TYPE = "PubPurposesSegmentType"; public static String PUB_PURPOSES_EXPRESS_CONSENT = "PubPurposesExpressConsent"; @@ -25,4 +29,45 @@ public class TcfCaV1Field { public static String CUSTOM_PURPOSES_EXPRESS_CONSENT = "CustomPurposesExpressConsent"; public static String CUSTOM_PURPOSES_IMPLIED_CONSENT = "CustomPurposesImpliedConsent"; + public static String DISCLOSED_VENDORS_SEGMENT_TYPE = "DisclosedVendorsSegmentType"; + public static String DISCLOSED_VENDORS = "DisclosedVendors"; + + //@formatter:off + public static List TCFCAV1_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + TcfCaV1Field.VERSION, + TcfCaV1Field.CREATED, + TcfCaV1Field.LAST_UPDATED, + TcfCaV1Field.CMP_ID, + TcfCaV1Field.CMP_VERSION, + TcfCaV1Field.CONSENT_SCREEN, + TcfCaV1Field.CONSENT_LANGUAGE, + TcfCaV1Field.VENDOR_LIST_VERSION, + TcfCaV1Field.TCF_POLICY_VERSION, + TcfCaV1Field.USE_NON_STANDARD_STACKS, + TcfCaV1Field.SPECIAL_FEATURE_EXPRESS_CONSENT, + TcfCaV1Field.PURPOSES_EXPRESS_CONSENT, + TcfCaV1Field.PURPOSES_IMPLIED_CONSENT, + TcfCaV1Field.VENDOR_EXPRESS_CONSENT, + TcfCaV1Field.VENDOR_IMPLIED_CONSENT, + TcfCaV1Field.PUB_RESTRICTIONS + }); + //@formatter:on + + //@formatter:off + public static List TCFCAV1_PUBLISHER_PURPOSES_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + TcfCaV1Field.PUB_PURPOSES_SEGMENT_TYPE, + TcfCaV1Field.PUB_PURPOSES_EXPRESS_CONSENT, + TcfCaV1Field.PUB_PURPOSES_IMPLIED_CONSENT, + TcfCaV1Field.NUM_CUSTOM_PURPOSES, + TcfCaV1Field.CUSTOM_PURPOSES_EXPRESS_CONSENT, + TcfCaV1Field.CUSTOM_PURPOSES_IMPLIED_CONSENT, + }); + //@formatter:on + + //@formatter:off + public static List TCFCAV1_DISCLOSED_VENDORS_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + TcfCaV1Field.DISCLOSED_VENDORS_SEGMENT_TYPE, + TcfCaV1Field.DISCLOSED_VENDORS, + }); + //@formatter:on } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/TcfEuV2Field.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/TcfEuV2Field.java index 660443c3..fedb510f 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/TcfEuV2Field.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/TcfEuV2Field.java @@ -1,5 +1,8 @@ package com.iab.gpp.encoder.field; +import java.util.Arrays; +import java.util.List; + public class TcfEuV2Field { public static String VERSION = "Version"; @@ -32,4 +35,52 @@ public class TcfEuV2Field { public static String VENDORS_DISCLOSED_SEGMENT_TYPE = "VendorsDisclosedSegmentType"; public static String VENDORS_DISCLOSED = "VendorsDisclosed"; + //@formatter:off + public static List TCFEUV2_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + TcfEuV2Field.VERSION, + TcfEuV2Field.CREATED, + TcfEuV2Field.LAST_UPDATED, + TcfEuV2Field.CMP_ID, + TcfEuV2Field.CMP_VERSION, + TcfEuV2Field.CONSENT_SCREEN, + TcfEuV2Field.CONSENT_LANGUAGE, + TcfEuV2Field.VENDOR_LIST_VERSION, + TcfEuV2Field.POLICY_VERSION, + TcfEuV2Field.IS_SERVICE_SPECIFIC, + TcfEuV2Field.USE_NON_STANDARD_STACKS, + TcfEuV2Field.SPECIAL_FEATURE_OPTINS, + TcfEuV2Field.PURPOSE_CONSENTS, + TcfEuV2Field.PURPOSE_LEGITIMATE_INTERESTS, + TcfEuV2Field.PURPOSE_ONE_TREATMENT, + TcfEuV2Field.PUBLISHER_COUNTRY_CODE, + TcfEuV2Field.VENDOR_CONSENTS, + TcfEuV2Field.VENDOR_LEGITIMATE_INTERESTS, + TcfEuV2Field.PUBLISHER_RESTRICTIONS + }); + //@formatter:on + + //@formatter:off + public static List TCFEUV2_PUBLISHER_PURPOSES_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + TcfEuV2Field.PUBLISHER_PURPOSES_SEGMENT_TYPE, + TcfEuV2Field.PUBLISHER_CONSENTS, + TcfEuV2Field.PUBLISHER_LEGITIMATE_INTERESTS, + TcfEuV2Field.NUM_CUSTOM_PURPOSES, + TcfEuV2Field.PUBLISHER_CUSTOM_CONSENTS, + TcfEuV2Field.PUBLISHER_CUSTOM_LEGITIMATE_INTERESTS, + }); + //@formatter:on + + //@formatter:off + public static List TCFEUV2_VENDORS_ALLOWED_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + TcfEuV2Field.VENDORS_ALLOWED_SEGMENT_TYPE, + TcfEuV2Field.VENDORS_ALLOWED, + }); + //@formatter:on + + //@formatter:off + public static List TCFEUV2_VENDORS_DISCLOSED_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + TcfEuV2Field.VENDORS_DISCLOSED_SEGMENT_TYPE, + TcfEuV2Field.VENDORS_DISCLOSED, + }); + //@formatter:on } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsCaV1Field.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsCaV1Field.java index 0c139803..07c1a13f 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsCaV1Field.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsCaV1Field.java @@ -1,5 +1,8 @@ package com.iab.gpp.encoder.field; +import java.util.Arrays; +import java.util.List; + public class UsCaV1Field { public static String VERSION = "Version"; @@ -19,4 +22,27 @@ public class UsCaV1Field { public static String GPC_SEGMENT_INCLUDED = "GpcSegmentIncluded"; public static String GPC = "Gpc"; + //@formatter:off + public static List USCAV1_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + UsCaV1Field.VERSION, + UsCaV1Field.SALE_OPT_OUT_NOTICE, + UsCaV1Field.SHARING_OPT_OUT_NOTICE, + UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, + UsCaV1Field.SALE_OPT_OUT, + UsCaV1Field.SHARING_OPT_OUT, + UsCaV1Field.SENSITIVE_DATA_PROCESSING, + UsCaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, + UsCaV1Field.PERSONAL_DATA_CONSENTS, + UsCaV1Field.MSPA_COVERED_TRANSACTION, + UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE, + UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE + }); + //@formatter:on + + //@formatter:off + public static List USCAV1_GPC_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + UsCaV1Field.GPC_SEGMENT_TYPE, + UsCaV1Field.GPC + }); + //@formatter:on } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsCoV1Field.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsCoV1Field.java index 8bcce1a3..36489c13 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsCoV1Field.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsCoV1Field.java @@ -1,5 +1,8 @@ package com.iab.gpp.encoder.field; +import java.util.Arrays; +import java.util.List; + public class UsCoV1Field { public static String VERSION = "Version"; @@ -17,4 +20,27 @@ public class UsCoV1Field { public static String GPC_SEGMENT_TYPE = "GpcSegmentType"; public static String GPC_SEGMENT_INCLUDED = "GpcSegmentIncluded"; public static String GPC = "Gpc"; + + //@formatter:off + public static List USCOV1_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + UsCoV1Field.VERSION, + UsCoV1Field.SHARING_NOTICE, + UsCoV1Field.SALE_OPT_OUT_NOTICE, + UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, + UsCoV1Field.SALE_OPT_OUT, + UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT, + UsCoV1Field.SENSITIVE_DATA_PROCESSING, + UsCoV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, + UsCoV1Field.MSPA_COVERED_TRANSACTION, + UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE, + UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE + }); + //@formatter:on + + //@formatter:off + public static List USCOV1_GPC_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + UsCoV1Field.GPC_SEGMENT_TYPE, + UsCoV1Field.GPC + }); + //@formatter:on } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsCtV1Field.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsCtV1Field.java index ba7b9b07..31e67a69 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsCtV1Field.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsCtV1Field.java @@ -1,5 +1,8 @@ package com.iab.gpp.encoder.field; +import java.util.Arrays; +import java.util.List; + public class UsCtV1Field { public static String VERSION = "Version"; @@ -17,4 +20,27 @@ public class UsCtV1Field { public static String GPC_SEGMENT_TYPE = "GpcSegmentType"; public static String GPC_SEGMENT_INCLUDED = "GpcSegmentIncluded"; public static String GPC = "Gpc"; + + //@formatter:off + public static List USCTV1_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + UsCtV1Field.VERSION, + UsCtV1Field.SHARING_NOTICE, + UsCtV1Field.SALE_OPT_OUT_NOTICE, + UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, + UsCtV1Field.SALE_OPT_OUT, + UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT, + UsCtV1Field.SENSITIVE_DATA_PROCESSING, + UsCtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, + UsCtV1Field.MSPA_COVERED_TRANSACTION, + UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE, + UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE + }); + //@formatter:on + + //@formatter:off + public static List USCTV1_GPC_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + UsCtV1Field.GPC_SEGMENT_TYPE, + UsCtV1Field.GPC + }); + //@formatter:on } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsNatV1Field.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsNatV1Field.java index 5a023e8f..0bdf0fb6 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsNatV1Field.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsNatV1Field.java @@ -1,5 +1,8 @@ package com.iab.gpp.encoder.field; +import java.util.Arrays; +import java.util.List; + public class UsNatV1Field { public static String VERSION = "Version"; @@ -23,4 +26,31 @@ public class UsNatV1Field { public static String GPC_SEGMENT_INCLUDED = "GpcSegmentIncluded"; public static String GPC = "Gpc"; + //@formatter:off + public static List USNATV1_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + UsNatV1Field.VERSION, + UsNatV1Field.SHARING_NOTICE, + UsNatV1Field.SALE_OPT_OUT_NOTICE, + UsNatV1Field.SHARING_OPT_OUT_NOTICE, + UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, + UsNatV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE, + UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, + UsNatV1Field.SALE_OPT_OUT, + UsNatV1Field.SHARING_OPT_OUT, + UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT, + UsNatV1Field.SENSITIVE_DATA_PROCESSING, + UsNatV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, + UsNatV1Field.PERSONAL_DATA_CONSENTS, + UsNatV1Field.MSPA_COVERED_TRANSACTION, + UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE, + UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE + }); + //@formatter:on + + //@formatter:off + public static List USNATV1_GPC_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + UsNatV1Field.GPC_SEGMENT_TYPE, + UsNatV1Field.GPC + }); + //@formatter:on } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsUtV1Field.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsUtV1Field.java index 7a649e90..be7584a4 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsUtV1Field.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsUtV1Field.java @@ -1,5 +1,8 @@ package com.iab.gpp.encoder.field; +import java.util.Arrays; +import java.util.List; + public class UsUtV1Field { public static String VERSION = "Version"; @@ -14,4 +17,21 @@ public class UsUtV1Field { public static String MSPA_COVERED_TRANSACTION = "MspaCoveredTransaction"; public static String MSPA_OPT_OUT_OPTION_MODE = "MspaOptOutOptionMode"; public static String MSPA_SERVICE_PROVIDER_MODE = "MspaServiceProviderMode"; + + //@formatter:off + public static List USUTV1_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + UsUtV1Field.VERSION, + UsUtV1Field.SHARING_NOTICE, + UsUtV1Field.SALE_OPT_OUT_NOTICE, + UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, + UsUtV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE, + UsUtV1Field.SALE_OPT_OUT, + UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT, + UsUtV1Field.SENSITIVE_DATA_PROCESSING, + UsUtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, + UsUtV1Field.MSPA_COVERED_TRANSACTION, + UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE, + UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE + }); + //@formatter:on } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsVaV1Field.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsVaV1Field.java index 6125d171..e926b916 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsVaV1Field.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsVaV1Field.java @@ -1,5 +1,8 @@ package com.iab.gpp.encoder.field; +import java.util.Arrays; +import java.util.List; + public class UsVaV1Field { public static String VERSION = "Version"; @@ -14,4 +17,19 @@ public class UsVaV1Field { public static String MSPA_OPT_OUT_OPTION_MODE = "MspaOptOutOptionMode"; public static String MSPA_SERVICE_PROVIDER_MODE = "MspaServiceProviderMode"; + //@formatter:off + public static List USVAV1_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + UsVaV1Field.VERSION, + UsVaV1Field.SHARING_NOTICE, + UsVaV1Field.SALE_OPT_OUT_NOTICE, + UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, + UsVaV1Field.SALE_OPT_OUT, + UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT, + UsVaV1Field.SENSITIVE_DATA_PROCESSING, + UsVaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, + UsVaV1Field.MSPA_COVERED_TRANSACTION, + UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE, + UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE + }); + //@formatter:on } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UspV1Field.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UspV1Field.java index c5346823..2551632c 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UspV1Field.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UspV1Field.java @@ -1,5 +1,8 @@ package com.iab.gpp.encoder.field; +import java.util.Arrays; +import java.util.List; + public class UspV1Field { public static String VERSION = "Version"; @@ -7,4 +10,12 @@ public class UspV1Field { public static String OPT_OUT_SALE = "OptOutSale"; public static String LSPA_COVERED = "LspaCovered"; + //@formatter:off + public static List USPV1_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + UspV1Field.VERSION, + UspV1Field.NOTICE, + UspV1Field.OPT_OUT_SALE, + UspV1Field.LSPA_COVERED + }); + //@formatter:on } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UspV1LegacyField.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UspV1LegacyField.java deleted file mode 100644 index 3b1642c1..00000000 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UspV1LegacyField.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.iab.gpp.encoder.field; - -public class UspV1LegacyField { - - public static String VERSION = "Version"; - public static String NOTICE = "Notice"; - public static String OPT_OUT_SALE = "OptOutSale"; - public static String LSPA_COVERED = "LspaCovered"; - -} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/AbstractEncodableBitStringSection.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/AbstractEncodableBitStringSection.java deleted file mode 100644 index 5b8f0b7c..00000000 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/AbstractEncodableBitStringSection.java +++ /dev/null @@ -1,81 +0,0 @@ -package com.iab.gpp.encoder.section; - -import java.util.Map; -import com.iab.gpp.encoder.datatype.AbstractEncodableBitStringDataType; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; -import com.iab.gpp.encoder.error.InvalidFieldException; - -public abstract class AbstractEncodableBitStringSection implements EncodableSection { - protected Map> fields; - protected String[] fieldOrder; - - @Override - public boolean hasField(String fieldName) { - return this.fields.containsKey(fieldName); - } - - @Override - public Object getFieldValue(String fieldName) { - if (this.fields.containsKey(fieldName)) { - return this.fields.get(fieldName).getValue(); - } else { - return null; - } - } - - @Override - public void setFieldValue(String fieldName, Object value) throws InvalidFieldException { - if (this.fields.containsKey(fieldName)) { - this.fields.get(fieldName).setValue(value); - } else { - throw new InvalidFieldException(fieldName + " not found"); - } - } - - public String[] getFieldOrder() { - return this.fieldOrder; - } - - public String encodeToBitString() throws EncodingException { - String bitString = ""; - for (int i = 0; i < this.fieldOrder.length; i++) { - String fieldName = this.fieldOrder[i]; - if (this.fields.containsKey(fieldName)) { - AbstractEncodableBitStringDataType field = this.fields.get(fieldName); - bitString += field.encode(); - } else { - throw new EncodingException("Field not found: '" + fieldName + "'"); - } - } - - return bitString; - } - - public void decodeFromBitString(String bitString) throws DecodingException { - int index = 0; - for (int i = 0; i < this.fieldOrder.length; i++) { - String fieldName = this.fieldOrder[i]; - if (this.fields.containsKey(fieldName)) { - AbstractEncodableBitStringDataType field = this.fields.get(fieldName); - String substring = field.substring(bitString, index); - field.decode(substring); - index += substring.length(); - } else { - throw new DecodingException("Field not found: '" + fieldName + "'"); - } - } - } - - @Override - public abstract String encode() throws EncodingException; - - @Override - public abstract void decode(String encodedString) throws DecodingException; - - @Override - public abstract int getId(); - - @Override - public abstract String getName(); -} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/AbstractEncodableSegmentedBitStringSection.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/AbstractEncodableSegmentedBitStringSection.java index d9339189..eb5d5459 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/AbstractEncodableSegmentedBitStringSection.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/AbstractEncodableSegmentedBitStringSection.java @@ -4,6 +4,7 @@ import java.util.List; import java.util.Map; import com.iab.gpp.encoder.datatype.AbstractEncodableBitStringDataType; +import com.iab.gpp.encoder.datatype.SubstringException; import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.error.EncodingException; import com.iab.gpp.encoder.error.InvalidFieldException; @@ -64,28 +65,37 @@ public List encodeSegmentsToBitStrings() throws EncodingException { public void decodeSegmentsFromBitStrings(List segmentBitStrings) throws DecodingException { for (int i = 0; i < this.segments.length && i < segmentBitStrings.size(); i++) { - String segmentBitString = segmentBitStrings.get(i); - if (segmentBitString != null && segmentBitString.length() > 0) { - int index = 0; - for (int j = 0; j < this.segments[i].length; j++) { - String fieldName = this.segments[i][j]; - if (this.fields.containsKey(fieldName)) { - try { - AbstractEncodableBitStringDataType field = this.fields.get(fieldName); - String substring = field.substring(segmentBitString, index); - field.decode(substring); - index += substring.length(); - } catch (Exception e) { + decodeSegmentFromBitString(segments[i], segmentBitStrings.get(i)); + } + } + + private void decodeSegmentFromBitString(String[] segment, String segmentBitString) throws DecodingException { + if (segmentBitString != null && segmentBitString.length() > 0) { + int index = 0; + for (int j = 0; j < segment.length; j++) { + String fieldName = segment[j]; + AbstractEncodableBitStringDataType field = this.fields.get(fieldName); + if (this.fields.containsKey(fieldName)) { + try { + String substring = field.substring(segmentBitString, index); + field.decode(substring); + index += substring.length(); + } catch (SubstringException e) { + if(field.getHardFailIfMissing()) { throw new DecodingException("Unable to decode " + fieldName, e); + } else { + return; } - } else { - throw new DecodingException("Field not found: '" + fieldName + "'"); + } catch (Exception e) { + throw new DecodingException("Unable to decode " + fieldName, e); } + } else { + throw new DecodingException("Field not found: '" + fieldName + "'"); } } } } - + @Override public abstract String encode() throws EncodingException; diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/AbstractLazilyEncodableSection.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/AbstractLazilyEncodableSection.java new file mode 100644 index 00000000..5e97e144 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/AbstractLazilyEncodableSection.java @@ -0,0 +1,91 @@ +package com.iab.gpp.encoder.section; + +import java.util.List; +import com.iab.gpp.encoder.error.InvalidFieldException; +import com.iab.gpp.encoder.segment.EncodableSegment; + +public abstract class AbstractLazilyEncodableSection implements EncodableSection { + + private List segments; + + private String encodedString = null; + + private boolean dirty = false; + private boolean decoded = true; + + public AbstractLazilyEncodableSection() { + this.segments = initializeSegments(); + } + + protected abstract List initializeSegments(); + + protected abstract String encodeSection(List segments); + + protected abstract List decodeSection(String encodedString); + + public boolean hasField(String fieldName) { + if (!this.decoded) { + this.segments = this.decodeSection(this.encodedString); + this.dirty = false; + this.decoded = true; + } + + for(EncodableSegment segment : segments) { + if(segment.getFieldNames().contains(fieldName)) { + return segment.hasField(fieldName); + } + } + + return false; + } + + public Object getFieldValue(String fieldName) { + if (!this.decoded) { + this.segments = this.decodeSection(this.encodedString); + this.dirty = false; + this.decoded = true; + } + + for(EncodableSegment segment : segments) { + if(segment.hasField(fieldName)) { + return segment.getFieldValue(fieldName); + } + } + + throw new InvalidFieldException("Invalid field: '" + fieldName + "'"); + } + + public void setFieldValue(String fieldName, Object value) { + if (!this.decoded) { + this.segments = this.decodeSection(this.encodedString); + this.dirty = false; + this.decoded = true; + } + + for(EncodableSegment segment : segments) { + if(segment.hasField(fieldName)) { + segment.setFieldValue(fieldName, value); + return; + } + } + + throw new InvalidFieldException("Invalid field: '" + fieldName + "'"); + } + + public String encode() { + if (this.encodedString == null || this.encodedString.isEmpty() || this.dirty) { + this.encodedString = this.encodeSection(this.segments); + this.dirty = false; + this.decoded = true; + } + + return this.encodedString; + } + + public void decode(String encodedString) { + this.encodedString = encodedString; + this.dirty = false; + this.decoded = false; + } + +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/EncodableSection.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/EncodableSection.java index a547e6d3..e1f0a854 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/EncodableSection.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/EncodableSection.java @@ -1,22 +1,20 @@ package com.iab.gpp.encoder.section; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; -import com.iab.gpp.encoder.error.InvalidFieldException; - public interface EncodableSection { int getId(); String getName(); + int getVersion(); + boolean hasField(String fieldName); Object getFieldValue(String fieldName); - void setFieldValue(String fieldName, Object value) throws InvalidFieldException; + void setFieldValue(String fieldName, Object value); - String encode() throws EncodingException; + String encode(); - void decode(String encodedString) throws DecodingException; + void decode(String encodedString); } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/HeaderV1.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/HeaderV1.java index 59ec9483..fd5d991c 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/HeaderV1.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/HeaderV1.java @@ -1,79 +1,79 @@ package com.iab.gpp.encoder.section; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import com.iab.gpp.encoder.datatype.EncodableFibonacciIntegerRange; -import com.iab.gpp.encoder.datatype.EncodableFixedInteger; -import com.iab.gpp.encoder.datatype.encoder.AbstractBase64UrlEncoder; -import com.iab.gpp.encoder.datatype.encoder.CompressedBase64UrlEncoder; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; import com.iab.gpp.encoder.field.HeaderV1Field; +import com.iab.gpp.encoder.segment.EncodableSegment; +import com.iab.gpp.encoder.segment.HeaderV1CoreSegment; -public class HeaderV1 extends AbstractEncodableBitStringSection { +public class HeaderV1 extends AbstractLazilyEncodableSection { + public static int ID = 3; public static int VERSION = 1; public static String NAME = "header"; - private AbstractBase64UrlEncoder base64UrlEncoder = new CompressedBase64UrlEncoder(); - public HeaderV1() { - initFields(); + super(); } - public HeaderV1(String encodedString) throws DecodingException { - initFields(); - - if (encodedString != null && encodedString.length() > 0) { - this.decode(encodedString); - } + public HeaderV1(String encodedString) { + super(); + decode(encodedString); } - private void initFields() { - fields = new HashMap<>(); - fields.put(HeaderV1Field.ID, new EncodableFixedInteger(6, HeaderV1.ID)); - fields.put(HeaderV1Field.VERSION, new EncodableFixedInteger(6, HeaderV1.VERSION)); - fields.put(HeaderV1Field.SECTION_IDS, new EncodableFibonacciIntegerRange(new ArrayList<>())); - - //@formatter:off - fieldOrder = new String[] { - HeaderV1Field.ID, - HeaderV1Field.VERSION, - HeaderV1Field.SECTION_IDS - }; - //@formatter:on + @Override + public int getId() { + return HeaderV1.ID; } @Override - public String encode() throws EncodingException { - String bitString = this.encodeToBitString(); - String encodedString = base64UrlEncoder.encode(bitString); - return encodedString; + public String getName() { + return HeaderV1.NAME; } @Override - public void decode(String encodedString) throws DecodingException { - String bitString = base64UrlEncoder.decode(encodedString); - this.decodeFromBitString(bitString); + public int getVersion() { + return HeaderV1.VERSION; } @Override - public int getId() { - return HeaderV1.ID; + protected List initializeSegments() { + List segments = new ArrayList<>(); + segments.add(new HeaderV1CoreSegment()); + return segments; } - + @Override - public String getName() { - return HeaderV1.NAME; + protected List decodeSection(String encodedString) { + List segments = initializeSegments(); + + if(encodedString != null && !encodedString.isEmpty()) { + String[] encodedSegments = encodedString.split("\\."); + + for(int i=0; i i) { + segments.get(i).decode(encodedSegments[i]); + } + } + } + + return segments; } - public Integer getVersion() { - return (Integer) this.fields.get(HeaderV1Field.VERSION).getValue(); + @Override + protected String encodeSection(List segments) { + List encodedSegments = new ArrayList<>(); + for(EncodableSegment segment : segments) { + encodedSegments.add(segment.encode()); + } + return String.join(".", encodedSegments); } + @SuppressWarnings("unchecked") public List getSectionsIds() { - return (List) this.fields.get(HeaderV1Field.SECTION_IDS).getValue(); + return (List) this.getFieldValue(HeaderV1Field.SECTION_IDS); } + + } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/TcfCaV1.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/TcfCaV1.java index ec3b4891..194a82dc 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/TcfCaV1.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/TcfCaV1.java @@ -3,174 +3,105 @@ import java.time.ZoneId; import java.time.ZonedDateTime; import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; import java.util.List; -import java.util.function.IntSupplier; -import java.util.stream.Collectors; -import com.iab.gpp.encoder.datatype.EncodableBoolean; -import com.iab.gpp.encoder.datatype.EncodableDatetime; -import com.iab.gpp.encoder.datatype.EncodableFixedBitfield; -import com.iab.gpp.encoder.datatype.EncodableFixedInteger; -import com.iab.gpp.encoder.datatype.EncodableFixedString; -import com.iab.gpp.encoder.datatype.EncodableFlexibleBitfield; -import com.iab.gpp.encoder.datatype.EncodableOptimizedFixedRange; -import com.iab.gpp.encoder.datatype.encoder.AbstractBase64UrlEncoder; -import com.iab.gpp.encoder.datatype.encoder.CompressedBase64UrlEncoder; +import com.iab.gpp.encoder.datatype.RangeEntry; import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; import com.iab.gpp.encoder.error.InvalidFieldException; import com.iab.gpp.encoder.field.TcfCaV1Field; +import com.iab.gpp.encoder.segment.EncodableSegment; +import com.iab.gpp.encoder.segment.TcfCaV1CoreSegment; +import com.iab.gpp.encoder.segment.TcfCaV1DisclosedVendorsSegment; +import com.iab.gpp.encoder.segment.TcfCaV1PublisherPurposesSegment; -public class TcfCaV1 extends AbstractEncodableSegmentedBitStringSection { +public class TcfCaV1 extends AbstractLazilyEncodableSection { + public static int ID = 5; public static int VERSION = 1; public static String NAME = "tcfcav1"; - private AbstractBase64UrlEncoder base64UrlEncoder = new CompressedBase64UrlEncoder(); - public TcfCaV1() { - initFields(); + super(); } - public TcfCaV1(String encodedString) throws DecodingException { - initFields(); + public TcfCaV1(String encodedString) { + super(); + decode(encodedString); + } - if (encodedString != null && encodedString.length() > 0) { - this.decode(encodedString); - } + @Override + public int getId() { + return TcfCaV1.ID; } - private void initFields() { - fields = new HashMap<>(); - - ZonedDateTime date = ZonedDateTime.now(); - - // core section - fields.put(TcfCaV1Field.VERSION, new EncodableFixedInteger(6, TcfCaV1.VERSION)); - fields.put(TcfCaV1Field.CREATED, new EncodableDatetime(date)); - fields.put(TcfCaV1Field.LAST_UPDATED, new EncodableDatetime(date)); - fields.put(TcfCaV1Field.CMP_ID, new EncodableFixedInteger(12, 0)); - fields.put(TcfCaV1Field.CMP_VERSION, new EncodableFixedInteger(12, 0)); - fields.put(TcfCaV1Field.CONSENT_SCREEN, new EncodableFixedInteger(6, 0)); - fields.put(TcfCaV1Field.CONSENT_LANGUAGE, new EncodableFixedString(2, "EN")); - fields.put(TcfCaV1Field.VENDOR_LIST_VERSION, new EncodableFixedInteger(12, 0)); - fields.put(TcfCaV1Field.TCF_POLICY_VERSION, new EncodableFixedInteger(6, 2)); - fields.put(TcfCaV1Field.USE_NON_STANDARD_STACKS, new EncodableBoolean(false)); - fields.put(TcfCaV1Field.SPECIAL_FEATURE_EXPRESS_CONSENT, new EncodableFixedBitfield( - Arrays.asList(false, false, false, false, false, false, false, false, false, false, false, false))); - fields.put(TcfCaV1Field.PURPOSES_EXPRESS_CONSENT, - new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, false, false))); - fields.put(TcfCaV1Field.PURPOSES_IMPLIED_CONSENT, - new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, false, false))); - fields.put(TcfCaV1Field.VENDOR_EXPRESS_CONSENT, new EncodableOptimizedFixedRange(new ArrayList<>())); - fields.put(TcfCaV1Field.VENDOR_IMPLIED_CONSENT, new EncodableOptimizedFixedRange(new ArrayList<>())); - - // publisher purposes segment - fields.put(TcfCaV1Field.PUB_PURPOSES_SEGMENT_TYPE, new EncodableFixedInteger(3, 3)); - fields.put(TcfCaV1Field.PUB_PURPOSES_EXPRESS_CONSENT, - new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, false, false))); - fields.put(TcfCaV1Field.PUB_PURPOSES_IMPLIED_CONSENT, - new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, false, false))); - - EncodableFixedInteger numCustomPurposes = new EncodableFixedInteger(6, 0); - fields.put(TcfCaV1Field.NUM_CUSTOM_PURPOSES, numCustomPurposes); - - IntSupplier getLengthSupplier = new IntSupplier() { - - @Override - public int getAsInt() { - return numCustomPurposes.getValue(); - } + @Override + public String getName() { + return TcfCaV1.NAME; + } - }; - - fields.put(TcfCaV1Field.CUSTOM_PURPOSES_EXPRESS_CONSENT, - new EncodableFlexibleBitfield(getLengthSupplier, new ArrayList<>())); - - fields.put(TcfCaV1Field.CUSTOM_PURPOSES_IMPLIED_CONSENT, - new EncodableFlexibleBitfield(getLengthSupplier, new ArrayList<>())); - - //@formatter:off - String[] coreSegment = new String[] { - TcfCaV1Field.VERSION, - TcfCaV1Field.CREATED, - TcfCaV1Field.LAST_UPDATED, - TcfCaV1Field.CMP_ID, - TcfCaV1Field.CMP_VERSION, - TcfCaV1Field.CONSENT_SCREEN, - TcfCaV1Field.CONSENT_LANGUAGE, - TcfCaV1Field.VENDOR_LIST_VERSION, - TcfCaV1Field.TCF_POLICY_VERSION, - TcfCaV1Field.USE_NON_STANDARD_STACKS, - TcfCaV1Field.SPECIAL_FEATURE_EXPRESS_CONSENT, - TcfCaV1Field.PURPOSES_EXPRESS_CONSENT, - TcfCaV1Field.PURPOSES_IMPLIED_CONSENT, - TcfCaV1Field.VENDOR_EXPRESS_CONSENT, - TcfCaV1Field.VENDOR_IMPLIED_CONSENT - }; - - String[] publisherPurposesSegment = new String[] { - TcfCaV1Field.PUB_PURPOSES_SEGMENT_TYPE, - TcfCaV1Field.PUB_PURPOSES_EXPRESS_CONSENT, - TcfCaV1Field.PUB_PURPOSES_IMPLIED_CONSENT, - TcfCaV1Field.NUM_CUSTOM_PURPOSES, - TcfCaV1Field.CUSTOM_PURPOSES_EXPRESS_CONSENT, - TcfCaV1Field.CUSTOM_PURPOSES_IMPLIED_CONSENT, - }; - - segments = new String[][] { - coreSegment, - publisherPurposesSegment - }; - //@formatter:on + @Override + public int getVersion() { + return TcfCaV1.VERSION; } @Override - public String encode() throws EncodingException { - List segmentBitStrings = this.encodeSegmentsToBitStrings(); - List encodedSegments = new ArrayList<>(); - if (segmentBitStrings.size() >= 1) { - encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(0))); - if (segmentBitStrings.size() >= 2) { - encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(1))); + protected List initializeSegments() { + List segments = new ArrayList<>(); + segments.add(new TcfCaV1CoreSegment()); + segments.add(new TcfCaV1PublisherPurposesSegment()); + segments.add(new TcfCaV1DisclosedVendorsSegment()); + return segments; + } + + @Override + public List decodeSection(String encodedString) { + List segments = initializeSegments(); + + if(encodedString != null && !encodedString.isEmpty()) { + String[] encodedSegments = encodedString.split("\\."); + for (int i = 0; i < encodedSegments.length; i++) { + + /** + * The first 3 bits contain the segment id. Rather than decode the entire string, just check the first character. + * + * A-H = '000' = 0 + * I-P = '001' = 1 + * Y-Z,a-f = '011' = 3 + * + * Note that there is no segment id field for the core segment. Instead the first 6 bits are reserved + * for the encoding version which only coincidentally works here because the version value is less than 8. + */ + + String encodedSegment = encodedSegments[i]; + if(!encodedSegment.isEmpty()) { + char firstChar = encodedSegment.charAt(0); + + if(firstChar >= 'A' && firstChar <= 'H') { + segments.get(0).decode(encodedSegments[i]); + } else if(firstChar >= 'I' && firstChar <= 'P') { + segments.get(2).decode(encodedSegments[i]); + } else if((firstChar >= 'Y' && firstChar <= 'Z') || (firstChar >= 'a' && firstChar <= 'f')) { + segments.get(1).decode(encodedSegments[i]); + } else { + throw new DecodingException("Invalid segment '" + encodedSegment + "'"); + } + } } } - - return encodedSegments.stream().collect(Collectors.joining(".")); + + return segments; } @Override - public void decode(String encodedSection) throws DecodingException { - String[] encodedSegments = encodedSection.split("\\."); - String[] segmentBitStrings = new String[4]; - for (int i = 0; i < encodedSegments.length; i++) { - /** - * first char will contain 6 bits, we only need the first 3. There is no segment type for the CORE - * string. Instead the first 6 bits are reserved for the encoding version, but because we're only on - * a maximum of encoding version 2 the first 3 bits in the core segment will evaluate to 0. - */ - String segmentBitString = base64UrlEncoder.decode(encodedSegments[i]); - switch (segmentBitString.substring(0, 3)) { - // unfortunately, the segment ordering doesn't match the segment ids - case "000": { - segmentBitStrings[0] = segmentBitString; - break; - } - case "011": { - segmentBitStrings[1] = segmentBitString; - break; - } - default: { - throw new DecodingException("Unable to decode segment '" + encodedSegments[i] + "'"); - } - } + public String encodeSection(List segments) { + List encodedSegments = new ArrayList<>(); + + encodedSegments.add(segments.get(0).encode()); + encodedSegments.add(segments.get(1).encode()); + if(!this.getDisclosedVendors().isEmpty()) { + encodedSegments.add(segments.get(2).encode()); } - this.decodeSegmentsFromBitStrings(Arrays.asList(segmentBitStrings)); + + return String.join(".", encodedSegments); } @Override @@ -185,107 +116,108 @@ public void setFieldValue(String fieldName, Object value) throws InvalidFieldExc } } - @Override - public int getId() { - return TcfCaV1.ID; - } - - @Override - public String getName() { - return TcfCaV1.NAME; - } - - public Integer getVersion() { - return (Integer) this.fields.get(TcfCaV1Field.VERSION).getValue(); - } - + public ZonedDateTime getCreated() { - return (ZonedDateTime) this.fields.get(TcfCaV1Field.CREATED).getValue(); + return (ZonedDateTime) this.getFieldValue(TcfCaV1Field.CREATED); } public ZonedDateTime getLastUpdated() { - return (ZonedDateTime) this.fields.get(TcfCaV1Field.LAST_UPDATED).getValue(); + return (ZonedDateTime) this.getFieldValue(TcfCaV1Field.LAST_UPDATED); } public Integer getCmpId() { - return (Integer) this.fields.get(TcfCaV1Field.CMP_ID).getValue(); + return (Integer) this.getFieldValue(TcfCaV1Field.CMP_ID); } public Integer getCmpVersion() { - return (Integer) this.fields.get(TcfCaV1Field.CMP_VERSION).getValue(); + return (Integer) this.getFieldValue(TcfCaV1Field.CMP_VERSION); } public Integer getConsentScreen() { - return (Integer) this.fields.get(TcfCaV1Field.CONSENT_SCREEN).getValue(); + return (Integer) this.getFieldValue(TcfCaV1Field.CONSENT_SCREEN); } public String getConsentLanguage() { - return (String) this.fields.get(TcfCaV1Field.CONSENT_LANGUAGE).getValue(); + return (String) this.getFieldValue(TcfCaV1Field.CONSENT_LANGUAGE); } public Integer getVendorListVersion() { - return (Integer) this.fields.get(TcfCaV1Field.VENDOR_LIST_VERSION).getValue(); + return (Integer) this.getFieldValue(TcfCaV1Field.VENDOR_LIST_VERSION); } public Integer getPolicyVersion() { - return (Integer) this.fields.get(TcfCaV1Field.TCF_POLICY_VERSION).getValue(); + return (Integer) this.getFieldValue(TcfCaV1Field.TCF_POLICY_VERSION); } public Boolean getUseNonStandardStacks() { - return (Boolean) this.fields.get(TcfCaV1Field.USE_NON_STANDARD_STACKS).getValue(); + return (Boolean) this.getFieldValue(TcfCaV1Field.USE_NON_STANDARD_STACKS); } @SuppressWarnings("unchecked") public List getSpecialFeatureExpressConsent() { - return (List) this.fields.get(TcfCaV1Field.SPECIAL_FEATURE_EXPRESS_CONSENT).getValue(); + return (List) this.getFieldValue(TcfCaV1Field.SPECIAL_FEATURE_EXPRESS_CONSENT); } @SuppressWarnings("unchecked") public List getPurposesExpressConsent() { - return (List) this.fields.get(TcfCaV1Field.PURPOSES_EXPRESS_CONSENT).getValue(); + return (List) this.getFieldValue(TcfCaV1Field.PURPOSES_EXPRESS_CONSENT); } @SuppressWarnings("unchecked") public List getPurposesImpliedConsent() { - return (List) this.fields.get(TcfCaV1Field.PURPOSES_IMPLIED_CONSENT).getValue(); + return (List) this.getFieldValue(TcfCaV1Field.PURPOSES_IMPLIED_CONSENT); } @SuppressWarnings("unchecked") public List getVendorExpressConsent() { - return (List) this.fields.get(TcfCaV1Field.VENDOR_EXPRESS_CONSENT).getValue(); + return (List) this.getFieldValue(TcfCaV1Field.VENDOR_EXPRESS_CONSENT); } @SuppressWarnings("unchecked") public List getVendorImpliedConsent() { - return (List) this.fields.get(TcfCaV1Field.VENDOR_IMPLIED_CONSENT).getValue(); + return (List) this.getFieldValue(TcfCaV1Field.VENDOR_IMPLIED_CONSENT); } + @SuppressWarnings("unchecked") + public List getPubRestrictions() { + return (List) this.getFieldValue(TcfCaV1Field.PUB_RESTRICTIONS); + } + public Integer getPubPurposesSegmentType() { - return (Integer) this.fields.get(TcfCaV1Field.PUB_PURPOSES_SEGMENT_TYPE).getValue(); + return (Integer) this.getFieldValue(TcfCaV1Field.PUB_PURPOSES_SEGMENT_TYPE); } @SuppressWarnings("unchecked") public List getPubPurposesExpressConsent() { - return (List) this.fields.get(TcfCaV1Field.PUB_PURPOSES_EXPRESS_CONSENT).getValue(); + return (List) this.getFieldValue(TcfCaV1Field.PUB_PURPOSES_EXPRESS_CONSENT); } @SuppressWarnings("unchecked") public List getPubPurposesImpliedConsent() { - return (List) this.fields.get(TcfCaV1Field.PUB_PURPOSES_IMPLIED_CONSENT).getValue(); + return (List) this.getFieldValue(TcfCaV1Field.PUB_PURPOSES_IMPLIED_CONSENT); } public Integer getNumCustomPurposes() { - return (Integer) this.fields.get(TcfCaV1Field.NUM_CUSTOM_PURPOSES).getValue(); + return (Integer) this.getFieldValue(TcfCaV1Field.NUM_CUSTOM_PURPOSES); } @SuppressWarnings("unchecked") public List getCustomPurposesExpressConsent() { - return (List) this.fields.get(TcfCaV1Field.CUSTOM_PURPOSES_EXPRESS_CONSENT).getValue(); + return (List) this.getFieldValue(TcfCaV1Field.CUSTOM_PURPOSES_EXPRESS_CONSENT); } @SuppressWarnings("unchecked") public List getCustomPurposesImpliedConsent() { - return (List) this.fields.get(TcfCaV1Field.CUSTOM_PURPOSES_IMPLIED_CONSENT).getValue(); + return (List) this.getFieldValue(TcfCaV1Field.CUSTOM_PURPOSES_IMPLIED_CONSENT); + } + + public Integer getDisclosedVendorsSegmentType() { + return (Integer) this.getFieldValue(TcfCaV1Field.DISCLOSED_VENDORS_SEGMENT_TYPE); + } + + @SuppressWarnings("unchecked") + public List getDisclosedVendors() { + return (List) this.getFieldValue(TcfCaV1Field.DISCLOSED_VENDORS); } } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/TcfEuV2.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/TcfEuV2.java index 625121bd..1f7f2b1e 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/TcfEuV2.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/TcfEuV2.java @@ -3,222 +3,123 @@ import java.time.ZoneId; import java.time.ZonedDateTime; import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; import java.util.List; -import java.util.function.IntSupplier; -import java.util.stream.Collectors; -import com.iab.gpp.encoder.datatype.EncodableBoolean; -import com.iab.gpp.encoder.datatype.EncodableDatetime; -import com.iab.gpp.encoder.datatype.EncodableFixedBitfield; -import com.iab.gpp.encoder.datatype.EncodableFixedInteger; -import com.iab.gpp.encoder.datatype.EncodableFixedIntegerRange; -import com.iab.gpp.encoder.datatype.EncodableFixedString; -import com.iab.gpp.encoder.datatype.EncodableFlexibleBitfield; -import com.iab.gpp.encoder.datatype.EncodableOptimizedFixedRange; -import com.iab.gpp.encoder.datatype.encoder.AbstractBase64UrlEncoder; -import com.iab.gpp.encoder.datatype.encoder.TraditionalBase64UrlEncoder; +import com.iab.gpp.encoder.datatype.RangeEntry; import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; import com.iab.gpp.encoder.error.InvalidFieldException; import com.iab.gpp.encoder.field.TcfEuV2Field; - -public class TcfEuV2 extends AbstractEncodableSegmentedBitStringSection { +import com.iab.gpp.encoder.segment.EncodableSegment; +import com.iab.gpp.encoder.segment.TcfEuV2CoreSegment; +import com.iab.gpp.encoder.segment.TcfEuV2PublisherPurposesSegment; +import com.iab.gpp.encoder.segment.TcfEuV2VendorsAllowedSegment; +import com.iab.gpp.encoder.segment.TcfEuV2VendorsDisclosedSegment; + +public class TcfEuV2 extends AbstractLazilyEncodableSection { + public static int ID = 2; public static int VERSION = 2; public static String NAME = "tcfeuv2"; - private AbstractBase64UrlEncoder base64UrlEncoder = new TraditionalBase64UrlEncoder(); - public TcfEuV2() { - initFields(); + super(); } - public TcfEuV2(String encodedString) throws DecodingException { - initFields(); + public TcfEuV2(String encodedString) { + super(); + decode(encodedString); + } - if (encodedString != null && encodedString.length() > 0) { - this.decode(encodedString); - } + @Override + public int getId() { + return TcfEuV2.ID; } - private void initFields() { - fields = new HashMap<>(); - - ZonedDateTime date = ZonedDateTime.now(); - - // core section - fields.put(TcfEuV2Field.VERSION, new EncodableFixedInteger(6, TcfEuV2.VERSION)); - fields.put(TcfEuV2Field.CREATED, new EncodableDatetime(date)); - fields.put(TcfEuV2Field.LAST_UPDATED, new EncodableDatetime(date)); - fields.put(TcfEuV2Field.CMP_ID, new EncodableFixedInteger(12, 0)); - fields.put(TcfEuV2Field.CMP_VERSION, new EncodableFixedInteger(12, 0)); - fields.put(TcfEuV2Field.CONSENT_SCREEN, new EncodableFixedInteger(6, 0)); - fields.put(TcfEuV2Field.CONSENT_LANGUAGE, new EncodableFixedString(2, "EN")); - fields.put(TcfEuV2Field.VENDOR_LIST_VERSION, new EncodableFixedInteger(12, 0)); - fields.put(TcfEuV2Field.POLICY_VERSION, new EncodableFixedInteger(6, 2)); - fields.put(TcfEuV2Field.IS_SERVICE_SPECIFIC, new EncodableBoolean(false)); - fields.put(TcfEuV2Field.USE_NON_STANDARD_STACKS, new EncodableBoolean(false)); - fields.put(TcfEuV2Field.SPECIAL_FEATURE_OPTINS, new EncodableFixedBitfield( - Arrays.asList(false, false, false, false, false, false, false, false, false, false, false, false))); - fields.put(TcfEuV2Field.PURPOSE_CONSENTS, - new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, false, false))); - fields.put(TcfEuV2Field.PURPOSE_LEGITIMATE_INTERESTS, - new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, false, false))); - fields.put(TcfEuV2Field.PURPOSE_ONE_TREATMENT, new EncodableBoolean(false)); - fields.put(TcfEuV2Field.PUBLISHER_COUNTRY_CODE, new EncodableFixedString(2, "AA")); - fields.put(TcfEuV2Field.VENDOR_CONSENTS, new EncodableOptimizedFixedRange(new ArrayList<>())); - fields.put(TcfEuV2Field.VENDOR_LEGITIMATE_INTERESTS, new EncodableOptimizedFixedRange(new ArrayList<>())); - - fields.put(TcfEuV2Field.PUBLISHER_RESTRICTIONS, new EncodableFixedIntegerRange(new ArrayList<>())); - - // publisher purposes segment - fields.put(TcfEuV2Field.PUBLISHER_PURPOSES_SEGMENT_TYPE, new EncodableFixedInteger(3, 3)); - fields.put(TcfEuV2Field.PUBLISHER_CONSENTS, - new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, false, false))); - fields.put(TcfEuV2Field.PUBLISHER_LEGITIMATE_INTERESTS, - new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, false, false))); - - EncodableFixedInteger numCustomPurposes = new EncodableFixedInteger(6, 0); - fields.put(TcfEuV2Field.NUM_CUSTOM_PURPOSES, numCustomPurposes); - - IntSupplier getLengthSupplier = new IntSupplier() { - - @Override - public int getAsInt() { - return numCustomPurposes.getValue(); - } + @Override + public String getName() { + return TcfEuV2.NAME; + } - }; - - fields.put(TcfEuV2Field.PUBLISHER_CUSTOM_CONSENTS, - new EncodableFlexibleBitfield(getLengthSupplier, new ArrayList<>())); - - fields.put(TcfEuV2Field.PUBLISHER_CUSTOM_LEGITIMATE_INTERESTS, - new EncodableFlexibleBitfield(getLengthSupplier, new ArrayList<>())); - - fields.put(TcfEuV2Field.VENDORS_ALLOWED_SEGMENT_TYPE, new EncodableFixedInteger(3, 2)); - fields.put(TcfEuV2Field.VENDORS_ALLOWED, new EncodableOptimizedFixedRange(new ArrayList<>())); - - fields.put(TcfEuV2Field.VENDORS_DISCLOSED_SEGMENT_TYPE, new EncodableFixedInteger(3, 1)); - fields.put(TcfEuV2Field.VENDORS_DISCLOSED, new EncodableOptimizedFixedRange(new ArrayList<>())); - - //@formatter:off - String[] coreSegment = new String[] { - TcfEuV2Field.VERSION, - TcfEuV2Field.CREATED, - TcfEuV2Field.LAST_UPDATED, - TcfEuV2Field.CMP_ID, - TcfEuV2Field.CMP_VERSION, - TcfEuV2Field.CONSENT_SCREEN, - TcfEuV2Field.CONSENT_LANGUAGE, - TcfEuV2Field.VENDOR_LIST_VERSION, - TcfEuV2Field.POLICY_VERSION, - TcfEuV2Field.IS_SERVICE_SPECIFIC, - TcfEuV2Field.USE_NON_STANDARD_STACKS, - TcfEuV2Field.SPECIAL_FEATURE_OPTINS, - TcfEuV2Field.PURPOSE_CONSENTS, - TcfEuV2Field.PURPOSE_LEGITIMATE_INTERESTS, - TcfEuV2Field.PURPOSE_ONE_TREATMENT, - TcfEuV2Field.PUBLISHER_COUNTRY_CODE, - TcfEuV2Field.VENDOR_CONSENTS, - TcfEuV2Field.VENDOR_LEGITIMATE_INTERESTS, - TcfEuV2Field.PUBLISHER_RESTRICTIONS - }; - - String[] publisherPurposesSegment = new String[] { - TcfEuV2Field.PUBLISHER_PURPOSES_SEGMENT_TYPE, - TcfEuV2Field.PUBLISHER_CONSENTS, - TcfEuV2Field.PUBLISHER_LEGITIMATE_INTERESTS, - TcfEuV2Field.NUM_CUSTOM_PURPOSES, - TcfEuV2Field.PUBLISHER_CUSTOM_CONSENTS, - TcfEuV2Field.PUBLISHER_CUSTOM_LEGITIMATE_INTERESTS, - }; - - String[] vendorsAllowedSegment = new String[] { - TcfEuV2Field.VENDORS_ALLOWED_SEGMENT_TYPE, - TcfEuV2Field.VENDORS_ALLOWED, - }; - - String[] vendorsDisclosedSegment = new String[] { - TcfEuV2Field.VENDORS_DISCLOSED_SEGMENT_TYPE, - TcfEuV2Field.VENDORS_DISCLOSED, - }; - - segments = new String[][] { - coreSegment, - publisherPurposesSegment, - vendorsAllowedSegment, - vendorsDisclosedSegment - }; - //@formatter:on + @Override + public int getVersion() { + return TcfEuV2.VERSION; } @Override - public String encode() throws EncodingException { - List segmentBitStrings = this.encodeSegmentsToBitStrings(); + protected List initializeSegments() { + List segments = new ArrayList<>(); + segments.add(new TcfEuV2CoreSegment()); + segments.add(new TcfEuV2PublisherPurposesSegment()); + segments.add(new TcfEuV2VendorsAllowedSegment()); + segments.add(new TcfEuV2VendorsDisclosedSegment()); + return segments; + } + + @Override + public List decodeSection(String encodedString) { + List segments = initializeSegments(); + + if(encodedString != null && !encodedString.isEmpty()) { + String[] encodedSegments = encodedString.split("\\."); + for (int i = 0; i < encodedSegments.length; i++) { + + /** + * The first 3 bits contain the segment id. Rather than decode the entire string, just check the first character. + * + * A-H = '000' = 0 + * I-P = '001' = 1 + * Q-X = '010' = 2 + * Y-Z,a-f = '011' = 3 + * + * Note that there is no segment id field for the core segment. Instead the first 6 bits are reserved + * for the encoding version which only coincidentally works here because the version value is less than 8. + */ + + String encodedSegment = encodedSegments[i]; + if(!encodedSegment.isEmpty()) { + char firstChar = encodedSegment.charAt(0); + + // unfortunately, the segment ordering doesn't match the segment ids + if(firstChar >= 'A' && firstChar <= 'H') { + segments.get(0).decode(encodedSegments[i]); + } else if(firstChar >= 'I' && firstChar <= 'P') { + segments.get(3).decode(encodedSegments[i]); + } else if(firstChar >= 'Q' && firstChar <= 'X') { + segments.get(2).decode(encodedSegments[i]); + } else if((firstChar >= 'Y' && firstChar <= 'Z') || (firstChar >= 'a' && firstChar <= 'f')) { + segments.get(1).decode(encodedSegments[i]); + } else { + throw new DecodingException("Invalid segment '" + encodedSegment + "'"); + } + } + } + } + + return segments; + } + + @Override + public String encodeSection(List segments) { List encodedSegments = new ArrayList<>(); - if (segmentBitStrings.size() >= 1) { - encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(0))); + if (segments.size() >= 1) { + encodedSegments.add(segments.get(0).encode()); Boolean isServiceSpecific = (Boolean) this.getFieldValue(TcfEuV2Field.IS_SERVICE_SPECIFIC); if (isServiceSpecific) { - if (segmentBitStrings.size() >= 2) { - encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(1))); + if (segments.size() >= 2) { + encodedSegments.add(segments.get(1).encode()); } } else { - if (segmentBitStrings.size() >= 2) { - encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(2))); + if (segments.size() >= 2) { + encodedSegments.add(segments.get(2).encode()); - if (segmentBitStrings.size() >= 3) { - encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(3))); + if (segments.size() >= 3) { + encodedSegments.add(segments.get(3).encode()); } } } } - return encodedSegments.stream().collect(Collectors.joining(".")); - } - - @Override - public void decode(String encodedSection) throws DecodingException { - String[] encodedSegments = encodedSection.split("\\."); - String[] segmentBitStrings = new String[4]; - for (int i = 0; i < encodedSegments.length; i++) { - /** - * first char will contain 6 bits, we only need the first 3. There is no segment type for the CORE - * string. Instead the first 6 bits are reserved for the encoding version, but because we're only on - * a maximum of encoding version 2 the first 3 bits in the core segment will evaluate to 0. - */ - String segmentBitString = base64UrlEncoder.decode(encodedSegments[i]); - switch (segmentBitString.substring(0, 3)) { - // unfortunately, the segment ordering doesn't match the segment ids - case "000": { - segmentBitStrings[0] = segmentBitString; - break; - } - case "001": { - segmentBitStrings[3] = segmentBitString; - break; - } - case "010": { - segmentBitStrings[2] = segmentBitString; - break; - } - case "011": { - segmentBitStrings[1] = segmentBitString; - break; - } - default: { - throw new DecodingException("Unable to decode segment '" + encodedSegments[i] + "'"); - } - } - } - this.decodeSegmentsFromBitStrings(Arrays.asList(segmentBitStrings)); + return String.join(".", encodedSegments); } @Override @@ -233,144 +134,130 @@ public void setFieldValue(String fieldName, Object value) throws InvalidFieldExc } } - @Override - public int getId() { - return TcfEuV2.ID; - } - - @Override - public String getName() { - return TcfEuV2.NAME; - } - - public Integer getVersion() { - return (Integer) this.fields.get(TcfEuV2Field.VERSION).getValue(); - } - + public ZonedDateTime getCreated() { - return (ZonedDateTime) this.fields.get(TcfEuV2Field.CREATED).getValue(); + return (ZonedDateTime) this.getFieldValue(TcfEuV2Field.CREATED); } public ZonedDateTime getLastUpdated() { - return (ZonedDateTime) this.fields.get(TcfEuV2Field.LAST_UPDATED).getValue(); + return (ZonedDateTime) this.getFieldValue(TcfEuV2Field.LAST_UPDATED); } public Integer getCmpId() { - return (Integer) this.fields.get(TcfEuV2Field.CMP_ID).getValue(); + return (Integer) this.getFieldValue(TcfEuV2Field.CMP_ID); } public Integer getCmpVersion() { - return (Integer) this.fields.get(TcfEuV2Field.CMP_VERSION).getValue(); + return (Integer) this.getFieldValue(TcfEuV2Field.CMP_VERSION); } public Integer getConsentScreen() { - return (Integer) this.fields.get(TcfEuV2Field.CONSENT_SCREEN).getValue(); + return (Integer) this.getFieldValue(TcfEuV2Field.CONSENT_SCREEN); } public String getConsentLanguage() { - return (String) this.fields.get(TcfEuV2Field.CONSENT_LANGUAGE).getValue(); + return (String) this.getFieldValue(TcfEuV2Field.CONSENT_LANGUAGE); } public Integer getVendorListVersion() { - return (Integer) this.fields.get(TcfEuV2Field.VENDOR_LIST_VERSION).getValue(); + return (Integer) this.getFieldValue(TcfEuV2Field.VENDOR_LIST_VERSION); } public Integer getPolicyVersion() { - return (Integer) this.fields.get(TcfEuV2Field.POLICY_VERSION).getValue(); + return (Integer) this.getFieldValue(TcfEuV2Field.POLICY_VERSION); } public Boolean getIsServiceSpecific() { - return (Boolean) this.fields.get(TcfEuV2Field.IS_SERVICE_SPECIFIC).getValue(); + return (Boolean) this.getFieldValue(TcfEuV2Field.IS_SERVICE_SPECIFIC); } public Boolean getUseNonStandardStacks() { - return (Boolean) this.fields.get(TcfEuV2Field.USE_NON_STANDARD_STACKS).getValue(); + return (Boolean) this.getFieldValue(TcfEuV2Field.USE_NON_STANDARD_STACKS); } @SuppressWarnings("unchecked") public List getSpecialFeatureOptins() { - return (List) this.fields.get(TcfEuV2Field.SPECIAL_FEATURE_OPTINS).getValue(); + return (List) this.getFieldValue(TcfEuV2Field.SPECIAL_FEATURE_OPTINS); } @SuppressWarnings("unchecked") public List getPurposeConsents() { - return (List) this.fields.get(TcfEuV2Field.PURPOSE_CONSENTS).getValue(); + return (List) this.getFieldValue(TcfEuV2Field.PURPOSE_CONSENTS); } @SuppressWarnings("unchecked") public List getPurposeLegitimateInterests() { - return (List) this.fields.get(TcfEuV2Field.PURPOSE_LEGITIMATE_INTERESTS).getValue(); + return (List) this.getFieldValue(TcfEuV2Field.PURPOSE_LEGITIMATE_INTERESTS); } public Boolean getPurposeOneTreatment() { - return (Boolean) this.fields.get(TcfEuV2Field.PURPOSE_ONE_TREATMENT).getValue(); + return (Boolean) this.getFieldValue(TcfEuV2Field.PURPOSE_ONE_TREATMENT); } public String getPublisherCountryCode() { - return (String) this.fields.get(TcfEuV2Field.PUBLISHER_COUNTRY_CODE).getValue(); + return (String) this.getFieldValue(TcfEuV2Field.PUBLISHER_COUNTRY_CODE); } @SuppressWarnings("unchecked") public List getVendorConsents() { - return (List) this.fields.get(TcfEuV2Field.VENDOR_CONSENTS).getValue(); + return (List) this.getFieldValue(TcfEuV2Field.VENDOR_CONSENTS); } @SuppressWarnings("unchecked") public List getVendorLegitimateInterests() { - return (List) this.fields.get(TcfEuV2Field.VENDOR_LEGITIMATE_INTERESTS).getValue(); + return (List) this.getFieldValue(TcfEuV2Field.VENDOR_LEGITIMATE_INTERESTS); } @SuppressWarnings("unchecked") - public List getPublisherRestrictions() { - return (List) this.fields.get(TcfEuV2Field.PUBLISHER_RESTRICTIONS).getValue(); + public List getPublisherRestrictions() { + return (List) this.getFieldValue(TcfEuV2Field.PUBLISHER_RESTRICTIONS); } public Integer getPublisherPurposesSegmentType() { - return (Integer) this.fields.get(TcfEuV2Field.PUBLISHER_PURPOSES_SEGMENT_TYPE).getValue(); + return (Integer) this.getFieldValue(TcfEuV2Field.PUBLISHER_PURPOSES_SEGMENT_TYPE); } @SuppressWarnings("unchecked") public List getPublisherConsents() { - return (List) this.fields.get(TcfEuV2Field.PUBLISHER_CONSENTS).getValue(); + return (List) this.getFieldValue(TcfEuV2Field.PUBLISHER_CONSENTS); } @SuppressWarnings("unchecked") public List getPublisherLegitimateInterests() { - return (List) this.fields.get(TcfEuV2Field.PUBLISHER_LEGITIMATE_INTERESTS).getValue(); + return (List) this.getFieldValue(TcfEuV2Field.PUBLISHER_LEGITIMATE_INTERESTS); } public Integer getNumCustomPurposes() { - return (Integer) this.fields.get(TcfEuV2Field.NUM_CUSTOM_PURPOSES).getValue(); + return (Integer) this.getFieldValue(TcfEuV2Field.NUM_CUSTOM_PURPOSES); } @SuppressWarnings("unchecked") public List getPublisherCustomConsents() { - return (List) this.fields.get(TcfEuV2Field.PUBLISHER_CUSTOM_CONSENTS).getValue(); + return (List) this.getFieldValue(TcfEuV2Field.PUBLISHER_CUSTOM_CONSENTS); } @SuppressWarnings("unchecked") public List getPublisherCustomLegitimateInterests() { - return (List) this.fields.get(TcfEuV2Field.PUBLISHER_CUSTOM_LEGITIMATE_INTERESTS).getValue(); + return (List) this.getFieldValue(TcfEuV2Field.PUBLISHER_CUSTOM_LEGITIMATE_INTERESTS); } public Integer getVendorsAllowedSegmentType() { - return (Integer) this.fields.get(TcfEuV2Field.VENDORS_ALLOWED_SEGMENT_TYPE).getValue(); + return (Integer) this.getFieldValue(TcfEuV2Field.VENDORS_ALLOWED_SEGMENT_TYPE); } @SuppressWarnings("unchecked") public List getVendorsAllowed() { - return (List) this.fields.get(TcfEuV2Field.VENDORS_ALLOWED).getValue(); + return (List) this.getFieldValue(TcfEuV2Field.VENDORS_ALLOWED); } public Integer getVendorsDisclosedSegmentType() { - return (Integer) this.fields.get(TcfEuV2Field.VENDORS_DISCLOSED_SEGMENT_TYPE).getValue(); + return (Integer) this.getFieldValue(TcfEuV2Field.VENDORS_DISCLOSED_SEGMENT_TYPE); } @SuppressWarnings("unchecked") public List getVendorsDisclosed() { - return (List) this.fields.get(TcfEuV2Field.VENDORS_DISCLOSED).getValue(); + return (List) this.getFieldValue(TcfEuV2Field.VENDORS_DISCLOSED); } - - - + + } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsCaV1.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsCaV1.java index de88746f..03442533 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsCaV1.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsCaV1.java @@ -1,208 +1,142 @@ package com.iab.gpp.encoder.section; import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; import java.util.List; -import java.util.stream.Collectors; -import com.iab.gpp.encoder.datatype.EncodableBoolean; -import com.iab.gpp.encoder.datatype.EncodableFixedInteger; -import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; -import com.iab.gpp.encoder.datatype.encoder.AbstractBase64UrlEncoder; -import com.iab.gpp.encoder.datatype.encoder.CompressedBase64UrlEncoder; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; import com.iab.gpp.encoder.field.UsCaV1Field; -import com.iab.gpp.encoder.field.UspV1Field; +import com.iab.gpp.encoder.segment.EncodableSegment; +import com.iab.gpp.encoder.segment.UsCaV1CoreSegment; +import com.iab.gpp.encoder.segment.UsCaV1GpcSegment; -public class UsCaV1 extends AbstractEncodableSegmentedBitStringSection { +public class UsCaV1 extends AbstractLazilyEncodableSection { + public static int ID = 8; public static int VERSION = 1; public static String NAME = "uscav1"; - private AbstractBase64UrlEncoder base64UrlEncoder = new CompressedBase64UrlEncoder(); - public UsCaV1() { - initFields(); + super(); } - public UsCaV1(String encodedString) throws DecodingException { - initFields(); - - if (encodedString != null && encodedString.length() > 0) { - this.decode(encodedString); - } + public UsCaV1(String encodedString) { + super(); + decode(encodedString); } - private void initFields() { - fields = new HashMap<>(); - - fields.put(UsCaV1Field.VERSION, new EncodableFixedInteger(6, UsCaV1.VERSION)); - fields.put(UsCaV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsCaV1Field.SHARING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsCaV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0)); - fields.put(UsCaV1Field.SHARING_OPT_OUT, new EncodableFixedInteger(2, 0)); - fields.put(UsCaV1Field.SENSITIVE_DATA_PROCESSING, - new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0, 0))); - fields.put(UsCaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, new EncodableFixedIntegerList(2, Arrays.asList(0, 0))); - fields.put(UsCaV1Field.PERSONAL_DATA_CONSENTS, new EncodableFixedInteger(2, 0)); - fields.put(UsCaV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 0)); - fields.put(UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0)); - fields.put(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0)); - - // gpc segment - fields.put(UsCaV1Field.GPC_SEGMENT_TYPE, new EncodableFixedInteger(2, 1)); - fields.put(UsCaV1Field.GPC_SEGMENT_INCLUDED, new EncodableBoolean(true)); - fields.put(UsCaV1Field.GPC, new EncodableBoolean(false)); - - //@formatter:off - String[] coreSegment = new String[] { - UsCaV1Field.VERSION, - UsCaV1Field.SALE_OPT_OUT_NOTICE, - UsCaV1Field.SHARING_OPT_OUT_NOTICE, - UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, - UsCaV1Field.SALE_OPT_OUT, - UsCaV1Field.SHARING_OPT_OUT, - UsCaV1Field.SENSITIVE_DATA_PROCESSING, - UsCaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, - UsCaV1Field.PERSONAL_DATA_CONSENTS, - UsCaV1Field.MSPA_COVERED_TRANSACTION, - UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE, - UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE - }; - - String[] gpcSegment = new String[] { - UsCaV1Field.GPC_SEGMENT_TYPE, - UsCaV1Field.GPC - }; - - segments = new String[][] { - coreSegment, - gpcSegment - }; - //@formatter:on + @Override + public int getId() { + return UsCaV1.ID; } @Override - public String encode() throws EncodingException { - List segmentBitStrings = this.encodeSegmentsToBitStrings(); - List encodedSegments = new ArrayList<>(); - if (segmentBitStrings.size() >= 1) { - encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(0))); - - if (segmentBitStrings.size() >= 2) { - Boolean gpcSegmentIncluded = (Boolean) this.fields.get(UsCaV1Field.GPC_SEGMENT_INCLUDED).getValue(); - if (gpcSegmentIncluded) { - encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(1))); - } - - } - } - - return encodedSegments.stream().collect(Collectors.joining(".")); + public String getName() { + return UsCaV1.NAME; } @Override - public void decode(String encodedSection) throws DecodingException { - String[] encodedSegments = encodedSection.split("\\."); - String[] segmentBitStrings = new String[2]; - boolean gpcSegmentIncluded = false; - for (int i = 0; i < encodedSegments.length; i++) { - /** - * first char will contain 6 bits, we only need the first 2. There is no segment type for the CORE - * string. Instead the first 6 bits are reserved for the encoding version, but because we're only on - * a maximum of encoding version 2 the first 2 bits in the core segment will evaluate to 0. - */ - String segmentBitString = base64UrlEncoder.decode(encodedSegments[i]); - switch (segmentBitString.substring(0, 2)) { - case "00": { - segmentBitStrings[0] = segmentBitString; - break; - } - case "01": { - gpcSegmentIncluded = true; - segmentBitStrings[1] = segmentBitString; - break; - } - default: { - throw new DecodingException("Unable to decode segment '" + encodedSegments[i] + "'"); - } - } - } - this.decodeSegmentsFromBitStrings(Arrays.asList(segmentBitStrings)); - this.fields.get(UsCaV1Field.GPC_SEGMENT_INCLUDED).setValue(gpcSegmentIncluded); + public int getVersion() { + return UsCaV1.VERSION; } @Override - public int getId() { - return UsCaV1.ID; + protected List initializeSegments() { + List segments = new ArrayList<>(); + segments.add(new UsCaV1CoreSegment()); + segments.add(new UsCaV1GpcSegment()); + return segments; } - + @Override - public String getName() { - return UsCaV1.NAME; + protected List decodeSection(String encodedString) { + List segments = initializeSegments(); + + if(encodedString != null && !encodedString.isEmpty()) { + String[] encodedSegments = encodedString.split("\\."); + + if(encodedSegments.length > 0) { + segments.get(0).decode(encodedSegments[0]); + } + + if(encodedSegments.length > 1) { + segments.get(1).setFieldValue(UsCaV1Field.GPC_SEGMENT_INCLUDED, true); + segments.get(1).decode(encodedSegments[1]); + } else { + segments.get(1).setFieldValue(UsCaV1Field.GPC_SEGMENT_INCLUDED, false); + } + } + + return segments; } - public Integer getVersion() { - return (Integer) this.fields.get(UspV1Field.VERSION).getValue(); + @Override + protected String encodeSection(List segments) { + List encodedSegments = new ArrayList<>(); + + if(!segments.isEmpty()) { + encodedSegments.add(segments.get(0).encode()); + if(segments.size() >= 2 && segments.get(1).getFieldValue(UsCaV1Field.GPC_SEGMENT_INCLUDED).equals(true)) { + encodedSegments.add(segments.get(1).encode()); + } + } + + return String.join(".", encodedSegments); } + public Integer getSaleOptOutNotice() { - return (Integer) this.fields.get(UsCaV1Field.SALE_OPT_OUT_NOTICE).getValue(); + return (Integer) this.getFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE); } public Integer getSensitiveDataLimitUseNotice() { - return (Integer) this.fields.get(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE).getValue(); + return (Integer) this.getFieldValue(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE); } public Integer getSharingOptOutNotice() { - return (Integer) this.fields.get(UsCaV1Field.SHARING_OPT_OUT_NOTICE).getValue(); + return (Integer) this.getFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE); } public Integer getSaleOptOut() { - return (Integer) this.fields.get(UsCaV1Field.SALE_OPT_OUT).getValue(); + return (Integer) this.getFieldValue(UsCaV1Field.SALE_OPT_OUT); } public Integer getSharingOptOut() { - return (Integer) this.fields.get(UsCaV1Field.SHARING_OPT_OUT).getValue(); + return (Integer) this.getFieldValue(UsCaV1Field.SHARING_OPT_OUT); } @SuppressWarnings("unchecked") public List getSensitiveDataProcessing() { - return (List) this.fields.get(UsCaV1Field.SENSITIVE_DATA_PROCESSING).getValue(); + return (List) this.getFieldValue(UsCaV1Field.SENSITIVE_DATA_PROCESSING); } @SuppressWarnings("unchecked") public List getKnownChildSensitiveDataConsents() { - return (List) this.fields.get(UsCaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS).getValue(); + return (List) this.getFieldValue(UsCaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS); } public Integer getPersonalDataConsents() { - return (Integer) this.fields.get(UsCaV1Field.PERSONAL_DATA_CONSENTS).getValue(); + return (Integer) this.getFieldValue(UsCaV1Field.PERSONAL_DATA_CONSENTS); } public Integer getMspaCoveredTransaction() { - return (Integer) this.fields.get(UsCaV1Field.MSPA_COVERED_TRANSACTION).getValue(); + return (Integer) this.getFieldValue(UsCaV1Field.MSPA_COVERED_TRANSACTION); } public Integer getMspaOptOutOptionMode() { - return (Integer) this.fields.get(UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE).getValue(); + return (Integer) this.getFieldValue(UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE); } public Integer getMspaServiceProviderMode() { - return (Integer) this.fields.get(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE).getValue(); + return (Integer) this.getFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE); } public Integer getGpcSegmentType() { - return (Integer) this.fields.get(UsCaV1Field.GPC_SEGMENT_TYPE).getValue(); + return (Integer) this.getFieldValue(UsCaV1Field.GPC_SEGMENT_TYPE); } public Boolean getGpcSegmentIncluded() { - return (Boolean) this.fields.get(UsCaV1Field.GPC_SEGMENT_INCLUDED).getValue(); + return (Boolean) this.getFieldValue(UsCaV1Field.GPC_SEGMENT_INCLUDED); } public Boolean getGpc() { - return (Boolean) this.fields.get(UsCaV1Field.GPC).getValue(); + return (Boolean) this.getFieldValue(UsCaV1Field.GPC); } } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsCoV1.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsCoV1.java index 05b2f9d6..22bd56a6 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsCoV1.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsCoV1.java @@ -1,202 +1,137 @@ package com.iab.gpp.encoder.section; import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; import java.util.List; -import java.util.stream.Collectors; -import com.iab.gpp.encoder.datatype.EncodableBoolean; -import com.iab.gpp.encoder.datatype.EncodableFixedInteger; -import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; -import com.iab.gpp.encoder.datatype.encoder.AbstractBase64UrlEncoder; -import com.iab.gpp.encoder.datatype.encoder.CompressedBase64UrlEncoder; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; -import com.iab.gpp.encoder.field.UsCaV1Field; import com.iab.gpp.encoder.field.UsCoV1Field; -import com.iab.gpp.encoder.field.UspV1Field; +import com.iab.gpp.encoder.segment.EncodableSegment; +import com.iab.gpp.encoder.segment.UsCoV1CoreSegment; +import com.iab.gpp.encoder.segment.UsCoV1GpcSegment; -public class UsCoV1 extends AbstractEncodableSegmentedBitStringSection { +public class UsCoV1 extends AbstractLazilyEncodableSection { + public static int ID = 10; public static int VERSION = 1; public static String NAME = "uscov1"; - private AbstractBase64UrlEncoder base64UrlEncoder = new CompressedBase64UrlEncoder(); - public UsCoV1() { - initFields(); + super(); } - public UsCoV1(String encodedString) throws DecodingException { - initFields(); - - if (encodedString != null && encodedString.length() > 0) { - this.decode(encodedString); - } + public UsCoV1(String encodedString) { + super(); + decode(encodedString); } - private void initFields() { - fields = new HashMap<>(); - - fields.put(UsCoV1Field.VERSION, new EncodableFixedInteger(6, UsCoV1.VERSION)); - fields.put(UsCoV1Field.SHARING_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsCoV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsCoV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0)); - fields.put(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT, new EncodableFixedInteger(2, 0)); - fields.put(UsCoV1Field.SENSITIVE_DATA_PROCESSING, - new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0))); - fields.put(UsCoV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, new EncodableFixedInteger(2, 0)); - fields.put(UsCoV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 0)); - fields.put(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0)); - fields.put(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0)); - - // gpc segment - fields.put(UsCoV1Field.GPC_SEGMENT_TYPE, new EncodableFixedInteger(2, 1)); - fields.put(UsCoV1Field.GPC_SEGMENT_INCLUDED, new EncodableBoolean(true)); - fields.put(UsCoV1Field.GPC, new EncodableBoolean(false)); - - - //@formatter:off - String[] coreSegment = new String[] { - UsCoV1Field.VERSION, - UsCoV1Field.SHARING_NOTICE, - UsCoV1Field.SALE_OPT_OUT_NOTICE, - UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, - UsCoV1Field.SALE_OPT_OUT, - UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT, - UsCoV1Field.SENSITIVE_DATA_PROCESSING, - UsCoV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, - UsCoV1Field.MSPA_COVERED_TRANSACTION, - UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE, - UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE - }; - - String[] gpcSegment = new String[] { - UsCoV1Field.GPC_SEGMENT_TYPE, - UsCoV1Field.GPC - }; - - segments = new String[][] { - coreSegment, - gpcSegment - }; - //@formatter:on + @Override + public int getId() { + return UsCoV1.ID; } @Override - public String encode() throws EncodingException { - List segmentBitStrings = this.encodeSegmentsToBitStrings(); - List encodedSegments = new ArrayList<>(); - if (segmentBitStrings.size() >= 1) { - encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(0))); - - if (segmentBitStrings.size() >= 2) { - Boolean gpcSegmentIncluded = (Boolean) this.fields.get(UsCoV1Field.GPC_SEGMENT_INCLUDED).getValue(); - if (gpcSegmentIncluded) { - encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(1))); - } - } - } - - return encodedSegments.stream().collect(Collectors.joining(".")); + public String getName() { + return UsCoV1.NAME; } @Override - public void decode(String encodedSection) throws DecodingException { - String[] encodedSegments = encodedSection.split("\\."); - String[] segmentBitStrings = new String[2]; - boolean gpcSegmentIncluded = false; - for (int i = 0; i < encodedSegments.length; i++) { - /** - * first char will contain 6 bits, we only need the first 2. There is no segment type for the CORE - * string. Instead the first 6 bits are reserved for the encoding version, but because we're only on - * a maximum of encoding version 2 the first 2 bits in the core segment will evaluate to 0. - */ - String segmentBitString = base64UrlEncoder.decode(encodedSegments[i]); - switch (segmentBitString.substring(0, 2)) { - case "00": { - segmentBitStrings[0] = segmentBitString; - break; - } - case "01": { - gpcSegmentIncluded = true; - segmentBitStrings[1] = segmentBitString; - break; - } - default: { - throw new DecodingException("Unable to decode segment '" + encodedSegments[i] + "'"); - } - } - } - this.decodeSegmentsFromBitStrings(Arrays.asList(segmentBitStrings)); - this.fields.get(UsCaV1Field.GPC_SEGMENT_INCLUDED).setValue(gpcSegmentIncluded); + public int getVersion() { + return UsCoV1.VERSION; } @Override - public int getId() { - return UsCoV1.ID; + protected List initializeSegments() { + List segments = new ArrayList<>(); + segments.add(new UsCoV1CoreSegment()); + segments.add(new UsCoV1GpcSegment()); + return segments; } - + @Override - public String getName() { - return UsCoV1.NAME; + protected List decodeSection(String encodedString) { + List segments = initializeSegments(); + + if(encodedString != null && !encodedString.isEmpty()) { + String[] encodedSegments = encodedString.split("\\."); + + if(encodedSegments.length > 0) { + segments.get(0).decode(encodedSegments[0]); + } + + if(encodedSegments.length > 1) { + segments.get(1).setFieldValue(UsCoV1Field.GPC_SEGMENT_INCLUDED, true); + segments.get(1).decode(encodedSegments[1]); + } else { + segments.get(1).setFieldValue(UsCoV1Field.GPC_SEGMENT_INCLUDED, false); + } + } + + return segments; } - public Integer getVersion() { - return (Integer) this.fields.get(UspV1Field.VERSION).getValue(); + @Override + protected String encodeSection(List segments) { + List encodedSegments = new ArrayList<>(); + + if(!segments.isEmpty()) { + encodedSegments.add(segments.get(0).encode()); + if(segments.size() >= 2 && segments.get(1).getFieldValue(UsCoV1Field.GPC_SEGMENT_INCLUDED).equals(true)) { + encodedSegments.add(segments.get(1).encode()); + } + } + + return String.join(".", encodedSegments); } + public Integer getSharingNotice() { - return (Integer) this.fields.get(UsCoV1Field.SHARING_NOTICE).getValue(); + return (Integer) this.getFieldValue(UsCoV1Field.SHARING_NOTICE); } public Integer getSaleOptOutNotice() { - return (Integer) this.fields.get(UsCoV1Field.SALE_OPT_OUT_NOTICE).getValue(); + return (Integer) this.getFieldValue(UsCoV1Field.SALE_OPT_OUT_NOTICE); } public Integer getTargetedAdvertisingOptOutNotice() { - return (Integer) this.fields.get(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE).getValue(); + return (Integer) this.getFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE); } public Integer getSaleOptOut() { - return (Integer) this.fields.get(UsCoV1Field.SALE_OPT_OUT).getValue(); + return (Integer) this.getFieldValue(UsCoV1Field.SALE_OPT_OUT); } public Integer getTargetedAdvertisingOptOut() { - return (Integer) this.fields.get(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT).getValue(); + return (Integer) this.getFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT); } @SuppressWarnings("unchecked") public List getSensitiveDataProcessing() { - return (List) this.fields.get(UsCoV1Field.SENSITIVE_DATA_PROCESSING).getValue(); + return (List) this.getFieldValue(UsCoV1Field.SENSITIVE_DATA_PROCESSING); } public Integer getKnownChildSensitiveDataConsents() { - return (Integer) this.fields.get(UsCoV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS).getValue(); + return (Integer) this.getFieldValue(UsCoV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS); } public Integer getMspaCoveredTransaction() { - return (Integer) this.fields.get(UsCoV1Field.MSPA_COVERED_TRANSACTION).getValue(); + return (Integer) this.getFieldValue(UsCoV1Field.MSPA_COVERED_TRANSACTION); } public Integer getMspaOptOutOptionMode() { - return (Integer) this.fields.get(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE).getValue(); + return (Integer) this.getFieldValue(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE); } public Integer getMspaServiceProviderMode() { - return (Integer) this.fields.get(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE).getValue(); + return (Integer) this.getFieldValue(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE); } public Integer getGpcSegmentType() { - return (Integer) this.fields.get(UsCoV1Field.GPC_SEGMENT_TYPE).getValue(); + return (Integer) this.getFieldValue(UsCoV1Field.GPC_SEGMENT_TYPE); } public Boolean getGpcSegmentIncluded() { - return (Boolean) this.fields.get(UsCoV1Field.GPC_SEGMENT_INCLUDED).getValue(); + return (Boolean) this.getFieldValue(UsCoV1Field.GPC_SEGMENT_INCLUDED); } public Boolean getGpc() { - return (Boolean) this.fields.get(UsCoV1Field.GPC).getValue(); + return (Boolean) this.getFieldValue(UsCoV1Field.GPC); } } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsCtV1.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsCtV1.java index 9df3e780..2acd3f2f 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsCtV1.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsCtV1.java @@ -1,203 +1,138 @@ package com.iab.gpp.encoder.section; import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; import java.util.List; -import java.util.stream.Collectors; -import com.iab.gpp.encoder.datatype.EncodableBoolean; -import com.iab.gpp.encoder.datatype.EncodableFixedInteger; -import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; -import com.iab.gpp.encoder.datatype.encoder.AbstractBase64UrlEncoder; -import com.iab.gpp.encoder.datatype.encoder.CompressedBase64UrlEncoder; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; -import com.iab.gpp.encoder.field.UsCaV1Field; import com.iab.gpp.encoder.field.UsCtV1Field; -import com.iab.gpp.encoder.field.UspV1Field; +import com.iab.gpp.encoder.segment.EncodableSegment; +import com.iab.gpp.encoder.segment.UsCtV1CoreSegment; +import com.iab.gpp.encoder.segment.UsCtV1GpcSegment; + +public class UsCtV1 extends AbstractLazilyEncodableSection { -public class UsCtV1 extends AbstractEncodableSegmentedBitStringSection { public static int ID = 12; public static int VERSION = 1; public static String NAME = "usctv1"; - private AbstractBase64UrlEncoder base64UrlEncoder = new CompressedBase64UrlEncoder(); - public UsCtV1() { - initFields(); + super(); } - public UsCtV1(String encodedString) throws DecodingException { - initFields(); + public UsCtV1(String encodedString) { + super(); + decode(encodedString); + } - if (encodedString != null && encodedString.length() > 0) { - this.decode(encodedString); - } + @Override + public int getId() { + return UsCtV1.ID; } - private void initFields() { - fields = new HashMap<>(); - - fields.put(UsCtV1Field.VERSION, new EncodableFixedInteger(6, UsCtV1.VERSION)); - fields.put(UsCtV1Field.SHARING_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsCtV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsCtV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0)); - fields.put(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT, new EncodableFixedInteger(2, 0)); - fields.put(UsCtV1Field.SENSITIVE_DATA_PROCESSING, - new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0))); - fields.put(UsCtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, - new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0))); - fields.put(UsCtV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 0)); - fields.put(UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0)); - fields.put(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0)); - - // gpc segment - fields.put(UsCtV1Field.GPC_SEGMENT_TYPE, new EncodableFixedInteger(2, 1)); - fields.put(UsCtV1Field.GPC_SEGMENT_INCLUDED, new EncodableBoolean(true)); - fields.put(UsCtV1Field.GPC, new EncodableBoolean(false)); - - //@formatter:off - String[] coreSegment = new String[] { - UsCtV1Field.VERSION, - UsCtV1Field.SHARING_NOTICE, - UsCtV1Field.SALE_OPT_OUT_NOTICE, - UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, - UsCtV1Field.SALE_OPT_OUT, - UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT, - UsCtV1Field.SENSITIVE_DATA_PROCESSING, - UsCtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, - UsCtV1Field.MSPA_COVERED_TRANSACTION, - UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE, - UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE - }; - - String[] gpcSegment = new String[] { - UsCtV1Field.GPC_SEGMENT_TYPE, - UsCtV1Field.GPC - }; - - segments = new String[][] { - coreSegment, - gpcSegment - }; - //@formatter:on + @Override + public String getName() { + return UsCtV1.NAME; } @Override - public String encode() throws EncodingException { - List segmentBitStrings = this.encodeSegmentsToBitStrings(); - List encodedSegments = new ArrayList<>(); - if (segmentBitStrings.size() >= 1) { - encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(0))); - - if (segmentBitStrings.size() >= 2) { - Boolean gpcSegmentIncluded = (Boolean) this.fields.get(UsCtV1Field.GPC_SEGMENT_INCLUDED).getValue(); - if (gpcSegmentIncluded) { - encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(1))); - } - } - } + public int getVersion() { + return UsCtV1.VERSION; + } - return encodedSegments.stream().collect(Collectors.joining(".")); + @Override + protected List initializeSegments() { + List segments = new ArrayList<>(); + segments.add(new UsCtV1CoreSegment()); + segments.add(new UsCtV1GpcSegment()); + return segments; } @Override - public void decode(String encodedSection) throws DecodingException { - String[] encodedSegments = encodedSection.split("\\."); - String[] segmentBitStrings = new String[2]; - boolean gpcSegmentIncluded = false; - for (int i = 0; i < encodedSegments.length; i++) { - /** - * first char will contain 6 bits, we only need the first 2. There is no segment type for the CORE - * string. Instead the first 6 bits are reserved for the encoding version, but because we're only on - * a maximum of encoding version 2 the first 2 bits in the core segment will evaluate to 0. - */ - String segmentBitString = base64UrlEncoder.decode(encodedSegments[i]); - switch (segmentBitString.substring(0, 2)) { - case "00": { - segmentBitStrings[0] = segmentBitString; - break; - } - case "01": { - gpcSegmentIncluded = true; - segmentBitStrings[1] = segmentBitString; - break; - } - default: { - throw new DecodingException("Unable to decode segment '" + encodedSegments[i] + "'"); - } + protected List decodeSection(String encodedString) { + List segments = initializeSegments(); + + if(encodedString != null && !encodedString.isEmpty()) { + String[] encodedSegments = encodedString.split("\\."); + + if(encodedSegments.length > 0) { + segments.get(0).decode(encodedSegments[0]); + } + + if(encodedSegments.length > 1) { + segments.get(1).setFieldValue(UsCtV1Field.GPC_SEGMENT_INCLUDED, true); + segments.get(1).decode(encodedSegments[1]); + } else { + segments.get(1).setFieldValue(UsCtV1Field.GPC_SEGMENT_INCLUDED, false); } } - this.decodeSegmentsFromBitStrings(Arrays.asList(segmentBitStrings)); - this.fields.get(UsCaV1Field.GPC_SEGMENT_INCLUDED).setValue(gpcSegmentIncluded); - } - @Override - public int getId() { - return UsCtV1.ID; + return segments; } @Override - public String getName() { - return UsCtV1.NAME; + protected String encodeSection(List segments) { + List encodedSegments = new ArrayList<>(); + + if(!segments.isEmpty()) { + encodedSegments.add(segments.get(0).encode()); + if(segments.size() >= 2 && segments.get(1).getFieldValue(UsCtV1Field.GPC_SEGMENT_INCLUDED).equals(true)) { + encodedSegments.add(segments.get(1).encode()); + } + } + + return String.join(".", encodedSegments); } - public Integer getVersion() { - return (Integer) this.fields.get(UspV1Field.VERSION).getValue(); - } public Integer getSharingNotice() { - return (Integer) this.fields.get(UsCtV1Field.SHARING_NOTICE).getValue(); + return (Integer) this.getFieldValue(UsCtV1Field.SHARING_NOTICE); } public Integer getSaleOptOutNotice() { - return (Integer) this.fields.get(UsCtV1Field.SALE_OPT_OUT_NOTICE).getValue(); + return (Integer) this.getFieldValue(UsCtV1Field.SALE_OPT_OUT_NOTICE); } public Integer getTargetedAdvertisingOptOutNotice() { - return (Integer) this.fields.get(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE).getValue(); + return (Integer) this.getFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE); } public Integer getSaleOptOut() { - return (Integer) this.fields.get(UsCtV1Field.SALE_OPT_OUT).getValue(); + return (Integer) this.getFieldValue(UsCtV1Field.SALE_OPT_OUT); } public Integer getTargetedAdvertisingOptOut() { - return (Integer) this.fields.get(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT).getValue(); + return (Integer) this.getFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT); } @SuppressWarnings("unchecked") public List getSensitiveDataProcessing() { - return (List) this.fields.get(UsCtV1Field.SENSITIVE_DATA_PROCESSING).getValue(); + return (List) this.getFieldValue(UsCtV1Field.SENSITIVE_DATA_PROCESSING); } @SuppressWarnings("unchecked") public List getKnownChildSensitiveDataConsents() { - return (List) this.fields.get(UsCtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS).getValue(); + return (List) this.getFieldValue(UsCtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS); } public Integer getMspaCoveredTransaction() { - return (Integer) this.fields.get(UsCtV1Field.MSPA_COVERED_TRANSACTION).getValue(); + return (Integer) this.getFieldValue(UsCtV1Field.MSPA_COVERED_TRANSACTION); } public Integer getMspaOptOutOptionMode() { - return (Integer) this.fields.get(UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE).getValue(); + return (Integer) this.getFieldValue(UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE); } public Integer getMspaServiceProviderMode() { - return (Integer) this.fields.get(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE).getValue(); + return (Integer) this.getFieldValue(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE); } public Integer getGpcSegmentType() { - return (Integer) this.fields.get(UsCtV1Field.GPC_SEGMENT_TYPE).getValue(); + return (Integer) this.getFieldValue(UsCtV1Field.GPC_SEGMENT_TYPE); } public Boolean getGpcSegmentIncluded() { - return (Boolean) this.fields.get(UsCtV1Field.GPC_SEGMENT_INCLUDED).getValue(); + return (Boolean) this.getFieldValue(UsCtV1Field.GPC_SEGMENT_INCLUDED); } public Boolean getGpc() { - return (Boolean) this.fields.get(UsCtV1Field.GPC).getValue(); + return (Boolean) this.getFieldValue(UsCtV1Field.GPC); } } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsNatV1.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsNatV1.java index 6cd943d9..0f0811cf 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsNatV1.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsNatV1.java @@ -1,233 +1,158 @@ package com.iab.gpp.encoder.section; import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; import java.util.List; -import java.util.stream.Collectors; -import com.iab.gpp.encoder.datatype.EncodableBoolean; -import com.iab.gpp.encoder.datatype.EncodableFixedInteger; -import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; -import com.iab.gpp.encoder.datatype.encoder.AbstractBase64UrlEncoder; -import com.iab.gpp.encoder.datatype.encoder.CompressedBase64UrlEncoder; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; -import com.iab.gpp.encoder.field.UsCaV1Field; import com.iab.gpp.encoder.field.UsNatV1Field; -import com.iab.gpp.encoder.field.UspV1Field; +import com.iab.gpp.encoder.segment.EncodableSegment; +import com.iab.gpp.encoder.segment.UsNatV1CoreSegment; +import com.iab.gpp.encoder.segment.UsNatV1GpcSegment; + +public class UsNatV1 extends AbstractLazilyEncodableSection { -public class UsNatV1 extends AbstractEncodableSegmentedBitStringSection { public static int ID = 7; public static int VERSION = 1; public static String NAME = "usnatv1"; - private AbstractBase64UrlEncoder base64UrlEncoder = new CompressedBase64UrlEncoder(); - public UsNatV1() { - initFields(); + super(); } - public UsNatV1(String encodedString) throws DecodingException { - initFields(); + public UsNatV1(String encodedString) { + super(); + decode(encodedString); + } - if (encodedString != null && encodedString.length() > 0) { - this.decode(encodedString); - } + @Override + public int getId() { + return UsNatV1.ID; } - private void initFields() { - fields = new HashMap<>(); - - fields.put(UsNatV1Field.VERSION, new EncodableFixedInteger(6, UsNatV1.VERSION)); - fields.put(UsNatV1Field.SHARING_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.SHARING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.SHARING_OPT_OUT, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.SENSITIVE_DATA_PROCESSING, - new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))); - fields.put(UsNatV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, new EncodableFixedIntegerList(2, Arrays.asList(0, 0))); - fields.put(UsNatV1Field.PERSONAL_DATA_CONSENTS, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0)); - - // gpc segment - fields.put(UsNatV1Field.GPC_SEGMENT_TYPE, new EncodableFixedInteger(2, 1)); - fields.put(UsNatV1Field.GPC_SEGMENT_INCLUDED, new EncodableBoolean(true)); - fields.put(UsNatV1Field.GPC, new EncodableBoolean(false)); - - - //@formatter:off - String[] coreSegment = new String[] { - UsNatV1Field.VERSION, - UsNatV1Field.SHARING_NOTICE, - UsNatV1Field.SALE_OPT_OUT_NOTICE, - UsNatV1Field.SHARING_OPT_OUT_NOTICE, - UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, - UsNatV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE, - UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, - UsNatV1Field.SALE_OPT_OUT, - UsNatV1Field.SHARING_OPT_OUT, - UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT, - UsNatV1Field.SENSITIVE_DATA_PROCESSING, - UsNatV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, - UsNatV1Field.PERSONAL_DATA_CONSENTS, - UsNatV1Field.MSPA_COVERED_TRANSACTION, - UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE, - UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE - }; - - String[] gpcSegment = new String[] { - UsNatV1Field.GPC_SEGMENT_TYPE, - UsNatV1Field.GPC - }; - - segments = new String[][] { - coreSegment, - gpcSegment - }; - //@formatter:on + @Override + public String getName() { + return UsNatV1.NAME; } @Override - public String encode() throws EncodingException { - List segmentBitStrings = this.encodeSegmentsToBitStrings(); - List encodedSegments = new ArrayList<>(); - if (segmentBitStrings.size() >= 1) { - encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(0))); - - if (segmentBitStrings.size() >= 2) { - Boolean gpcSegmentIncluded = (Boolean) this.fields.get(UsNatV1Field.GPC_SEGMENT_INCLUDED).getValue(); - if (gpcSegmentIncluded) { - encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(1))); - } - } - } + public int getVersion() { + return UsNatV1.VERSION; + } - return encodedSegments.stream().collect(Collectors.joining(".")); + @Override + protected List initializeSegments() { + List segments = new ArrayList<>(); + segments.add(new UsNatV1CoreSegment()); + segments.add(new UsNatV1GpcSegment()); + return segments; } @Override - public void decode(String encodedSection) throws DecodingException { - String[] encodedSegments = encodedSection.split("\\."); - String[] segmentBitStrings = new String[2]; - boolean gpcSegmentIncluded = false; - for (int i = 0; i < encodedSegments.length; i++) { - /** - * first char will contain 6 bits, we only need the first 2. There is no segment type for the CORE - * string. Instead the first 6 bits are reserved for the encoding version, but because we're only on - * a maximum of encoding version 2 the first 2 bits in the core segment will evaluate to 0. - */ - String segmentBitString = base64UrlEncoder.decode(encodedSegments[i]); - switch (segmentBitString.substring(0, 2)) { - case "00": { - segmentBitStrings[0] = segmentBitString; - break; - } - case "01": { - gpcSegmentIncluded = true; - segmentBitStrings[1] = segmentBitString; - break; - } - default: { - throw new DecodingException("Unable to decode segment '" + encodedSegments[i] + "'"); - } + protected List decodeSection(String encodedString) { + List segments = initializeSegments(); + + if(encodedString != null && !encodedString.isEmpty()) { + String[] encodedSegments = encodedString.split("\\."); + + if(encodedSegments.length > 0) { + segments.get(0).decode(encodedSegments[0]); + } + + if(encodedSegments.length > 1) { + segments.get(1).setFieldValue(UsNatV1Field.GPC_SEGMENT_INCLUDED, true); + segments.get(1).decode(encodedSegments[1]); + } else { + segments.get(1).setFieldValue(UsNatV1Field.GPC_SEGMENT_INCLUDED, false); } } - this.decodeSegmentsFromBitStrings(Arrays.asList(segmentBitStrings)); - this.fields.get(UsCaV1Field.GPC_SEGMENT_INCLUDED).setValue(gpcSegmentIncluded); - } - @Override - public int getId() { - return UsNatV1.ID; + return segments; } @Override - public String getName() { - return UsNatV1.NAME; + protected String encodeSection(List segments) { + List encodedSegments = new ArrayList<>(); + + if(!segments.isEmpty()) { + encodedSegments.add(segments.get(0).encode()); + if(segments.size() >= 2 && segments.get(1).getFieldValue(UsNatV1Field.GPC_SEGMENT_INCLUDED).equals(true)) { + encodedSegments.add(segments.get(1).encode()); + } + } + + return String.join(".", encodedSegments); } - public Integer getVersion() { - return (Integer) this.fields.get(UspV1Field.VERSION).getValue(); - } public Integer getSharingNotice() { - return (Integer) this.fields.get(UsNatV1Field.SHARING_NOTICE).getValue(); + return (Integer) this.getFieldValue(UsNatV1Field.SHARING_NOTICE); } public Integer getSaleOptOutNotice() { - return (Integer) this.fields.get(UsNatV1Field.SALE_OPT_OUT_NOTICE).getValue(); + return (Integer) this.getFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE); } public Integer getSharingOptOutNotice() { - return (Integer) this.fields.get(UsNatV1Field.SHARING_OPT_OUT_NOTICE).getValue(); + return (Integer) this.getFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE); } public Integer getTargetedAdvertisingOptOutNotice() { - return (Integer) this.fields.get(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE).getValue(); + return (Integer) this.getFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE); } public Integer getSensitiveDataProcessingOptOutNotice() { - return (Integer) this.fields.get(UsNatV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE).getValue(); + return (Integer) this.getFieldValue(UsNatV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE); } public Integer getSensitiveDataLimitUseNotice() { - return (Integer) this.fields.get(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE).getValue(); + return (Integer) this.getFieldValue(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE); } public Integer getSaleOptOut() { - return (Integer) this.fields.get(UsNatV1Field.SALE_OPT_OUT).getValue(); + return (Integer) this.getFieldValue(UsNatV1Field.SALE_OPT_OUT); } public Integer getSharingOptOut() { - return (Integer) this.fields.get(UsNatV1Field.SHARING_OPT_OUT).getValue(); + return (Integer) this.getFieldValue(UsNatV1Field.SHARING_OPT_OUT); } public Integer getTargetedAdvertisingOptOut() { - return (Integer) this.fields.get(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT).getValue(); + return (Integer) this.getFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT); } @SuppressWarnings("unchecked") public List getSensitiveDataProcessing() { - return (List) this.fields.get(UsNatV1Field.SENSITIVE_DATA_PROCESSING).getValue(); + return (List) this.getFieldValue(UsNatV1Field.SENSITIVE_DATA_PROCESSING); } @SuppressWarnings("unchecked") public List getKnownChildSensitiveDataConsents() { - return (List) this.fields.get(UsNatV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS).getValue(); + return (List) this.getFieldValue(UsNatV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS); } public Integer getPersonalDataConsents() { - return (Integer) this.fields.get(UsNatV1Field.PERSONAL_DATA_CONSENTS).getValue(); + return (Integer) this.getFieldValue(UsNatV1Field.PERSONAL_DATA_CONSENTS); } public Integer getMspaCoveredTransaction() { - return (Integer) this.fields.get(UsNatV1Field.MSPA_COVERED_TRANSACTION).getValue(); + return (Integer) this.getFieldValue(UsNatV1Field.MSPA_COVERED_TRANSACTION); } public Integer getMspaOptOutOptionMode() { - return (Integer) this.fields.get(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE).getValue(); + return (Integer) this.getFieldValue(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE); } public Integer getMspaServiceProviderMode() { - return (Integer) this.fields.get(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE).getValue(); + return (Integer) this.getFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE); } public Integer getGpcSegmentType() { - return (Integer) this.fields.get(UsNatV1Field.GPC_SEGMENT_TYPE).getValue(); + return (Integer) this.getFieldValue(UsNatV1Field.GPC_SEGMENT_TYPE); } public Boolean getGpcSegmentIncluded() { - return (Boolean) this.fields.get(UsNatV1Field.GPC_SEGMENT_INCLUDED).getValue(); + return (Boolean) this.getFieldValue(UsNatV1Field.GPC_SEGMENT_INCLUDED); } public Boolean getGpc() { - return (Boolean) this.fields.get(UsNatV1Field.GPC).getValue(); + return (Boolean) this.getFieldValue(UsNatV1Field.GPC); } } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsUtV1.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsUtV1.java index 9bd56c35..a73a0b6f 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsUtV1.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsUtV1.java @@ -1,141 +1,119 @@ package com.iab.gpp.encoder.section; -import java.util.Arrays; -import java.util.HashMap; +import java.util.ArrayList; import java.util.List; -import com.iab.gpp.encoder.datatype.EncodableFixedInteger; -import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; -import com.iab.gpp.encoder.datatype.encoder.AbstractBase64UrlEncoder; -import com.iab.gpp.encoder.datatype.encoder.CompressedBase64UrlEncoder; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; import com.iab.gpp.encoder.field.UsUtV1Field; -import com.iab.gpp.encoder.field.UspV1Field; +import com.iab.gpp.encoder.segment.EncodableSegment; +import com.iab.gpp.encoder.segment.UsUtV1CoreSegment; -public class UsUtV1 extends AbstractEncodableBitStringSection { +public class UsUtV1 extends AbstractLazilyEncodableSection { + public static int ID = 11; public static int VERSION = 1; public static String NAME = "usutv1"; - private AbstractBase64UrlEncoder base64UrlEncoder = new CompressedBase64UrlEncoder(); - public UsUtV1() { - initFields(); + super(); } - public UsUtV1(String encodedString) throws DecodingException { - initFields(); - - if (encodedString != null && encodedString.length() > 0) { - this.decode(encodedString); - } + public UsUtV1(String encodedString) { + super(); + decode(encodedString); } - private void initFields() { - fields = new HashMap<>(); - - fields.put(UsUtV1Field.VERSION, new EncodableFixedInteger(6, UsUtV1.VERSION)); - fields.put(UsUtV1Field.SHARING_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsUtV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsUtV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsUtV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0)); - fields.put(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT, new EncodableFixedInteger(2, 0)); - fields.put(UsUtV1Field.SENSITIVE_DATA_PROCESSING, - new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0))); - fields.put(UsUtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, new EncodableFixedInteger(2, 0)); - fields.put(UsUtV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 0)); - fields.put(UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0)); - fields.put(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0)); - - //@formatter:off - fieldOrder = new String[] { - UsUtV1Field.VERSION, - UsUtV1Field.SHARING_NOTICE, - UsUtV1Field.SALE_OPT_OUT_NOTICE, - UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, - UsUtV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE, - UsUtV1Field.SALE_OPT_OUT, - UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT, - UsUtV1Field.SENSITIVE_DATA_PROCESSING, - UsUtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, - UsUtV1Field.MSPA_COVERED_TRANSACTION, - UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE, - UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE - }; - //@formatter:on + @Override + public int getId() { + return UsUtV1.ID; } @Override - public String encode() throws EncodingException { - String bitString = this.encodeToBitString(); - String encodedString = base64UrlEncoder.encode(bitString); - return encodedString; + public String getName() { + return UsUtV1.NAME; } @Override - public void decode(String encodedString) throws DecodingException { - String bitString = base64UrlEncoder.decode(encodedString); - this.decodeFromBitString(bitString); + public int getVersion() { + return UsUtV1.VERSION; } @Override - public int getId() { - return UsUtV1.ID; + protected List initializeSegments() { + List segments = new ArrayList<>(); + segments.add(new UsUtV1CoreSegment()); + return segments; } - + @Override - public String getName() { - return UsUtV1.NAME; + protected List decodeSection(String encodedString) { + List segments = initializeSegments(); + + if(encodedString != null && !encodedString.isEmpty()) { + String[] encodedSegments = encodedString.split("\\."); + + for(int i=0; i i) { + segments.get(i).decode(encodedSegments[i]); + } + } + } + + return segments; } - public Integer getVersion() { - return (Integer) this.fields.get(UspV1Field.VERSION).getValue(); + @Override + protected String encodeSection(List segments) { + List encodedSegments = new ArrayList<>(); + for(EncodableSegment segment : segments) { + encodedSegments.add(segment.encode()); + } + return String.join(".", encodedSegments); } + public Integer getSharingNotice() { - return (Integer) this.fields.get(UsUtV1Field.SHARING_NOTICE).getValue(); + return (Integer) this.getFieldValue(UsUtV1Field.SHARING_NOTICE); } public Integer getSaleOptOutNotice() { - return (Integer) this.fields.get(UsUtV1Field.SALE_OPT_OUT_NOTICE).getValue(); + return (Integer) this.getFieldValue(UsUtV1Field.SALE_OPT_OUT_NOTICE); } public Integer getTargetedAdvertisingOptOutNotice() { - return (Integer) this.fields.get(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE).getValue(); + return (Integer) this.getFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE); } public Integer getSensitiveDataProcessingOptOutNotice() { - return (Integer) this.fields.get(UsUtV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE).getValue(); + return (Integer) this.getFieldValue(UsUtV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE); } public Integer getSaleOptOut() { - return (Integer) this.fields.get(UsUtV1Field.SALE_OPT_OUT).getValue(); + return (Integer) this.getFieldValue(UsUtV1Field.SALE_OPT_OUT); } public Integer getTargetedAdvertisingOptOut() { - return (Integer) this.fields.get(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT).getValue(); + return (Integer) this.getFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT); } @SuppressWarnings("unchecked") public List getSensitiveDataProcessing() { - return (List) this.fields.get(UsUtV1Field.SENSITIVE_DATA_PROCESSING).getValue(); + return (List) this.getFieldValue(UsUtV1Field.SENSITIVE_DATA_PROCESSING); } public Integer getKnownChildSensitiveDataConsents() { - return (Integer) this.fields.get(UsUtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS).getValue(); + return (Integer) this.getFieldValue(UsUtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS); } public Integer getMspaCoveredTransaction() { - return (Integer) this.fields.get(UsUtV1Field.MSPA_COVERED_TRANSACTION).getValue(); + return (Integer) this.getFieldValue(UsUtV1Field.MSPA_COVERED_TRANSACTION); } public Integer getMspaOptOutOptionMode() { - return (Integer) this.fields.get(UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE).getValue(); + return (Integer) this.getFieldValue(UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE); } public Integer getMspaServiceProviderMode() { - return (Integer) this.fields.get(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE).getValue(); + return (Integer) this.getFieldValue(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE); } - + + } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsVaV1.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsVaV1.java index fdd48f49..6695b943 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsVaV1.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsVaV1.java @@ -1,135 +1,113 @@ package com.iab.gpp.encoder.section; -import java.util.Arrays; -import java.util.HashMap; +import java.util.ArrayList; import java.util.List; -import com.iab.gpp.encoder.datatype.EncodableFixedInteger; -import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; -import com.iab.gpp.encoder.datatype.encoder.AbstractBase64UrlEncoder; -import com.iab.gpp.encoder.datatype.encoder.CompressedBase64UrlEncoder; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; -import com.iab.gpp.encoder.field.UspV1Field; import com.iab.gpp.encoder.field.UsVaV1Field; +import com.iab.gpp.encoder.segment.EncodableSegment; +import com.iab.gpp.encoder.segment.UsVaV1CoreSegment; + +public class UsVaV1 extends AbstractLazilyEncodableSection { -public class UsVaV1 extends AbstractEncodableBitStringSection { public static int ID = 9; public static int VERSION = 1; public static String NAME = "usvav1"; - private AbstractBase64UrlEncoder base64UrlEncoder = new CompressedBase64UrlEncoder(); - public UsVaV1() { - initFields(); + super(); } - public UsVaV1(String encodedString) throws DecodingException { - initFields(); - - if (encodedString != null && encodedString.length() > 0) { - this.decode(encodedString); - } + public UsVaV1(String encodedString) { + super(); + decode(encodedString); } - private void initFields() { - fields = new HashMap<>(); - - fields.put(UsVaV1Field.VERSION, new EncodableFixedInteger(6, UsVaV1.VERSION)); - fields.put(UsVaV1Field.SHARING_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsVaV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsVaV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0)); - fields.put(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT, new EncodableFixedInteger(2, 0)); - fields.put(UsVaV1Field.SENSITIVE_DATA_PROCESSING, - new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0))); - fields.put(UsVaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, new EncodableFixedInteger(2, 0)); - fields.put(UsVaV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 0)); - fields.put(UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0)); - fields.put(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0)); - - //@formatter:off - fieldOrder = new String[] { - UsVaV1Field.VERSION, - UsVaV1Field.SHARING_NOTICE, - UsVaV1Field.SALE_OPT_OUT_NOTICE, - UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, - UsVaV1Field.SALE_OPT_OUT, - UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT, - UsVaV1Field.SENSITIVE_DATA_PROCESSING, - UsVaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, - UsVaV1Field.MSPA_COVERED_TRANSACTION, - UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE, - UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE - }; - //@formatter:on + @Override + public int getId() { + return UsVaV1.ID; } @Override - public String encode() throws EncodingException { - String bitString = this.encodeToBitString(); - String encodedString = base64UrlEncoder.encode(bitString); - return encodedString; + public String getName() { + return UsVaV1.NAME; } @Override - public void decode(String encodedString) throws DecodingException { - String bitString = base64UrlEncoder.decode(encodedString); - this.decodeFromBitString(bitString); + public int getVersion() { + return UsVaV1.VERSION; } @Override - public int getId() { - return UsVaV1.ID; + protected List initializeSegments() { + List segments = new ArrayList<>(); + segments.add(new UsVaV1CoreSegment()); + return segments; } @Override - public String getName() { - return UsVaV1.NAME; + protected List decodeSection(String encodedString) { + List segments = initializeSegments(); + + if(encodedString != null && !encodedString.isEmpty()) { + String[] encodedSegments = encodedString.split("\\."); + + for (int i = 0; i < segments.size(); i++) { + if (encodedSegments.length > i) { + segments.get(i).decode(encodedSegments[i]); + } + } + } + + return segments; } - public Integer getVersion() { - return (Integer) this.fields.get(UspV1Field.VERSION).getValue(); + @Override + protected String encodeSection(List segments) { + List encodedSegments = new ArrayList<>(); + for (EncodableSegment segment : segments) { + encodedSegments.add(segment.encode()); + } + return String.join(".", encodedSegments); } + public Integer getSharingNotice() { - return (Integer) this.fields.get(UsVaV1Field.SHARING_NOTICE).getValue(); + return (Integer) this.getFieldValue(UsVaV1Field.SHARING_NOTICE); } public Integer getSaleOptOutNotice() { - return (Integer) this.fields.get(UsVaV1Field.SALE_OPT_OUT_NOTICE).getValue(); + return (Integer) this.getFieldValue(UsVaV1Field.SALE_OPT_OUT_NOTICE); } public Integer getTargetedAdvertisingOptOutNotice() { - return (Integer) this.fields.get(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE).getValue(); + return (Integer) this.getFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE); } public Integer getSaleOptOut() { - return (Integer) this.fields.get(UsVaV1Field.SALE_OPT_OUT).getValue(); + return (Integer) this.getFieldValue(UsVaV1Field.SALE_OPT_OUT); } public Integer getTargetedAdvertisingOptOut() { - return (Integer) this.fields.get(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT).getValue(); + return (Integer) this.getFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT); } @SuppressWarnings("unchecked") public List getSensitiveDataProcessing() { - return (List) this.fields.get(UsVaV1Field.SENSITIVE_DATA_PROCESSING).getValue(); + return (List) this.getFieldValue(UsVaV1Field.SENSITIVE_DATA_PROCESSING); } public Integer getKnownChildSensitiveDataConsents() { - return (Integer) this.fields.get(UsVaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS).getValue(); + return (Integer) this.getFieldValue(UsVaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS); } public Integer getMspaCoveredTransaction() { - return (Integer) this.fields.get(UsVaV1Field.MSPA_COVERED_TRANSACTION).getValue(); + return (Integer) this.getFieldValue(UsVaV1Field.MSPA_COVERED_TRANSACTION); } public Integer getMspaOptOutOptionMode() { - return (Integer) this.fields.get(UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE).getValue(); + return (Integer) this.getFieldValue(UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE); } public Integer getMspaServiceProviderMode() { - return (Integer) this.fields.get(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE).getValue(); + return (Integer) this.getFieldValue(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE); } - } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UspV1.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UspV1.java index cdb20122..e70261e4 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UspV1.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UspV1.java @@ -1,107 +1,84 @@ package com.iab.gpp.encoder.section; -import java.util.HashMap; -import java.util.Map; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; -import com.iab.gpp.encoder.error.InvalidFieldException; -import com.iab.gpp.encoder.field.UspV1LegacyField; - -public class UspV1 implements EncodableSection { +import java.util.ArrayList; +import java.util.List; +import com.iab.gpp.encoder.field.UspV1Field; +import com.iab.gpp.encoder.segment.EncodableSegment; +import com.iab.gpp.encoder.segment.UspV1CoreSegment; + +public class UspV1 extends AbstractLazilyEncodableSection { + public static int ID = 6; public static int VERSION = 1; public static String NAME = "uspv1"; - protected Map fields; - public UspV1() { - initFields(); - } - - public UspV1(String encodedString) throws DecodingException { - initFields(); - - if (encodedString != null && encodedString.length() > 0) { - this.decode(encodedString); - } + super(); } - private void initFields() { - fields = new HashMap<>(); - fields.put(UspV1LegacyField.VERSION, UspV1.VERSION); - fields.put(UspV1LegacyField.NOTICE, "-"); - fields.put(UspV1LegacyField.OPT_OUT_SALE, "-"); - fields.put(UspV1LegacyField.LSPA_COVERED, "-"); + public UspV1(String encodedString) { + super(); + decode(encodedString); } @Override - public boolean hasField(String fieldName) { - return this.fields.containsKey(fieldName); + public int getId() { + return UspV1.ID; } @Override - public Object getFieldValue(String fieldName) { - if (this.fields.containsKey(fieldName)) { - return this.fields.get(fieldName); - } else { - return null; - } + public String getName() { + return UspV1.NAME; } @Override - public void setFieldValue(String fieldName, Object value) throws InvalidFieldException { - if (this.fields.containsKey(fieldName)) { - this.fields.put(fieldName, value); - } else { - throw new InvalidFieldException(fieldName + " not found"); - } + public int getVersion() { + return UspV1.VERSION; } @Override - public String encode() throws EncodingException { - String str = ""; - str += this.getFieldValue(UspV1LegacyField.VERSION); - str += this.getFieldValue(UspV1LegacyField.NOTICE); - str += this.getFieldValue(UspV1LegacyField.OPT_OUT_SALE); - str += this.getFieldValue(UspV1LegacyField.LSPA_COVERED); - return str; + protected List initializeSegments() { + List segments = new ArrayList<>(); + segments.add(new UspV1CoreSegment()); + return segments; } - + @Override - public void decode(String encodedString) throws DecodingException { - try { - this.setFieldValue(UspV1LegacyField.VERSION, Integer.parseInt(String.valueOf(encodedString.charAt(0)))); - this.setFieldValue(UspV1LegacyField.NOTICE, String.valueOf(encodedString.charAt(1))); - this.setFieldValue(UspV1LegacyField.OPT_OUT_SALE, String.valueOf(encodedString.charAt(2))); - this.setFieldValue(UspV1LegacyField.LSPA_COVERED, String.valueOf(encodedString.charAt(3))); - } catch (InvalidFieldException e) { - throw new DecodingException(e); + protected List decodeSection(String encodedString) { + List segments = initializeSegments(); + + if(encodedString != null && !encodedString.isEmpty()) { + String[] encodedSegments = encodedString.split("\\."); + + for(int i=0; i i) { + segments.get(i).decode(encodedSegments[i]); + } + } } + + return segments; } @Override - public int getId() { - return UspV1.ID; - } - - @Override - public String getName() { - return UspV1.NAME; - } - - public Integer getVersion() { - return (Integer) this.fields.get(UspV1LegacyField.VERSION); + protected String encodeSection(List segments) { + List encodedSegments = new ArrayList<>(); + for(EncodableSegment segment : segments) { + encodedSegments.add(segment.encode()); + } + return String.join(".", encodedSegments); } - public String getNotice() { - return (String) fields.get(UspV1LegacyField.NOTICE); + + public Character getNotice() { + return (Character) this.getFieldValue(UspV1Field.NOTICE); } - public String getOptOutSale() { - return (String) fields.get(UspV1LegacyField.OPT_OUT_SALE); + public Character getOptOutSale() { + return (Character) this.getFieldValue(UspV1Field.OPT_OUT_SALE); } - public String getLspaCovered() { - return (String) fields.get(UspV1LegacyField.LSPA_COVERED); + public Character getLspaCovered() { + return (Character) this.getFieldValue(UspV1Field.LSPA_COVERED); } } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/AbstractLazilyEncodableSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/AbstractLazilyEncodableSegment.java new file mode 100644 index 00000000..8726e16d --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/AbstractLazilyEncodableSegment.java @@ -0,0 +1,76 @@ +package com.iab.gpp.encoder.segment; + +import com.iab.gpp.encoder.error.InvalidFieldException; +import com.iab.gpp.encoder.field.Fields; + +public abstract class AbstractLazilyEncodableSegment> implements EncodableSegment { + + protected T fields; + + private String encodedString = null; + + private boolean dirty = false; + private boolean decoded = true; + + public AbstractLazilyEncodableSegment() { + this.fields = initializeFields(); + } + + protected abstract T initializeFields(); + + protected abstract String encodeSegment(T fields); + + protected abstract void decodeSegment(String encodedString, T Fields); + + public boolean hasField(String fieldName) { + return this.fields.containsKey(fieldName); + } + + public Object getFieldValue(String fieldName) { + if (!this.decoded) { + this.decodeSegment(this.encodedString, this.fields); + this.dirty = false; + this.decoded = true; + } + + if (this.fields.containsKey(fieldName)) { + return this.fields.get(fieldName).getValue(); + } else { + throw new InvalidFieldException("Invalid field: '" + fieldName + "'"); + } + } + + public void setFieldValue(String fieldName, Object value) { + if (!this.decoded) { + this.decodeSegment(this.encodedString, this.fields); + this.dirty = false; + this.decoded = true; + } + + if (this.fields.containsKey(fieldName)) { + this.fields.get(fieldName).setValue(value); + this.dirty = true; + } else { + throw new InvalidFieldException(fieldName + " not found"); + } + } + + public String encode() { + if (this.encodedString == null || this.encodedString.isEmpty() || this.dirty) { + this.validate(); + this.encodedString = encodeSegment(this.fields); + this.dirty = false; + this.decoded = true; + } + + return this.encodedString; + } + + public void decode(String encodedString) { + this.encodedString = encodedString; + this.dirty = false; + this.decoded = false; + } + + +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/EncodableSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/EncodableSegment.java new file mode 100644 index 00000000..d2363a82 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/EncodableSegment.java @@ -0,0 +1,20 @@ +package com.iab.gpp.encoder.segment; + +import java.util.List; + +public interface EncodableSegment { + + List getFieldNames(); + + boolean hasField(String fieldName); + + Object getFieldValue(String fieldName); + + void setFieldValue(String fieldName, Object value); + + String encode(); + + void decode(String encodedString); + + default void validate() {}; +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/HeaderV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/HeaderV1CoreSegment.java new file mode 100644 index 00000000..5f944d90 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/HeaderV1CoreSegment.java @@ -0,0 +1,63 @@ +package com.iab.gpp.encoder.segment; + +import java.util.ArrayList; +import java.util.List; +import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; +import com.iab.gpp.encoder.bitstring.BitStringEncoder; +import com.iab.gpp.encoder.datatype.EncodableFibonacciIntegerRange; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.field.EncodableBitStringFields; +import com.iab.gpp.encoder.field.HeaderV1Field; +import com.iab.gpp.encoder.section.HeaderV1; + +public class HeaderV1CoreSegment extends AbstractLazilyEncodableSegment { + + private AbstractBase64UrlEncoder base64UrlEncoder = CompressedBase64UrlEncoder.getInstance(); + private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); + + public HeaderV1CoreSegment() { + super(); + } + + public HeaderV1CoreSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return HeaderV1Field.HEADER_CORE_SEGMENT_FIELD_NAMES; + } + + @Override + protected EncodableBitStringFields initializeFields() { + EncodableBitStringFields fields = new EncodableBitStringFields(); + fields.put(HeaderV1Field.ID, new EncodableFixedInteger(6, HeaderV1.ID)); + fields.put(HeaderV1Field.VERSION, new EncodableFixedInteger(6, HeaderV1.VERSION)); + fields.put(HeaderV1Field.SECTION_IDS, new EncodableFibonacciIntegerRange(new ArrayList<>())); + return fields; + } + + @Override + protected String encodeSegment(EncodableBitStringFields fields) { + String bitString = bitStringEncoder.encode(fields, getFieldNames()); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { + if(encodedString == null || encodedString.isEmpty()) { + this.fields.reset(fields); + } + try { + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } catch (Exception e) { + throw new DecodingException("Unable to decode HeaderV1CoreSegment '" + encodedString + "'", e); + } + } + +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfCaV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfCaV1CoreSegment.java new file mode 100644 index 00000000..fbdc9479 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfCaV1CoreSegment.java @@ -0,0 +1,89 @@ +package com.iab.gpp.encoder.segment; + +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; +import com.iab.gpp.encoder.bitstring.BitStringEncoder; +import com.iab.gpp.encoder.datatype.EncodableArrayOfFixedIntegerRanges; +import com.iab.gpp.encoder.datatype.EncodableBoolean; +import com.iab.gpp.encoder.datatype.EncodableDatetime; +import com.iab.gpp.encoder.datatype.EncodableFixedBitfield; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.datatype.EncodableFixedString; +import com.iab.gpp.encoder.datatype.EncodableOptimizedFixedRange; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.field.EncodableBitStringFields; +import com.iab.gpp.encoder.field.TcfCaV1Field; +import com.iab.gpp.encoder.section.TcfCaV1; + +public class TcfCaV1CoreSegment extends AbstractLazilyEncodableSegment { + + private AbstractBase64UrlEncoder base64UrlEncoder = CompressedBase64UrlEncoder.getInstance(); + private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); + + public TcfCaV1CoreSegment() { + super(); + } + + public TcfCaV1CoreSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return TcfCaV1Field.TCFCAV1_CORE_SEGMENT_FIELD_NAMES; + } + + @Override + protected EncodableBitStringFields initializeFields() { + ZonedDateTime date = ZonedDateTime.now(); + + EncodableBitStringFields fields = new EncodableBitStringFields(); + fields.put(TcfCaV1Field.VERSION, new EncodableFixedInteger(6, TcfCaV1.VERSION)); + fields.put(TcfCaV1Field.CREATED, new EncodableDatetime(date)); + fields.put(TcfCaV1Field.LAST_UPDATED, new EncodableDatetime(date)); + fields.put(TcfCaV1Field.CMP_ID, new EncodableFixedInteger(12, 0)); + fields.put(TcfCaV1Field.CMP_VERSION, new EncodableFixedInteger(12, 0)); + fields.put(TcfCaV1Field.CONSENT_SCREEN, new EncodableFixedInteger(6, 0)); + fields.put(TcfCaV1Field.CONSENT_LANGUAGE, new EncodableFixedString(2, "EN")); + fields.put(TcfCaV1Field.VENDOR_LIST_VERSION, new EncodableFixedInteger(12, 0)); + fields.put(TcfCaV1Field.TCF_POLICY_VERSION, new EncodableFixedInteger(6, 2)); + fields.put(TcfCaV1Field.USE_NON_STANDARD_STACKS, new EncodableBoolean(false)); + fields.put(TcfCaV1Field.SPECIAL_FEATURE_EXPRESS_CONSENT, new EncodableFixedBitfield( + Arrays.asList(false, false, false, false, false, false, false, false, false, false, false, false))); + fields.put(TcfCaV1Field.PURPOSES_EXPRESS_CONSENT, + new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, false, false, false))); + fields.put(TcfCaV1Field.PURPOSES_IMPLIED_CONSENT, + new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, false, false, false))); + fields.put(TcfCaV1Field.VENDOR_EXPRESS_CONSENT, new EncodableOptimizedFixedRange(new ArrayList<>())); + fields.put(TcfCaV1Field.VENDOR_IMPLIED_CONSENT, new EncodableOptimizedFixedRange(new ArrayList<>())); + fields.put(TcfCaV1Field.PUB_RESTRICTIONS, new EncodableArrayOfFixedIntegerRanges(6, 2, new ArrayList<>(), false)); + return fields; + } + + @Override + protected String encodeSegment(EncodableBitStringFields fields) { + String bitString = bitStringEncoder.encode(fields, getFieldNames()); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { + if(encodedString == null || encodedString.isEmpty()) { + this.fields.reset(fields); + } + try { + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } catch (Exception e) { + throw new DecodingException("Unable to decode TcfCaV1CoreSegment '" + encodedString + "'", e); + } + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfCaV1DisclosedVendorsSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfCaV1DisclosedVendorsSegment.java new file mode 100644 index 00000000..cbd7e90f --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfCaV1DisclosedVendorsSegment.java @@ -0,0 +1,60 @@ +package com.iab.gpp.encoder.segment; + +import java.util.ArrayList; +import java.util.List; +import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; +import com.iab.gpp.encoder.bitstring.BitStringEncoder; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.datatype.EncodableOptimizedFixedRange; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.field.EncodableBitStringFields; +import com.iab.gpp.encoder.field.TcfCaV1Field; + +public class TcfCaV1DisclosedVendorsSegment extends AbstractLazilyEncodableSegment { + + private AbstractBase64UrlEncoder base64UrlEncoder = CompressedBase64UrlEncoder.getInstance(); + private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); + + public TcfCaV1DisclosedVendorsSegment() { + super(); + } + + public TcfCaV1DisclosedVendorsSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return TcfCaV1Field.TCFCAV1_DISCLOSED_VENDORS_SEGMENT_FIELD_NAMES; + } + + @Override + protected EncodableBitStringFields initializeFields() { + EncodableBitStringFields fields = new EncodableBitStringFields(); + fields.put(TcfCaV1Field.DISCLOSED_VENDORS_SEGMENT_TYPE, new EncodableFixedInteger(3, 1)); + fields.put(TcfCaV1Field.DISCLOSED_VENDORS, new EncodableOptimizedFixedRange(new ArrayList<>())); + return fields; + } + + @Override + protected String encodeSegment(EncodableBitStringFields fields) { + String bitString = bitStringEncoder.encode(fields, getFieldNames()); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { + if (encodedString == null || encodedString.isEmpty()) { + this.fields.reset(fields); + } + try { + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } catch (Exception e) { + throw new DecodingException("Unable to decode TcfCaV1DisclosedVendorsSegment '" + encodedString + "'", e); + } + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfCaV1PublisherPurposesSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfCaV1PublisherPurposesSegment.java new file mode 100644 index 00000000..1ab89c0b --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfCaV1PublisherPurposesSegment.java @@ -0,0 +1,86 @@ +package com.iab.gpp.encoder.segment; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.function.IntSupplier; +import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; +import com.iab.gpp.encoder.bitstring.BitStringEncoder; +import com.iab.gpp.encoder.datatype.EncodableFixedBitfield; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.datatype.EncodableFlexibleBitfield; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.field.EncodableBitStringFields; +import com.iab.gpp.encoder.field.TcfCaV1Field; + +public class TcfCaV1PublisherPurposesSegment extends AbstractLazilyEncodableSegment { + + private AbstractBase64UrlEncoder base64UrlEncoder = CompressedBase64UrlEncoder.getInstance(); + private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); + + public TcfCaV1PublisherPurposesSegment() { + super(); + } + + public TcfCaV1PublisherPurposesSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return TcfCaV1Field.TCFCAV1_PUBLISHER_PURPOSES_SEGMENT_FIELD_NAMES; + } + + @Override + protected EncodableBitStringFields initializeFields() { + EncodableBitStringFields fields = new EncodableBitStringFields(); + fields.put(TcfCaV1Field.PUB_PURPOSES_SEGMENT_TYPE, new EncodableFixedInteger(3, 3)); + fields.put(TcfCaV1Field.PUB_PURPOSES_EXPRESS_CONSENT, + new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, false, false, false))); + fields.put(TcfCaV1Field.PUB_PURPOSES_IMPLIED_CONSENT, + new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, false, false, false))); + + EncodableFixedInteger numCustomPurposes = new EncodableFixedInteger(6, 0); + fields.put(TcfCaV1Field.NUM_CUSTOM_PURPOSES, numCustomPurposes); + + IntSupplier getLengthSupplier = new IntSupplier() { + + @Override + public int getAsInt() { + return numCustomPurposes.getValue(); + } + + }; + + fields.put(TcfCaV1Field.CUSTOM_PURPOSES_EXPRESS_CONSENT, + new EncodableFlexibleBitfield(getLengthSupplier, new ArrayList<>())); + + fields.put(TcfCaV1Field.CUSTOM_PURPOSES_IMPLIED_CONSENT, + new EncodableFlexibleBitfield(getLengthSupplier, new ArrayList<>())); + return fields; + } + + @Override + protected String encodeSegment(EncodableBitStringFields fields) { + String bitString = bitStringEncoder.encode(fields, getFieldNames()); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { + if(encodedString == null || encodedString.isEmpty()) { + this.fields.reset(fields); + } + try { + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } catch (Exception e) { + throw new DecodingException("Unable to decode TcfCaV1PublisherPurposesSegment '" + encodedString + "'", e); + } + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfEuV2CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfEuV2CoreSegment.java new file mode 100644 index 00000000..5b516bde --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfEuV2CoreSegment.java @@ -0,0 +1,93 @@ +package com.iab.gpp.encoder.segment; + +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.base64.TraditionalBase64UrlEncoder; +import com.iab.gpp.encoder.bitstring.BitStringEncoder; +import com.iab.gpp.encoder.datatype.EncodableArrayOfFixedIntegerRanges; +import com.iab.gpp.encoder.datatype.EncodableBoolean; +import com.iab.gpp.encoder.datatype.EncodableDatetime; +import com.iab.gpp.encoder.datatype.EncodableFixedBitfield; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.datatype.EncodableFixedString; +import com.iab.gpp.encoder.datatype.EncodableOptimizedFixedRange; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.field.EncodableBitStringFields; +import com.iab.gpp.encoder.field.TcfEuV2Field; +import com.iab.gpp.encoder.section.TcfEuV2; + +public class TcfEuV2CoreSegment extends AbstractLazilyEncodableSegment { + + private AbstractBase64UrlEncoder base64UrlEncoder = TraditionalBase64UrlEncoder.getInstance(); + private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); + + public TcfEuV2CoreSegment() { + super(); + } + + public TcfEuV2CoreSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return TcfEuV2Field.TCFEUV2_CORE_SEGMENT_FIELD_NAMES; + } + + @Override + protected EncodableBitStringFields initializeFields() { + ZonedDateTime date = ZonedDateTime.now(); + + EncodableBitStringFields fields = new EncodableBitStringFields(); + fields.put(TcfEuV2Field.VERSION, new EncodableFixedInteger(6, TcfEuV2.VERSION)); + fields.put(TcfEuV2Field.CREATED, new EncodableDatetime(date)); + fields.put(TcfEuV2Field.LAST_UPDATED, new EncodableDatetime(date)); + fields.put(TcfEuV2Field.CMP_ID, new EncodableFixedInteger(12, 0)); + fields.put(TcfEuV2Field.CMP_VERSION, new EncodableFixedInteger(12, 0)); + fields.put(TcfEuV2Field.CONSENT_SCREEN, new EncodableFixedInteger(6, 0)); + fields.put(TcfEuV2Field.CONSENT_LANGUAGE, new EncodableFixedString(2, "EN")); + fields.put(TcfEuV2Field.VENDOR_LIST_VERSION, new EncodableFixedInteger(12, 0)); + fields.put(TcfEuV2Field.POLICY_VERSION, new EncodableFixedInteger(6, 2)); + fields.put(TcfEuV2Field.IS_SERVICE_SPECIFIC, new EncodableBoolean(false)); + fields.put(TcfEuV2Field.USE_NON_STANDARD_STACKS, new EncodableBoolean(false)); + fields.put(TcfEuV2Field.SPECIAL_FEATURE_OPTINS, new EncodableFixedBitfield( + Arrays.asList(false, false, false, false, false, false, false, false, false, false, false, false))); + fields.put(TcfEuV2Field.PURPOSE_CONSENTS, + new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, false, false, false))); + fields.put(TcfEuV2Field.PURPOSE_LEGITIMATE_INTERESTS, + new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, false, false, false))); + fields.put(TcfEuV2Field.PURPOSE_ONE_TREATMENT, new EncodableBoolean(false)); + fields.put(TcfEuV2Field.PUBLISHER_COUNTRY_CODE, new EncodableFixedString(2, "AA")); + fields.put(TcfEuV2Field.VENDOR_CONSENTS, new EncodableOptimizedFixedRange(new ArrayList<>())); + fields.put(TcfEuV2Field.VENDOR_LEGITIMATE_INTERESTS, new EncodableOptimizedFixedRange(new ArrayList<>())); + + fields.put(TcfEuV2Field.PUBLISHER_RESTRICTIONS, new EncodableArrayOfFixedIntegerRanges(6, 2, new ArrayList<>(), false)); + return fields; + } + + @Override + protected String encodeSegment(EncodableBitStringFields fields) { + String bitString = bitStringEncoder.encode(fields, getFieldNames()); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { + if(encodedString == null || encodedString.isEmpty()) { + this.fields.reset(fields); + } + try { + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } catch (Exception e) { + throw new DecodingException("Unable to decode TcfEuV2CoreSegment '" + encodedString + "'", e); + } + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfEuV2PublisherPurposesSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfEuV2PublisherPurposesSegment.java new file mode 100644 index 00000000..0b751017 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfEuV2PublisherPurposesSegment.java @@ -0,0 +1,86 @@ +package com.iab.gpp.encoder.segment; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.function.IntSupplier; +import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.base64.TraditionalBase64UrlEncoder; +import com.iab.gpp.encoder.bitstring.BitStringEncoder; +import com.iab.gpp.encoder.datatype.EncodableFixedBitfield; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.datatype.EncodableFlexibleBitfield; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.field.EncodableBitStringFields; +import com.iab.gpp.encoder.field.TcfEuV2Field; + +public class TcfEuV2PublisherPurposesSegment extends AbstractLazilyEncodableSegment { + + private AbstractBase64UrlEncoder base64UrlEncoder = TraditionalBase64UrlEncoder.getInstance(); + private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); + + public TcfEuV2PublisherPurposesSegment() { + super(); + } + + public TcfEuV2PublisherPurposesSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return TcfEuV2Field.TCFEUV2_PUBLISHER_PURPOSES_SEGMENT_FIELD_NAMES; + } + + @Override + protected EncodableBitStringFields initializeFields() { + EncodableBitStringFields fields = new EncodableBitStringFields(); + fields.put(TcfEuV2Field.PUBLISHER_PURPOSES_SEGMENT_TYPE, new EncodableFixedInteger(3, 3)); + fields.put(TcfEuV2Field.PUBLISHER_CONSENTS, + new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, false, false, false))); + fields.put(TcfEuV2Field.PUBLISHER_LEGITIMATE_INTERESTS, + new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, false, false, false))); + + EncodableFixedInteger numCustomPurposes = new EncodableFixedInteger(6, 0); + fields.put(TcfEuV2Field.NUM_CUSTOM_PURPOSES, numCustomPurposes); + + IntSupplier getLengthSupplier = new IntSupplier() { + + @Override + public int getAsInt() { + return numCustomPurposes.getValue(); + } + + }; + + fields.put(TcfEuV2Field.PUBLISHER_CUSTOM_CONSENTS, + new EncodableFlexibleBitfield(getLengthSupplier, new ArrayList<>())); + + fields.put(TcfEuV2Field.PUBLISHER_CUSTOM_LEGITIMATE_INTERESTS, + new EncodableFlexibleBitfield(getLengthSupplier, new ArrayList<>())); + return fields; + } + + @Override + protected String encodeSegment(EncodableBitStringFields fields) { + String bitString = bitStringEncoder.encode(fields, getFieldNames()); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { + if(encodedString == null || encodedString.isEmpty()) { + this.fields.reset(fields); + } + try { + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } catch (Exception e) { + throw new DecodingException("Unable to decode TcfEuV2PublisherPurposesSegment '" + encodedString + "'", e); + } + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfEuV2VendorsAllowedSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfEuV2VendorsAllowedSegment.java new file mode 100644 index 00000000..e09b48bb --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfEuV2VendorsAllowedSegment.java @@ -0,0 +1,60 @@ +package com.iab.gpp.encoder.segment; + +import java.util.ArrayList; +import java.util.List; +import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.base64.TraditionalBase64UrlEncoder; +import com.iab.gpp.encoder.bitstring.BitStringEncoder; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.datatype.EncodableOptimizedFixedRange; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.field.EncodableBitStringFields; +import com.iab.gpp.encoder.field.TcfEuV2Field; + +public class TcfEuV2VendorsAllowedSegment extends AbstractLazilyEncodableSegment { + + private AbstractBase64UrlEncoder base64UrlEncoder = TraditionalBase64UrlEncoder.getInstance(); + private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); + + public TcfEuV2VendorsAllowedSegment() { + super(); + } + + public TcfEuV2VendorsAllowedSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return TcfEuV2Field.TCFEUV2_VENDORS_ALLOWED_SEGMENT_FIELD_NAMES; + } + + @Override + protected EncodableBitStringFields initializeFields() { + EncodableBitStringFields fields = new EncodableBitStringFields(); + fields.put(TcfEuV2Field.VENDORS_ALLOWED_SEGMENT_TYPE, new EncodableFixedInteger(3, 2)); + fields.put(TcfEuV2Field.VENDORS_ALLOWED, new EncodableOptimizedFixedRange(new ArrayList<>())); + return fields; + } + + @Override + protected String encodeSegment(EncodableBitStringFields fields) { + String bitString = bitStringEncoder.encode(fields, getFieldNames()); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { + if(encodedString == null || encodedString.isEmpty()) { + this.fields.reset(fields); + } + try { + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } catch (Exception e) { + throw new DecodingException("Unable to decode TcfEuV2VendorsAllowedSegment '" + encodedString + "'", e); + } + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfEuV2VendorsDisclosedSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfEuV2VendorsDisclosedSegment.java new file mode 100644 index 00000000..c66b012d --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfEuV2VendorsDisclosedSegment.java @@ -0,0 +1,60 @@ +package com.iab.gpp.encoder.segment; + +import java.util.ArrayList; +import java.util.List; +import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.base64.TraditionalBase64UrlEncoder; +import com.iab.gpp.encoder.bitstring.BitStringEncoder; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.datatype.EncodableOptimizedFixedRange; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.field.EncodableBitStringFields; +import com.iab.gpp.encoder.field.TcfEuV2Field; + +public class TcfEuV2VendorsDisclosedSegment extends AbstractLazilyEncodableSegment { + + private AbstractBase64UrlEncoder base64UrlEncoder = TraditionalBase64UrlEncoder.getInstance(); + private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); + + public TcfEuV2VendorsDisclosedSegment() { + super(); + } + + public TcfEuV2VendorsDisclosedSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return TcfEuV2Field.TCFEUV2_VENDORS_DISCLOSED_SEGMENT_FIELD_NAMES; + } + + @Override + protected EncodableBitStringFields initializeFields() { + EncodableBitStringFields fields = new EncodableBitStringFields(); + fields.put(TcfEuV2Field.VENDORS_DISCLOSED_SEGMENT_TYPE, new EncodableFixedInteger(3, 1)); + fields.put(TcfEuV2Field.VENDORS_DISCLOSED, new EncodableOptimizedFixedRange(new ArrayList<>())); + return fields; + } + + @Override + protected String encodeSegment(EncodableBitStringFields fields) { + String bitString = bitStringEncoder.encode(fields, getFieldNames()); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { + if(encodedString == null || encodedString.isEmpty()) { + this.fields.reset(fields); + } + try { + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } catch (Exception e) { + throw new DecodingException("Unable to decode TcfEuV2VendorsDisclosedSegment '" + encodedString + "'", e); + } + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCaV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCaV1CoreSegment.java new file mode 100644 index 00000000..73738284 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCaV1CoreSegment.java @@ -0,0 +1,190 @@ +package com.iab.gpp.encoder.segment; + +import java.util.Arrays; +import java.util.List; +import java.util.function.Predicate; +import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; +import com.iab.gpp.encoder.bitstring.BitStringEncoder; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.ValidationException; +import com.iab.gpp.encoder.field.EncodableBitStringFields; +import com.iab.gpp.encoder.field.UsCaV1Field; +import com.iab.gpp.encoder.section.UsCaV1; + +public class UsCaV1CoreSegment extends AbstractLazilyEncodableSegment { + + private AbstractBase64UrlEncoder base64UrlEncoder = CompressedBase64UrlEncoder.getInstance(); + private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); + + public UsCaV1CoreSegment() { + super(); + } + + public UsCaV1CoreSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return UsCaV1Field.USCAV1_CORE_SEGMENT_FIELD_NAMES; + } + + @Override + protected EncodableBitStringFields initializeFields() { + Predicate nullableBooleanAsTwoBitIntegerValidator = (n -> n >= 0 && n <= 2); + Predicate nonNullableBooleanAsTwoBitIntegerValidator = (n -> n >= 1 && n <= 2); + Predicate> nullableBooleanAsTwoBitIntegerListValidator = (l -> { + for (int n : l) { + if (n < 0 || n > 2) { + return false; + } + } + return true; + }); + + EncodableBitStringFields fields = new EncodableBitStringFields(); + fields.put(UsCaV1Field.VERSION, new EncodableFixedInteger(6, UsCaV1.VERSION)); + fields.put(UsCaV1Field.SALE_OPT_OUT_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsCaV1Field.SHARING_OPT_OUT_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsCaV1Field.SALE_OPT_OUT, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsCaV1Field.SHARING_OPT_OUT, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsCaV1Field.SENSITIVE_DATA_PROCESSING, + new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0, 0)) + .withValidator(nullableBooleanAsTwoBitIntegerListValidator)); + fields.put(UsCaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, new EncodableFixedIntegerList(2, Arrays.asList(0, 0)) + .withValidator(nullableBooleanAsTwoBitIntegerListValidator)); + fields.put(UsCaV1Field.PERSONAL_DATA_CONSENTS, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsCaV1Field.MSPA_COVERED_TRANSACTION, + new EncodableFixedInteger(2, 1).withValidator(nonNullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + return fields; + } + + @Override + protected String encodeSegment(EncodableBitStringFields fields) { + String bitString = bitStringEncoder.encode(fields, getFieldNames()); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { + if (encodedString == null || encodedString.isEmpty()) { + this.fields.reset(fields); + } + try { + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } catch (Exception e) { + throw new DecodingException("Unable to decode UsCaV1CoreSegment '" + encodedString + "'", e); + } + } + + @Override + public void validate() { + Integer sharingOptOutNotice = ((EncodableFixedInteger) fields.get(UsCaV1Field.SHARING_OPT_OUT_NOTICE)).getValue(); + Integer sharingOptOut = ((EncodableFixedInteger) fields.get(UsCaV1Field.SHARING_OPT_OUT)).getValue(); + Integer saleOptOutNotice = ((EncodableFixedInteger) fields.get(UsCaV1Field.SALE_OPT_OUT_NOTICE)).getValue(); + Integer saleOptOut = ((EncodableFixedInteger) fields.get(UsCaV1Field.SALE_OPT_OUT)).getValue(); + Integer mspaServiceProviderMode = + ((EncodableFixedInteger) fields.get(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE)).getValue(); + Integer mspaOptOutOptionMode = + ((EncodableFixedInteger) fields.get(UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE)).getValue(); + Integer sensitiveDataLimtUserNotice = + ((EncodableFixedInteger) fields.get(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE)).getValue(); + + if (sharingOptOutNotice == 0) { + if (sharingOptOut != 0) { + throw new ValidationException( + "Invalid usca sharing notice / opt out combination: {" + sharingOptOutNotice + " / " + sharingOptOut + "}"); + } + } else if (sharingOptOutNotice == 1) { + if (sharingOptOut != 1 && sharingOptOut != 2) { + throw new ValidationException( + "Invalid usca sharing notice / opt out combination: {" + sharingOptOutNotice + " / " + sharingOptOut + "}"); + } + } else if (sharingOptOutNotice == 2) { + if (sharingOptOut != 1) { + throw new ValidationException( + "Invalid usca sharing notice / opt out combination: {" + sharingOptOutNotice + " / " + sharingOptOut + "}"); + } + } + + if (saleOptOutNotice == 0) { + if (saleOptOut != 0) { + throw new ValidationException( + "Invalid usca sale notice / opt out combination: {" + saleOptOutNotice + " / " + saleOptOut + "}"); + } + } else if (saleOptOutNotice == 1) { + if (saleOptOut != 1 && saleOptOut != 2) { + throw new ValidationException( + "Invalid usca sale notice / opt out combination: {" + saleOptOutNotice + " / " + saleOptOut + "}"); + } + } else if (saleOptOutNotice == 2) { + if (saleOptOut != 1) { + throw new ValidationException( + "Invalid usca sale notice / opt out combination: {" + saleOptOutNotice + " / " + saleOptOut + "}"); + } + } + + if (mspaServiceProviderMode == 0) { + if (saleOptOutNotice != 0) { + throw new ValidationException("Invalid usca mspa service provider mode / sale opt out notice combination: {" + + mspaServiceProviderMode + " / " + saleOptOutNotice + "}"); + } + + if (sharingOptOutNotice != 0) { + throw new ValidationException("Invalid usca mspa service provider mode / sharing opt out notice combination: {" + + mspaServiceProviderMode + " / " + sharingOptOutNotice + "}"); + } + + if (sensitiveDataLimtUserNotice != 0) { + throw new ValidationException( + "Invalid usca mspa service provider mode / sensitive data limit use notice combination: {" + + mspaServiceProviderMode + " / " + sensitiveDataLimtUserNotice + "}"); + } + } else if (mspaServiceProviderMode == 1) { + if (mspaOptOutOptionMode != 2) { + throw new ValidationException("Invalid usca mspa service provider / opt out option modes combination: {" + + mspaServiceProviderMode + " / " + mspaServiceProviderMode + "}"); + } + + if (saleOptOutNotice != 0) { + throw new ValidationException("Invalid usca mspa service provider mode / sale opt out notice combination: {" + + mspaServiceProviderMode + " / " + saleOptOutNotice + "}"); + } + + if (sharingOptOutNotice != 0) { + throw new ValidationException("Invalid usca mspa service provider mode / sharing opt out notice combination: {" + + mspaServiceProviderMode + " / " + sharingOptOutNotice + "}"); + } + + if (sensitiveDataLimtUserNotice != 0) { + throw new ValidationException( + "Invalid usca mspa service provider mode / sensitive data limit use notice combination: {" + + mspaServiceProviderMode + " / " + sensitiveDataLimtUserNotice + "}"); + } + } else if (mspaServiceProviderMode == 2) { + if (mspaOptOutOptionMode != 1) { + throw new ValidationException("Invalid usca mspa service provider / opt out option modes combination: {" + + mspaServiceProviderMode + " / " + mspaOptOutOptionMode + "}"); + } + } + } + + +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCaV1GpcSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCaV1GpcSegment.java new file mode 100644 index 00000000..b55e9a28 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCaV1GpcSegment.java @@ -0,0 +1,60 @@ +package com.iab.gpp.encoder.segment; + +import java.util.List; +import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; +import com.iab.gpp.encoder.bitstring.BitStringEncoder; +import com.iab.gpp.encoder.datatype.EncodableBoolean; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.field.EncodableBitStringFields; +import com.iab.gpp.encoder.field.UsCaV1Field; + +public class UsCaV1GpcSegment extends AbstractLazilyEncodableSegment { + + private AbstractBase64UrlEncoder base64UrlEncoder = CompressedBase64UrlEncoder.getInstance(); + private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); + + public UsCaV1GpcSegment() { + super(); + } + + public UsCaV1GpcSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return UsCaV1Field.USCAV1_GPC_SEGMENT_FIELD_NAMES; + } + + @Override + protected EncodableBitStringFields initializeFields() { + EncodableBitStringFields fields = new EncodableBitStringFields(); + fields.put(UsCaV1Field.GPC_SEGMENT_TYPE, new EncodableFixedInteger(2, 1)); + fields.put(UsCaV1Field.GPC_SEGMENT_INCLUDED, new EncodableBoolean(true)); + fields.put(UsCaV1Field.GPC, new EncodableBoolean(false)); + return fields; + } + + @Override + protected String encodeSegment(EncodableBitStringFields fields) { + String bitString = bitStringEncoder.encode(fields, getFieldNames()); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { + if(encodedString == null || encodedString.isEmpty()) { + this.fields.reset(fields); + } + try { + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } catch (Exception e) { + throw new DecodingException("Unable to decode UsCaV1GpcSegment '" + encodedString + "'", e); + } + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCoV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCoV1CoreSegment.java new file mode 100644 index 00000000..5fc86ff3 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCoV1CoreSegment.java @@ -0,0 +1,166 @@ +package com.iab.gpp.encoder.segment; + +import java.util.Arrays; +import java.util.List; +import java.util.function.Predicate; +import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; +import com.iab.gpp.encoder.bitstring.BitStringEncoder; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.ValidationException; +import com.iab.gpp.encoder.field.EncodableBitStringFields; +import com.iab.gpp.encoder.field.UsCoV1Field; +import com.iab.gpp.encoder.section.UsCoV1; + +public class UsCoV1CoreSegment extends AbstractLazilyEncodableSegment { + + private AbstractBase64UrlEncoder base64UrlEncoder = CompressedBase64UrlEncoder.getInstance(); + private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); + + public UsCoV1CoreSegment() { + super(); + } + + public UsCoV1CoreSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return UsCoV1Field.USCOV1_CORE_SEGMENT_FIELD_NAMES; + } + + @Override + protected EncodableBitStringFields initializeFields() { + Predicate nullableBooleanAsTwoBitIntegerValidator = (n -> n >= 0 && n <= 2); + Predicate nonNullableBooleanAsTwoBitIntegerValidator = (n -> n >= 1 && n <= 2); + Predicate> nullableBooleanAsTwoBitIntegerListValidator = (l -> { + for (int n : l) { + if (n < 0 || n > 2) { + return false; + } + } + return true; + }); + + EncodableBitStringFields fields = new EncodableBitStringFields(); + fields.put(UsCoV1Field.VERSION, new EncodableFixedInteger(6, UsCoV1.VERSION)); + fields.put(UsCoV1Field.SHARING_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsCoV1Field.SALE_OPT_OUT_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsCoV1Field.SALE_OPT_OUT, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsCoV1Field.SENSITIVE_DATA_PROCESSING, + new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0)) + .withValidator(nullableBooleanAsTwoBitIntegerListValidator)); + fields.put(UsCoV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsCoV1Field.MSPA_COVERED_TRANSACTION, + new EncodableFixedInteger(2, 1).withValidator(nonNullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + return fields; + } + + @Override + protected String encodeSegment(EncodableBitStringFields fields) { + String bitString = bitStringEncoder.encode(fields, getFieldNames()); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { + if (encodedString == null || encodedString.isEmpty()) { + this.fields.reset(fields); + } + try { + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } catch (Exception e) { + throw new DecodingException("Unable to decode UsCoV1CoreSegment '" + encodedString + "'", e); + } + } + + @Override + public void validate() { + Integer saleOptOutNotice = ((EncodableFixedInteger) fields.get(UsCoV1Field.SALE_OPT_OUT_NOTICE)).getValue(); + Integer saleOptOut = ((EncodableFixedInteger) fields.get(UsCoV1Field.SALE_OPT_OUT)).getValue(); + Integer targetedAdvertisingOptOutNotice = + ((EncodableFixedInteger) fields.get(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE)).getValue(); + Integer targetedAdvertisingOptOut = + ((EncodableFixedInteger) fields.get(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT)).getValue(); + Integer mspaServiceProviderMode = + ((EncodableFixedInteger) fields.get(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE)).getValue(); + Integer mspaOptOutOptionMode = + ((EncodableFixedInteger) fields.get(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE)).getValue(); + + if (saleOptOutNotice == 0) { + if (saleOptOut != 0) { + throw new ValidationException( + "Invalid usco sale notice / opt out combination: {" + saleOptOutNotice + " / " + saleOptOut + "}"); + } + } else if (saleOptOutNotice == 1) { + if (saleOptOut != 1 && saleOptOut != 2) { + throw new ValidationException( + "Invalid usco sale notice / opt out combination: {" + saleOptOutNotice + " / " + saleOptOut + "}"); + } + } else if (saleOptOutNotice == 2) { + if (saleOptOut != 1) { + throw new ValidationException( + "Invalid usco sale notice / opt out combination: {" + saleOptOutNotice + " / " + saleOptOut + "}"); + } + } + + if (targetedAdvertisingOptOutNotice == 0) { + if (targetedAdvertisingOptOut != 0) { + throw new ValidationException("Invalid usco targeted advertising notice / opt out combination: {" + + targetedAdvertisingOptOutNotice + " / " + targetedAdvertisingOptOut + "}"); + } + } else if (targetedAdvertisingOptOutNotice == 1) { + if (saleOptOut != 1 && saleOptOut != 2) { + throw new ValidationException("Invalid usco targeted advertising notice / opt out combination: {" + + targetedAdvertisingOptOutNotice + " / " + targetedAdvertisingOptOut + "}"); + } + } else if (targetedAdvertisingOptOutNotice == 2) { + if (saleOptOut != 1) { + throw new ValidationException("Invalid usco targeted advertising notice / opt out combination: {" + + targetedAdvertisingOptOutNotice + " / " + targetedAdvertisingOptOut + "}"); + } + } + + if (mspaServiceProviderMode == 0) { + if (saleOptOutNotice != 0) { + throw new ValidationException("Invalid usco mspa service provider mode / sale opt out notice combination: {" + + mspaServiceProviderMode + " / " + saleOptOutNotice + "}"); + } + } else if (mspaServiceProviderMode == 1) { + if (mspaOptOutOptionMode != 2) { + throw new ValidationException("Invalid usco mspa service provider / opt out option modes combination: {" + + mspaServiceProviderMode + " / " + mspaServiceProviderMode + "}"); + } + + if (saleOptOutNotice != 0) { + throw new ValidationException("Invalid usco mspa service provider mode / sale opt out notice combination: {" + + mspaServiceProviderMode + " / " + saleOptOutNotice + "}"); + } + } else if (mspaServiceProviderMode == 2) { + if (mspaOptOutOptionMode != 1) { + throw new ValidationException("Invalid usco mspa service provider / opt out option modes combination: {" + + mspaServiceProviderMode + " / " + mspaOptOutOptionMode + "}"); + } + } + } + + +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCoV1GpcSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCoV1GpcSegment.java new file mode 100644 index 00000000..0d0594de --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCoV1GpcSegment.java @@ -0,0 +1,60 @@ +package com.iab.gpp.encoder.segment; + +import java.util.List; +import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; +import com.iab.gpp.encoder.bitstring.BitStringEncoder; +import com.iab.gpp.encoder.datatype.EncodableBoolean; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.field.EncodableBitStringFields; +import com.iab.gpp.encoder.field.UsCoV1Field; + +public class UsCoV1GpcSegment extends AbstractLazilyEncodableSegment { + + private AbstractBase64UrlEncoder base64UrlEncoder = CompressedBase64UrlEncoder.getInstance(); + private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); + + public UsCoV1GpcSegment() { + super(); + } + + public UsCoV1GpcSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return UsCoV1Field.USCOV1_GPC_SEGMENT_FIELD_NAMES; + } + + @Override + protected EncodableBitStringFields initializeFields() { + EncodableBitStringFields fields = new EncodableBitStringFields(); + fields.put(UsCoV1Field.GPC_SEGMENT_TYPE, new EncodableFixedInteger(2, 1)); + fields.put(UsCoV1Field.GPC_SEGMENT_INCLUDED, new EncodableBoolean(true)); + fields.put(UsCoV1Field.GPC, new EncodableBoolean(false)); + return fields; + } + + @Override + protected String encodeSegment(EncodableBitStringFields fields) { + String bitString = bitStringEncoder.encode(fields, getFieldNames()); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { + if(encodedString == null || encodedString.isEmpty()) { + this.fields.reset(fields); + } + try { + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } catch (Exception e) { + throw new DecodingException("Unable to decode UsCoV1GpcSegment '" + encodedString + "'", e); + } + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCtV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCtV1CoreSegment.java new file mode 100644 index 00000000..a07bed72 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCtV1CoreSegment.java @@ -0,0 +1,166 @@ +package com.iab.gpp.encoder.segment; + +import java.util.Arrays; +import java.util.List; +import java.util.function.Predicate; +import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; +import com.iab.gpp.encoder.bitstring.BitStringEncoder; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.ValidationException; +import com.iab.gpp.encoder.field.EncodableBitStringFields; +import com.iab.gpp.encoder.field.UsCtV1Field; +import com.iab.gpp.encoder.section.UsCtV1; + +public class UsCtV1CoreSegment extends AbstractLazilyEncodableSegment { + + private AbstractBase64UrlEncoder base64UrlEncoder = CompressedBase64UrlEncoder.getInstance(); + private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); + + public UsCtV1CoreSegment() { + super(); + } + + public UsCtV1CoreSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return UsCtV1Field.USCTV1_CORE_SEGMENT_FIELD_NAMES; + } + + @Override + protected EncodableBitStringFields initializeFields() { + Predicate nullableBooleanAsTwoBitIntegerValidator = (n -> n >= 0 && n <= 2); + Predicate nonNullableBooleanAsTwoBitIntegerValidator = (n -> n >= 1 && n <= 2); + Predicate> nullableBooleanAsTwoBitIntegerListValidator = (l -> { + for (int n : l) { + if (n < 0 || n > 2) { + return false; + } + } + return true; + }); + + EncodableBitStringFields fields = new EncodableBitStringFields(); + fields.put(UsCtV1Field.VERSION, new EncodableFixedInteger(6, UsCtV1.VERSION)); + fields.put(UsCtV1Field.SHARING_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsCtV1Field.SALE_OPT_OUT_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsCtV1Field.SALE_OPT_OUT, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsCtV1Field.SENSITIVE_DATA_PROCESSING, + new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0)) + .withValidator(nullableBooleanAsTwoBitIntegerListValidator)); + fields.put(UsCtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0)) + .withValidator(nullableBooleanAsTwoBitIntegerListValidator)); + fields.put(UsCtV1Field.MSPA_COVERED_TRANSACTION, + new EncodableFixedInteger(2, 1).withValidator(nonNullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + return fields; + } + + @Override + protected String encodeSegment(EncodableBitStringFields fields) { + String bitString = bitStringEncoder.encode(fields, getFieldNames()); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { + if (encodedString == null || encodedString.isEmpty()) { + this.fields.reset(fields); + } + try { + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } catch (Exception e) { + throw new DecodingException("Unable to decode UsCtV1CoreSegment '" + encodedString + "'", e); + } + } + + @Override + public void validate() { + Integer saleOptOutNotice = ((EncodableFixedInteger) fields.get(UsCtV1Field.SALE_OPT_OUT_NOTICE)).getValue(); + Integer saleOptOut = ((EncodableFixedInteger) fields.get(UsCtV1Field.SALE_OPT_OUT)).getValue(); + Integer targetedAdvertisingOptOutNotice = + ((EncodableFixedInteger) fields.get(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE)).getValue(); + Integer targetedAdvertisingOptOut = + ((EncodableFixedInteger) fields.get(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT)).getValue(); + Integer mspaServiceProviderMode = + ((EncodableFixedInteger) fields.get(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE)).getValue(); + Integer mspaOptOutOptionMode = + ((EncodableFixedInteger) fields.get(UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE)).getValue(); + + if (saleOptOutNotice == 0) { + if (saleOptOut != 0) { + throw new ValidationException( + "Invalid usct sale notice / opt out combination: {" + saleOptOutNotice + " / " + saleOptOut + "}"); + } + } else if (saleOptOutNotice == 1) { + if (saleOptOut != 1 && saleOptOut != 2) { + throw new ValidationException( + "Invalid usct sale notice / opt out combination: {" + saleOptOutNotice + " / " + saleOptOut + "}"); + } + } else if (saleOptOutNotice == 2) { + if (saleOptOut != 1) { + throw new ValidationException( + "Invalid usct sale notice / opt out combination: {" + saleOptOutNotice + " / " + saleOptOut + "}"); + } + } + + if (targetedAdvertisingOptOutNotice == 0) { + if (targetedAdvertisingOptOut != 0) { + throw new ValidationException("Invalid usct targeted advertising notice / opt out combination: {" + + targetedAdvertisingOptOutNotice + " / " + targetedAdvertisingOptOut + "}"); + } + } else if (targetedAdvertisingOptOutNotice == 1) { + if (saleOptOut != 1 && saleOptOut != 2) { + throw new ValidationException("Invalid usct targeted advertising notice / opt out combination: {" + + targetedAdvertisingOptOutNotice + " / " + targetedAdvertisingOptOut + "}"); + } + } else if (targetedAdvertisingOptOutNotice == 2) { + if (saleOptOut != 1) { + throw new ValidationException("Invalid usct targeted advertising notice / opt out combination: {" + + targetedAdvertisingOptOutNotice + " / " + targetedAdvertisingOptOut + "}"); + } + } + + if (mspaServiceProviderMode == 0) { + if (saleOptOutNotice != 0) { + throw new ValidationException("Invalid usct mspa service provider mode / sale opt out notice combination: {" + + mspaServiceProviderMode + " / " + saleOptOutNotice + "}"); + } + } else if (mspaServiceProviderMode == 1) { + if (mspaOptOutOptionMode != 2) { + throw new ValidationException("Invalid usct mspa service provider / opt out option modes combination: {" + + mspaServiceProviderMode + " / " + mspaServiceProviderMode + "}"); + } + + if (saleOptOutNotice != 0) { + throw new ValidationException("Invalid usct mspa service provider mode / sale opt out notice combination: {" + + mspaServiceProviderMode + " / " + saleOptOutNotice + "}"); + } + } else if (mspaServiceProviderMode == 2) { + if (mspaOptOutOptionMode != 1) { + throw new ValidationException("Invalid usct mspa service provider / opt out option modes combination: {" + + mspaServiceProviderMode + " / " + mspaOptOutOptionMode + "}"); + } + } + } + + +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCtV1GpcSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCtV1GpcSegment.java new file mode 100644 index 00000000..b10649a3 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCtV1GpcSegment.java @@ -0,0 +1,60 @@ +package com.iab.gpp.encoder.segment; + +import java.util.List; +import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; +import com.iab.gpp.encoder.bitstring.BitStringEncoder; +import com.iab.gpp.encoder.datatype.EncodableBoolean; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.field.EncodableBitStringFields; +import com.iab.gpp.encoder.field.UsCtV1Field; + +public class UsCtV1GpcSegment extends AbstractLazilyEncodableSegment { + + private AbstractBase64UrlEncoder base64UrlEncoder = CompressedBase64UrlEncoder.getInstance(); + private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); + + public UsCtV1GpcSegment() { + super(); + } + + public UsCtV1GpcSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return UsCtV1Field.USCTV1_GPC_SEGMENT_FIELD_NAMES; + } + + @Override + protected EncodableBitStringFields initializeFields() { + EncodableBitStringFields fields = new EncodableBitStringFields(); + fields.put(UsCtV1Field.GPC_SEGMENT_TYPE, new EncodableFixedInteger(2, 1)); + fields.put(UsCtV1Field.GPC_SEGMENT_INCLUDED, new EncodableBoolean(true)); + fields.put(UsCtV1Field.GPC, new EncodableBoolean(false)); + return fields; + } + + @Override + protected String encodeSegment(EncodableBitStringFields fields) { + String bitString = bitStringEncoder.encode(fields, getFieldNames()); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { + if(encodedString == null || encodedString.isEmpty()) { + this.fields.reset(fields); + } + try { + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } catch (Exception e) { + throw new DecodingException("Unable to decode UsCtV1GpcSegment '" + encodedString + "'", e); + } + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsNatV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsNatV1CoreSegment.java new file mode 100644 index 00000000..de3bc0dd --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsNatV1CoreSegment.java @@ -0,0 +1,237 @@ +package com.iab.gpp.encoder.segment; + +import java.util.Arrays; +import java.util.List; +import java.util.function.Predicate; +import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; +import com.iab.gpp.encoder.bitstring.BitStringEncoder; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.ValidationException; +import com.iab.gpp.encoder.field.EncodableBitStringFields; +import com.iab.gpp.encoder.field.UsNatV1Field; +import com.iab.gpp.encoder.section.UsNatV1; + +public class UsNatV1CoreSegment extends AbstractLazilyEncodableSegment { + + private AbstractBase64UrlEncoder base64UrlEncoder = CompressedBase64UrlEncoder.getInstance(); + private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); + + public UsNatV1CoreSegment() { + super(); + } + + public UsNatV1CoreSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return UsNatV1Field.USNATV1_CORE_SEGMENT_FIELD_NAMES; + } + + @Override + protected EncodableBitStringFields initializeFields() { + Predicate nullableBooleanAsTwoBitIntegerValidator = (n -> n >= 0 && n <= 2); + Predicate nonNullableBooleanAsTwoBitIntegerValidator = (n -> n >= 1 && n <= 2); + Predicate> nullableBooleanAsTwoBitIntegerListValidator = (l -> { + for (int n : l) { + if (n < 0 || n > 2) { + return false; + } + } + return true; + }); + + EncodableBitStringFields fields = new EncodableBitStringFields(); + fields.put(UsNatV1Field.VERSION, new EncodableFixedInteger(6, UsNatV1.VERSION)); + fields.put(UsNatV1Field.SHARING_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsNatV1Field.SALE_OPT_OUT_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsNatV1Field.SHARING_OPT_OUT_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsNatV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsNatV1Field.SALE_OPT_OUT, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsNatV1Field.SHARING_OPT_OUT, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsNatV1Field.SENSITIVE_DATA_PROCESSING, + new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)) + .withValidator(nullableBooleanAsTwoBitIntegerListValidator)); + fields.put(UsNatV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, new EncodableFixedIntegerList(2, Arrays.asList(0, 0)) + .withValidator(nullableBooleanAsTwoBitIntegerListValidator)); + fields.put(UsNatV1Field.PERSONAL_DATA_CONSENTS, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsNatV1Field.MSPA_COVERED_TRANSACTION, + new EncodableFixedInteger(2, 1).withValidator(nonNullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + return fields; + } + + @Override + protected String encodeSegment(EncodableBitStringFields fields) { + String bitString = bitStringEncoder.encode(fields, getFieldNames()); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { + if (encodedString == null || encodedString.isEmpty()) { + this.fields.reset(fields); + } + try { + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } catch (Exception e) { + throw new DecodingException("Unable to decode UsNatV1CoreSegment '" + encodedString + "'", e); + } + } + + @Override + public void validate() { + Integer sharingNotice = ((EncodableFixedInteger) fields.get(UsNatV1Field.SHARING_NOTICE)).getValue(); + Integer sharingOptOutNotice = ((EncodableFixedInteger) fields.get(UsNatV1Field.SHARING_OPT_OUT_NOTICE)).getValue(); + Integer sharingOptOut = ((EncodableFixedInteger) fields.get(UsNatV1Field.SHARING_OPT_OUT)).getValue(); + Integer saleOptOutNotice = ((EncodableFixedInteger) fields.get(UsNatV1Field.SALE_OPT_OUT_NOTICE)).getValue(); + Integer saleOptOut = ((EncodableFixedInteger) fields.get(UsNatV1Field.SALE_OPT_OUT)).getValue(); + Integer targetedAdvertisingOptOutNotice = + ((EncodableFixedInteger) fields.get(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE)).getValue(); + Integer targetedAdvertisingOptOut = + ((EncodableFixedInteger) fields.get(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT)).getValue(); + Integer mspaServiceProviderMode = + ((EncodableFixedInteger) fields.get(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE)).getValue(); + Integer mspaOptOutOptionMode = + ((EncodableFixedInteger) fields.get(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE)).getValue(); + Integer sensitiveDataLimtUserNotice = + ((EncodableFixedInteger) fields.get(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE)).getValue(); + + if (sharingNotice == 0) { + if (sharingOptOut != 0) { + throw new ValidationException( + "Invalid usnat sharing notice / opt out combination: {" + sharingNotice + " / " + sharingOptOut + "}"); + } + } else if (sharingNotice == 1) { + if (sharingOptOut != 1 && sharingOptOut != 2) { + throw new ValidationException( + "Invalid usnat sharing notice / opt out combination: {" + sharingNotice + " / " + sharingOptOut + "}"); + } + } else if (sharingNotice == 2) { + if (sharingOptOut != 1) { + throw new ValidationException( + "Invalid usnat sharing notice / opt out combination: {" + sharingNotice + " / " + sharingOptOut + "}"); + } + } + + if (sharingOptOutNotice == 0) { + if (sharingOptOut != 0) { + throw new ValidationException("Invalid usnat sharing notice / opt out combination: {" + sharingOptOutNotice + + " / " + sharingOptOut + "}"); + } + } else if (sharingOptOutNotice == 1) { + if (sharingOptOut != 1 && sharingOptOut != 2) { + throw new ValidationException("Invalid usnat sharing notice / opt out combination: {" + sharingOptOutNotice + + " / " + sharingOptOut + "}"); + } + } else if (sharingOptOutNotice == 2) { + if (sharingOptOut != 1) { + throw new ValidationException("Invalid usnat sharing notice / opt out combination: {" + sharingOptOutNotice + + " / " + sharingOptOut + "}"); + } + } + + if (saleOptOutNotice == 0) { + if (saleOptOut != 0) { + throw new ValidationException( + "Invalid usnat sale notice / opt out combination: {" + saleOptOutNotice + " / " + saleOptOut + "}"); + } + } else if (saleOptOutNotice == 1) { + if (saleOptOut != 1 && saleOptOut != 2) { + throw new ValidationException( + "Invalid usnat sale notice / opt out combination: {" + saleOptOutNotice + " / " + saleOptOut + "}"); + } + } else if (saleOptOutNotice == 2) { + if (saleOptOut != 1) { + throw new ValidationException( + "Invalid usnat sale notice / opt out combination: {" + saleOptOutNotice + " / " + saleOptOut + "}"); + } + } + + if (targetedAdvertisingOptOutNotice == 0) { + if (targetedAdvertisingOptOut != 0) { + throw new ValidationException("Invalid usnat targeted advertising notice / opt out combination: {" + + targetedAdvertisingOptOutNotice + " / " + targetedAdvertisingOptOut + "}"); + } + } else if (targetedAdvertisingOptOutNotice == 1) { + if (saleOptOut != 1 && saleOptOut != 2) { + throw new ValidationException("Invalid usnat targeted advertising notice / opt out combination: {" + + targetedAdvertisingOptOutNotice + " / " + targetedAdvertisingOptOut + "}"); + } + } else if (targetedAdvertisingOptOutNotice == 2) { + if (saleOptOut != 1) { + throw new ValidationException("Invalid usnat targeted advertising notice / opt out combination: {" + + targetedAdvertisingOptOutNotice + " / " + targetedAdvertisingOptOut + "}"); + } + } + + if (mspaServiceProviderMode == 0) { + if (saleOptOutNotice != 0) { + throw new ValidationException("Invalid usnat mspa service provider mode / sale opt out notice combination: {" + + mspaServiceProviderMode + " / " + saleOptOutNotice + "}"); + } + + if (sharingOptOutNotice != 0) { + throw new ValidationException("Invalid usnat mspa service provider mode / sharing opt out notice combination: {" + + mspaServiceProviderMode + " / " + sharingOptOutNotice + "}"); + } + + if (sensitiveDataLimtUserNotice != 0) { + throw new ValidationException( + "Invalid usnat mspa service provider mode / sensitive data limit use notice combination: {" + + mspaServiceProviderMode + " / " + sensitiveDataLimtUserNotice + "}"); + } + } else if (mspaServiceProviderMode == 1) { + if (mspaOptOutOptionMode != 2) { + throw new ValidationException("Invalid usnat mspa service provider / opt out option modes combination: {" + + mspaServiceProviderMode + " / " + mspaServiceProviderMode + "}"); + } + + if (saleOptOutNotice != 0) { + throw new ValidationException("Invalid usnat mspa service provider mode / sale opt out notice combination: {" + + mspaServiceProviderMode + " / " + saleOptOutNotice + "}"); + } + + if (sharingOptOutNotice != 0) { + throw new ValidationException("Invalid usnat mspa service provider mode / sharing opt out notice combination: {" + + mspaServiceProviderMode + " / " + sharingOptOutNotice + "}"); + } + + if (sensitiveDataLimtUserNotice != 0) { + throw new ValidationException( + "Invalid usnat mspa service provider mode / sensitive data limit use notice combination: {" + + mspaServiceProviderMode + " / " + sensitiveDataLimtUserNotice + "}"); + } + } else if (mspaServiceProviderMode == 2) { + if (mspaOptOutOptionMode != 1) { + throw new ValidationException("Invalid usnat mspa service provider / opt out option modes combination: {" + + mspaServiceProviderMode + " / " + mspaOptOutOptionMode + "}"); + } + } + } + + +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsNatV1GpcSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsNatV1GpcSegment.java new file mode 100644 index 00000000..848e360f --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsNatV1GpcSegment.java @@ -0,0 +1,60 @@ +package com.iab.gpp.encoder.segment; + +import java.util.List; +import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; +import com.iab.gpp.encoder.bitstring.BitStringEncoder; +import com.iab.gpp.encoder.datatype.EncodableBoolean; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.field.EncodableBitStringFields; +import com.iab.gpp.encoder.field.UsNatV1Field; + +public class UsNatV1GpcSegment extends AbstractLazilyEncodableSegment { + + private AbstractBase64UrlEncoder base64UrlEncoder = CompressedBase64UrlEncoder.getInstance(); + private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); + + public UsNatV1GpcSegment() { + super(); + } + + public UsNatV1GpcSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return UsNatV1Field.USNATV1_GPC_SEGMENT_FIELD_NAMES; + } + + @Override + protected EncodableBitStringFields initializeFields() { + EncodableBitStringFields fields = new EncodableBitStringFields(); + fields.put(UsNatV1Field.GPC_SEGMENT_TYPE, new EncodableFixedInteger(2, 1)); + fields.put(UsNatV1Field.GPC_SEGMENT_INCLUDED, new EncodableBoolean(true)); + fields.put(UsNatV1Field.GPC, new EncodableBoolean(false)); + return fields; + } + + @Override + protected String encodeSegment(EncodableBitStringFields fields) { + String bitString = bitStringEncoder.encode(fields, getFieldNames()); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { + if(encodedString == null || encodedString.isEmpty()) { + this.fields.reset(fields); + } + try { + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } catch (Exception e) { + throw new DecodingException("Unable to decode UsNatV1GpcSegment '" + encodedString + "'", e); + } + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsUtV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsUtV1CoreSegment.java new file mode 100644 index 00000000..1602e079 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsUtV1CoreSegment.java @@ -0,0 +1,168 @@ +package com.iab.gpp.encoder.segment; + +import java.util.Arrays; +import java.util.List; +import java.util.function.Predicate; +import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; +import com.iab.gpp.encoder.bitstring.BitStringEncoder; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.ValidationException; +import com.iab.gpp.encoder.field.EncodableBitStringFields; +import com.iab.gpp.encoder.field.UsUtV1Field; +import com.iab.gpp.encoder.section.UsUtV1; + +public class UsUtV1CoreSegment extends AbstractLazilyEncodableSegment { + + private AbstractBase64UrlEncoder base64UrlEncoder = CompressedBase64UrlEncoder.getInstance(); + private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); + + public UsUtV1CoreSegment() { + super(); + } + + public UsUtV1CoreSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return UsUtV1Field.USUTV1_CORE_SEGMENT_FIELD_NAMES; + } + + @Override + protected EncodableBitStringFields initializeFields() { + Predicate nullableBooleanAsTwoBitIntegerValidator = (n -> n >= 0 && n <= 2); + Predicate nonNullableBooleanAsTwoBitIntegerValidator = (n -> n >= 1 && n <= 2); + Predicate> nullableBooleanAsTwoBitIntegerListValidator = (l -> { + for (int n : l) { + if (n < 0 || n > 2) { + return false; + } + } + return true; + }); + + EncodableBitStringFields fields = new EncodableBitStringFields(); + fields.put(UsUtV1Field.VERSION, new EncodableFixedInteger(6, UsUtV1.VERSION)); + fields.put(UsUtV1Field.SHARING_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsUtV1Field.SALE_OPT_OUT_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsUtV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsUtV1Field.SALE_OPT_OUT, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsUtV1Field.SENSITIVE_DATA_PROCESSING, + new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0)) + .withValidator(nullableBooleanAsTwoBitIntegerListValidator)); + fields.put(UsUtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsUtV1Field.MSPA_COVERED_TRANSACTION, + new EncodableFixedInteger(2, 1).withValidator(nonNullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + return fields; + } + + @Override + protected String encodeSegment(EncodableBitStringFields fields) { + String bitString = bitStringEncoder.encode(fields, getFieldNames()); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { + if (encodedString == null || encodedString.isEmpty()) { + this.fields.reset(fields); + } + try { + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } catch (Exception e) { + throw new DecodingException("Unable to decode UsUtV1CoreSegment '" + encodedString + "'", e); + } + } + + @Override + public void validate() { + Integer saleOptOutNotice = ((EncodableFixedInteger) fields.get(UsUtV1Field.SALE_OPT_OUT_NOTICE)).getValue(); + Integer saleOptOut = ((EncodableFixedInteger) fields.get(UsUtV1Field.SALE_OPT_OUT)).getValue(); + Integer targetedAdvertisingOptOutNotice = + ((EncodableFixedInteger) fields.get(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE)).getValue(); + Integer targetedAdvertisingOptOut = + ((EncodableFixedInteger) fields.get(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT)).getValue(); + Integer mspaServiceProviderMode = + ((EncodableFixedInteger) fields.get(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE)).getValue(); + Integer mspaOptOutOptionMode = + ((EncodableFixedInteger) fields.get(UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE)).getValue(); + + if (saleOptOutNotice == 0) { + if (saleOptOut != 0) { + throw new ValidationException( + "Invalid usut sale notice / opt out combination: {" + saleOptOutNotice + " / " + saleOptOut + "}"); + } + } else if (saleOptOutNotice == 1) { + if (saleOptOut != 1 && saleOptOut != 2) { + throw new ValidationException( + "Invalid usut sale notice / opt out combination: {" + saleOptOutNotice + " / " + saleOptOut + "}"); + } + } else if (saleOptOutNotice == 2) { + if (saleOptOut != 1) { + throw new ValidationException( + "Invalid usut sale notice / opt out combination: {" + saleOptOutNotice + " / " + saleOptOut + "}"); + } + } + + if (targetedAdvertisingOptOutNotice == 0) { + if (targetedAdvertisingOptOut != 0) { + throw new ValidationException("Invalid usut targeted advertising notice / opt out combination: {" + + targetedAdvertisingOptOutNotice + " / " + targetedAdvertisingOptOut + "}"); + } + } else if (targetedAdvertisingOptOutNotice == 1) { + if (saleOptOut != 1 && saleOptOut != 2) { + throw new ValidationException("Invalid usut targeted advertising notice / opt out combination: {" + + targetedAdvertisingOptOutNotice + " / " + targetedAdvertisingOptOut + "}"); + } + } else if (targetedAdvertisingOptOutNotice == 2) { + if (saleOptOut != 1) { + throw new ValidationException("Invalid usut targeted advertising notice / opt out combination: {" + + targetedAdvertisingOptOutNotice + " / " + targetedAdvertisingOptOut + "}"); + } + } + + if (mspaServiceProviderMode == 0) { + if (saleOptOutNotice != 0) { + throw new ValidationException("Invalid usut mspa service provider mode / sale opt out notice combination: {" + + mspaServiceProviderMode + " / " + saleOptOutNotice + "}"); + } + } else if (mspaServiceProviderMode == 1) { + if (mspaOptOutOptionMode != 2) { + throw new ValidationException("Invalid usut mspa service provider / opt out option modes combination: {" + + mspaServiceProviderMode + " / " + mspaServiceProviderMode + "}"); + } + + if (saleOptOutNotice != 0) { + throw new ValidationException("Invalid usut mspa service provider mode / sale opt out notice combination: {" + + mspaServiceProviderMode + " / " + saleOptOutNotice + "}"); + } + } else if (mspaServiceProviderMode == 2) { + if (mspaOptOutOptionMode != 1) { + throw new ValidationException("Invalid usut mspa service provider / opt out option modes combination: {" + + mspaServiceProviderMode + " / " + mspaOptOutOptionMode + "}"); + } + } + } + + +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsVaV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsVaV1CoreSegment.java new file mode 100644 index 00000000..08a8a8dd --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsVaV1CoreSegment.java @@ -0,0 +1,166 @@ +package com.iab.gpp.encoder.segment; + +import java.util.Arrays; +import java.util.List; +import java.util.function.Predicate; +import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; +import com.iab.gpp.encoder.bitstring.BitStringEncoder; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.ValidationException; +import com.iab.gpp.encoder.field.EncodableBitStringFields; +import com.iab.gpp.encoder.field.UsVaV1Field; +import com.iab.gpp.encoder.section.UsVaV1; + +public class UsVaV1CoreSegment extends AbstractLazilyEncodableSegment { + + private AbstractBase64UrlEncoder base64UrlEncoder = CompressedBase64UrlEncoder.getInstance(); + private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); + + public UsVaV1CoreSegment() { + super(); + } + + public UsVaV1CoreSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return UsVaV1Field.USVAV1_CORE_SEGMENT_FIELD_NAMES; + } + + @Override + protected EncodableBitStringFields initializeFields() { + Predicate nullableBooleanAsTwoBitIntegerValidator = (n -> n >= 0 && n <= 2); + Predicate nonNullableBooleanAsTwoBitIntegerValidator = (n -> n >= 1 && n <= 2); + Predicate> nullableBooleanAsTwoBitIntegerListValidator = (l -> { + for (int n : l) { + if (n < 0 || n > 2) { + return false; + } + } + return true; + }); + + EncodableBitStringFields fields = new EncodableBitStringFields(); + fields.put(UsVaV1Field.VERSION, new EncodableFixedInteger(6, UsVaV1.VERSION)); + fields.put(UsVaV1Field.SHARING_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsVaV1Field.SALE_OPT_OUT_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsVaV1Field.SALE_OPT_OUT, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsVaV1Field.SENSITIVE_DATA_PROCESSING, + new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0)) + .withValidator(nullableBooleanAsTwoBitIntegerListValidator)); + fields.put(UsVaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsVaV1Field.MSPA_COVERED_TRANSACTION, + new EncodableFixedInteger(2, 1).withValidator(nonNullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + return fields; + } + + @Override + protected String encodeSegment(EncodableBitStringFields fields) { + String bitString = bitStringEncoder.encode(fields, getFieldNames()); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { + if (encodedString == null || encodedString.isEmpty()) { + this.fields.reset(fields); + } + try { + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } catch (Exception e) { + throw new DecodingException("Unable to decode UsVaV1CoreSegment '" + encodedString + "'", e); + } + } + + @Override + public void validate() { + Integer saleOptOutNotice = ((EncodableFixedInteger) fields.get(UsVaV1Field.SALE_OPT_OUT_NOTICE)).getValue(); + Integer saleOptOut = ((EncodableFixedInteger) fields.get(UsVaV1Field.SALE_OPT_OUT)).getValue(); + Integer targetedAdvertisingOptOutNotice = + ((EncodableFixedInteger) fields.get(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE)).getValue(); + Integer targetedAdvertisingOptOut = + ((EncodableFixedInteger) fields.get(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT)).getValue(); + Integer mspaServiceProviderMode = + ((EncodableFixedInteger) fields.get(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE)).getValue(); + Integer mspaOptOutOptionMode = + ((EncodableFixedInteger) fields.get(UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE)).getValue(); + + if (saleOptOutNotice == 0) { + if (saleOptOut != 0) { + throw new ValidationException( + "Invalid usva sale notice / opt out combination: {" + saleOptOutNotice + " / " + saleOptOut + "}"); + } + } else if (saleOptOutNotice == 1) { + if (saleOptOut != 1 && saleOptOut != 2) { + throw new ValidationException( + "Invalid usva sale notice / opt out combination: {" + saleOptOutNotice + " / " + saleOptOut + "}"); + } + } else if (saleOptOutNotice == 2) { + if (saleOptOut != 1) { + throw new ValidationException( + "Invalid usva sale notice / opt out combination: {" + saleOptOutNotice + " / " + saleOptOut + "}"); + } + } + + if (targetedAdvertisingOptOutNotice == 0) { + if (targetedAdvertisingOptOut != 0) { + throw new ValidationException("Invalid usva targeted advertising notice / opt out combination: {" + + targetedAdvertisingOptOutNotice + " / " + targetedAdvertisingOptOut + "}"); + } + } else if (targetedAdvertisingOptOutNotice == 1) { + if (saleOptOut != 1 && saleOptOut != 2) { + throw new ValidationException("Invalid usva targeted advertising notice / opt out combination: {" + + targetedAdvertisingOptOutNotice + " / " + targetedAdvertisingOptOut + "}"); + } + } else if (targetedAdvertisingOptOutNotice == 2) { + if (saleOptOut != 1) { + throw new ValidationException("Invalid usva targeted advertising notice / opt out combination: {" + + targetedAdvertisingOptOutNotice + " / " + targetedAdvertisingOptOut + "}"); + } + } + + if (mspaServiceProviderMode == 0) { + if (saleOptOutNotice != 0) { + throw new ValidationException("Invalid usva mspa service provider mode / sale opt out notice combination: {" + + mspaServiceProviderMode + " / " + saleOptOutNotice + "}"); + } + } else if (mspaServiceProviderMode == 1) { + if (mspaOptOutOptionMode != 2) { + throw new ValidationException("Invalid usva mspa service provider / opt out option modes combination: {" + + mspaServiceProviderMode + " / " + mspaServiceProviderMode + "}"); + } + + if (saleOptOutNotice != 0) { + throw new ValidationException("Invalid usva mspa service provider mode / sale opt out notice combination: {" + + mspaServiceProviderMode + " / " + saleOptOutNotice + "}"); + } + } else if (mspaServiceProviderMode == 2) { + if (mspaOptOutOptionMode != 1) { + throw new ValidationException("Invalid usva mspa service provider / opt out option modes combination: {" + + mspaServiceProviderMode + " / " + mspaOptOutOptionMode + "}"); + } + } + } + + +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UspV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UspV1CoreSegment.java new file mode 100644 index 00000000..59b3c557 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UspV1CoreSegment.java @@ -0,0 +1,64 @@ +package com.iab.gpp.encoder.segment; + +import java.util.List; +import com.iab.gpp.encoder.datatype.UnencodableCharacter; +import com.iab.gpp.encoder.datatype.UnencodableInteger; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.field.GenericFields; +import com.iab.gpp.encoder.field.UspV1Field; +import com.iab.gpp.encoder.section.UspV1; + +public class UspV1CoreSegment extends AbstractLazilyEncodableSegment { + + public UspV1CoreSegment() { + super(); + } + + public UspV1CoreSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return UspV1Field.USPV1_CORE_SEGMENT_FIELD_NAMES; + } + + @Override + protected GenericFields initializeFields() { + GenericFields fields = new GenericFields(); + fields.put(UspV1Field.VERSION, new UnencodableInteger(UspV1.VERSION)); + fields.put(UspV1Field.NOTICE, new UnencodableCharacter('-', (v -> v == 'Y' || v == 'N' || v == '-'))); + fields.put(UspV1Field.OPT_OUT_SALE, new UnencodableCharacter('-', (v -> v == 'Y' || v == 'N' || v == '-'))); + fields.put(UspV1Field.LSPA_COVERED, new UnencodableCharacter('-', (v -> v == 'Y' || v == 'N' || v == '-'))); + return fields; + } + + @Override + protected String encodeSegment(GenericFields fields) { + String str = ""; + str += fields.get(UspV1Field.VERSION).getValue(); + str += fields.get(UspV1Field.NOTICE).getValue(); + str += fields.get(UspV1Field.OPT_OUT_SALE).getValue(); + str += fields.get(UspV1Field.LSPA_COVERED).getValue(); + return str; + } + + @Override + protected void decodeSegment(String encodedString, GenericFields fields) { + if (encodedString == null || encodedString.length() != 4) { + throw new DecodingException("Invalid uspv1 string: '" + encodedString + "'"); + } + + try { + fields.get(UspV1Field.VERSION).setValue(Integer.parseInt(encodedString.substring(0, 1))); + fields.get(UspV1Field.NOTICE).setValue(encodedString.charAt(1)); + fields.get(UspV1Field.OPT_OUT_SALE).setValue(encodedString.charAt(2)); + fields.get(UspV1Field.LSPA_COVERED).setValue(encodedString.charAt(3)); + } catch (Exception e) { + throw new DecodingException("Unable to decode UspV1CoreSegment '" + encodedString + "'", e); + } + } + +} + diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java index a28858af..9f9bb3c9 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java @@ -4,13 +4,9 @@ import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.Arrays; -import java.util.List; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; -import com.iab.gpp.encoder.error.InvalidFieldException; -import com.iab.gpp.encoder.error.LazyDecodingException; import com.iab.gpp.encoder.field.TcfCaV1Field; import com.iab.gpp.encoder.field.TcfEuV2Field; import com.iab.gpp.encoder.field.UsCaV1Field; @@ -18,8 +14,8 @@ import com.iab.gpp.encoder.field.UsCtV1Field; import com.iab.gpp.encoder.field.UsNatV1Field; import com.iab.gpp.encoder.field.UsUtV1Field; -import com.iab.gpp.encoder.field.UspV1Field; import com.iab.gpp.encoder.field.UsVaV1Field; +import com.iab.gpp.encoder.field.UspV1Field; import com.iab.gpp.encoder.section.TcfCaV1; import com.iab.gpp.encoder.section.TcfEuV2; import com.iab.gpp.encoder.section.UsCaV1; @@ -27,15 +23,15 @@ import com.iab.gpp.encoder.section.UsCtV1; import com.iab.gpp.encoder.section.UsNatV1; import com.iab.gpp.encoder.section.UsUtV1; -import com.iab.gpp.encoder.section.UspV1; import com.iab.gpp.encoder.section.UsVaV1; +import com.iab.gpp.encoder.section.UspV1; public class GppModelTest { private ZonedDateTime utcDateTime = ZonedDateTime.of(2022, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC")); @Test - public void testEncodeDefault() throws EncodingException, LazyDecodingException { + public void testEncodeDefault() { GppModel gppModel = new GppModel(); Assertions.assertEquals(false, gppModel.hasSection(UspV1.ID)); Assertions.assertEquals(false, gppModel.hasSection(TcfEuV2.ID)); @@ -61,16 +57,20 @@ public void testEncodeDefault() throws EncodingException, LazyDecodingException @Test public void testDecodingException() { - try { - GppModel gppModel = new GppModel("invalid gpp string"); - Assertions.fail("Expected LazyDecodingException"); - } catch (DecodingException e) { - - } + Assertions.assertThrows(DecodingException.class, () -> { + new GppModel("invalid gpp string").getHeader(); + }); } + @Test() + public void testDecodeGarbage() { + Assertions.assertThrows(DecodingException.class, () -> { + new GppModel("z").getUsCtV1Section(); + }); + } + @Test - public void testEncodeDefaultAll() throws EncodingException, InvalidFieldException, LazyDecodingException { + public void testEncodeDefaultAll() { GppModel gppModel = new GppModel(); Assertions.assertEquals(false, gppModel.hasSection(TcfEuV2.NAME)); @@ -111,13 +111,13 @@ public void testEncodeDefaultAll() throws EncodingException, InvalidFieldExcepti String gppString = gppModel.encode(); Assertions.assertEquals( - "DBACOaw~CPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAA.YAAAAAAAAAA~1---~BAAAAAAAAAA.QA~BAAAAAAA.QA~BAAAAAA~BAAAAAA.QA~BAAAAAAA~BAAAAAAA.QA", + "DBACOaw~CPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAA.YAAAAAAAAAA~1---~BAAAAAAAAQA.QA~BAAAAABA.QA~BAAAABA~BAAAAEA.QA~BAAAAAQA~BAAAAAEA.QA", gppString); } @Test - public void testEncodeUspv1() throws EncodingException, InvalidFieldException, LazyDecodingException { + public void testEncodeUspv1() { GppModel gppModel = new GppModel(); Assertions.assertEquals(false, gppModel.hasSection(UspV1.ID)); Assertions.assertEquals(false, gppModel.hasSection(TcfEuV2.ID)); @@ -127,9 +127,9 @@ public void testEncodeUspv1() throws EncodingException, InvalidFieldException, L Assertions.assertEquals(false, gppModel.hasSection(TcfEuV2.NAME)); Assertions.assertEquals(false, gppModel.hasSection(TcfCaV1.NAME)); - gppModel.setFieldValue(UspV1.NAME, UspV1Field.NOTICE, "Y"); - gppModel.setFieldValue(UspV1.NAME, UspV1Field.OPT_OUT_SALE, "N"); - gppModel.setFieldValue(UspV1.NAME, UspV1Field.LSPA_COVERED, "N"); + gppModel.setFieldValue(UspV1.NAME, UspV1Field.NOTICE, 'Y'); + gppModel.setFieldValue(UspV1.NAME, UspV1Field.OPT_OUT_SALE, 'N'); + gppModel.setFieldValue(UspV1.NAME, UspV1Field.LSPA_COVERED, 'N'); Assertions.assertEquals(Arrays.asList(6), gppModel.getSectionIds()); Assertions.assertEquals(true, gppModel.hasSection(UspV1.ID)); @@ -157,7 +157,7 @@ public void testEncodeUspv1() throws EncodingException, InvalidFieldException, L } @Test - public void testEncodeTcfEuV2() throws EncodingException, InvalidFieldException, LazyDecodingException { + public void testEncodeTcfEuV2() { GppModel gppModel = new GppModel(); Assertions.assertEquals(false, gppModel.hasSection(UspV1.ID)); Assertions.assertEquals(false, gppModel.hasSection(TcfEuV2.ID)); @@ -207,7 +207,7 @@ public void testEncodeTcfEuV2() throws EncodingException, InvalidFieldException, } @Test - public void testEncodeUspV1AndTcfEuV2() throws EncodingException, InvalidFieldException, LazyDecodingException { + public void testEncodeUspV1AndTcfEuV2() { GppModel gppModel = new GppModel(); Assertions.assertEquals(false, gppModel.hasSection(UspV1.NAME)); Assertions.assertEquals(false, gppModel.hasSection(TcfEuV2.NAME)); @@ -231,9 +231,9 @@ public void testEncodeUspV1AndTcfEuV2() throws EncodingException, InvalidFieldEx Assertions.assertEquals(true, gppModel.hasSection(TcfEuV2.NAME)); Assertions.assertEquals(false, gppModel.hasSection(TcfCaV1.NAME)); - gppModel.setFieldValue(UspV1.NAME, UspV1Field.NOTICE, "Y"); - gppModel.setFieldValue(UspV1.NAME, UspV1Field.OPT_OUT_SALE, "N"); - gppModel.setFieldValue(UspV1.NAME, UspV1Field.LSPA_COVERED, "N"); + gppModel.setFieldValue(UspV1.NAME, UspV1Field.NOTICE, 'Y'); + gppModel.setFieldValue(UspV1.NAME, UspV1Field.OPT_OUT_SALE, 'N'); + gppModel.setFieldValue(UspV1.NAME, UspV1Field.LSPA_COVERED, 'N'); Assertions.assertEquals(true, gppModel.hasSection(UspV1.NAME)); Assertions.assertEquals(true, gppModel.hasSection(TcfEuV2.NAME)); @@ -252,8 +252,7 @@ public void testEncodeUspV1AndTcfEuV2() throws EncodingException, InvalidFieldEx } @Test - public void testEncodeUspV1AndTcfEuV2AndTcfCaV1() - throws EncodingException, InvalidFieldException, LazyDecodingException { + public void testEncodeUspV1AndTcfEuV2AndTcfCaV1() { GppModel gppModel = new GppModel(); Assertions.assertEquals(false, gppModel.hasSection(UspV1.ID)); Assertions.assertEquals(false, gppModel.hasSection(TcfEuV2.ID)); @@ -287,9 +286,9 @@ public void testEncodeUspV1AndTcfEuV2AndTcfCaV1() Assertions.assertEquals(true, gppModel.hasSection(TcfEuV2.NAME)); Assertions.assertEquals(false, gppModel.hasSection(TcfCaV1.NAME)); - gppModel.setFieldValue(UspV1.NAME, UspV1Field.NOTICE, "Y"); - gppModel.setFieldValue(UspV1.NAME, UspV1Field.OPT_OUT_SALE, "N"); - gppModel.setFieldValue(UspV1.NAME, UspV1Field.LSPA_COVERED, "N"); + gppModel.setFieldValue(UspV1.NAME, UspV1Field.NOTICE, 'Y'); + gppModel.setFieldValue(UspV1.NAME, UspV1Field.OPT_OUT_SALE, 'N'); + gppModel.setFieldValue(UspV1.NAME, UspV1Field.LSPA_COVERED, 'N'); Assertions.assertEquals(true, gppModel.hasSection(UspV1.ID)); Assertions.assertEquals(true, gppModel.hasSection(TcfEuV2.ID)); @@ -339,7 +338,7 @@ public void testEncodeUspV1AndTcfEuV2AndTcfCaV1() String gppString = gppModel.encode(); Assertions.assertEquals( - "DBACOeA~CPSG_8APSG_8ANwAAAENAwCAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~BPSG_8APSG_8AAyACAENGdCgf_gfgAfgfgBgABABAAABAB4AACAC.fHHHA4444ao~1YNN", + "DBACOeA~CPSG_8APSG_8ANwAAAENAwCAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~BPSG_8APSG_8AAyACAENGdCgf_gfgAfgfgBgABABAAABAB4AACACAAA.fHHHA4444ao~1YNN", gppString); Assertions.assertEquals(4, gppString.split("~").length); @@ -355,7 +354,7 @@ public void testEncodeUspV1AndTcfEuV2AndTcfCaV1() } @Test - public void testDecodeDefaults() throws DecodingException { + public void testDecodeDefaults() { String gppString = "DBAA"; GppModel gppModel = new GppModel(gppString); @@ -370,9 +369,9 @@ public void testDecodeDefaults() throws DecodingException { } @Test - public void testDecodeDefaultsAll() throws DecodingException { + public void testDecodeDefaultsAll() { String gppString = - "DBACOaw~CPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAA.YAAAAAAAAAA~1---~BAAAAAAAAAA.QA~BAAAAAAA.QA~BAAAAAA~BAAAAAA.QA~BAAAAAAA~BAAAAAAA.QA"; + "DBACOaw~CPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAA.YAAAAAAAAAA~1---~BAAAAAAAAQA.QA~BAAAAABA.QA~BAAAABA~BAAAAEA.QA~BAAAAAQA~BAAAAAEA.QA"; GppModel gppModel = new GppModel(gppString); Assertions.assertEquals(true, gppModel.hasSection(TcfEuV2.NAME)); @@ -387,7 +386,7 @@ public void testDecodeDefaultsAll() throws DecodingException { } @Test - public void testDecodeUspv1() throws DecodingException { + public void testDecodeUspv1() { String gppString = "DBABTA~1YNN"; GppModel gppModel = new GppModel(gppString); @@ -400,17 +399,17 @@ public void testDecodeUspv1() throws DecodingException { Assertions.assertEquals(false, gppModel.hasSection(TcfEuV2.NAME)); Assertions.assertEquals(false, gppModel.hasSection(TcfCaV1.NAME)); - Assertions.assertEquals("Y", gppModel.getFieldValue(UspV1.ID, UspV1Field.NOTICE)); - Assertions.assertEquals("N", gppModel.getFieldValue(UspV1.ID, UspV1Field.OPT_OUT_SALE)); - Assertions.assertEquals("N", gppModel.getFieldValue(UspV1.ID, UspV1Field.LSPA_COVERED)); + Assertions.assertEquals('Y', gppModel.getFieldValue(UspV1.ID, UspV1Field.NOTICE)); + Assertions.assertEquals('N', gppModel.getFieldValue(UspV1.ID, UspV1Field.OPT_OUT_SALE)); + Assertions.assertEquals('N', gppModel.getFieldValue(UspV1.ID, UspV1Field.LSPA_COVERED)); - Assertions.assertEquals("Y", gppModel.getFieldValue(UspV1.NAME, UspV1Field.NOTICE)); - Assertions.assertEquals("N", gppModel.getFieldValue(UspV1.NAME, UspV1Field.OPT_OUT_SALE)); - Assertions.assertEquals("N", gppModel.getFieldValue(UspV1.NAME, UspV1Field.LSPA_COVERED)); + Assertions.assertEquals('Y', gppModel.getFieldValue(UspV1.NAME, UspV1Field.NOTICE)); + Assertions.assertEquals('N', gppModel.getFieldValue(UspV1.NAME, UspV1Field.OPT_OUT_SALE)); + Assertions.assertEquals('N', gppModel.getFieldValue(UspV1.NAME, UspV1Field.LSPA_COVERED)); } @Test - public void testDecodeTcfEuV2() throws DecodingException { + public void testDecodeTcfEuV2() { String gppString = "DBABMA~CPSG_8APSG_8ANwAAAENAwCAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA"; GppModel gppModel = new GppModel(gppString); @@ -453,7 +452,7 @@ public void testDecodeTcfEuV2() throws DecodingException { } @Test - public void testDecodeUspv1AndTcfEuV2() throws DecodingException { + public void testDecodeUspv1AndTcfEuV2() { String gppString = "DBACNYA~CPSG_8APSG_8ANwAAAENAwCAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~1YNN"; GppModel gppModel = new GppModel(gppString); @@ -467,13 +466,13 @@ public void testDecodeUspv1AndTcfEuV2() throws DecodingException { Assertions.assertEquals(false, gppModel.hasSection(TcfCaV1.NAME)); - Assertions.assertEquals("Y", gppModel.getFieldValue(UspV1.ID, UspV1Field.NOTICE)); - Assertions.assertEquals("N", gppModel.getFieldValue(UspV1.ID, UspV1Field.OPT_OUT_SALE)); - Assertions.assertEquals("N", gppModel.getFieldValue(UspV1.ID, UspV1Field.LSPA_COVERED)); + Assertions.assertEquals('Y', gppModel.getFieldValue(UspV1.ID, UspV1Field.NOTICE)); + Assertions.assertEquals('N', gppModel.getFieldValue(UspV1.ID, UspV1Field.OPT_OUT_SALE)); + Assertions.assertEquals('N', gppModel.getFieldValue(UspV1.ID, UspV1Field.LSPA_COVERED)); - Assertions.assertEquals("Y", gppModel.getFieldValue(UspV1.NAME, UspV1Field.NOTICE)); - Assertions.assertEquals("N", gppModel.getFieldValue(UspV1.NAME, UspV1Field.OPT_OUT_SALE)); - Assertions.assertEquals("N", gppModel.getFieldValue(UspV1.NAME, UspV1Field.LSPA_COVERED)); + Assertions.assertEquals('Y', gppModel.getFieldValue(UspV1.NAME, UspV1Field.NOTICE)); + Assertions.assertEquals('N', gppModel.getFieldValue(UspV1.NAME, UspV1Field.OPT_OUT_SALE)); + Assertions.assertEquals('N', gppModel.getFieldValue(UspV1.NAME, UspV1Field.LSPA_COVERED)); Assertions.assertEquals(2, gppModel.getFieldValue(TcfEuV2.ID, TcfEuV2Field.VERSION)); Assertions.assertEquals(880, gppModel.getFieldValue(TcfEuV2.ID, TcfEuV2Field.CMP_ID)); @@ -511,15 +510,15 @@ public void testDecodeUspv1AndTcfEuV2() throws DecodingException { UspV1 uspV1Section = (UspV1) gppModel.getSection(UspV1.NAME); Integer uspV1Version = uspV1Section.getVersion(); - String notice = uspV1Section.getNotice(); + Character notice = uspV1Section.getNotice(); Assertions.assertEquals(1, uspV1Version); - Assertions.assertEquals("Y", notice); + Assertions.assertEquals('Y', notice); } @Test - public void testDecodeUspv1AndTcfEuV2AndTcfCaV1() throws DecodingException { + public void testDecodeUspv1AndTcfEuV2AndTcfCaV1() { String gppString = - "DBACOeA~CPSG_8APSG_8ANwAAAENAwCAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~BPSG_8APSG_8AAyACAENGdCgf_gfgAfgfgBgABABAAABAB4AACAC.fHHHA4444ao~1YNN"; + "DBACOeA~CPSG_8APSG_8ANwAAAENAwCAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~BPSG_8APSG_8AAyACAENGdCgf_gfgAfgfgBgABABAAABAB4AACACAAA.fHHHA4444ao~1YNN"; GppModel gppModel = new GppModel(gppString); Assertions.assertEquals(Arrays.asList(2, 5, 6), gppModel.getSectionIds()); @@ -527,9 +526,9 @@ public void testDecodeUspv1AndTcfEuV2AndTcfCaV1() throws DecodingException { Assertions.assertEquals(true, gppModel.hasSection(TcfEuV2.NAME)); Assertions.assertEquals(true, gppModel.hasSection(TcfCaV1.NAME)); - Assertions.assertEquals("Y", gppModel.getFieldValue(UspV1.NAME, UspV1Field.NOTICE)); - Assertions.assertEquals("N", gppModel.getFieldValue(UspV1.NAME, UspV1Field.OPT_OUT_SALE)); - Assertions.assertEquals("N", gppModel.getFieldValue(UspV1.NAME, UspV1Field.LSPA_COVERED)); + Assertions.assertEquals('Y', gppModel.getFieldValue(UspV1.NAME, UspV1Field.NOTICE)); + Assertions.assertEquals('N', gppModel.getFieldValue(UspV1.NAME, UspV1Field.OPT_OUT_SALE)); + Assertions.assertEquals('N', gppModel.getFieldValue(UspV1.NAME, UspV1Field.LSPA_COVERED)); Assertions.assertEquals(2, gppModel.getFieldValue(TcfEuV2.NAME, TcfEuV2Field.VERSION)); Assertions.assertEquals(880, gppModel.getFieldValue(TcfEuV2.NAME, TcfEuV2Field.CMP_ID)); @@ -553,9 +552,9 @@ public void testDecodeUspv1AndTcfEuV2AndTcfCaV1() throws DecodingException { UspV1 uspV1Section = (UspV1) gppModel.getSection(UspV1.NAME); Integer uspV1Version = uspV1Section.getVersion(); - String notice = uspV1Section.getNotice(); + Character notice = uspV1Section.getNotice(); Assertions.assertEquals(1, uspV1Version); - Assertions.assertEquals("Y", notice); + Assertions.assertEquals('Y', notice); TcfCaV1 tcfCaV1Section = (TcfCaV1) gppModel.getSection(TcfCaV1.NAME); Assertions.assertEquals(50, tcfCaV1Section.getCmpId()); @@ -598,7 +597,7 @@ public void testDecodeUspv1AndTcfEuV2AndTcfCaV1() throws DecodingException { } @Test - public void testEncode1() throws EncodingException, InvalidFieldException, LazyDecodingException { + public void testEncode1() { GppModel gppModel = new GppModel(); gppModel.setFieldValue(TcfEuV2.NAME, TcfEuV2Field.VENDOR_CONSENTS, Arrays.asList(28)); @@ -609,7 +608,7 @@ public void testEncode1() throws EncodingException, InvalidFieldException, LazyD } @Test - public void testEncode2() throws EncodingException, InvalidFieldException, LazyDecodingException { + public void testEncode2() { GppModel gppModel = new GppModel(); gppModel.setFieldValue(TcfEuV2.NAME, TcfEuV2Field.VENDOR_CONSENTS, Arrays.asList(29)); @@ -620,7 +619,7 @@ public void testEncode2() throws EncodingException, InvalidFieldException, LazyD } @Test - public void testEncode3() throws EncodingException, InvalidFieldException, LazyDecodingException { + public void testEncode3() { GppModel gppModel = new GppModel(); gppModel.setFieldValue(TcfEuV2.NAME, TcfEuV2Field.VENDOR_CONSENTS, Arrays.asList(1, 173, 722)); @@ -632,26 +631,26 @@ public void testEncode3() throws EncodingException, InvalidFieldException, LazyD } @Test - public void testDecode1() throws DecodingException { + public void testDecode1() { GppModel gppModel = new GppModel("DBABMA~CPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAOAAAABAAAAA.QAAA.IAAA"); Assertions.assertEquals(Arrays.asList(28), gppModel.getFieldValue(TcfEuV2.NAME, TcfEuV2Field.VENDOR_CONSENTS)); } @Test - public void testDecode2() throws DecodingException { + public void testDecode2() { GppModel gppModel = new GppModel("DBABMA~CPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAOwAQAOgAAAA.QAAA.IAAA"); Assertions.assertEquals(Arrays.asList(29), gppModel.getFieldValue(TcfEuV2.NAME, TcfEuV2Field.VENDOR_CONSENTS)); } @Test - public void testDecode3() throws DecodingException { + public void testDecode3() { GppModel gppModel = new GppModel("DBABMA~CPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAFpQAwAAgCtAWkAAAAAAA.QAAA.IAAA"); Assertions.assertEquals(Arrays.asList(1, 173, 722), gppModel.getFieldValue(TcfEuV2.NAME, TcfEuV2Field.VENDOR_CONSENTS)); } @Test - public void testConsistency() throws InvalidFieldException, EncodingException, DecodingException { + public void testConsistency() { GppModel fromObjectModel = new GppModel(); fromObjectModel.setFieldValue(TcfEuV2.NAME, TcfEuV2Field.PURPOSE_CONSENTS, @@ -666,11 +665,79 @@ public void testConsistency() throws InvalidFieldException, EncodingException, D GppModel decodedModel = new GppModel(fromObjectModel.encode()); Assertions.assertEquals( - Arrays.asList(true, true, true, true, true, true, true, true, true, true, false, false, false, false, - false, false, false, false, false, false, false, false, false, false), + Arrays.asList(true, true, true, true, true, true, true, true, true, true, false, false, false, false, false, + false, false, false, false, false, false, false, false, false), decodedModel.getFieldValue(TcfEuV2.NAME, TcfEuV2Field.PURPOSE_CONSENTS)); Assertions.assertEquals(Arrays.asList(21, 32, 81, 128, 173, 210, 238, 755), decodedModel.getFieldValue(TcfEuV2.NAME, TcfEuV2Field.VENDOR_CONSENTS)); } + + @Test + public void testNullConstructor() { + GppModel gppModel = new GppModel(null); + Assertions.assertEquals("DBAA", gppModel.encode()); + + gppModel.setFieldValue("uspv1", UspV1Field.NOTICE, 'Y'); + Assertions.assertEquals("DBABTA~1Y--", gppModel.encode()); + } + + @Test + public void testEmptyStringConstructor() { + GppModel gppModel = new GppModel(""); + Assertions.assertEquals("DBAA", gppModel.encode()); + + gppModel.setFieldValue("uspv1", UspV1Field.NOTICE, 'Y'); + Assertions.assertEquals("DBABTA~1Y--", gppModel.encode()); + } + + @Test + public void testDecodingNull() { + GppModel gppModel = new GppModel("DBABTA~1---"); + Assertions.assertEquals("DBABTA~1---", gppModel.encode()); + + gppModel.decode(null); + Assertions.assertEquals("DBAA", gppModel.encode()); + + gppModel.setFieldValue("uspv1", UspV1Field.NOTICE, 'Y'); + Assertions.assertEquals("DBABTA~1Y--", gppModel.encode()); + } + + @Test + public void testDecodingEmptyString() { + GppModel gppModel = new GppModel("DBABTA~1---"); + Assertions.assertEquals("DBABTA~1---", gppModel.encode()); + + gppModel.decode(null); + Assertions.assertEquals("DBAA", gppModel.encode()); + + gppModel.setFieldValue("uspv1", UspV1Field.NOTICE, 'Y'); + Assertions.assertEquals("DBABTA~1Y--", gppModel.encode()); + } + + @Test + public void testMismatchedSections() { + try { + GppModel gppModel = new GppModel("DBACOeA~CPSG_8APSG_8ANwAAAENAwCAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~BPSG_8APSG_8AAyACAENGdCgf_gfgAfgfgBgABABAAABAB4AACACAAA.fHHHA4444ao"); + gppModel.getHeader().getSectionsIds(); + Assertions.fail("Expected DecodingException"); + } catch (DecodingException e) { + + } catch (Exception e) { + Assertions.fail("Expected DecodingException"); + } + } + + @Test + public void testEmptySections() { + try { + GppModel gppModel = new GppModel("DBACOeA~~1YNN"); + gppModel.getHeader().getSectionsIds(); + Assertions.fail("Expected DecodingException"); + } catch (DecodingException e) { + + } catch (Exception e) { + Assertions.fail("Expected DecodingException"); + } + } } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/TraditionalBase64UrlEncoderTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/base64/TraditionalBase64UrlEncoderTest.java similarity index 60% rename from iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/TraditionalBase64UrlEncoderTest.java rename to iabgpp-encoder/src/test/java/com/iab/gpp/encoder/base64/TraditionalBase64UrlEncoderTest.java index a24cdf12..bd154790 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/TraditionalBase64UrlEncoderTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/base64/TraditionalBase64UrlEncoderTest.java @@ -1,42 +1,40 @@ -package com.iab.gpp.encoder.datatype.encoder; +package com.iab.gpp.encoder.base64; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; public class TraditionalBase64UrlEncoderTest { - private TraditionalBase64UrlEncoder base64UrlEncoder = new TraditionalBase64UrlEncoder(); + private TraditionalBase64UrlEncoder base64UrlEncoder = TraditionalBase64UrlEncoder.getInstance(); @Test - public void testEncode1() throws EncodingException { + public void testEncode1() { Assertions.assertEquals("DBABMAAA", base64UrlEncoder.encode("0000110000010000000000010011")); } @Test - public void testEncode2() throws EncodingException { + public void testEncode2() { Assertions.assertEquals("DBACNYAA", base64UrlEncoder.encode("000011000001000000000010001101011")); } @Test - public void testEncode3() throws EncodingException { + public void testEncode3() { Assertions.assertEquals("DBABjwAA", base64UrlEncoder.encode("00001100000100000000000110001111")); } @Test - public void testDecode1() throws DecodingException { + public void testDecode1() { Assertions.assertEquals("000011000001000000000001001100000000000000000000", base64UrlEncoder.decode("DBABMAAA")); } @Test - public void testDecode2() throws DecodingException { + public void testDecode2() { Assertions.assertEquals("000011000001000000000010001101011000000000000000", base64UrlEncoder.decode("DBACNYAA")); } @Test - public void testDecode3() throws DecodingException { + public void testDecode3() { Assertions.assertEquals("000011000001000000000001100011110000000000000000", base64UrlEncoder.decode("DBABjwAA")); } - + } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableBooleanTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableBooleanTest.java index 3ea44dbb..d015acd1 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableBooleanTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableBooleanTest.java @@ -6,13 +6,13 @@ public class EncodableBooleanTest { @Test - public void testSubstring1() { + public void testSubstring1() throws SubstringException { Assertions.assertEquals("000000000000000000000000000000000000", new EncodableDatetime().substring("10000000000000000000000000000000000001", 1)); } @Test - public void testSubstring2() { + public void testSubstring2() throws SubstringException { Assertions.assertEquals("111111111111111111111111111111111111", new EncodableDatetime().substring("01111111111111111111111111111111111110", 1)); } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableDatetimeTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableDatetimeTest.java index d7a6a759..43d271ba 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableDatetimeTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableDatetimeTest.java @@ -7,13 +7,13 @@ public class EncodableDatetimeTest { @Test - public void testSubstring1() throws DecodingException { + public void testSubstring1() throws DecodingException, SubstringException { Assertions.assertEquals("000000000000000000000000000000000000", new EncodableDatetime().substring("10000000000000000000000000000000000001", 1)); } @Test - public void testSubstring2() throws DecodingException { + public void testSubstring2() throws DecodingException, SubstringException { Assertions.assertEquals("111111111111111111111111111111111111", new EncodableDatetime().substring("01111111111111111111111111111111111110", 1)); } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFibonacciIntegerRangeTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFibonacciIntegerRangeTest.java index faac8ddc..765d5154 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFibonacciIntegerRangeTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFibonacciIntegerRangeTest.java @@ -7,7 +7,7 @@ public class EncodableFibonacciIntegerRangeTest { @Test - public void testSubstring1() throws DecodingException { + public void testSubstring1() throws DecodingException, SubstringException { Assertions.assertEquals("0000000000100001110110011", new EncodableFibonacciIntegerRange().substring("100000000001000011101100110", 1)); } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFibonacciIntegerTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFibonacciIntegerTest.java index bb982c7f..61dd7d0a 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFibonacciIntegerTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFibonacciIntegerTest.java @@ -7,7 +7,7 @@ public class EncodableFibonacciIntegerTest { @Test - public void testSubstring1() throws DecodingException { + public void testSubstring1() throws DecodingException, SubstringException { Assertions.assertEquals("0011", new EncodableFibonacciInteger().substring("100111", 1)); } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFixedBitfieldTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFixedBitfieldTest.java index f448f433..89ad98af 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFixedBitfieldTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFixedBitfieldTest.java @@ -6,12 +6,12 @@ public class EncodableFixedBitfieldTest { @Test - public void testSubstring1() { + public void testSubstring1() throws SubstringException { Assertions.assertEquals("000", new EncodableFixedBitfield(3).substring("10001", 1)); } @Test - public void testSubstring2() { + public void testSubstring2() throws SubstringException { Assertions.assertEquals("111", new EncodableFixedBitfield(3).substring("01110", 1)); } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFixedIntegerListTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFixedIntegerListTest.java index 9d33e1da..7146cc01 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFixedIntegerListTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFixedIntegerListTest.java @@ -6,12 +6,12 @@ public class EncodableFixedIntegerListTest { @Test - public void testSubstring1() { + public void testSubstring1() throws SubstringException { Assertions.assertEquals("1000", new EncodableFixedIntegerList(2, 2).substring("10001", 0)); } @Test - public void testSubstring2() { + public void testSubstring2() throws SubstringException { Assertions.assertEquals("1110", new EncodableFixedIntegerList(2, 2).substring("01110", 1)); } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFixedIntegerRangeTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFixedIntegerRangeTest.java index 51a16c39..0982aa40 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFixedIntegerRangeTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFixedIntegerRangeTest.java @@ -4,32 +4,33 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.EncodingException; public class EncodableFixedIntegerRangeTest { @Test - public void testSubstring1() throws DecodingException { + public void testSubstring1() throws DecodingException, SubstringException { Assertions.assertEquals("00000000001000000000000000011100000000000001010000000000001000", new EncodableFixedIntegerRange().substring("1000000000010000000000000000111000000000000010100000000000010001", 1)); } @Test - public void testSubstring2() throws DecodingException { + public void testSubstring2() throws DecodingException, SubstringException { Assertions.assertEquals("00000000000100000000000011101", new EncodableFixedIntegerRange().substring( "000010001111010010000110111111111100000000001111010010000110111111111100000000000000000000000000000000000000000100001101000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000001110110000000000010000000000001110100000000000000000000000000000", 230)); } @Test - public void testEncode1() { + public void testEncode1() throws EncodingException { EncodableFixedIntegerRange encodableFixedIntegerRange = new EncodableFixedIntegerRange(); encodableFixedIntegerRange.setValue(Arrays.asList(28)); Assertions.assertEquals("00000000000100000000000011100", encodableFixedIntegerRange.encode()); } @Test - public void testEncode2() { + public void testEncode2() throws EncodingException { EncodableFixedIntegerRange encodableFixedIntegerRange = new EncodableFixedIntegerRange(); encodableFixedIntegerRange.setValue(Arrays.asList(29)); Assertions.assertEquals("00000000000100000000000011101", encodableFixedIntegerRange.encode()); diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFixedIntegerTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFixedIntegerTest.java index 1236da01..709fd156 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFixedIntegerTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFixedIntegerTest.java @@ -6,12 +6,12 @@ public class EncodableFixedIntegerTest { @Test - public void testSubstring1() { + public void testSubstring1() throws SubstringException { Assertions.assertEquals("000", new EncodableFixedInteger(3).substring("10001", 1)); } @Test - public void testSubstring2() { + public void testSubstring2() throws SubstringException { Assertions.assertEquals("111", new EncodableFixedInteger(3).substring("01110", 1)); } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFixedStringTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFixedStringTest.java index a9014d8e..969a6c15 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFixedStringTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFixedStringTest.java @@ -6,12 +6,12 @@ public class EncodableFixedStringTest { @Test - public void testSubstring1() { + public void testSubstring1() throws SubstringException { Assertions.assertEquals("000000000000", new EncodableFixedString(2).substring("10000000000001", 1)); } @Test - public void testSubstring2() { + public void testSubstring2() throws SubstringException { Assertions.assertEquals("111111111111", new EncodableFixedString(2).substring("01111111111110", 1)); } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableOptimizedFixedRangeTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableOptimizedFixedRangeTest.java index 73af6f6e..5551b3e4 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableOptimizedFixedRangeTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableOptimizedFixedRangeTest.java @@ -3,71 +3,69 @@ import java.util.Arrays; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; public class EncodableOptimizedFixedRangeTest { private EncodableOptimizedFixedRange encodableOptimizedFixedRange = new EncodableOptimizedFixedRange(); @Test - public void testEncode1() throws EncodingException { + public void testEncode1() { encodableOptimizedFixedRange.setValue(Arrays.asList(12, 24, 48)); Assertions.assertEquals("00000000001100000000000000001000000000001000000000000000000000001", encodableOptimizedFixedRange.encode()); } @Test - public void testEncode2() throws EncodingException { + public void testEncode2() { encodableOptimizedFixedRange.setValue(Arrays.asList(18, 30)); Assertions.assertEquals("00000000000111100000000000000000001000000000001", encodableOptimizedFixedRange.encode()); } @Test - public void testEncode3() throws EncodingException { + public void testEncode3() { encodableOptimizedFixedRange.setValue(Arrays.asList(28)); Assertions.assertEquals("000000000001110000000000000000000000000000001", encodableOptimizedFixedRange.encode()); } @Test - public void testEncode4() throws EncodingException { + public void testEncode4() { encodableOptimizedFixedRange.setValue(Arrays.asList(29)); Assertions.assertEquals("0000000000011101100000000000100000000000011101", encodableOptimizedFixedRange.encode()); } @Test - public void testDecode1() throws DecodingException { + public void testDecode1() { encodableOptimizedFixedRange.decode("00000000001100000000000000001000000000001000000000000000000000001"); Assertions.assertEquals(Arrays.asList(12, 24, 48), encodableOptimizedFixedRange.getValue()); } @Test - public void testDecode2() throws DecodingException { + public void testDecode2() { encodableOptimizedFixedRange.decode("00000000000111100000000000000000001000000000001"); Assertions.assertEquals(Arrays.asList(18, 30), encodableOptimizedFixedRange.getValue()); } @Test - public void testDecode3() throws DecodingException { + public void testDecode3() { encodableOptimizedFixedRange.decode("000000000001110000000000000000000000000000001"); Assertions.assertEquals(Arrays.asList(28), encodableOptimizedFixedRange.getValue()); } @Test - public void testDecode4() throws DecodingException { + public void testDecode4() { encodableOptimizedFixedRange.decode("0000000000011101100000000000100000000000011101"); Assertions.assertEquals(Arrays.asList(29), encodableOptimizedFixedRange.getValue()); } @Test - public void testSubstring1() throws DecodingException { + public void testSubstring1() throws SubstringException { Assertions.assertEquals("000000000001110000000000000000000000000000001", encodableOptimizedFixedRange.substring( "000010001111010010000110111111111100000000001111010010000110111111111100000000000000000000000000000000000000000100001101000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000001110000000000000000000000000000001000000000000000000000000000000", 213)); } @Test - public void testSubstring2() throws DecodingException { + public void testSubstring2() throws SubstringException { Assertions.assertEquals("0000000000011101100000000000100000000000011101", encodableOptimizedFixedRange.substring( "000010001111010010000110111111111100000000001111010010000110111111111100000000000000000000000000000000000000000100001101000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000001110110000000000010000000000001110100000000000000000000000000000", 213)); diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/BooleanEncoderTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/BooleanEncoderTest.java index 3d1450f5..fea6ee70 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/BooleanEncoderTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/BooleanEncoderTest.java @@ -3,27 +3,26 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; public class BooleanEncoderTest { @Test - public void testEncode1() throws EncodingException { + public void testEncode1() { Assertions.assertEquals("0", BooleanEncoder.encode(false)); } @Test - public void testEncode2() throws EncodingException { + public void testEncode2() { Assertions.assertEquals("1", BooleanEncoder.encode(true)); } @Test - public void testDecode1() throws DecodingException { + public void testDecode1() { Assertions.assertEquals(false, BooleanEncoder.decode("0")); } @Test - public void testDecode2() throws DecodingException { + public void testDecode2() { Assertions.assertEquals(true, BooleanEncoder.decode("1")); } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedBitfieldEncoderTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedBitfieldEncoderTest.java index 77b5c9cf..d66e3538 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedBitfieldEncoderTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedBitfieldEncoderTest.java @@ -10,72 +10,82 @@ public class FixedBitfieldEncoderTest { @Test - public void testEncode1() throws EncodingException { + public void testEncode1() { Assertions.assertEquals("00", FixedBitfieldEncoder.encode(new ArrayList<>(), 2)); } @Test - public void testEncode2() throws EncodingException { + public void testEncode2() { Assertions.assertEquals("0", FixedBitfieldEncoder.encode(Arrays.asList(false), 1)); } @Test - public void testEncode3() throws EncodingException { + public void testEncode3() { Assertions.assertEquals("1", FixedBitfieldEncoder.encode(Arrays.asList(true), 1)); } @Test - public void testEncode4() throws EncodingException { + public void testEncode4() { Assertions.assertEquals("00", FixedBitfieldEncoder.encode(Arrays.asList(false, false), 2)); } @Test - public void testEncode5() throws EncodingException { + public void testEncode5() { Assertions.assertEquals("01", FixedBitfieldEncoder.encode(Arrays.asList(false, true), 2)); } @Test - public void testEncode6() throws EncodingException { + public void testEncode6() { Assertions.assertEquals("10", FixedBitfieldEncoder.encode(Arrays.asList(true, false), 2)); } @Test - public void testEncode7() throws EncodingException { + public void testEncode7() { Assertions.assertEquals("11", FixedBitfieldEncoder.encode(Arrays.asList(true, true), 2)); } @Test - public void testDecode1() throws DecodingException { + public void testEncode8() { + try { + FixedBitfieldEncoder.encode(Arrays.asList(true, true, true), 2); + Assertions.fail("EncodingException expected"); + } catch (EncodingException e) { + + } + } + + @Test + public void testDecode1() { Assertions.assertEquals(new ArrayList<>(), FixedBitfieldEncoder.decode("")); } @Test - public void testDecode2() throws DecodingException { + public void testDecode2() { Assertions.assertEquals(Arrays.asList(false), FixedBitfieldEncoder.decode("0")); } @Test - public void testDecode3() throws DecodingException { + public void testDecode3() { Assertions.assertEquals(Arrays.asList(true), FixedBitfieldEncoder.decode("1")); } @Test - public void testDecode4() throws DecodingException { + public void testDecode4() { Assertions.assertEquals(Arrays.asList(false, false), FixedBitfieldEncoder.decode("00")); } @Test - public void testDecode5() throws DecodingException { + public void testDecode5() { Assertions.assertEquals(Arrays.asList(false, true), FixedBitfieldEncoder.decode("01")); } @Test - public void testDecode6() throws DecodingException { + public void testDecode6() { Assertions.assertEquals(Arrays.asList(true, false), FixedBitfieldEncoder.decode("10")); } @Test - public void testDecode7() throws DecodingException { + public void testDecode7() { Assertions.assertEquals(Arrays.asList(true, true), FixedBitfieldEncoder.decode("11")); } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedIntegerEncoderTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedIntegerEncoderTest.java index cc8cc48b..a30b882b 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedIntegerEncoderTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedIntegerEncoderTest.java @@ -3,6 +3,7 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.EncodingException; public class FixedIntegerEncoderTest { @@ -30,6 +31,16 @@ public void testEncode4() { public void testEncode5() { Assertions.assertEquals("00000111", FixedIntegerEncoder.encode(7, 8)); } + + @Test + public void testEncode6() { + try { + FixedIntegerEncoder.encode(8, 1); + Assertions.fail("EncodingException expected"); + } catch (EncodingException e) { + + } + } @Test public void testDecode1() throws DecodingException { diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedIntegerListEncoderTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedIntegerListEncoderTest.java index 2c95b455..25de7e17 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedIntegerListEncoderTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedIntegerListEncoderTest.java @@ -10,177 +10,187 @@ public class FixedIntegerListEncoderTest { @Test - public void testEncode1() throws EncodingException { + public void testEncode1() { Assertions.assertEquals("0000", FixedIntegerListEncoder.encode(new ArrayList<>(), 2, 2)); } @Test - public void testEncode2() throws EncodingException { + public void testEncode2() { Assertions.assertEquals("0000", FixedIntegerListEncoder.encode(Arrays.asList(0), 2, 2)); } @Test - public void testEncode3() throws EncodingException { + public void testEncode3() { Assertions.assertEquals("0000", FixedIntegerListEncoder.encode(Arrays.asList(0, 0), 2, 2)); } @Test - public void testEncode4() throws EncodingException { + public void testEncode4() { Assertions.assertEquals("0001", FixedIntegerListEncoder.encode(Arrays.asList(0, 1), 2, 2)); } @Test - public void testEncode5() throws EncodingException { + public void testEncode5() { Assertions.assertEquals("0010", FixedIntegerListEncoder.encode(Arrays.asList(0, 2), 2, 2)); } @Test - public void testEncode6() throws EncodingException { + public void testEncode6() { Assertions.assertEquals("0011", FixedIntegerListEncoder.encode(Arrays.asList(0, 3), 2, 2)); } @Test - public void testEncode7() throws EncodingException { + public void testEncode7() { Assertions.assertEquals("0100", FixedIntegerListEncoder.encode(Arrays.asList(1, 0), 2, 2)); } @Test - public void testEncode8() throws EncodingException { + public void testEncode8() { Assertions.assertEquals("0101", FixedIntegerListEncoder.encode(Arrays.asList(1, 1), 2, 2)); } @Test - public void testEncode9() throws EncodingException { + public void testEncode9() { Assertions.assertEquals("0110", FixedIntegerListEncoder.encode(Arrays.asList(1, 2), 2, 2)); } @Test - public void testEncode10() throws EncodingException { + public void testEncode10() { Assertions.assertEquals("0111", FixedIntegerListEncoder.encode(Arrays.asList(1, 3), 2, 2)); } @Test - public void testEncode11() throws EncodingException { + public void testEncode11() { Assertions.assertEquals("1000", FixedIntegerListEncoder.encode(Arrays.asList(2, 0), 2, 2)); } @Test - public void testEncode12() throws EncodingException { + public void testEncode12() { Assertions.assertEquals("1001", FixedIntegerListEncoder.encode(Arrays.asList(2, 1), 2, 2)); } @Test - public void testEncode13() throws EncodingException { + public void testEncode13() { Assertions.assertEquals("1010", FixedIntegerListEncoder.encode(Arrays.asList(2, 2), 2, 2)); } @Test - public void testEncode14() throws EncodingException { + public void testEncode14() { Assertions.assertEquals("1011", FixedIntegerListEncoder.encode(Arrays.asList(2, 3), 2, 2)); } @Test - public void testEncode15() throws EncodingException { + public void testEncode15() { Assertions.assertEquals("1100", FixedIntegerListEncoder.encode(Arrays.asList(3, 0), 2, 2)); } @Test - public void testEncode16() throws EncodingException { + public void testEncode16() { Assertions.assertEquals("1101", FixedIntegerListEncoder.encode(Arrays.asList(3, 1), 2, 2)); } @Test - public void testEncode17() throws EncodingException { + public void testEncode17() { Assertions.assertEquals("1110", FixedIntegerListEncoder.encode(Arrays.asList(3, 2), 2, 2)); } @Test - public void testEncode18() throws EncodingException { + public void testEncode18() { Assertions.assertEquals("1111", FixedIntegerListEncoder.encode(Arrays.asList(3, 3), 2, 2)); } @Test - public void testDecode1() throws DecodingException { + public void testEncode19() { + try { + FixedIntegerListEncoder.encode(Arrays.asList(3, 3), 1, 1); + Assertions.fail("EncodingException expected"); + } catch (EncodingException e) { + + } + } + + @Test + public void testDecode1() { Assertions.assertEquals(Arrays.asList(0, 0), FixedIntegerListEncoder.decode("", 2, 2)); } @Test - public void testDecode2() throws DecodingException { + public void testDecode2() { Assertions.assertEquals(Arrays.asList(0, 0), FixedIntegerListEncoder.decode("0000", 2, 2)); } @Test - public void testDecode3() throws DecodingException { + public void testDecode3() { Assertions.assertEquals(Arrays.asList(0, 1), FixedIntegerListEncoder.decode("0001", 2, 2)); } @Test - public void testDecode4() throws DecodingException { + public void testDecode4() { Assertions.assertEquals(Arrays.asList(0, 2), FixedIntegerListEncoder.decode("0010", 2, 2)); } @Test - public void testDecode5() throws DecodingException { + public void testDecode5() { Assertions.assertEquals(Arrays.asList(0, 3), FixedIntegerListEncoder.decode("0011", 2, 2)); } @Test - public void testDecode6() throws DecodingException { + public void testDecode6() { Assertions.assertEquals(Arrays.asList(1, 0), FixedIntegerListEncoder.decode("0100", 2, 2)); } @Test - public void testDecode7() throws DecodingException { + public void testDecode7() { Assertions.assertEquals(Arrays.asList(1, 1), FixedIntegerListEncoder.decode("0101", 2, 2)); } @Test - public void testDecode8() throws DecodingException { + public void testDecode8() { Assertions.assertEquals(Arrays.asList(1, 2), FixedIntegerListEncoder.decode("0110", 2, 2)); } @Test - public void testDecode9() throws DecodingException { + public void testDecode9() { Assertions.assertEquals(Arrays.asList(1, 3), FixedIntegerListEncoder.decode("0111", 2, 2)); } @Test - public void testDecode10() throws DecodingException { + public void testDecode10() { Assertions.assertEquals(Arrays.asList(2, 0), FixedIntegerListEncoder.decode("1000", 2, 2)); } @Test - public void testDecode11() throws DecodingException { + public void testDecode11() { Assertions.assertEquals(Arrays.asList(2, 1), FixedIntegerListEncoder.decode("1001", 2, 2)); } @Test - public void testDecode12() throws DecodingException { + public void testDecode12() { Assertions.assertEquals(Arrays.asList(2, 2), FixedIntegerListEncoder.decode("1010", 2, 2)); } @Test - public void testDecode13() throws DecodingException { + public void testDecode13() { Assertions.assertEquals(Arrays.asList(2, 3), FixedIntegerListEncoder.decode("1011", 2, 2)); } @Test - public void testDecode14() throws DecodingException { + public void testDecode14() { Assertions.assertEquals(Arrays.asList(3, 0), FixedIntegerListEncoder.decode("1100", 2, 2)); } @Test - public void testDecode15() throws DecodingException { + public void testDecode15() { Assertions.assertEquals(Arrays.asList(3, 1), FixedIntegerListEncoder.decode("1101", 2, 2)); } @Test - public void testDecode16() throws DecodingException { + public void testDecode16() { Assertions.assertEquals(Arrays.asList(3, 2), FixedIntegerListEncoder.decode("1110", 2, 2)); } @Test - public void testDecode17() throws DecodingException { + public void testDecode17() { Assertions.assertEquals(Arrays.asList(3, 3), FixedIntegerListEncoder.decode("1111", 2, 2)); } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedLongEncoderTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedLongEncoderTest.java index b762f314..9a90a6dd 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedLongEncoderTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedLongEncoderTest.java @@ -3,6 +3,7 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.EncodingException; public class FixedLongEncoderTest { @@ -31,10 +32,21 @@ public void testEncode5() { Assertions.assertEquals("00000111", FixedLongEncoder.encode(7, 8)); } + @Test public void testEncode6() { Assertions.assertEquals("001111011111010001110101111011110101", FixedLongEncoder.encode(16630898421L, 36)); } + + @Test + public void testEncode7() { + try { + FixedIntegerEncoder.encode(8, 1); + Assertions.fail("EncodingException expected"); + } catch (EncodingException e) { + + } + } @Test public void testDecode1() throws DecodingException { diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedStringEncoderTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedStringEncoderTest.java index aba5ee84..4fef7dcc 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedStringEncoderTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedStringEncoderTest.java @@ -8,12 +8,12 @@ public class FixedStringEncoderTest { @Test - public void testEncode1() throws EncodingException { + public void testEncode1() { Assertions.assertEquals("000000000001", FixedStringEncoder.encode("AB", 2)); } @Test - public void testEncode2() throws EncodingException { + public void testEncode2() { Assertions.assertEquals("100000111111", FixedStringEncoder.encode("a", 2)); } @@ -28,12 +28,12 @@ public void testEncode3() { } @Test - public void testDecode1() throws DecodingException { + public void testDecode1() { Assertions.assertEquals("AB", FixedStringEncoder.decode("000000000001")); } @Test - public void testDecode2() throws DecodingException { + public void testDecode2() { Assertions.assertEquals("a", FixedStringEncoder.decode("100000111111")); } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/HeaderV1Test.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/HeaderV1Test.java index 4c74ec5a..5ed478a5 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/HeaderV1Test.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/HeaderV1Test.java @@ -5,79 +5,32 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; -import com.iab.gpp.encoder.error.InvalidFieldException; public class HeaderV1Test { @Test - public void testEncodeToBitString1() throws EncodingException, InvalidFieldException { - HeaderV1 headerV1 = new HeaderV1(); - headerV1.setFieldValue("SectionIds", new ArrayList<>()); - Assertions.assertEquals("000011000001000000000000", headerV1.encodeToBitString()); - } - - @Test - public void testEncodeToBitString2() throws EncodingException, InvalidFieldException { - HeaderV1 headerV1 = new HeaderV1(); - headerV1.setFieldValue("SectionIds", Arrays.asList(2)); - Assertions.assertEquals("0000110000010000000000010011", headerV1.encodeToBitString()); - } - - @Test - public void testEncodeToBitString3() throws EncodingException, InvalidFieldException { - HeaderV1 headerV1 = new HeaderV1(); - headerV1.setFieldValue("SectionIds", Arrays.asList(2, 6)); - Assertions.assertEquals("000011000001000000000010001101011", headerV1.encodeToBitString()); - } - - @Test - public void testDecodeFromBitString1() throws DecodingException { - HeaderV1 headerV1 = new HeaderV1(); - headerV1.decodeFromBitString("000011000001000000000000"); - Assertions.assertEquals(new ArrayList<>(), headerV1.getFieldValue("SectionIds")); - Assertions.assertEquals(headerV1.getFieldValue("SectionIds"), headerV1.getSectionsIds()); - } - - @Test - public void testDecodeFromBitString2() throws DecodingException { - HeaderV1 headerV1 = new HeaderV1(); - headerV1.decodeFromBitString("0000110000010000000000010011"); - Assertions.assertEquals(Arrays.asList(2), headerV1.getFieldValue("SectionIds")); - Assertions.assertEquals(headerV1.getFieldValue("SectionIds"), headerV1.getSectionsIds()); - } - - @Test - public void testDecodeFromBitString3() throws DecodingException { - HeaderV1 headerV1 = new HeaderV1(); - headerV1.decodeFromBitString("000001000011000000000010001101011"); - Assertions.assertEquals(Arrays.asList(2, 6), headerV1.getFieldValue("SectionIds")); - Assertions.assertEquals(headerV1.getFieldValue("SectionIds"), headerV1.getSectionsIds()); - } - - @Test - public void testEncode1() throws EncodingException, InvalidFieldException { + public void testEncode1() { HeaderV1 headerV1 = new HeaderV1(); headerV1.setFieldValue("SectionIds", new ArrayList<>()); Assertions.assertEquals("DBAA", headerV1.encode()); } @Test - public void testEncode2() throws EncodingException, InvalidFieldException { + public void testEncode2() { HeaderV1 headerV1 = new HeaderV1(); headerV1.setFieldValue("SectionIds", Arrays.asList(2)); Assertions.assertEquals("DBABMA", headerV1.encode()); } @Test - public void testEncode3() throws EncodingException, InvalidFieldException { + public void testEncode3() { HeaderV1 headerV1 = new HeaderV1(); headerV1.setFieldValue("SectionIds", Arrays.asList(2, 6)); Assertions.assertEquals("DBACNYA", headerV1.encode()); } @Test - public void testDecode1() throws DecodingException { + public void testDecode1() { HeaderV1 headerV1 = new HeaderV1(); headerV1.decode("DBAA"); Assertions.assertEquals(new ArrayList<>(), headerV1.getFieldValue("SectionIds")); @@ -86,7 +39,7 @@ public void testDecode1() throws DecodingException { } @Test - public void testDecode2() throws DecodingException { + public void testDecode2() { HeaderV1 headerV1 = new HeaderV1(); headerV1.decode("DBABMA"); Assertions.assertEquals(Arrays.asList(2), headerV1.getFieldValue("SectionIds")); @@ -95,11 +48,18 @@ public void testDecode2() throws DecodingException { } @Test - public void testDecode3() throws DecodingException { + public void testDecode3() { HeaderV1 headerV1 = new HeaderV1(); headerV1.decode("DBACNYA"); Assertions.assertEquals(Arrays.asList(2, 6), headerV1.getFieldValue("SectionIds")); Assertions.assertEquals(headerV1.getFieldValue("Version"), headerV1.getVersion()); Assertions.assertEquals(headerV1.getFieldValue("SectionIds"), headerV1.getSectionsIds()); } + + @Test() + public void testDecodeGarbage() { + Assertions.assertThrows(DecodingException.class, () -> { + new HeaderV1("z").getSectionsIds(); + }); + } } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/TcfCaV1Test.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/TcfCaV1Test.java index 49b204d2..3f53a288 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/TcfCaV1Test.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/TcfCaV1Test.java @@ -3,9 +3,12 @@ import java.time.ZoneId; import java.time.ZonedDateTime; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import com.iab.gpp.encoder.datatype.RangeEntry; import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.error.EncodingException; import com.iab.gpp.encoder.error.InvalidFieldException; @@ -14,16 +17,16 @@ public class TcfCaV1Test { @Test - public void testEncode1() throws EncodingException, InvalidFieldException { + public void testEncode1() { TcfCaV1 tcfCaV1 = new TcfCaV1(); tcfCaV1.setFieldValue(TcfCaV1Field.CREATED, ZonedDateTime.of(2022, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC"))); tcfCaV1.setFieldValue(TcfCaV1Field.LAST_UPDATED, ZonedDateTime.of(2022, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC"))); - Assertions.assertEquals("BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAA.YAAAAAAAAAA", tcfCaV1.encode()); + Assertions.assertEquals("BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAA.YAAAAAAAAAA", tcfCaV1.encode()); } @Test - public void testEncode2() throws EncodingException, InvalidFieldException { + public void testEncode2() { TcfCaV1 tcfCaV1 = new TcfCaV1(); tcfCaV1.setFieldValue(TcfCaV1Field.CMP_ID, 50); @@ -53,12 +56,38 @@ public void testEncode2() throws EncodingException, InvalidFieldException { tcfCaV1.setFieldValue(TcfCaV1Field.CREATED, ZonedDateTime.of(2022, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC"))); tcfCaV1.setFieldValue(TcfCaV1Field.LAST_UPDATED, ZonedDateTime.of(2022, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC"))); - Assertions.assertEquals("BPSG_8APSG_8AAyACAENGdCgf_gfgAfgfgBgABABAAABAB4AACAC.fHHHA4444ao", tcfCaV1.encode()); + Assertions.assertEquals("BPSG_8APSG_8AAyACAENGdCgf_gfgAfgfgBgABABAAABAB4AACACAAA.fHHHA4444ao", tcfCaV1.encode()); } @Test - public void testDecode1() throws DecodingException { - TcfCaV1 tcfCaV1 = new TcfCaV1("CAAAAAAAAAAAAAAAAAENAACAAAAAAAAAAAAAAAAA.YAAAAAAAAAA"); + public void testEncode3() throws EncodingException, InvalidFieldException { + + TcfCaV1 tcfCaV1 = new TcfCaV1(); + tcfCaV1.setFieldValue(TcfCaV1Field.DISCLOSED_VENDORS, Arrays.asList(1, 2, 3, 5, 6, 7, 10, 11, 12)); + + tcfCaV1.setFieldValue(TcfCaV1Field.CREATED, ZonedDateTime.of(2022, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC"))); + tcfCaV1.setFieldValue(TcfCaV1Field.LAST_UPDATED, ZonedDateTime.of(2022, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC"))); + + Assertions.assertEquals("BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAA.YAAAAAAAAAA.IAGO5w", tcfCaV1.encode()); + } + + @Test + public void testEncode4() throws EncodingException, InvalidFieldException { + + List pubRestrictions = new ArrayList<>(); + pubRestrictions.add(new RangeEntry(1, 1, Arrays.asList(1, 2, 3, 5, 6, 7, 9))); + + TcfCaV1 tcfCaV1 = new TcfCaV1(); + tcfCaV1.setFieldValue(TcfCaV1Field.PUB_RESTRICTIONS, pubRestrictions); + + tcfCaV1.setFieldValue(TcfCaV1Field.CREATED, ZonedDateTime.of(2022, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC"))); + tcfCaV1.setFieldValue(TcfCaV1Field.LAST_UPDATED, ZonedDateTime.of(2022, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC"))); + Assertions.assertEquals("BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAACCgBwABAAOAAoADgAJA.YAAAAAAAAAA", tcfCaV1.encode()); + } + + @Test + public void testDecode1() { + TcfCaV1 tcfCaV1 = new TcfCaV1("BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAA.YAAAAAAAAAA"); Assertions.assertEquals(0, tcfCaV1.getCmpId()); Assertions.assertEquals(0, tcfCaV1.getCmpVersion()); @@ -90,8 +119,8 @@ public void testDecode1() throws DecodingException { Assertions.assertEquals(0, tcfCaV1.getNumCustomPurposes()); Assertions.assertEquals(Arrays.asList(), tcfCaV1.getCustomPurposesExpressConsent()); Assertions.assertEquals(Arrays.asList(), tcfCaV1.getCustomPurposesImpliedConsent()); - Assertions.assertEquals(ZonedDateTime.of(1970, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC")), tcfCaV1.getCreated()); - Assertions.assertEquals(ZonedDateTime.of(1970, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC")), tcfCaV1.getLastUpdated()); + Assertions.assertEquals(ZonedDateTime.of(2022, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC")), tcfCaV1.getCreated()); + Assertions.assertEquals(ZonedDateTime.of(2022, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC")), tcfCaV1.getLastUpdated()); Assertions.assertEquals("EN", tcfCaV1.getConsentLanguage()); Assertions.assertEquals(5, tcfCaV1.getId()); @@ -99,8 +128,8 @@ public void testDecode1() throws DecodingException { } @Test - public void testDecode2() throws DecodingException { - TcfCaV1 tcfCaV1 = new TcfCaV1("CPSG_8APSG_8AAyACAENGdCgf_gfgAfgfgBgABABAAABAB4AACAC.fHHHA4444ao"); + public void testDecode2() { + TcfCaV1 tcfCaV1 = new TcfCaV1("BPSG_8APSG_8AAyACAENGdCgf_gfgAfgfgBgABABAAABAB4AACACAAA.fHHHA4444ao"); Assertions.assertEquals(50, tcfCaV1.getCmpId()); Assertions.assertEquals(2, tcfCaV1.getCmpVersion()); @@ -136,4 +165,37 @@ public void testDecode2() throws DecodingException { Assertions.assertEquals(5, tcfCaV1.getId()); Assertions.assertEquals(3, tcfCaV1.getPubPurposesSegmentType()); } + + @Test + public void testDecode3() throws DecodingException { + TcfCaV1 tcfCaV1 = new TcfCaV1("BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAA.YAAAAAAAAAA.IAGO5w"); + + Assertions.assertEquals(1, tcfCaV1.getDisclosedVendorsSegmentType()); + Assertions.assertEquals(Arrays.asList(1, 2, 3, 5, 6, 7, 10, 11, 12), tcfCaV1.getDisclosedVendors()); + } + + @Test + public void testDecode4() throws DecodingException { + TcfCaV1 tcfCaV1 = new TcfCaV1("BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAACCgBwABAAOAAoADgAJA.YAAAAAAAAAA"); + + List pubRestictions = tcfCaV1.getPubRestrictions(); + Assertions.assertEquals(1, pubRestictions.size()); + Assertions.assertEquals(1, pubRestictions.get(0).getKey()); + Assertions.assertEquals(1, pubRestictions.get(0).getType()); + Assertions.assertEquals(Arrays.asList(1, 2, 3, 5, 6, 7, 9), pubRestictions.get(0).getIds()); + } + + @Test() + public void testDecodeGarbage1() { + Assertions.assertThrows(DecodingException.class, () -> { + new TcfCaV1("A").getPubRestrictions(); + }); + } + + @Test() + public void testDecodeGarbage2() { + Assertions.assertThrows(DecodingException.class, () -> { + new TcfCaV1("z").getPubRestrictions(); + }); + } } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/TcfEuV2Test.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/TcfEuV2Test.java index 20eb2a7b..945f7468 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/TcfEuV2Test.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/TcfEuV2Test.java @@ -6,15 +6,14 @@ import java.util.List; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import com.iab.gpp.encoder.datatype.RangeEntry; import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; -import com.iab.gpp.encoder.error.InvalidFieldException; import com.iab.gpp.encoder.field.TcfEuV2Field; public class TcfEuV2Test { @Test - public void testEncode1() throws EncodingException, InvalidFieldException { + public void testEncode1() { TcfEuV2 tcfEuV2 = new TcfEuV2(); tcfEuV2.setFieldValue(TcfEuV2Field.CREATED, ZonedDateTime.of(2022, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC"))); tcfEuV2.setFieldValue(TcfEuV2Field.LAST_UPDATED, ZonedDateTime.of(2022, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC"))); @@ -22,16 +21,30 @@ public void testEncode1() throws EncodingException, InvalidFieldException { } @Test - public void testEncode2() throws EncodingException, InvalidFieldException { + public void testEncode2() { TcfEuV2 tcfEuV2 = new TcfEuV2(); tcfEuV2.setFieldValue(TcfEuV2Field.IS_SERVICE_SPECIFIC, true); tcfEuV2.setFieldValue(TcfEuV2Field.CREATED, ZonedDateTime.of(2022, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC"))); tcfEuV2.setFieldValue(TcfEuV2Field.LAST_UPDATED, ZonedDateTime.of(2022, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC"))); + + Assertions.assertEquals(3, tcfEuV2.getFieldValue(TcfEuV2Field.PUBLISHER_PURPOSES_SEGMENT_TYPE)); + Assertions.assertEquals( + Arrays.asList(false, false, false, false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false), + tcfEuV2.getFieldValue(TcfEuV2Field.PUBLISHER_CONSENTS)); + Assertions.assertEquals( + Arrays.asList(false, false, false, false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false), + tcfEuV2.getFieldValue(TcfEuV2Field.PUBLISHER_LEGITIMATE_INTERESTS)); + Assertions.assertEquals(0, tcfEuV2.getFieldValue(TcfEuV2Field.NUM_CUSTOM_PURPOSES)); + Assertions.assertEquals(Arrays.asList(), tcfEuV2.getFieldValue(TcfEuV2Field.PUBLISHER_CUSTOM_CONSENTS)); + Assertions.assertEquals(Arrays.asList(), tcfEuV2.getFieldValue(TcfEuV2Field.PUBLISHER_CUSTOM_LEGITIMATE_INTERESTS)); + Assertions.assertEquals("CPSG_8APSG_8AAAAAAENAACgAAAAAAAAAAAAAAAAAAAA.YAAAAAAAAAAA", tcfEuV2.encode()); } @Test - public void testDecode1() throws DecodingException { + public void testDecode1() { TcfEuV2 tcfEuV2 = new TcfEuV2("CAAAAAAAAAAAAAAAAAENAACAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA"); Assertions.assertEquals(2, tcfEuV2.getVersion()); @@ -84,7 +97,7 @@ public void testDecode1() throws DecodingException { } @Test - public void testDecode2() throws DecodingException { + public void testDecode2() { TcfEuV2 tcfEuV2 = new TcfEuV2("CPSG_8APSG_8AAAAAAENAACgAAAAAAAAAAAAAAAAAAAA.YAAAAAAAAAAA"); Assertions.assertEquals(2, tcfEuV2.getVersion()); @@ -138,7 +151,7 @@ public void testDecode2() throws DecodingException { @SuppressWarnings("unchecked") @Test - public void testDecode3() throws DecodingException { + public void testDecode3() { TcfEuV2 tcfEuV2 = new TcfEuV2( "CPcqBNJPcqBNJNwAAAENAwCAAAAAAAAAAAAAAAAAAAAA.YAAAAAAAAAA.QGLtV_T9fb2vj-_Z99_tkeYwf95y3p-wzhheMs-8NyZeH_B4Wv2MyvBX4JiQKGRgksjLBAQdtHGlcTQgBwIlViTLMYk2MjzNKJrJEilsbO2dYGD9Pn8HT3ZCY70-vv__7v3ff_3g.IGLtV_T9fb2vj-_Z99_tkeYwf95y3p-wzhheMs-8NyZeH_B4Wv2MyvBX4JiQKGRgksjLBAQdtHGlcTQgBwIlViTLMYk2MjzNKJrJEilsbO2dYGD9Pn8HT3ZCY70-vv__7v3ff_3g"); @@ -241,7 +254,7 @@ public void testDecode3() throws DecodingException { @SuppressWarnings("unchecked") @Test - public void testDecode4() throws DecodingException { + public void testDecode4() { TcfEuV2 tcfEuV2 = new TcfEuV2( "CPi8wgAPi8wgAAOACBENCuCoAP_AAEfAACiQJHNd_H__bX9n-f7_6ft0eY1f9_r37uQzDhfNk-8F3L_W_LwX_2E7NF36tq4KmR4ku1LBIUNtHMnUDUmxaokVrzHsak2cpzNKJ_BkknsZe2dYGF9vm5tj-QKZ7_5_d3f52T_9_9v-39z33913v3d93-_13LjdV5_9H_v9fR_b8_Kf9_5-_4v8_____3_e______8AEEggCTDVuIAuxLHAm0DCKBECMKwkKoFABBQDC0QGADg4KdlYBPrCBAAgFAEYEQIcAUYEAgAAAgCQiACQIsEAAAIgEAAIAEQiEABAwCCgAsDAIAAQDQMUQoABAkIMiAiKUwICIEggJbKhBKC6Q0wgCrLACgkRsFAAiAAAUgACAsHAMESAlYsECTFG-QAjBCgFEqFaAGGgAwABBI4RABgACCRwqADAAEEjgA"); @@ -278,7 +291,7 @@ public void testDecode4() throws DecodingException { @SuppressWarnings("unchecked") @Test - public void testDecode5() throws DecodingException { + public void testDecode5() { TcfEuV2 tcfEuV2 = new TcfEuV2( "CPgA5EAPgA5EAAOACBENCuCoAP_AAEfAACiQI0Nd_H__bX9n-f7_6Pt0cY1f9_r3ruQzDhfFk-8F3L_W3LwX32E7NF36pq4KmR4ku1LBIQFtHMnUDUmxaokVrzHsak2cpyNKI7BkknsZe2dYGF9Pm5lD-QKZ7_5_d3f52T_9_9v-39z339V3v3d93-_12PjdV599H_v9fR_b8_Kf9_5-_4v8___4IQAAAAQQ_AJMNW4gC7EscCbQMIoAQIwrCQqAUAEFAMLRAYAODgpmVgEusIEACAUARgRAhxBRgQCAAACAJCIAJAiwQAIAiAQAAgARAIQAEDAIKACwMAgABANAxACgAECQgyICIpTAgIgSCAlsqEEoKpDTCAKssAKARGwUACIAABSAAICwcAwRICViwQJMUbwAw0AGAAIJHCIAMAAQSOFQAYAAgkcA"); @@ -314,7 +327,7 @@ public void testDecode5() throws DecodingException { } @Test - public void testDecode6() throws DecodingException { + public void testDecode6() { TcfEuV2 tcfEuV2 = new TcfEuV2("COv_eg6Ov_eg6AOADBENAaCgAP_AAH_AACiQAVEUQQoAIQAqIoghAAQgAA.YAAAAAAAAAAAAAAAAAA"); Assertions.assertEquals(2, tcfEuV2.getFieldValue("Version")); @@ -348,4 +361,61 @@ public void testDecode6() throws DecodingException { Assertions.assertEquals(Arrays.asList(2, 6, 8, 12, 18, 23, 37, 42), tcfEuV2.getFieldValue("VendorLegitimateInterests")); } + + @Test + public void testDecode7() throws DecodingException { + TcfEuV2 tcfEuV2 = new TcfEuV2("COoC-kUOoC-kUAHABAENAwCoAIAAAELAAAwIF5wAoAAgAGAvMACX_ABBAAQAFA"); + + Assertions.assertEquals(2, tcfEuV2.getFieldValue("Version")); + Assertions.assertEquals("2019-10-07T05:17:54Z[UTC]", tcfEuV2.getFieldValue("Created").toString()); + Assertions.assertEquals("2019-10-07T05:17:54Z[UTC]", tcfEuV2.getFieldValue("LastUpdated").toString()); + Assertions.assertEquals(7, tcfEuV2.getFieldValue("CmpId")); + Assertions.assertEquals(1, tcfEuV2.getFieldValue("CmpVersion")); + Assertions.assertEquals(0, tcfEuV2.getFieldValue("ConsentScreen")); + Assertions.assertEquals("EN", tcfEuV2.getFieldValue("ConsentLanguage")); + Assertions.assertEquals(48, tcfEuV2.getFieldValue("VendorListVersion")); + Assertions.assertEquals(2, tcfEuV2.getFieldValue("PolicyVersion")); + Assertions.assertEquals(true, tcfEuV2.getFieldValue("IsServiceSpecific")); + Assertions.assertEquals(false, tcfEuV2.getFieldValue("UseNonStandardStacks")); + + Assertions.assertEquals( + Arrays.asList(true, false, false, false, false, false, false, false, false, false, false, false), + tcfEuV2.getFieldValue("SpecialFeatureOptins")); + Assertions.assertEquals( + Arrays.asList(true, false, false, false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false), + tcfEuV2.getFieldValue("PurposeConsents")); + Assertions.assertEquals( + Arrays.asList(false, true, false, false, false, false, true, false, true, true, false, false, false, false, + false, false, false, false, false, false, false, false, false, false), + tcfEuV2.getFieldValue("PurposeLegitimateInterests")); + + Assertions.assertEquals(false, tcfEuV2.getFieldValue("PurposeOneTreatment")); + Assertions.assertEquals("GB", tcfEuV2.getFieldValue("PublisherCountryCode")); + + Assertions.assertEquals(Arrays.asList(1, 2, 3, 755), tcfEuV2.getFieldValue("VendorConsents")); + + Assertions.assertEquals(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9), + tcfEuV2.getFieldValue("VendorLegitimateInterests")); + + Assertions.assertEquals(1, ((List)tcfEuV2.getFieldValue("PublisherRestrictions")).size()); + RangeEntry rangeEntry = ((List)tcfEuV2.getFieldValue("PublisherRestrictions")).get(0); + Assertions.assertEquals(1, rangeEntry.getKey()); + Assertions.assertEquals(0, rangeEntry.getType()); + Assertions.assertEquals(Arrays.asList(10), rangeEntry.getIds()); + } + + @Test() + public void testDecodeGarbage1() { + Assertions.assertThrows(DecodingException.class, () -> { + new TcfEuV2("A").getCreated(); + }); + } + + @Test() + public void testDecodeGarbage2() { + Assertions.assertThrows(DecodingException.class, () -> { + new TcfEuV2("z").getCreated(); + }); + } } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCaV1Test.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCaV1Test.java index 1a10fa9e..4615a866 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCaV1Test.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCaV1Test.java @@ -5,100 +5,529 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; -import com.iab.gpp.encoder.error.InvalidFieldException; +import com.iab.gpp.encoder.error.ValidationException; import com.iab.gpp.encoder.field.UsCaV1Field; public class UsCaV1Test { @Test - public void testEncode1() throws EncodingException { + public void testEncode1() { UsCaV1 usCaV1 = new UsCaV1(); - Assertions.assertEquals("BAAAAAAA.QA", usCaV1.encode()); + Assertions.assertEquals("BAAAAABA.QA", usCaV1.encode()); } @Test - public void testEncode2() throws EncodingException, InvalidFieldException { + public void testEncode2() { UsCaV1 usCaV1 = new UsCaV1(); usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE, 1); - usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE, 2); - usCaV1.setFieldValue(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 3); + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE, 1); + usCaV1.setFieldValue(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 1); usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT, 1); - usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT, 2); - usCaV1.setFieldValue(UsCaV1Field.SENSITIVE_DATA_PROCESSING, Arrays.asList(0, 1, 2, 3, 0, 1, 2, 3, 0)); - usCaV1.setFieldValue(UsCaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, Arrays.asList(0, 1)); + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT, 1); + usCaV1.setFieldValue(UsCaV1Field.SENSITIVE_DATA_PROCESSING, Arrays.asList(2, 1, 0, 2, 1, 0, 2, 1, 0)); + usCaV1.setFieldValue(UsCaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, Arrays.asList(2, 1)); usCaV1.setFieldValue(UsCaV1Field.PERSONAL_DATA_CONSENTS, 1); - usCaV1.setFieldValue(UsCaV1Field.MSPA_COVERED_TRANSACTION, 3); + usCaV1.setFieldValue(UsCaV1Field.MSPA_COVERED_TRANSACTION, 1); usCaV1.setFieldValue(UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); usCaV1.setFieldValue(UsCaV1Field.GPC, true); - Assertions.assertEquals("BbYbGwXY.YA", usCaV1.encode()); + Assertions.assertEquals("BVWSSSVY.YA", usCaV1.encode()); } @Test - public void testEncode3() throws EncodingException, InvalidFieldException { + public void testEncode3() { UsCaV1 usCaV1 = new UsCaV1(); usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE, 1); usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE, 1); - usCaV1.setFieldValue(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 0); - usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT, 2); - usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT, 2); - usCaV1.setFieldValue(UsCaV1Field.SENSITIVE_DATA_PROCESSING, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0, 0)); - usCaV1.setFieldValue(UsCaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, Arrays.asList(0, 0)); - usCaV1.setFieldValue(UsCaV1Field.PERSONAL_DATA_CONSENTS, 0); + usCaV1.setFieldValue(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 1); + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT, 1); + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT, 1); + usCaV1.setFieldValue(UsCaV1Field.SENSITIVE_DATA_PROCESSING, Arrays.asList(2, 1, 0, 2, 1, 0, 2, 1, 0)); + usCaV1.setFieldValue(UsCaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, Arrays.asList(2, 1)); + usCaV1.setFieldValue(UsCaV1Field.PERSONAL_DATA_CONSENTS, 1); usCaV1.setFieldValue(UsCaV1Field.MSPA_COVERED_TRANSACTION, 1); usCaV1.setFieldValue(UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); - usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); usCaV1.setFieldValue(UsCaV1Field.GPC, true); - Assertions.assertEquals("BUoAAABQ.YA", usCaV1.encode()); + Assertions.assertEquals("BVWSSSVY.YA", usCaV1.encode()); + } + + @Test + public void testSetInvalidValues() { + UsCaV1 usCaV1 = new UsCaV1(); + + try { + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, -1); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.SENSITIVE_DATA_PROCESSING, Arrays.asList(0, 0, 0, 0, 3, 0, 0, 0, 0)); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, Arrays.asList(0, 3)); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.PERSONAL_DATA_CONSENTS, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.MSPA_COVERED_TRANSACTION, 0); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + } + + @Test + public void testValidateSharing() { + UsCaV1 usCaV1 = new UsCaV1(); + + try { + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE, 0); + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT, 1); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE, 0); + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT, 2); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE, 1); + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT, 0); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE, 2); + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT, 0); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE, 2); + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT, 2); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE, 0); + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT, 0); + usCaV1.encode(); + + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE, 1); + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT, 1); + usCaV1.encode(); + + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE, 1); + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT, 2); + usCaV1.encode(); + + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE, 2); + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT, 1); + usCaV1.encode(); + } + + @Test + public void testValidateSale() { + UsCaV1 usCaV1 = new UsCaV1(); + + try { + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE, 0); + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT, 1); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE, 0); + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT, 2); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE, 1); + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT, 0); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE, 2); + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT, 0); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE, 2); + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT, 2); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE, 0); + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT, 0); + usCaV1.encode(); + + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE, 1); + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT, 1); + usCaV1.encode(); + + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE, 1); + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT, 2); + usCaV1.encode(); + + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE, 2); + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT, 1); + usCaV1.encode(); } + + @Test + public void testValidateMspaServiceProviderMode() { + UsCaV1 usCaV1 = new UsCaV1(); + + try { + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usCaV1.setFieldValue(UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usCaV1.setFieldValue(UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usCaV1.setFieldValue(UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usCaV1.setFieldValue(UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE, 2); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE, 1); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE, 2); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE, 1); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE, 2); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usCaV1.setFieldValue(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 1); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usCaV1.setFieldValue(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 2); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + + try { + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE, 1); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE, 2); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE, 1); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE, 2); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usCaV1.setFieldValue(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 1); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usCaV1.setFieldValue(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 2); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE, 0); + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE, 0); + usCaV1.setFieldValue(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 0); + + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usCaV1.setFieldValue(UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + usCaV1.encode(); + + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usCaV1.setFieldValue(UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); + usCaV1.encode(); + + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usCaV1.setFieldValue(UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE, 2); + usCaV1.encode(); + + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usCaV1.setFieldValue(UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE, 2); + usCaV1.encode(); + + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usCaV1.setFieldValue(UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); + usCaV1.encode(); + + + usCaV1.setFieldValue(UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE, 0); + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE, 0); + usCaV1.setFieldValue(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 0); + usCaV1.encode(); + + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE, 0); + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE, 0); + usCaV1.setFieldValue(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 0); + usCaV1.encode(); + + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE, 0); + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE, 0); + usCaV1.setFieldValue(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 0); + usCaV1.encode(); + + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE, 1); + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE, 1); + usCaV1.setFieldValue(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 1); + usCaV1.encode(); + + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE, 2); + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE, 2); + usCaV1.setFieldValue(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 2); + usCaV1.encode(); + } + @Test - public void testEncodeWithGpcSegmentExcluded() throws EncodingException, InvalidFieldException { + public void testEncodeWithGpcSegmentExcluded() { UsCaV1 usCaV1 = new UsCaV1(); usCaV1.setFieldValue(UsCaV1Field.GPC_SEGMENT_INCLUDED, false); - Assertions.assertEquals("BAAAAAAA", usCaV1.encode()); + Assertions.assertEquals("BAAAAABA", usCaV1.encode()); } @Test - public void testDecode1() throws DecodingException { - UsCaV1 usCaV1 = new UsCaV1("BbYbGwXY.YA"); + public void testDecode1() { + UsCaV1 usCaV1 = new UsCaV1("BVWSSSVY.YA"); Assertions.assertEquals(1, usCaV1.getSaleOptOutNotice()); - Assertions.assertEquals(2, usCaV1.getSharingOptOut()); - Assertions.assertEquals(3, usCaV1.getSensitiveDataLimitUseNotice()); + Assertions.assertEquals(1, usCaV1.getSharingOptOut()); + Assertions.assertEquals(1, usCaV1.getSensitiveDataLimitUseNotice()); Assertions.assertEquals(1, usCaV1.getSaleOptOut()); - Assertions.assertEquals(2, usCaV1.getSharingOptOut()); - Assertions.assertEquals(Arrays.asList(0, 1, 2, 3, 0, 1, 2, 3, 0), usCaV1.getSensitiveDataProcessing()); - Assertions.assertEquals(Arrays.asList(0, 1), usCaV1.getKnownChildSensitiveDataConsents()); + Assertions.assertEquals(1, usCaV1.getSharingOptOut()); + Assertions.assertEquals(Arrays.asList(2, 1, 0, 2, 1, 0, 2, 1, 0), usCaV1.getSensitiveDataProcessing()); + Assertions.assertEquals(Arrays.asList(2, 1), usCaV1.getKnownChildSensitiveDataConsents()); Assertions.assertEquals(1, usCaV1.getPersonalDataConsents()); - Assertions.assertEquals(3, usCaV1.getMspaCoveredTransaction()); + Assertions.assertEquals(1, usCaV1.getMspaCoveredTransaction()); Assertions.assertEquals(1, usCaV1.getMspaOptOutOptionMode()); Assertions.assertEquals(2, usCaV1.getMspaServiceProviderMode()); Assertions.assertEquals(true, usCaV1.getGpc()); } @Test - public void testDecodeWithGpcSegmentExcluded() throws DecodingException { - UsCaV1 usCaV1 = new UsCaV1("BbYbGwXY"); + public void testDecodeWithGpcSegmentExcluded() { + UsCaV1 usCaV1 = new UsCaV1("BVWSSSVY"); Assertions.assertEquals(1, usCaV1.getSaleOptOutNotice()); - Assertions.assertEquals(2, usCaV1.getSharingOptOut()); - Assertions.assertEquals(3, usCaV1.getSensitiveDataLimitUseNotice()); + Assertions.assertEquals(1, usCaV1.getSharingOptOut()); + Assertions.assertEquals(1, usCaV1.getSensitiveDataLimitUseNotice()); Assertions.assertEquals(1, usCaV1.getSaleOptOut()); - Assertions.assertEquals(2, usCaV1.getSharingOptOut()); - Assertions.assertEquals(Arrays.asList(0, 1, 2, 3, 0, 1, 2, 3, 0), usCaV1.getSensitiveDataProcessing()); - Assertions.assertEquals(Arrays.asList(0, 1), usCaV1.getKnownChildSensitiveDataConsents()); + Assertions.assertEquals(1, usCaV1.getSharingOptOut()); + Assertions.assertEquals(Arrays.asList(2, 1, 0, 2, 1, 0, 2, 1, 0), usCaV1.getSensitiveDataProcessing()); + Assertions.assertEquals(Arrays.asList(2, 1), usCaV1.getKnownChildSensitiveDataConsents()); Assertions.assertEquals(1, usCaV1.getPersonalDataConsents()); - Assertions.assertEquals(3, usCaV1.getMspaCoveredTransaction()); + Assertions.assertEquals(1, usCaV1.getMspaCoveredTransaction()); Assertions.assertEquals(1, usCaV1.getMspaOptOutOptionMode()); Assertions.assertEquals(2, usCaV1.getMspaServiceProviderMode()); Assertions.assertEquals(false, usCaV1.getGpcSegmentIncluded()); } + + @Test() + public void testDecodeGarbage() { + Assertions.assertThrows(DecodingException.class, () -> { + new UsCaV1("z").getPersonalDataConsents(); + }); + } } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCoV1Test.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCoV1Test.java index 9c730803..dd238be3 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCoV1Test.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCoV1Test.java @@ -5,75 +5,416 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; -import com.iab.gpp.encoder.error.InvalidFieldException; +import com.iab.gpp.encoder.error.ValidationException; import com.iab.gpp.encoder.field.UsCoV1Field; public class UsCoV1Test { @Test - public void testEncode1() throws EncodingException { + public void testEncode1() { UsCoV1 usCoV1 = new UsCoV1(); - Assertions.assertEquals("BAAAAAA.QA", usCoV1.encode()); + Assertions.assertEquals("BAAAAEA.QA", usCoV1.encode()); } @Test - public void testEncode2() throws EncodingException, InvalidFieldException { + public void testEncode2() { UsCoV1 usCoV1 = new UsCoV1(); usCoV1.setFieldValue(UsCoV1Field.SHARING_NOTICE, 1); - usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT_NOTICE, 2); - usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 3); + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT_NOTICE, 1); + usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 1); usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT, 1); - usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT, 2); - usCoV1.setFieldValue(UsCoV1Field.SENSITIVE_DATA_PROCESSING, Arrays.asList(0, 1, 2, 3, 0, 1, 2)); - usCoV1.setFieldValue(UsCoV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, 3); + usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT, 1); + usCoV1.setFieldValue(UsCoV1Field.SENSITIVE_DATA_PROCESSING, Arrays.asList(2, 1, 0, 2, 1, 0, 2)); + usCoV1.setFieldValue(UsCoV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, 1); usCoV1.setFieldValue(UsCoV1Field.MSPA_COVERED_TRANSACTION, 1); - usCoV1.setFieldValue(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE, 2); - usCoV1.setFieldValue(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, 3); + usCoV1.setFieldValue(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); + usCoV1.setFieldValue(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); usCoV1.setFieldValue(UsCoV1Field.GPC, true); - Assertions.assertEquals("BbYbG2w.YA", usCoV1.encode()); + Assertions.assertEquals("BVWSSVg.YA", usCoV1.encode()); + } + + @Test + public void testSetInvalidValues() { + UsCoV1 usCoV1 = new UsCoV1(); + + try { + usCoV1.setFieldValue(UsCoV1Field.SHARING_NOTICE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT_NOTICE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCoV1.setFieldValue(UsCoV1Field.SENSITIVE_DATA_PROCESSING, Arrays.asList(0, 1, 2, 3, 0, 1, 2)); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCoV1.setFieldValue(UsCoV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCoV1.setFieldValue(UsCoV1Field.MSPA_COVERED_TRANSACTION, 0); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCoV1.setFieldValue(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE, -1); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCoV1.setFieldValue(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, 5); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + } @Test - public void testEncodeWithGpcSegmentExcluded() throws EncodingException, InvalidFieldException { + public void testValidateSale() { + UsCoV1 usCoV1 = new UsCoV1(); + + try { + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT_NOTICE, 0); + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT, 1); + usCoV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT_NOTICE, 0); + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT, 2); + usCoV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT_NOTICE, 1); + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT, 0); + usCoV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT_NOTICE, 2); + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT, 0); + usCoV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT_NOTICE, 2); + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT, 2); + usCoV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT_NOTICE, 0); + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT, 0); + usCoV1.encode(); + + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT_NOTICE, 1); + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT, 1); + usCoV1.encode(); + + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT_NOTICE, 1); + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT, 2); + usCoV1.encode(); + + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT_NOTICE, 2); + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT, 1); + usCoV1.encode(); + } + + @Test + public void testValidateTargetedAdvertising() { + UsCoV1 usCoV1 = new UsCoV1(); + + try { + usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 0); + usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT, 1); + usCoV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 0); + usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT, 2); + usCoV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 1); + usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT, 0); + usCoV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 2); + usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT, 0); + usCoV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 2); + usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT, 2); + usCoV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 0); + usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT, 0); + usCoV1.encode(); + + usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 1); + usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT, 1); + usCoV1.encode(); + + usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 1); + usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT, 2); + usCoV1.encode(); + + usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 2); + usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT, 1); + usCoV1.encode(); + } + + @Test + public void testValidateMspaServiceProviderMode() { + UsCoV1 usCoV1 = new UsCoV1(); + + try { + usCoV1.setFieldValue(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usCoV1.setFieldValue(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + usCoV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCoV1.setFieldValue(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usCoV1.setFieldValue(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); + usCoV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCoV1.setFieldValue(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usCoV1.setFieldValue(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + usCoV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCoV1.setFieldValue(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usCoV1.setFieldValue(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE, 2); + usCoV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCoV1.setFieldValue(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT_NOTICE, 1); + usCoV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCoV1.setFieldValue(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT_NOTICE, 2); + usCoV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + + + + try { + usCoV1.setFieldValue(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT_NOTICE, 1); + usCoV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCoV1.setFieldValue(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT_NOTICE, 2); + usCoV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + + + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT_NOTICE, 0); + + usCoV1.setFieldValue(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usCoV1.setFieldValue(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + usCoV1.encode(); + + usCoV1.setFieldValue(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usCoV1.setFieldValue(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); + usCoV1.encode(); + + usCoV1.setFieldValue(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usCoV1.setFieldValue(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE, 2); + usCoV1.encode(); + + usCoV1.setFieldValue(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usCoV1.setFieldValue(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE, 2); + usCoV1.encode(); + + usCoV1.setFieldValue(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usCoV1.setFieldValue(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); + usCoV1.encode(); + + + usCoV1.setFieldValue(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + + usCoV1.setFieldValue(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT_NOTICE, 0); + usCoV1.encode(); + + usCoV1.setFieldValue(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT_NOTICE, 0); + usCoV1.encode(); + + usCoV1.setFieldValue(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT_NOTICE, 0); + usCoV1.encode(); + + usCoV1.setFieldValue(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT_NOTICE, 1); + usCoV1.encode(); + + usCoV1.setFieldValue(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT_NOTICE, 2); + usCoV1.encode(); + } + + @Test + public void testEncodeWithGpcSegmentExcluded() { UsCoV1 usCoV1 = new UsCoV1(); usCoV1.setFieldValue(UsCoV1Field.GPC_SEGMENT_INCLUDED, false); - Assertions.assertEquals("BAAAAAA", usCoV1.encode()); + Assertions.assertEquals("BAAAAEA", usCoV1.encode()); } @Test - public void testDecode1() throws DecodingException { - UsCoV1 usCoV1 = new UsCoV1("BbYbG2wA.YA"); + public void testDecode1() { + UsCoV1 usCoV1 = new UsCoV1("BVWSSVg.YA"); Assertions.assertEquals(1, usCoV1.getSharingNotice()); - Assertions.assertEquals(2, usCoV1.getSaleOptOutNotice()); - Assertions.assertEquals(3, usCoV1.getTargetedAdvertisingOptOutNotice()); + Assertions.assertEquals(1, usCoV1.getSaleOptOutNotice()); + Assertions.assertEquals(1, usCoV1.getTargetedAdvertisingOptOutNotice()); Assertions.assertEquals(1, usCoV1.getSaleOptOut()); - Assertions.assertEquals(2, usCoV1.getTargetedAdvertisingOptOut()); - Assertions.assertEquals(Arrays.asList(0, 1, 2, 3, 0, 1, 2), usCoV1.getSensitiveDataProcessing()); - Assertions.assertEquals(3, usCoV1.getKnownChildSensitiveDataConsents()); + Assertions.assertEquals(1, usCoV1.getTargetedAdvertisingOptOut()); + Assertions.assertEquals(Arrays.asList(2, 1, 0, 2, 1, 0, 2), usCoV1.getSensitiveDataProcessing()); + Assertions.assertEquals(1, usCoV1.getKnownChildSensitiveDataConsents()); Assertions.assertEquals(1, usCoV1.getMspaCoveredTransaction()); - Assertions.assertEquals(2, usCoV1.getMspaOptOutOptionMode()); - Assertions.assertEquals(3, usCoV1.getMspaServiceProviderMode()); + Assertions.assertEquals(1, usCoV1.getMspaOptOutOptionMode()); + Assertions.assertEquals(2, usCoV1.getMspaServiceProviderMode()); Assertions.assertEquals(true, usCoV1.getGpc()); } @Test - public void testDecodeWithGpcSegmentExcluded() throws DecodingException { - UsCoV1 usCoV1 = new UsCoV1("BbYbG2wA"); + public void testDecodeWithGpcSegmentExcluded() { + UsCoV1 usCoV1 = new UsCoV1("BVWSSVg"); Assertions.assertEquals(1, usCoV1.getSharingNotice()); - Assertions.assertEquals(2, usCoV1.getSaleOptOutNotice()); - Assertions.assertEquals(3, usCoV1.getTargetedAdvertisingOptOutNotice()); + Assertions.assertEquals(1, usCoV1.getSaleOptOutNotice()); + Assertions.assertEquals(1, usCoV1.getTargetedAdvertisingOptOutNotice()); Assertions.assertEquals(1, usCoV1.getSaleOptOut()); - Assertions.assertEquals(2, usCoV1.getTargetedAdvertisingOptOut()); - Assertions.assertEquals(Arrays.asList(0, 1, 2, 3, 0, 1, 2), usCoV1.getSensitiveDataProcessing()); - Assertions.assertEquals(3, usCoV1.getKnownChildSensitiveDataConsents()); + Assertions.assertEquals(1, usCoV1.getTargetedAdvertisingOptOut()); + Assertions.assertEquals(Arrays.asList(2, 1, 0, 2, 1, 0, 2), usCoV1.getSensitiveDataProcessing()); + Assertions.assertEquals(1, usCoV1.getKnownChildSensitiveDataConsents()); Assertions.assertEquals(1, usCoV1.getMspaCoveredTransaction()); - Assertions.assertEquals(2, usCoV1.getMspaOptOutOptionMode()); - Assertions.assertEquals(3, usCoV1.getMspaServiceProviderMode()); + Assertions.assertEquals(1, usCoV1.getMspaOptOutOptionMode()); + Assertions.assertEquals(2, usCoV1.getMspaServiceProviderMode()); Assertions.assertEquals(false, usCoV1.getGpcSegmentIncluded()); } + + @Test() + public void testDecodeGarbage() { + Assertions.assertThrows(DecodingException.class, () -> { + new UsCoV1("z").getTargetedAdvertisingOptOut(); + }); + } } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCtV1Test.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCtV1Test.java index 2053e24c..9276651c 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCtV1Test.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCtV1Test.java @@ -5,75 +5,414 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; -import com.iab.gpp.encoder.error.InvalidFieldException; +import com.iab.gpp.encoder.error.ValidationException; import com.iab.gpp.encoder.field.UsCtV1Field; public class UsCtV1Test { @Test - public void testEncode1() throws EncodingException { + public void testEncode1() { UsCtV1 usCtV1 = new UsCtV1(); - Assertions.assertEquals("BAAAAAAA.QA", usCtV1.encode()); + Assertions.assertEquals("BAAAAAEA.QA", usCtV1.encode()); } @Test - public void testEncode2() throws EncodingException, InvalidFieldException { + public void testEncode2() { UsCtV1 usCtV1 = new UsCtV1(); usCtV1.setFieldValue(UsCtV1Field.SHARING_NOTICE, 1); - usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT_NOTICE, 2); - usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 3); + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT_NOTICE, 1); + usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 1); usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT, 1); - usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT, 2); - usCtV1.setFieldValue(UsCtV1Field.SENSITIVE_DATA_PROCESSING, Arrays.asList(0, 1, 2, 3, 0, 1, 2, 3)); - usCtV1.setFieldValue(UsCtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, Arrays.asList(1, 2, 3)); + usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT, 1); + usCtV1.setFieldValue(UsCtV1Field.SENSITIVE_DATA_PROCESSING, Arrays.asList(2, 1, 0, 2, 1, 0, 2, 1)); + usCtV1.setFieldValue(UsCtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, Arrays.asList(2, 1, 0)); usCtV1.setFieldValue(UsCtV1Field.MSPA_COVERED_TRANSACTION, 1); - usCtV1.setFieldValue(UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE, 2); - usCtV1.setFieldValue(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, 3); + usCtV1.setFieldValue(UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); + usCtV1.setFieldValue(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); usCtV1.setFieldValue(UsCtV1Field.GPC, true); - Assertions.assertEquals("BbYbG22w.YA", usCtV1.encode()); + Assertions.assertEquals("BVWSSZFg.YA", usCtV1.encode()); + } + + @Test + public void testSetInvalidValues() { + UsCtV1 usCtV1 = new UsCtV1(); + + try { + usCtV1.setFieldValue(UsCtV1Field.SHARING_NOTICE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT_NOTICE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT, -1); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCtV1.setFieldValue(UsCtV1Field.SENSITIVE_DATA_PROCESSING, Arrays.asList(0, 1, 2, 3, 1, 2, 0, 1)); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCtV1.setFieldValue(UsCtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, Arrays.asList(1, 2, 3)); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCtV1.setFieldValue(UsCtV1Field.MSPA_COVERED_TRANSACTION, 0); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCtV1.setFieldValue(UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE, 4); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCtV1.setFieldValue(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, -1); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } } @Test - public void testEncodeWithGpcSegmentExcluded() throws EncodingException, InvalidFieldException { + public void testValidateSale() { + UsCtV1 usCtV1 = new UsCtV1(); + + try { + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT_NOTICE, 0); + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT, 1); + usCtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT_NOTICE, 0); + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT, 2); + usCtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT_NOTICE, 1); + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT, 0); + usCtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT_NOTICE, 2); + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT, 0); + usCtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT_NOTICE, 2); + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT, 2); + usCtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT_NOTICE, 0); + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT, 0); + usCtV1.encode(); + + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT_NOTICE, 1); + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT, 1); + usCtV1.encode(); + + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT_NOTICE, 1); + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT, 2); + usCtV1.encode(); + + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT_NOTICE, 2); + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT, 1); + usCtV1.encode(); + } + + @Test + public void testValidateTargetedAdvertising() { + UsCtV1 usCtV1 = new UsCtV1(); + + try { + usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 0); + usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT, 1); + usCtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 0); + usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT, 2); + usCtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 1); + usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT, 0); + usCtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 2); + usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT, 0); + usCtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 2); + usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT, 2); + usCtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 0); + usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT, 0); + usCtV1.encode(); + + usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 1); + usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT, 1); + usCtV1.encode(); + + usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 1); + usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT, 2); + usCtV1.encode(); + + usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 2); + usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT, 1); + usCtV1.encode(); + } + + @Test + public void testValidateMspaServiceProviderMode() { + UsCtV1 usCtV1 = new UsCtV1(); + + try { + usCtV1.setFieldValue(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usCtV1.setFieldValue(UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + usCtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCtV1.setFieldValue(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usCtV1.setFieldValue(UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); + usCtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCtV1.setFieldValue(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usCtV1.setFieldValue(UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + usCtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCtV1.setFieldValue(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usCtV1.setFieldValue(UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE, 2); + usCtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCtV1.setFieldValue(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT_NOTICE, 1); + usCtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCtV1.setFieldValue(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT_NOTICE, 2); + usCtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + + + try { + usCtV1.setFieldValue(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT_NOTICE, 1); + usCtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCtV1.setFieldValue(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT_NOTICE, 2); + usCtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + + + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT_NOTICE, 0); + + usCtV1.setFieldValue(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usCtV1.setFieldValue(UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + usCtV1.encode(); + + usCtV1.setFieldValue(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usCtV1.setFieldValue(UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); + usCtV1.encode(); + + usCtV1.setFieldValue(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usCtV1.setFieldValue(UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE, 2); + usCtV1.encode(); + + usCtV1.setFieldValue(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usCtV1.setFieldValue(UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE, 2); + usCtV1.encode(); + + usCtV1.setFieldValue(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usCtV1.setFieldValue(UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); + usCtV1.encode(); + + + usCtV1.setFieldValue(UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + + usCtV1.setFieldValue(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT_NOTICE, 0); + usCtV1.encode(); + + usCtV1.setFieldValue(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT_NOTICE, 0); + usCtV1.encode(); + + usCtV1.setFieldValue(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT_NOTICE, 0); + usCtV1.encode(); + + usCtV1.setFieldValue(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT_NOTICE, 1); + usCtV1.encode(); + + usCtV1.setFieldValue(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT_NOTICE, 2); + usCtV1.encode(); + } + + @Test + public void testEncodeWithGpcSegmentExcluded() { UsCtV1 usCtV1 = new UsCtV1(); usCtV1.setFieldValue(UsCtV1Field.GPC_SEGMENT_INCLUDED, false); - Assertions.assertEquals("BAAAAAAA", usCtV1.encode()); + Assertions.assertEquals("BAAAAAEA", usCtV1.encode()); } @Test public void testDecode1() throws DecodingException { - UsCtV1 usCtV1 = new UsCtV1("BbYbG22w.YAAA"); + UsCtV1 usCtV1 = new UsCtV1("BVWSSZFg.YA"); Assertions.assertEquals(1, usCtV1.getSharingNotice()); - Assertions.assertEquals(2, usCtV1.getSaleOptOutNotice()); - Assertions.assertEquals(3, usCtV1.getTargetedAdvertisingOptOutNotice()); + Assertions.assertEquals(1, usCtV1.getSaleOptOutNotice()); + Assertions.assertEquals(1, usCtV1.getTargetedAdvertisingOptOutNotice()); Assertions.assertEquals(1, usCtV1.getSaleOptOut()); - Assertions.assertEquals(2, usCtV1.getTargetedAdvertisingOptOut()); - Assertions.assertEquals(Arrays.asList(0, 1, 2, 3, 0, 1, 2, 3), usCtV1.getSensitiveDataProcessing()); - Assertions.assertEquals(Arrays.asList(1, 2, 3), usCtV1.getKnownChildSensitiveDataConsents()); + Assertions.assertEquals(1, usCtV1.getTargetedAdvertisingOptOut()); + Assertions.assertEquals(Arrays.asList(2, 1, 0, 2, 1, 0, 2, 1), usCtV1.getSensitiveDataProcessing()); + Assertions.assertEquals(Arrays.asList(2, 1, 0), usCtV1.getKnownChildSensitiveDataConsents()); Assertions.assertEquals(1, usCtV1.getMspaCoveredTransaction()); - Assertions.assertEquals(2, usCtV1.getMspaOptOutOptionMode()); - Assertions.assertEquals(3, usCtV1.getMspaServiceProviderMode()); + Assertions.assertEquals(1, usCtV1.getMspaOptOutOptionMode()); + Assertions.assertEquals(2, usCtV1.getMspaServiceProviderMode()); Assertions.assertEquals(true, usCtV1.getGpc()); } @Test public void testDecodeWithGpcSegmentExcluded() throws DecodingException { - UsCtV1 usCtV1 = new UsCtV1("BbYbG22w"); + UsCtV1 usCtV1 = new UsCtV1("BVWSSZFg"); Assertions.assertEquals(1, usCtV1.getSharingNotice()); - Assertions.assertEquals(2, usCtV1.getSaleOptOutNotice()); - Assertions.assertEquals(3, usCtV1.getTargetedAdvertisingOptOutNotice()); + Assertions.assertEquals(1, usCtV1.getSaleOptOutNotice()); + Assertions.assertEquals(1, usCtV1.getTargetedAdvertisingOptOutNotice()); Assertions.assertEquals(1, usCtV1.getSaleOptOut()); - Assertions.assertEquals(2, usCtV1.getTargetedAdvertisingOptOut()); - Assertions.assertEquals(Arrays.asList(0, 1, 2, 3, 0, 1, 2, 3), usCtV1.getSensitiveDataProcessing()); - Assertions.assertEquals(Arrays.asList(1, 2, 3), usCtV1.getKnownChildSensitiveDataConsents()); + Assertions.assertEquals(1, usCtV1.getTargetedAdvertisingOptOut()); + Assertions.assertEquals(Arrays.asList(2, 1, 0, 2, 1, 0, 2, 1), usCtV1.getSensitiveDataProcessing()); + Assertions.assertEquals(Arrays.asList(2, 1, 0), usCtV1.getKnownChildSensitiveDataConsents()); Assertions.assertEquals(1, usCtV1.getMspaCoveredTransaction()); - Assertions.assertEquals(2, usCtV1.getMspaOptOutOptionMode()); - Assertions.assertEquals(3, usCtV1.getMspaServiceProviderMode()); + Assertions.assertEquals(1, usCtV1.getMspaOptOutOptionMode()); + Assertions.assertEquals(2, usCtV1.getMspaServiceProviderMode()); Assertions.assertEquals(false, usCtV1.getGpcSegmentIncluded()); } + + @Test() + public void testDecodeGarbage() { + Assertions.assertThrows(DecodingException.class, () -> { + new UsCtV1("z").getSharingNotice(); + }); + } } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsNatV1Test.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsNatV1Test.java index f0707542..4a5b549b 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsNatV1Test.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsNatV1Test.java @@ -5,116 +5,643 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; -import com.iab.gpp.encoder.error.InvalidFieldException; +import com.iab.gpp.encoder.error.ValidationException; import com.iab.gpp.encoder.field.UsNatV1Field; public class UsNatV1Test { @Test - public void testEncode1() throws EncodingException { + public void testEncode1() { UsNatV1 usNatV1 = new UsNatV1(); - Assertions.assertEquals("BAAAAAAAAAA.QA", usNatV1.encode()); + Assertions.assertEquals("BAAAAAAAAQA.QA", usNatV1.encode()); } @Test - public void testEncode2() throws EncodingException, InvalidFieldException { + public void testEncode2() { UsNatV1 usNatV1 = new UsNatV1(); usNatV1.setFieldValue(UsNatV1Field.SHARING_NOTICE, 1); - usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE, 2); - usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 3); + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE, 1); + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 1); usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 1); - usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE, 2); - usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 3); + usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE, 1); + usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 1); usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT, 1); - usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT, 2); - usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT, 3); - usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_PROCESSING, Arrays.asList(0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3)); - usNatV1.setFieldValue(UsNatV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, Arrays.asList(0, 1)); + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT, 1); + usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT, 1); + usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_PROCESSING, Arrays.asList(2, 1, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0)); + usNatV1.setFieldValue(UsNatV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, Arrays.asList(2, 1)); usNatV1.setFieldValue(UsNatV1Field.PERSONAL_DATA_CONSENTS, 1); usNatV1.setFieldValue(UsNatV1Field.MSPA_COVERED_TRANSACTION, 1); - usNatV1.setFieldValue(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE, 2); - usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 3); + usNatV1.setFieldValue(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); usNatV1.setFieldValue(UsNatV1Field.GPC, true); - Assertions.assertEquals("BbbbGxsbFbA.YA", usNatV1.encode()); + Assertions.assertEquals("BVVVkkkklWA.YA", usNatV1.encode()); + } + + @Test + public void testSetInvalidValues() { + UsNatV1 usNatV1 = new UsNatV1(); + + try { + usNatV1.setFieldValue(UsNatV1Field.SHARING_NOTICE, -1); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 4); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_PROCESSING, Arrays.asList(0, 1, 2, 3, 0, 1, 2, 0, 0, 1, 2, 0)); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, Arrays.asList(0, 3)); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.PERSONAL_DATA_CONSENTS, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.MSPA_COVERED_TRANSACTION, 0); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + + } + + @Test + public void testValidateSharing() { + UsNatV1 usNatV1 = new UsNatV1(); + + try { + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 0); + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 0); + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT, 1); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 0); + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT, 2); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 1); + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT, 0); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 2); + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT, 0); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 2); + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT, 2); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 0); + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT, 0); + usNatV1.encode(); + + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 1); + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT, 1); + usNatV1.encode(); + + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 1); + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT, 2); + usNatV1.encode(); + + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 2); + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT, 1); + usNatV1.encode(); + } + + @Test + public void testValidateSale() { + UsNatV1 usNatV1 = new UsNatV1(); + + try { + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE, 0); + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT, 1); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE, 0); + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT, 2); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE, 1); + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT, 0); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE, 2); + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT, 0); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE, 2); + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT, 2); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE, 0); + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT, 0); + usNatV1.encode(); + + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE, 1); + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT, 1); + usNatV1.encode(); + + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE, 1); + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT, 2); + usNatV1.encode(); + + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE, 2); + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT, 1); + usNatV1.encode(); + } + + @Test + public void testValidateTargetedAdvertising() { + UsNatV1 usNatV1 = new UsNatV1(); + + try { + usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 0); + usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT, 1); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 0); + usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT, 2); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 1); + usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT, 0); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 2); + usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT, 0); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 2); + usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT, 2); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 0); + usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT, 0); + usNatV1.encode(); + + usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 1); + usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT, 1); + usNatV1.encode(); + + usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 1); + usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT, 2); + usNatV1.encode(); + + usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 2); + usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT, 1); + usNatV1.encode(); } + + @Test + public void testValidateMspaServiceProviderMode() { + UsNatV1 usNatV1 = new UsNatV1(); + + try { + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usNatV1.setFieldValue(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usNatV1.setFieldValue(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usNatV1.setFieldValue(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usNatV1.setFieldValue(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE, 2); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE, 1); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE, 2); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 1); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 2); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 1); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 2); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + + try { + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE, 1); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE, 2); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 1); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 2); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 1); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 2); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE, 0); + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 0); + usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 0); + + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usNatV1.setFieldValue(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + usNatV1.encode(); + + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usNatV1.setFieldValue(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); + usNatV1.encode(); + + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usNatV1.setFieldValue(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE, 2); + usNatV1.encode(); + + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usNatV1.setFieldValue(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE, 2); + usNatV1.encode(); + + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usNatV1.setFieldValue(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); + usNatV1.encode(); + + + usNatV1.setFieldValue(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE, 0); + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 0); + usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 0); + usNatV1.encode(); + + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE, 0); + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 0); + usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 0); + usNatV1.encode(); + + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE, 0); + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 0); + usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 0); + usNatV1.encode(); + + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE, 1); + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 1); + usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 1); + usNatV1.encode(); + + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE, 2); + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 2); + usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 2); + usNatV1.encode(); + } + + @Test - public void testEncode3() throws EncodingException, InvalidFieldException { + public void testEncode3() { UsNatV1 usNatV1 = new UsNatV1(); usNatV1.setFieldValue(UsNatV1Field.SHARING_NOTICE, 1); usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE, 1); usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 1); usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 1); - usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE, 0); - usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 0); + usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE, 1); + usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 1); usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT, 1); usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT, 1); usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT, 1); - usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_PROCESSING, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)); - usNatV1.setFieldValue(UsNatV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, Arrays.asList(0, 0)); - usNatV1.setFieldValue(UsNatV1Field.PERSONAL_DATA_CONSENTS, 0); + usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_PROCESSING, Arrays.asList(2, 1, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0)); + usNatV1.setFieldValue(UsNatV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, Arrays.asList(2, 1)); + usNatV1.setFieldValue(UsNatV1Field.PERSONAL_DATA_CONSENTS, 1); usNatV1.setFieldValue(UsNatV1Field.MSPA_COVERED_TRANSACTION, 1); usNatV1.setFieldValue(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); - usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); usNatV1.setFieldValue(UsNatV1Field.GPC, true); - Assertions.assertEquals("BVQVAAAAAUA.YA", usNatV1.encode()); + Assertions.assertEquals("BVVVkkkklWA.YA", usNatV1.encode()); } @Test - public void testEncodeWithGpcSegmentIncluded() throws EncodingException, InvalidFieldException { + public void testEncodeWithGpcSegmentIncluded() { UsNatV1 usNatV1 = new UsNatV1(); usNatV1.setFieldValue(UsNatV1Field.GPC_SEGMENT_INCLUDED, false); - Assertions.assertEquals("BAAAAAAAAAA", usNatV1.encode()); + Assertions.assertEquals("BAAAAAAAAQA", usNatV1.encode()); } @Test public void testDecode1() throws DecodingException { - UsNatV1 usNatV1 = new UsNatV1("BbbbGxsbFbA.YA"); + UsNatV1 usNatV1 = new UsNatV1("BVVVkkkklWA.YA"); Assertions.assertEquals(1, usNatV1.getSharingNotice()); - Assertions.assertEquals(2, usNatV1.getSaleOptOutNotice()); - Assertions.assertEquals(3, usNatV1.getSharingOptOutNotice()); + Assertions.assertEquals(1, usNatV1.getSaleOptOutNotice()); + Assertions.assertEquals(1, usNatV1.getSharingOptOutNotice()); Assertions.assertEquals(1, usNatV1.getTargetedAdvertisingOptOutNotice()); - Assertions.assertEquals(2, usNatV1.getSensitiveDataProcessingOptOutNotice()); - Assertions.assertEquals(3, usNatV1.getSensitiveDataLimitUseNotice()); + Assertions.assertEquals(1, usNatV1.getSensitiveDataProcessingOptOutNotice()); + Assertions.assertEquals(1, usNatV1.getSensitiveDataLimitUseNotice()); Assertions.assertEquals(1, usNatV1.getSaleOptOut()); - Assertions.assertEquals(2, usNatV1.getSharingOptOut()); - Assertions.assertEquals(3, usNatV1.getTargetedAdvertisingOptOut()); - Assertions.assertEquals(Arrays.asList(0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3), usNatV1.getSensitiveDataProcessing()); - Assertions.assertEquals(Arrays.asList(0, 1), usNatV1.getKnownChildSensitiveDataConsents()); + Assertions.assertEquals(1, usNatV1.getSharingOptOut()); + Assertions.assertEquals(1, usNatV1.getTargetedAdvertisingOptOut()); + Assertions.assertEquals(Arrays.asList(2, 1, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0), usNatV1.getSensitiveDataProcessing()); + Assertions.assertEquals(Arrays.asList(2, 1), usNatV1.getKnownChildSensitiveDataConsents()); Assertions.assertEquals(1, usNatV1.getPersonalDataConsents()); Assertions.assertEquals(1, usNatV1.getMspaCoveredTransaction()); - Assertions.assertEquals(2, usNatV1.getMspaOptOutOptionMode()); - Assertions.assertEquals(3, usNatV1.getMspaServiceProviderMode()); + Assertions.assertEquals(1, usNatV1.getMspaOptOutOptionMode()); + Assertions.assertEquals(2, usNatV1.getMspaServiceProviderMode()); Assertions.assertEquals(true, usNatV1.getGpc()); } @Test public void testDecodeWithGpcSegmentExcluded() throws DecodingException { - UsNatV1 usNatV1 = new UsNatV1("BbbbGxsbFbA"); + UsNatV1 usNatV1 = new UsNatV1("BVVVkkkklWA"); Assertions.assertEquals(1, usNatV1.getSharingNotice()); - Assertions.assertEquals(2, usNatV1.getSaleOptOutNotice()); - Assertions.assertEquals(3, usNatV1.getSharingOptOutNotice()); + Assertions.assertEquals(1, usNatV1.getSaleOptOutNotice()); + Assertions.assertEquals(1, usNatV1.getSharingOptOutNotice()); Assertions.assertEquals(1, usNatV1.getTargetedAdvertisingOptOutNotice()); - Assertions.assertEquals(2, usNatV1.getSensitiveDataProcessingOptOutNotice()); - Assertions.assertEquals(3, usNatV1.getSensitiveDataLimitUseNotice()); + Assertions.assertEquals(1, usNatV1.getSensitiveDataProcessingOptOutNotice()); + Assertions.assertEquals(1, usNatV1.getSensitiveDataLimitUseNotice()); Assertions.assertEquals(1, usNatV1.getSaleOptOut()); - Assertions.assertEquals(2, usNatV1.getSharingOptOut()); - Assertions.assertEquals(3, usNatV1.getTargetedAdvertisingOptOut()); - Assertions.assertEquals(Arrays.asList(0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3), usNatV1.getSensitiveDataProcessing()); - Assertions.assertEquals(Arrays.asList(0, 1), usNatV1.getKnownChildSensitiveDataConsents()); + Assertions.assertEquals(1, usNatV1.getSharingOptOut()); + Assertions.assertEquals(1, usNatV1.getTargetedAdvertisingOptOut()); + Assertions.assertEquals(Arrays.asList(2, 1, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0), usNatV1.getSensitiveDataProcessing()); + Assertions.assertEquals(Arrays.asList(2, 1), usNatV1.getKnownChildSensitiveDataConsents()); Assertions.assertEquals(1, usNatV1.getPersonalDataConsents()); Assertions.assertEquals(1, usNatV1.getMspaCoveredTransaction()); - Assertions.assertEquals(2, usNatV1.getMspaOptOutOptionMode()); - Assertions.assertEquals(3, usNatV1.getMspaServiceProviderMode()); + Assertions.assertEquals(1, usNatV1.getMspaOptOutOptionMode()); + Assertions.assertEquals(2, usNatV1.getMspaServiceProviderMode()); Assertions.assertEquals(false, usNatV1.getGpcSegmentIncluded()); } + + @Test() + public void testDecodeGarbage() { + Assertions.assertThrows(DecodingException.class, () -> { + new UsNatV1("z").getSharingNotice(); + }); + } } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsUtV1Test.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsUtV1Test.java index f26808a6..b2dd77b3 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsUtV1Test.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsUtV1Test.java @@ -5,50 +5,396 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; -import com.iab.gpp.encoder.error.InvalidFieldException; +import com.iab.gpp.encoder.error.ValidationException; import com.iab.gpp.encoder.field.UsUtV1Field; public class UsUtV1Test { @Test - public void testEncode1() throws EncodingException { + public void testEncode1() { UsUtV1 usUtV1 = new UsUtV1(); - Assertions.assertEquals("BAAAAAAA", usUtV1.encode()); + Assertions.assertEquals("BAAAAAQA", usUtV1.encode()); } @Test - public void testEncode2() throws EncodingException, InvalidFieldException { + public void testEncode2() { UsUtV1 usUtV1 = new UsUtV1(); usUtV1.setFieldValue(UsUtV1Field.SHARING_NOTICE, 1); - usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT_NOTICE, 2); - usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 3); + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT_NOTICE, 1); + usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 1); usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT, 1); usUtV1.setFieldValue(UsUtV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE, 1); - usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT, 2); - usUtV1.setFieldValue(UsUtV1Field.SENSITIVE_DATA_PROCESSING, Arrays.asList(0, 1, 2, 3, 0, 1, 2, 3)); - usUtV1.setFieldValue(UsUtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, 3); + usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT, 1); + usUtV1.setFieldValue(UsUtV1Field.SENSITIVE_DATA_PROCESSING, Arrays.asList(2, 1, 0, 2, 1, 0, 2, 1)); + usUtV1.setFieldValue(UsUtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, 1); usUtV1.setFieldValue(UsUtV1Field.MSPA_COVERED_TRANSACTION, 1); - usUtV1.setFieldValue(UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE, 2); - usUtV1.setFieldValue(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, 3); + usUtV1.setFieldValue(UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); + usUtV1.setFieldValue(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + + Assertions.assertEquals("BVVkklWA", usUtV1.encode()); + } + + @Test + public void testSetInvalidValues() { + UsUtV1 usUtV1 = new UsUtV1(); + + try { + usUtV1.setFieldValue(UsUtV1Field.SHARING_NOTICE, -1); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT_NOTICE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT, 4); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.SENSITIVE_DATA_PROCESSING, Arrays.asList(0, 1, 2, 3, 0, 1, 2, 0)); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.MSPA_COVERED_TRANSACTION, 0); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + } + + @Test + public void testValidateSale() { + UsUtV1 usUtV1 = new UsUtV1(); + + try { + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT_NOTICE, 0); + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT, 1); + usUtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT_NOTICE, 0); + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT, 2); + usUtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT_NOTICE, 1); + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT, 0); + usUtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT_NOTICE, 2); + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT, 0); + usUtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT_NOTICE, 2); + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT, 2); + usUtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT_NOTICE, 0); + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT, 0); + usUtV1.encode(); + + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT_NOTICE, 1); + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT, 1); + usUtV1.encode(); + + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT_NOTICE, 1); + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT, 2); + usUtV1.encode(); + + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT_NOTICE, 2); + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT, 1); + usUtV1.encode(); + } + + @Test + public void testValidateTargetedAdvertising() { + UsUtV1 usUtV1 = new UsUtV1(); + + try { + usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 0); + usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT, 1); + usUtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 0); + usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT, 2); + usUtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 1); + usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT, 0); + usUtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 2); + usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT, 0); + usUtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 2); + usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT, 2); + usUtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } - Assertions.assertEquals("BbWGxvbA", usUtV1.encode()); + usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 0); + usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT, 0); + usUtV1.encode(); + + usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 1); + usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT, 1); + usUtV1.encode(); + + usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 1); + usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT, 2); + usUtV1.encode(); + + usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 2); + usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT, 1); + usUtV1.encode(); } + + @Test + public void testValidateMspaServiceProviderMode() { + UsUtV1 usUtV1 = new UsUtV1(); + + try { + usUtV1.setFieldValue(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usUtV1.setFieldValue(UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + usUtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usUtV1.setFieldValue(UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); + usUtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usUtV1.setFieldValue(UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + usUtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usUtV1.setFieldValue(UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE, 2); + usUtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT_NOTICE, 1); + usUtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT_NOTICE, 2); + usUtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + + try { + usUtV1.setFieldValue(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT_NOTICE, 1); + usUtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT_NOTICE, 2); + usUtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT_NOTICE, 0); + + usUtV1.setFieldValue(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usUtV1.setFieldValue(UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + usUtV1.encode(); + + usUtV1.setFieldValue(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usUtV1.setFieldValue(UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); + usUtV1.encode(); + + usUtV1.setFieldValue(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usUtV1.setFieldValue(UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE, 2); + usUtV1.encode(); + + usUtV1.setFieldValue(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usUtV1.setFieldValue(UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE, 2); + usUtV1.encode(); + + usUtV1.setFieldValue(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usUtV1.setFieldValue(UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); + usUtV1.encode(); + + + usUtV1.setFieldValue(UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + + usUtV1.setFieldValue(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT_NOTICE, 0); + usUtV1.encode(); + + usUtV1.setFieldValue(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT_NOTICE, 0); + usUtV1.encode(); + + usUtV1.setFieldValue(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT_NOTICE, 0); + usUtV1.encode(); + + usUtV1.setFieldValue(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT_NOTICE, 1); + usUtV1.encode(); + + usUtV1.setFieldValue(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT_NOTICE, 2); + usUtV1.encode(); + } + @Test public void testDecode1() throws DecodingException { - UsUtV1 usUtV1 = new UsUtV1("BbWGxvbA"); + UsUtV1 usUtV1 = new UsUtV1("BVVkklWA"); Assertions.assertEquals(1, usUtV1.getSharingNotice()); - Assertions.assertEquals(2, usUtV1.getSaleOptOutNotice()); - Assertions.assertEquals(3, usUtV1.getTargetedAdvertisingOptOutNotice()); + Assertions.assertEquals(1, usUtV1.getSaleOptOutNotice()); + Assertions.assertEquals(1, usUtV1.getTargetedAdvertisingOptOutNotice()); Assertions.assertEquals(1, usUtV1.getSaleOptOut()); - Assertions.assertEquals(2, usUtV1.getTargetedAdvertisingOptOut()); - Assertions.assertEquals(Arrays.asList(0, 1, 2, 3, 0, 1, 2, 3), usUtV1.getSensitiveDataProcessing()); - Assertions.assertEquals(3, usUtV1.getKnownChildSensitiveDataConsents()); + Assertions.assertEquals(1, usUtV1.getTargetedAdvertisingOptOut()); + Assertions.assertEquals(Arrays.asList(2, 1, 0, 2, 1, 0, 2, 1), usUtV1.getSensitiveDataProcessing()); + Assertions.assertEquals(1, usUtV1.getKnownChildSensitiveDataConsents()); Assertions.assertEquals(1, usUtV1.getMspaCoveredTransaction()); - Assertions.assertEquals(2, usUtV1.getMspaOptOutOptionMode()); - Assertions.assertEquals(3, usUtV1.getMspaServiceProviderMode()); + Assertions.assertEquals(1, usUtV1.getMspaOptOutOptionMode()); + Assertions.assertEquals(2, usUtV1.getMspaServiceProviderMode()); + } + + @Test() + public void testDecodeGarbage() { + Assertions.assertThrows(DecodingException.class, () -> { + new UsUtV1("z").getKnownChildSensitiveDataConsents(); + }); } } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsVaV1Test.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsVaV1Test.java index e65bec8c..7c232941 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsVaV1Test.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsVaV1Test.java @@ -7,51 +7,392 @@ import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.error.EncodingException; import com.iab.gpp.encoder.error.InvalidFieldException; +import com.iab.gpp.encoder.error.ValidationException; import com.iab.gpp.encoder.field.UsVaV1Field; public class UsVaV1Test { @Test - public void testEncode1() throws EncodingException { + public void testEncode1() { UsVaV1 usVaV1 = new UsVaV1(); - Assertions.assertEquals("BAAAAAA", usVaV1.encode()); + Assertions.assertEquals("BAAAABA", usVaV1.encode()); } @Test - public void testEncode2() throws EncodingException { + public void testEncode2() { UsVaV1 usVaV1 = new UsVaV1(); try { usVaV1.setFieldValue(UsVaV1Field.SHARING_NOTICE, 1); - usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT_NOTICE, 2); - usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 3); + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT_NOTICE, 1); + usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 1); usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT, 1); - usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT, 2); - usVaV1.setFieldValue(UsVaV1Field.SENSITIVE_DATA_PROCESSING, Arrays.asList(0, 1, 2, 3, 0, 1, 2, 3)); - usVaV1.setFieldValue(UsVaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, 3); + usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT, 1); + usVaV1.setFieldValue(UsVaV1Field.SENSITIVE_DATA_PROCESSING, Arrays.asList(2, 1, 0, 2, 1, 0, 2, 1)); + usVaV1.setFieldValue(UsVaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, 1); usVaV1.setFieldValue(UsVaV1Field.MSPA_COVERED_TRANSACTION, 1); - usVaV1.setFieldValue(UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE, 2); - usVaV1.setFieldValue(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, 3); + usVaV1.setFieldValue(UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); + usVaV1.setFieldValue(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); } catch (InvalidFieldException e) { throw new EncodingException(e); } - Assertions.assertEquals("BbYbG9s", usVaV1.encode()); + Assertions.assertEquals("BVWSSVY", usVaV1.encode()); + } + + @Test + public void testSetInvalidValues() { + UsVaV1 usVaV1 = new UsVaV1(); + + try { + usVaV1.setFieldValue(UsVaV1Field.SHARING_NOTICE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT_NOTICE, -1); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 4); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usVaV1.setFieldValue(UsVaV1Field.SENSITIVE_DATA_PROCESSING, Arrays.asList(0, 1, 2, 3, 1, 2, 0, 1)); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usVaV1.setFieldValue(UsVaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usVaV1.setFieldValue(UsVaV1Field.MSPA_COVERED_TRANSACTION, 0); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usVaV1.setFieldValue(UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usVaV1.setFieldValue(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + } + + @Test + public void testValidateSale() { + UsVaV1 usVaV1 = new UsVaV1(); + + try { + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT_NOTICE, 0); + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT, 1); + usVaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT_NOTICE, 0); + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT, 2); + usVaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT_NOTICE, 1); + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT, 0); + usVaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT_NOTICE, 2); + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT, 0); + usVaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT_NOTICE, 2); + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT, 2); + usVaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT_NOTICE, 0); + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT, 0); + usVaV1.encode(); + + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT_NOTICE, 1); + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT, 1); + usVaV1.encode(); + + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT_NOTICE, 1); + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT, 2); + usVaV1.encode(); + + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT_NOTICE, 2); + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT, 1); + usVaV1.encode(); + } + + @Test + public void testValidateTargetedAdvertising() { + UsVaV1 usVaV1 = new UsVaV1(); + + try { + usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 0); + usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT, 1); + usVaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 0); + usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT, 2); + usVaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 1); + usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT, 0); + usVaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 2); + usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT, 0); + usVaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 2); + usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT, 2); + usVaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 0); + usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT, 0); + usVaV1.encode(); + + usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 1); + usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT, 1); + usVaV1.encode(); + + usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 1); + usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT, 2); + usVaV1.encode(); + + usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 2); + usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT, 1); + usVaV1.encode(); + } + + @Test + public void testValidateMspaServiceProviderMode() { + UsVaV1 usVaV1 = new UsVaV1(); + + try { + usVaV1.setFieldValue(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usVaV1.setFieldValue(UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + usVaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usVaV1.setFieldValue(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usVaV1.setFieldValue(UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); + usVaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usVaV1.setFieldValue(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usVaV1.setFieldValue(UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + usVaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usVaV1.setFieldValue(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usVaV1.setFieldValue(UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE, 2); + usVaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usVaV1.setFieldValue(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT_NOTICE, 1); + usVaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usVaV1.setFieldValue(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT_NOTICE, 2); + usVaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + + + try { + usVaV1.setFieldValue(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT_NOTICE, 1); + usVaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usVaV1.setFieldValue(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT_NOTICE, 2); + usVaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT_NOTICE, 0); + + usVaV1.setFieldValue(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usVaV1.setFieldValue(UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + usVaV1.encode(); + + usVaV1.setFieldValue(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usVaV1.setFieldValue(UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); + usVaV1.encode(); + + usVaV1.setFieldValue(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usVaV1.setFieldValue(UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE, 2); + usVaV1.encode(); + + usVaV1.setFieldValue(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usVaV1.setFieldValue(UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE, 2); + usVaV1.encode(); + + usVaV1.setFieldValue(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usVaV1.setFieldValue(UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); + usVaV1.encode(); + + + usVaV1.setFieldValue(UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + + usVaV1.setFieldValue(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT_NOTICE, 0); + usVaV1.encode(); + + usVaV1.setFieldValue(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT_NOTICE, 0); + usVaV1.encode(); + + usVaV1.setFieldValue(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT_NOTICE, 0); + usVaV1.encode(); + + usVaV1.setFieldValue(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT_NOTICE, 1); + usVaV1.encode(); + + usVaV1.setFieldValue(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT_NOTICE, 2); + usVaV1.encode(); } @Test public void testDecode1() throws DecodingException { - UsVaV1 usVaV1 = new UsVaV1("BbYbG9s"); + UsVaV1 usVaV1 = new UsVaV1("BVWSSVY"); Assertions.assertEquals(1, usVaV1.getSharingNotice()); - Assertions.assertEquals(2, usVaV1.getSaleOptOutNotice()); - Assertions.assertEquals(3, usVaV1.getTargetedAdvertisingOptOutNotice()); + Assertions.assertEquals(1, usVaV1.getSaleOptOutNotice()); + Assertions.assertEquals(1, usVaV1.getTargetedAdvertisingOptOutNotice()); Assertions.assertEquals(1, usVaV1.getSaleOptOut()); - Assertions.assertEquals(2, usVaV1.getTargetedAdvertisingOptOut()); - Assertions.assertEquals(Arrays.asList(0, 1, 2, 3, 0, 1, 2, 3), usVaV1.getSensitiveDataProcessing()); - Assertions.assertEquals(3, usVaV1.getKnownChildSensitiveDataConsents()); + Assertions.assertEquals(1, usVaV1.getTargetedAdvertisingOptOut()); + Assertions.assertEquals(Arrays.asList(2, 1, 0, 2, 1, 0, 2, 1), usVaV1.getSensitiveDataProcessing()); + Assertions.assertEquals(1, usVaV1.getKnownChildSensitiveDataConsents()); Assertions.assertEquals(1, usVaV1.getMspaCoveredTransaction()); - Assertions.assertEquals(2, usVaV1.getMspaOptOutOptionMode()); - Assertions.assertEquals(3, usVaV1.getMspaServiceProviderMode()); + Assertions.assertEquals(1, usVaV1.getMspaOptOutOptionMode()); + Assertions.assertEquals(2, usVaV1.getMspaServiceProviderMode()); + } + + @Test() + public void testDecodeGarbage() { + Assertions.assertThrows(DecodingException.class, () -> { + new UsVaV1("z").getMspaCoveredTransaction(); + }); } } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UspV1Test.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UspV1Test.java index 13eb280d..ffc7e741 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UspV1Test.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UspV1Test.java @@ -3,34 +3,33 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; import com.iab.gpp.encoder.error.InvalidFieldException; public class UspV1Test { @Test - public void testEncode1() throws EncodingException { + public void testEncode1() { UspV1 uspv1 = new UspV1(); Assertions.assertEquals("1---", uspv1.encode()); } @Test - public void testEncode2() throws EncodingException, InvalidFieldException { + public void testEncode2() { UspV1 uspv1 = new UspV1(); - uspv1.setFieldValue("Notice", "Y"); - uspv1.setFieldValue("OptOutSale", "N"); - uspv1.setFieldValue("LspaCovered", "N"); + uspv1.setFieldValue("Notice", 'Y'); + uspv1.setFieldValue("OptOutSale", 'N'); + uspv1.setFieldValue("LspaCovered", 'N'); Assertions.assertEquals("1YNN", uspv1.encode()); } @Test - public void testEncode3() throws EncodingException, InvalidFieldException { + public void testEncode3() { UspV1 uspv1 = new UspV1(); uspv1.setFieldValue("Version", 2); - uspv1.setFieldValue("Notice", "N"); - uspv1.setFieldValue("OptOutSale", "Y"); - uspv1.setFieldValue("LspaCovered", "Y"); + uspv1.setFieldValue("Notice", 'N'); + uspv1.setFieldValue("OptOutSale", 'Y'); + uspv1.setFieldValue("LspaCovered", 'Y'); Assertions.assertEquals("2NYY", uspv1.encode()); } @@ -39,9 +38,9 @@ public void testEncode3() throws EncodingException, InvalidFieldException { public void testDecode1() throws DecodingException, InvalidFieldException { UspV1 uspv1 = new UspV1("1NYN"); Assertions.assertEquals(1, uspv1.getFieldValue("Version")); - Assertions.assertEquals("N", uspv1.getFieldValue("Notice")); - Assertions.assertEquals("Y", uspv1.getFieldValue("OptOutSale")); - Assertions.assertEquals("N", uspv1.getFieldValue("LspaCovered")); + Assertions.assertEquals('N', uspv1.getFieldValue("Notice")); + Assertions.assertEquals('Y', uspv1.getFieldValue("OptOutSale")); + Assertions.assertEquals('N', uspv1.getFieldValue("LspaCovered")); Assertions.assertEquals(uspv1.getFieldValue("Version"), uspv1.getVersion()); Assertions.assertEquals(uspv1.getFieldValue("Notice"), uspv1.getNotice()); @@ -51,11 +50,11 @@ public void testDecode1() throws DecodingException, InvalidFieldException { @Test public void testDecode2() throws DecodingException, InvalidFieldException { - UspV1 uspv1 = new UspV1("2YNY"); - Assertions.assertEquals(2, uspv1.getFieldValue("Version")); - Assertions.assertEquals("Y", uspv1.getFieldValue("Notice")); - Assertions.assertEquals("N", uspv1.getFieldValue("OptOutSale")); - Assertions.assertEquals("Y", uspv1.getFieldValue("LspaCovered")); + UspV1 uspv1 = new UspV1("1YNY"); + Assertions.assertEquals(1, uspv1.getFieldValue("Version")); + Assertions.assertEquals('Y', uspv1.getFieldValue("Notice")); + Assertions.assertEquals('N', uspv1.getFieldValue("OptOutSale")); + Assertions.assertEquals('Y', uspv1.getFieldValue("LspaCovered")); Assertions.assertEquals(uspv1.getFieldValue("Version"), uspv1.getVersion()); Assertions.assertEquals(uspv1.getFieldValue("Notice"), uspv1.getNotice()); diff --git a/iabgpp-extras-jackson/src/test/resources/vendorlist/v2/purposes-fr.json b/iabgpp-extras-jackson/src/test/resources/vendorlist/v2/purposes-fr.json new file mode 100644 index 00000000..98cfa81b --- /dev/null +++ b/iabgpp-extras-jackson/src/test/resources/vendorlist/v2/purposes-fr.json @@ -0,0 +1 @@ +{"vendorListVersion":29,"lastUpdated":"2020-03-12T16:40:38Z","purposes":{"1":{"id":1,"name":"Stocker et/ou acc\u00e9der \u00e0 des informations stock\u00e9es sur un terminal","description":"Les cookies, identifiants de votre terminal ou autres informations peuvent \u00eatre stock\u00e9s ou consult\u00e9s sur votre terminal pour les finalit\u00e9s qui vous sont pr\u00e9sent\u00e9es.","descriptionLegal":"Les partenaires peuvent :\n* Stocker des informations et acc\u00e9der \u00e0 des informations stock\u00e9es sur le terminal, comme les cookies et les identifiants du terminal pr\u00e9sent\u00e9s \u00e0 un utilisateur.\n"},"2":{"id":2,"name":"S\u00e9lectionner des publicit\u00e9s standard","description":"Les publicit\u00e9s peuvent vous \u00eatre pr\u00e9sent\u00e9es en fonction du contenu \u00e9ditorial que vous consultez, de l\u2019application que vous utilisez, de votre localisation approximative, ou de votre type de terminal\n","descriptionLegal":"Pour s\u00e9lectionner des publicit\u00e9s standard, les partenaires peuvent :\n* Utiliser des informations en temps r\u00e9el sur le contexte dans lequel la publicit\u00e9 sera affich\u00e9e, pour afficher la publicit\u00e9, y compris des informations sur le contenu et le terminal, telles que : type de terminal et capacit\u00e9s, user agent, URL, adresse IP \n* Utiliser des donn\u00e9es de g\u00e9olocalisation non-pr\u00e9cises d\u2019un utilisateur\n* Contr\u00f4ler la fr\u00e9quence de diffusion des publicit\u00e9s \u00e0 un utilisateur.\n* D\u00e9finir l\u2019ordre dans lequel les publicit\u00e9s sont pr\u00e9sent\u00e9es \u00e0 un utilisateur.\n* Emp\u00eacher une publicit\u00e9 de s\u2019afficher dans un contexte \u00e9ditorial inadapt\u00e9 (dangereux pour la marque)\nLes partenaires ne peuvent pas :\n* Cr\u00e9er un profil publicitaire personnalis\u00e9 \u00e0 l\u2019aide de ces informations pour la s\u00e9lection de publicit\u00e9s futures sans base l\u00e9gale distincte. \nN.B. \u00ab Non-pr\u00e9cises \u00bb signifie qu\u2019une g\u00e9olocalisation approximative dans un rayon d\u2019au moins 500 m\u00e8tres est autoris\u00e9e.\n"},"3":{"id":3,"name":"Cr\u00e9er un profil personnalis\u00e9 de publicit\u00e9s","description":"Un profil peut \u00eatre cr\u00e9\u00e9 sur vous et sur vos centres d\u2019int\u00e9r\u00eat pour vous pr\u00e9senter des publicit\u00e9s personnalis\u00e9es susceptibles de vous int\u00e9resser.","descriptionLegal":"Pour cr\u00e9er un profil de publicit\u00e9s personnalis\u00e9es, les partenaires peuvent :\n* Collecter des informations sur un utilisateur, notamment son activit\u00e9, ses centres d\u2019int\u00e9r\u00eat, les sites ou applications consult\u00e9s, les donn\u00e9es d\u00e9mographiques ou la g\u00e9olocalisation d\u2019un utilisateur, pour cr\u00e9er ou modifier un profil utilisateur \u00e0 utiliser dans des publicit\u00e9s personnalis\u00e9es.\n"},"4":{"id":4,"name":"S\u00e9lectionner des publicit\u00e9s personnalis\u00e9es","description":"Des publicit\u00e9s personnalis\u00e9es peuvent vous \u00eatre pr\u00e9sent\u00e9es sur la base d\u2019un profil cr\u00e9\u00e9 sur vous.","descriptionLegal":"Pour s\u00e9lectionner des publicit\u00e9s personnalis\u00e9es, les partenaires peuvent :\n* S\u00e9lectionner des publicit\u00e9s personnalis\u00e9es sur la base d\u2019un profil utilisateur ou d\u2019autres donn\u00e9es d\u2019utilisateur historiques, y compris l\u2019activit\u00e9 pass\u00e9e d\u2019un utilisateur, ses centres d\u2019int\u00e9r\u00eat, les sites qu\u2019il a visit\u00e9s ou les applications qu\u2019il a utilis\u00e9es, sa localisation ou ses donn\u00e9es d\u00e9mographiques.\n"},"5":{"id":5,"name":"Cr\u00e9er un profil pour afficher un contenu personnalis\u00e9","description":"Un profil peut \u00eatre cr\u00e9\u00e9 sur vous et sur vos centres d\u2019int\u00e9r\u00eat afin de vous pr\u00e9senter du contenu personnalis\u00e9 susceptible de vous int\u00e9resser.","descriptionLegal":"Pour cr\u00e9er un profil pour afficher du contenu personnalis\u00e9, les partenaires peuvent :\n* Collecter des informations sur un utilisateur, y compris l\u2019activit\u00e9 d\u2019un utilisateur, ses centres d\u2019int\u00e9r\u00eat, les sites qu\u2019il a visit\u00e9s ou les applications qu\u2019il a utilis\u00e9es, ses donn\u00e9es d\u00e9mographiques ou sa localisation, pour cr\u00e9er ou modifier un profil utilisateur pour afficher du contenu personnalis\u00e9.\n"},"6":{"id":6,"name":"S\u00e9lectionner du contenu personnalis\u00e9","description":"Du contenu personnalis\u00e9 peut vous \u00eatre pr\u00e9sent\u00e9 sur la base de votre profil utilisateur. ","descriptionLegal":"Pour s\u00e9lectionner du contenu personnalis\u00e9, les partenaires peuvent :\n* S\u00e9lectionner du contenu personnalis\u00e9 sur la base d\u2019un profil utilisateur induit des donn\u00e9es relatives \u00e0 son activit\u00e9 en ligne, ses centres d\u2019int\u00e9r\u00eat, les sites qu\u2019il a visit\u00e9s, les applications qu\u2019il a utilis\u00e9es, sa localisation ou ses donn\u00e9es socio-d\u00e9mographiques.\n"},"7":{"id":7,"name":"Mesurer la performance des publicit\u00e9s","description":"La performance et l\u2019efficacit\u00e9 des publicit\u00e9s que vous voyez ou avec lesquelles vous interagissez peuvent \u00eatre mesur\u00e9es.","descriptionLegal":"Pour mesurer la performance des publicit\u00e9s, les partenaires peuvent:\n* Mesurer si et comment des publicit\u00e9s ont \u00e9t\u00e9 pr\u00e9sent\u00e9e \u00e0 un utilisateur et comment celui-ci a interagi avec celles-ci\n* G\u00e9n\u00e9rer des rapports sur les publicit\u00e9s, notamment sur leur performance\n* G\u00e9n\u00e9rer des rapports sur les utilisateurs ayant interagi avec des publicit\u00e9s en utilisant des donn\u00e9es issues de cette interaction \n* Fournir des rapports aux \u00e9diteurs sur les publicit\u00e9s pr\u00e9sent\u00e9es/affich\u00e9es sur leurs propri\u00e9t\u00e9s num\u00e9riques \n* \u00c9valuer si une publicit\u00e9 diffus\u00e9e dans un contexte \u00e9ditorial appropri\u00e9 (conforme \u00e0 l\u2019image de la marque) sans danger pour la marque)\n* D\u00e9terminer le pourcentage du visionnage \u00e9ventuel de la publicit\u00e9 et sa dur\u00e9e \n* Combiner ces informations avec d\u2019autres informations collect\u00e9es au pr\u00e9alable, pouvant provenir de sites internet et applications\nLes partenaires ne peuvent pas: \n* Croiser des donn\u00e9es d\u2019audience, issues ou d\u00e9riv\u00e9es d\u2019un panel, avec des donn\u00e9es de mesure de performance, sans base l\u00e9gale pour titre \"Finalit\u00e9 9\". \n"},"8":{"id":8,"name":"Mesurer la performance du contenu","description":"La performance et l\u2019efficacit\u00e9 du contenu que vous voyez ou avec lequel vous interagissez peuvent \u00eatre mesur\u00e9es.","descriptionLegal":"Pour mesurer la performance du contenu, les partenaires peuvent:\n* Mesurer comment le contenu a \u00e9t\u00e9 diffus\u00e9 et comment les utilisateurs ont interagi avec, et g\u00e9n\u00e9rer des rapports.\n* G\u00e9n\u00e9rer des rapports \u00e0 l\u2019aide d\u2019informations directement mesurables ou connues, sur les utilisateurs qui ont interagi avec le contenu\nLes partenaires ne peuvent pas:\n* Mesurer si et comment des publicit\u00e9s (y compris des publicit\u00e9s natives) ont \u00e9t\u00e9 pr\u00e9sent\u00e9es \u00e0 un utilisateur et comment celui-ci a interagi avec, sans base l\u00e9gale distincte\n* Croiser des donn\u00e9es d\u2019audience, issues ou d\u00e9riv\u00e9es d\u2019un panel, avec des donn\u00e9es de mesure de performance, sans base l\u00e9gale pour titre \"Finalit\u00e9 9\u201d. "},"9":{"id":9,"name":"Exploiter des \u00e9tudes de march\u00e9 afin de g\u00e9n\u00e9rer des donn\u00e9es d\u2019audience","description":"Les \u00e9tudes de march\u00e9 peuvent servir \u00e0 en apprendre davantage sur les audiences qui visitent des sites/utilisent des applications et voient des publicit\u00e9s.","descriptionLegal":"Pour utiliser des \u00e9tudes de march\u00e9 afin de g\u00e9n\u00e9rer des donn\u00e9es d\u2019audience, les partenaires peuvent:\n* Fournir des rapports agr\u00e9g\u00e9s aux annonceurs ou \u00e0 leurs repr\u00e9sentants sur les audiences expos\u00e9es \u00e0 leurs publicit\u00e9s, en utilisant des donn\u00e9es issues d\u2019un panel ou d\u2019un autre dispositif.\n* Fournir des rapports agr\u00e9g\u00e9s aux \u00e9diteurs sur les audiences expos\u00e9es \u00e0 des contenus et/ou des publicit\u00e9s ou qui ont interagi avec des contenus et/ou les publicit\u00e9s sur leurs sites, en utilisant des donn\u00e9es issues d\u2019un panel ou d\u2019un autre dispositif. \n* Combiner des donn\u00e9es hors ligne \u00e0 celles d\u2019un utilisateur en ligne dans le cadre d\u2019\u00e9tudes de march\u00e9 pour g\u00e9n\u00e9rer des donn\u00e9es d\u2019audience si les partenaires ont d\u00e9clar\u00e9 faire correspondre et associer des sources de donn\u00e9es hors ligne (Fonctionnalit\u00e9 1)\n* Texte dans la version anglaise : Combiner ces informations avec des donn\u00e9es d\u00e9j\u00e0 collect\u00e9es que ce soit sur le web ou via des applications. \nLes partenaires ne peuvent pas : \n* Mesurer la performance et l\u2019efficacit\u00e9 des publicit\u00e9s qui ont \u00e9t\u00e9 pr\u00e9sent\u00e9es \u00e0 un utilisateur en particulier, ou avec lesquelles il a interagi, sans s\u2019appuyer sur une base l\u00e9gale sp\u00e9cifique pour la mesure de la performance publicitaire.\n* \u00c9valuer le contenu qui a \u00e9t\u00e9 pr\u00e9sent\u00e9 \u00e0 un utilisateur en particulier et la fa\u00e7on dont ce dernier a r\u00e9agi sans s\u2019appuyer sur une base l\u00e9gale sp\u00e9cifique pour la mesure de la performance des contenus.\n"},"10":{"id":10,"name":"D\u00e9velopper et am\u00e9liorer les produits","description":"Vos donn\u00e9es peuvent \u00eatre utilis\u00e9es pour am\u00e9liorer les syst\u00e8mes et logiciels existants et pour d\u00e9velopper de nouveaux produits.","descriptionLegal":"Pour d\u00e9velopper de nouveaux produits et am\u00e9liorer des produits existants, les partenaires peuvent:\n* Utiliser des informations pour am\u00e9liorer leurs produits existants en y ajoutant de nouvelles fonctionnalit\u00e9s et pour d\u00e9velopper de nouveaux produits\n* Cr\u00e9er de nouveaux mod\u00e8les et algorithmes gr\u00e2ce au machine-learning \nLes partenaires ne peuvent pas:\n* Effectuer toute autre op\u00e9ration de traitement des donn\u00e9es autoris\u00e9e par une autre finalit\u00e9 dans le cadre de cette finalit\u00e9\n"}},"specialPurposes":{"1":{"id":1,"name":"Assurer la s\u00e9curit\u00e9, pr\u00e9venir la fraude et d\u00e9boguer","description":"Vos donn\u00e9es peuvent \u00eatre utilis\u00e9es pour surveiller et pr\u00e9venir les activit\u00e9s frauduleuses, et s\u2019assurer que les syst\u00e8mes et processus fonctionnent correctement et en toute s\u00e9curit\u00e9.","descriptionLegal":"Pour garantir la s\u00e9curit\u00e9, pr\u00e9venir la fraude et d\u00e9boguer, les partenaires peuvent:\n* Veiller \u00e0 ce que les donn\u00e9es soient transmises en toute s\u00e9curit\u00e9 \n* D\u00e9tecter et pr\u00e9venir les activit\u00e9s malveillantes, frauduleuses, inappropri\u00e9es ou ill\u00e9gales.\n* Assurer un fonctionnement correct et efficace des syst\u00e8mes et des processus, y compris surveiller et am\u00e9liorer la performance des syst\u00e8mes et processus utilis\u00e9s pour des finalit\u00e9s autoris\u00e9es\nLes partenaires ne peuvent pas:\n* Effectuer, au titre de cette finalit\u00e9, toute autre op\u00e9ration de traitement des donn\u00e9es autoris\u00e9e pour une finalit\u00e9 diff\u00e9rente .\nRemarque: Les donn\u00e9es collect\u00e9es et utilis\u00e9es pour assurer la s\u00e9curit\u00e9, pr\u00e9venir la fraude et d\u00e9boguer peuvent inclure des caract\u00e9ristiques d\u2019appareil envoy\u00e9es automatiquement \u00e0 des fins d'identification, des donn\u00e9es de g\u00e9olocalisation pr\u00e9cises et des donn\u00e9es obtenues par l\u2019analyse active des caract\u00e9ristiques de l\u2019appareil \u00e0 des fins d\u2019identification sans notification distincte et/ou opt-in distinct \n"},"2":{"id":2,"name":"Diffuser techniquement les publicit\u00e9s ou le contenu","description":"Votre terminal peut recevoir et envoyer des informations qui vous permettent de voir des publicit\u00e9s et du contenu et d\u2019interagir avec eux.","descriptionLegal":"Pour fournir des informations et r\u00e9pondre aux appels techniques, les partenaires peuvent:\n* Utiliser l\u2019adresse IP d\u2019un utilisateur pour diffuser une publicit\u00e9 sur Internet\n* R\u00e9agir \u00e0 l\u2019interaction d\u2019un utilisateur avec une publicit\u00e9 en dirigeant l\u2019utilisateur vers une page d\u2019accueil\n* Utiliser l\u2019adresse IP d\u2019un utilisateur pour diffuser du contenu sur Internet\n* R\u00e9agir \u00e0 l\u2019interaction d\u2019un utilisateur avec du contenu en dirigeant l\u2019utilisateur vers une page d\u2019accueil\n* Utiliser des informations sur le type de terminal et les capacit\u00e9s du terminal pour pr\u00e9senter des publicit\u00e9s ou du contenu, par exemple, pour pr\u00e9senter une publicit\u00e9 \u00e0 la bonne taille ou une vid\u00e9o dans un format pris en charge par le terminal \nLes partenaires ne peuvent pas:\n* Effectuer, au titre de cette finalit\u00e9, toute autre op\u00e9ration de traitement des donn\u00e9es autoris\u00e9e pour une finalit\u00e9 diff\u00e9rente \n"}},"features":{"1":{"id":1,"name":"Mettre en correspondance et combiner des sources de donn\u00e9es hors ligne","description":"Les donn\u00e9es issues de sources de donn\u00e9es hors ligne peuvent \u00eatre combin\u00e9es \u00e0 votre activit\u00e9 en ligne \u00e0 l\u2019appui d\u2019une ou de plusieurs finalit\u00e9s.","descriptionLegal":"Les partenaires peuvent : \n* Combiner des donn\u00e9es obtenues hors ligne avec des donn\u00e9es collect\u00e9es en ligne \u00e0 l\u2019appui d\u2019une ou de plusieurs Finalit\u00e9s ou Finalit\u00e9s sp\u00e9ciales.\n"},"2":{"id":2,"name":"Relier diff\u00e9rents terminaux","description":"Diff\u00e9rents terminaux peuvent \u00eatre identifi\u00e9s comme vous appartenant ou appartenant \u00e0 votre foyer \u00e0 l\u2019appui d\u2019une ou de plusieurs finalit\u00e9s","descriptionLegal":"Les partnenaires peuvent :\n* D\u00e9terminer, selon une approche d\u00e9terministe, que deux terminaux ou plus appartiennent au m\u00eame utilisateur ou au m\u00eame foyer\n* D\u00e9terminer, selon une approche probabiliste, que deux terminaux ou plus appartiennent au m\u00eame utilisateur ou au m\u00eame foyer\n* Analyser activement les caract\u00e9ristiques du terminal pour l\u2019identification probabiliste si les utilisateurs ont autoris\u00e9 les partenanaires \u00e0 analyser activement les caract\u00e9ristiques du terminal pour l\u2019identification (Fonctionnalit\u00e9 sp\u00e9ciale 2)\n"},"3":{"id":3,"name":"Recevoir et utiliser des caract\u00e9ristiques d\u2019identification d\u2019appareil envoy\u00e9es automatiquement","description":"Votre appareil peut \u00eatre distingu\u00e9 d\u2019autres appareils en fonction des informations qu\u2019il envoie automatiquement, telles que l\u2019adresse IP ou le type de navigateur.","descriptionLegal":"Les partenaires peuvent :\n* Cr\u00e9er un identifiant \u00e0 l\u2019aide des donn\u00e9es collect\u00e9es automatiquement \u00e0 partir d\u2019un appareil pour des caract\u00e9ristiques sp\u00e9cifiques ; par ex., adresse IP, cha\u00eene d\u2019agent utilisateur.\n* Utiliser cet identifiant pour r\u00e9identifier un appareil.\nLes partenaires ne peuvent pas :\n* Cr\u00e9er un identifiant \u00e0 l\u2019aide des donn\u00e9es collect\u00e9es via une analyse active d\u2019un terminal pour l\u2019identification de caract\u00e9ristiques sp\u00e9cifiques (par exemple, des polices install\u00e9es ou la r\u00e9solution d\u2019\u00e9cran) sans une adh\u00e9sion distincte de l\u2019utilisateur \u00e0 l\u2019analyse active des caract\u00e9ristiques de l\u2019appareil \u00e0 des fins d\u2019identification.\n* Utiliser cet identifiant pour r\u00e9-identifier un terminal.\n"}},"specialFeatures":{"1":{"id":1,"name":"Utiliser des donn\u00e9es de g\u00e9olocalisation pr\u00e9cises","description":"Vos donn\u00e9es de g\u00e9olocalisation pr\u00e9cises peuvent \u00eatre utilis\u00e9es \u00e0 l\u2019appui d\u2019une ou de plusieurs finalit\u00e9s. Cela signifie que votre localisation peut \u00eatre pr\u00e9cise \u00e0 plusieurs m\u00e8tres pr\u00e8s.","descriptionLegal":"Les partnenaires peuvent :\n* Collecter et traiter des donn\u00e9es de g\u00e9olocalisation pr\u00e9cises \u00e0 l\u2019appui d\u2019une ou de plusieurs finalit\u00e9s.\nN.B. Une g\u00e9olocalisation pr\u00e9cise signifie qu\u2019il n\u2019y a aucune restriction \u00e0 la pr\u00e9cision de la localisation d\u2019un utilisateur ; elle peut \u00eatre pr\u00e9cise \u00e0 quelques m\u00e8tres pr\u00e8s.\n"},"2":{"id":2,"name":"Analyser activement les caract\u00e9ristiques du terminal pour l\u2019identification","description":"Votre terminal peut \u00eatre identifi\u00e9 sur la base d\u2019une analyse de la combinaison unique de caract\u00e9ristiques de votre terminal.","descriptionLegal":"Les partenaires peuvent :\n* Cr\u00e9er un identifiant \u00e0 l\u2019aide des donn\u00e9es collect\u00e9es via une analyse active d\u2019un terminal pour l\u2019identification de caract\u00e9ristiques sp\u00e9cifiques, par exemple des polices install\u00e9es ou la r\u00e9solution d\u2019\u00e9cran. \n* Utiliser cet identifiant pour r\u00e9-identifier un terminal.\n"}},"stacks":{"1":{"id":1,"purposes":[],"specialFeatures":[1,2],"name":"Donn\u00e9es de g\u00e9olocalisation pr\u00e9cises et identification par analyse du terminal","description":"Des informations de g\u00e9olocalisation pr\u00e9cises et des informations sur les caract\u00e9ristiques de l\u2019appareil peuvent \u00eatre utilis\u00e9es."},"2":{"id":2,"purposes":[2,7],"specialFeatures":[],"name":"Publicit\u00e9s standards et mesure de performance des publicit\u00e9s","description":"Des publicit\u00e9s standards peuvent \u00eatre diffus\u00e9es. La performance des publicit\u00e9s peut \u00eatre mesur\u00e9e."},"3":{"id":3,"purposes":[2,3,4],"specialFeatures":[],"name":"Publicit\u00e9s personnalis\u00e9es","description":"Les publicit\u00e9s peuvent \u00eatre personnalis\u00e9es sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser les publicit\u00e9s."},"4":{"id":4,"purposes":[2,7,9],"specialFeatures":[],"name":"Publicit\u00e9s standards et mesure de performance des publicit\u00e9s","description":"Des publicit\u00e9s standards peuvent \u00eatre diffus\u00e9es. La performance des publicit\u00e9s peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"5":{"id":5,"purposes":[2,3,7],"specialFeatures":[],"name":"Publicit\u00e9s standards, profil de publicit\u00e9s personnalis\u00e9es et mesure de performance des publicit\u00e9s","description":"Des publicit\u00e9s standards peuvent \u00eatre diffus\u00e9es. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser les publicit\u00e9s. La performance des publicit\u00e9s peut \u00eatre mesur\u00e9e."},"6":{"id":6,"purposes":[2,4,7],"specialFeatures":[],"name":"Affichage de publicit\u00e9s personnalis\u00e9es et mesure de performance des publicit\u00e9s","description":"Les publicit\u00e9s peuvent \u00eatre personnalis\u00e9es sur la base d\u2019un profil. La performance des publicit\u00e9s peut \u00eatre mesur\u00e9e."},"7":{"id":7,"purposes":[2,4,7,9],"specialFeatures":[],"name":"Affichage de publicit\u00e9s personnalis\u00e9es, mesure de performance des publicit\u00e9s, et donn\u00e9es d\u2019audience","description":"Les publicit\u00e9s peuvent \u00eatre personnalis\u00e9es sur la base d\u2019un profil. La performance des publicit\u00e9s peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"8":{"id":8,"purposes":[2,3,4,7],"specialFeatures":[],"name":"Publicit\u00e9s personnalis\u00e9es et mesure de performance des annonces","description":"Les publicit\u00e9s peuvent \u00eatre personnalis\u00e9es sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser les publicit\u00e9s. La performance des publicit\u00e9s peut \u00eatre mesur\u00e9e."},"9":{"id":9,"purposes":[2,3,4,7,9],"specialFeatures":[],"name":"Publicit\u00e9s personnalis\u00e9es, mesure de performance des publicit\u00e9s, et donn\u00e9es d\u2019audience","description":"Les publicit\u00e9s peuvent \u00eatre personnalis\u00e9es sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser les publicit\u00e9s. La performance des publicit\u00e9s peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"10":{"id":10,"purposes":[3,4],"specialFeatures":[],"name":"Profil de publicit\u00e9s personnalis\u00e9es et affichage","description":"Les publicit\u00e9s peuvent \u00eatre personnalis\u00e9es sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser les publicit\u00e9s. "},"11":{"id":11,"purposes":[5,6],"specialFeatures":[],"name":"Contenu personnalis\u00e9","description":"Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu."},"12":{"id":12,"purposes":[6,8],"specialFeatures":[],"name":"Affichage de contenu personnalis\u00e9 et mesure de performance du contenu","description":"Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. La performance du contenu peut \u00eatre mesur\u00e9e."},"13":{"id":13,"purposes":[6,8,9],"specialFeatures":[],"name":"Affichage de contenu personnalis\u00e9, mesure de performance du contenu et donn\u00e9es d\u2019audience","description":"Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. La performance du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"14":{"id":14,"purposes":[5,6,8],"specialFeatures":[],"name":"Contenu personnalis\u00e9 et mesure de performance du contenu","description":"Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu. La performance du contenu peut \u00eatre mesur\u00e9e."},"15":{"id":15,"purposes":[5,6,8,9],"specialFeatures":[],"name":"Contenu personnalis\u00e9, mesure de performance du contenu et donn\u00e9es d\u2019audience","description":"Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu. La performance du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"16":{"id":16,"purposes":[5,6,8,9,10],"specialFeatures":[],"name":"Contenu personnalis\u00e9, mesure de performance du contenu, donn\u00e9es d\u2019audience, et d\u00e9veloppement produit","description":"Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu. La performance du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu. Les donn\u00e9es peuvent \u00eatre utilis\u00e9es pour cr\u00e9er ou am\u00e9liorer l\u2019exp\u00e9rience utilisateur, des syst\u00e8mes et logiciels"},"17":{"id":17,"purposes":[7,8,9],"specialFeatures":[],"name":"Mesure de performance des annonces et du contenu et donn\u00e9es d\u2019audience","description":"La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"18":{"id":18,"purposes":[7,8],"specialFeatures":[],"name":"Mesure de performance des publicit\u00e9s et du contenu","description":"La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e."},"19":{"id":19,"purposes":[7,9],"specialFeatures":[],"name":"Mesure de performance des publicit\u00e9s et donn\u00e9es d\u2019audience","description":"La performance des publicit\u00e9s peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu"},"20":{"id":20,"purposes":[7,8,9,10],"specialFeatures":[],"name":"Mesure de performance des publicit\u00e9s et du contenu, donn\u00e9es d\u2019audience, et d\u00e9veloppement produit","description":"La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu. Les donn\u00e9es peuvent \u00eatre utilis\u00e9es pour cr\u00e9er ou am\u00e9liorer l\u2019exp\u00e9rience utilisateur, les syst\u00e8mes et les logiciels. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"21":{"id":21,"purposes":[8,9,10],"specialFeatures":[],"name":"Mesure de performance du contenu, donn\u00e9es d\u2019audience, et d\u00e9veloppement produit.","description":"La performance du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu. Les donn\u00e9es peuvent \u00eatre utilis\u00e9es pour cr\u00e9er ou am\u00e9liorer l\u2019exp\u00e9rience utilisateur, les syst\u00e8mes et les logiciels."},"22":{"id":22,"purposes":[8,10],"specialFeatures":[],"name":"Mesure de performance du contenu, et d\u00e9veloppement produit","description":"La performance du contenu peut \u00eatre mesur\u00e9e. Les donn\u00e9es peuvent \u00eatre utilis\u00e9es pour cr\u00e9er ou am\u00e9liorer l\u2019exp\u00e9rience utilisateur, les syst\u00e8mes et les logiciels."},"23":{"id":23,"purposes":[2,4,6,7,8],"specialFeatures":[],"name":"Affichage de publicit\u00e9s et de contenu personnalis\u00e9s, mesure de performance des publicit\u00e9s et du contenu","description":"Les publicit\u00e9s et le contenu peuvent \u00eatre personnalis\u00e9s sur la base d\u2019un profil. La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e."},"24":{"id":24,"purposes":[2,4,6,7,8,9],"specialFeatures":[],"name":"Affichage de publicit\u00e9s et de contenu personnalis\u00e9s, mesure de performance des publicit\u00e9s et du contenu, et donn\u00e9es d\u2019audience","description":"Les publicit\u00e9s et le contenu peuvent \u00eatre personnalis\u00e9s sur la base d\u2019un profil. La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu. Les donn\u00e9es peuvent \u00eatre utilis\u00e9es pour cr\u00e9er ou am\u00e9liorer l\u2019exp\u00e9rience utilisateur, les syst\u00e8mes et les logiciels."},"25":{"id":25,"purposes":[2,3,4,5,6,7,8],"specialFeatures":[],"name":"Publicit\u00e9s et contenu personnalis\u00e9s, mesure de performance des publicit\u00e9s et du contenu","description":"Les publicit\u00e9s et le contenu peuvent \u00eatre personnalis\u00e9s sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser les publicit\u00e9s et le contenu. La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e."},"26":{"id":26,"purposes":[2,3,4,5,6,7,8,9],"specialFeatures":[],"name":"Publicit\u00e9s et contenu personnalis\u00e9s, mesure de performance des publicit\u00e9s et du contenu, et donn\u00e9es d\u2019audience","description":"Les publicit\u00e9s et le contenu peuvent \u00eatre personnalis\u00e9s sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser les publicit\u00e9s et le contenu. La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"27":{"id":27,"purposes":[3,5],"specialFeatures":[],"name":"Publicit\u00e9s personnalis\u00e9es et profil de contenu","description":"Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour personnaliser les publicit\u00e9s et le contenu. "},"28":{"id":28,"purposes":[2,4,6],"specialFeatures":[],"name":"Affichage de publicit\u00e9s et de contenu personnalis\u00e9s","description":"Les publicit\u00e9s et le contenu peuvent \u00eatre personnalis\u00e9s sur la base d\u2019un profil. "},"29":{"id":29,"purposes":[2,7,8,9],"specialFeatures":[],"name":"Publicit\u00e9s standards, mesure de performance des publicit\u00e9s et du contenu, et donn\u00e9es d\u2019audience","description":"Des publicit\u00e9s standards peuvent \u00eatre diffus\u00e9es. La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"30":{"id":30,"purposes":[2,4,5,6,7,8,9],"specialFeatures":[],"name":"Affichage de publicit\u00e9s personnalis\u00e9es, contenu personnalis\u00e9, mesure de performance des publicit\u00e9s et du contenu, et donn\u00e9es d\u2019audience","description":"Les publicit\u00e9s et le contenu peuvent \u00eatre personnalis\u00e9s sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu. La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"31":{"id":31,"purposes":[2,4,5,6,7,8,9,10],"specialFeatures":[],"name":"Affichage de publicit\u00e9s personnalis\u00e9es, contenu personnalis\u00e9, mesure de performance des publicit\u00e9s et du contenu, donn\u00e9es d\u2019audience et d\u00e9veloppement de produit","description":"Les publicit\u00e9s et le contenu peuvent \u00eatre personnalis\u00e9s sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu. La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu. Les donn\u00e9es peuvent \u00eatre utilis\u00e9es pour cr\u00e9er ou am\u00e9liorer l\u2019exp\u00e9rience utilisateur, les syst\u00e8mes et les logiciels."},"32":{"id":32,"purposes":[2,5,6,7,8,9],"specialFeatures":[],"name":"Publicit\u00e9s standards, contenu personnalis\u00e9, mesure de performance des publicit\u00e9s et du contenu, et donn\u00e9es d\u2019audience","description":"Des publicit\u00e9s standards peuvent \u00eatre diffus\u00e9es. Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu. La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"33":{"id":33,"purposes":[2,5,6,7,8,9,10],"specialFeatures":[],"name":"Publicit\u00e9s standards, contenu personnalis\u00e9, mesure de performance des publicit\u00e9s et du contenu, donn\u00e9es d\u2019audience, et d\u00e9veloppement produit","description":"Des publicit\u00e9s standards peuvent \u00eatre diffus\u00e9es. Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu. La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu. Les donn\u00e9es peuvent \u00eatre utilis\u00e9es pour cr\u00e9er ou am\u00e9liorer l\u2019exp\u00e9rience utilisateur, les syst\u00e8mes et les logiciels."},"34":{"id":34,"purposes":[2,5,6,8,9],"specialFeatures":[],"name":"Publicit\u00e9s standards, contenu personnalis\u00e9, mesure de performance du contenu, et donn\u00e9es d\u2019audience","description":"Des publicit\u00e9s standards peuvent \u00eatre diffus\u00e9es. Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu. La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"35":{"id":35,"purposes":[2,5,6,8,9,10],"specialFeatures":[],"name":"Publicit\u00e9s standards, contenu personnalis\u00e9, mesure de performance du contenu, donn\u00e9es d\u2019audience et d\u00e9veloppement de produit ","description":"Des publicit\u00e9s standards peuvent \u00eatre diffus\u00e9es. Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu. La performance du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu. Les donn\u00e9es peuvent \u00eatre utilis\u00e9es pour cr\u00e9er ou am\u00e9liorer l\u2019exp\u00e9rience utilisateur, les syst\u00e8mes et les logiciels."},"36":{"id":36,"purposes":[2,5,6,7],"specialFeatures":[],"name":"Publicit\u00e9s standard, contenu personnalis\u00e9 et mesure de performance des publicit\u00e9s","description":"Des publicit\u00e9s standards peuvent \u00eatre diffus\u00e9es. Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu. La performance des publicit\u00e9s peut \u00eatre mesur\u00e9e."},"37":{"id":37,"purposes":[2,5,6,7,10],"specialFeatures":[],"name":"Publicit\u00e9s standards, contenu personnalis\u00e9, mesure de performance des publicit\u00e9s, et d\u00e9veloppement produit","description":"Des publicit\u00e9s standards peuvent \u00eatre diffus\u00e9es. Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu. La performance des publicit\u00e9s peut \u00eatre mesur\u00e9e. Les donn\u00e9es peuvent \u00eatre utilis\u00e9es pour cr\u00e9er ou am\u00e9liorer l\u2019exp\u00e9rience utilisateur, les syst\u00e8mes et les logiciels."}}} \ No newline at end of file diff --git a/iabgpp-extras-jackson/src/test/resources/vendorlist/v3.0/purposes-fr.json b/iabgpp-extras-jackson/src/test/resources/vendorlist/v3.0/purposes-fr.json new file mode 100644 index 00000000..98cfa81b --- /dev/null +++ b/iabgpp-extras-jackson/src/test/resources/vendorlist/v3.0/purposes-fr.json @@ -0,0 +1 @@ +{"vendorListVersion":29,"lastUpdated":"2020-03-12T16:40:38Z","purposes":{"1":{"id":1,"name":"Stocker et/ou acc\u00e9der \u00e0 des informations stock\u00e9es sur un terminal","description":"Les cookies, identifiants de votre terminal ou autres informations peuvent \u00eatre stock\u00e9s ou consult\u00e9s sur votre terminal pour les finalit\u00e9s qui vous sont pr\u00e9sent\u00e9es.","descriptionLegal":"Les partenaires peuvent :\n* Stocker des informations et acc\u00e9der \u00e0 des informations stock\u00e9es sur le terminal, comme les cookies et les identifiants du terminal pr\u00e9sent\u00e9s \u00e0 un utilisateur.\n"},"2":{"id":2,"name":"S\u00e9lectionner des publicit\u00e9s standard","description":"Les publicit\u00e9s peuvent vous \u00eatre pr\u00e9sent\u00e9es en fonction du contenu \u00e9ditorial que vous consultez, de l\u2019application que vous utilisez, de votre localisation approximative, ou de votre type de terminal\n","descriptionLegal":"Pour s\u00e9lectionner des publicit\u00e9s standard, les partenaires peuvent :\n* Utiliser des informations en temps r\u00e9el sur le contexte dans lequel la publicit\u00e9 sera affich\u00e9e, pour afficher la publicit\u00e9, y compris des informations sur le contenu et le terminal, telles que : type de terminal et capacit\u00e9s, user agent, URL, adresse IP \n* Utiliser des donn\u00e9es de g\u00e9olocalisation non-pr\u00e9cises d\u2019un utilisateur\n* Contr\u00f4ler la fr\u00e9quence de diffusion des publicit\u00e9s \u00e0 un utilisateur.\n* D\u00e9finir l\u2019ordre dans lequel les publicit\u00e9s sont pr\u00e9sent\u00e9es \u00e0 un utilisateur.\n* Emp\u00eacher une publicit\u00e9 de s\u2019afficher dans un contexte \u00e9ditorial inadapt\u00e9 (dangereux pour la marque)\nLes partenaires ne peuvent pas :\n* Cr\u00e9er un profil publicitaire personnalis\u00e9 \u00e0 l\u2019aide de ces informations pour la s\u00e9lection de publicit\u00e9s futures sans base l\u00e9gale distincte. \nN.B. \u00ab Non-pr\u00e9cises \u00bb signifie qu\u2019une g\u00e9olocalisation approximative dans un rayon d\u2019au moins 500 m\u00e8tres est autoris\u00e9e.\n"},"3":{"id":3,"name":"Cr\u00e9er un profil personnalis\u00e9 de publicit\u00e9s","description":"Un profil peut \u00eatre cr\u00e9\u00e9 sur vous et sur vos centres d\u2019int\u00e9r\u00eat pour vous pr\u00e9senter des publicit\u00e9s personnalis\u00e9es susceptibles de vous int\u00e9resser.","descriptionLegal":"Pour cr\u00e9er un profil de publicit\u00e9s personnalis\u00e9es, les partenaires peuvent :\n* Collecter des informations sur un utilisateur, notamment son activit\u00e9, ses centres d\u2019int\u00e9r\u00eat, les sites ou applications consult\u00e9s, les donn\u00e9es d\u00e9mographiques ou la g\u00e9olocalisation d\u2019un utilisateur, pour cr\u00e9er ou modifier un profil utilisateur \u00e0 utiliser dans des publicit\u00e9s personnalis\u00e9es.\n"},"4":{"id":4,"name":"S\u00e9lectionner des publicit\u00e9s personnalis\u00e9es","description":"Des publicit\u00e9s personnalis\u00e9es peuvent vous \u00eatre pr\u00e9sent\u00e9es sur la base d\u2019un profil cr\u00e9\u00e9 sur vous.","descriptionLegal":"Pour s\u00e9lectionner des publicit\u00e9s personnalis\u00e9es, les partenaires peuvent :\n* S\u00e9lectionner des publicit\u00e9s personnalis\u00e9es sur la base d\u2019un profil utilisateur ou d\u2019autres donn\u00e9es d\u2019utilisateur historiques, y compris l\u2019activit\u00e9 pass\u00e9e d\u2019un utilisateur, ses centres d\u2019int\u00e9r\u00eat, les sites qu\u2019il a visit\u00e9s ou les applications qu\u2019il a utilis\u00e9es, sa localisation ou ses donn\u00e9es d\u00e9mographiques.\n"},"5":{"id":5,"name":"Cr\u00e9er un profil pour afficher un contenu personnalis\u00e9","description":"Un profil peut \u00eatre cr\u00e9\u00e9 sur vous et sur vos centres d\u2019int\u00e9r\u00eat afin de vous pr\u00e9senter du contenu personnalis\u00e9 susceptible de vous int\u00e9resser.","descriptionLegal":"Pour cr\u00e9er un profil pour afficher du contenu personnalis\u00e9, les partenaires peuvent :\n* Collecter des informations sur un utilisateur, y compris l\u2019activit\u00e9 d\u2019un utilisateur, ses centres d\u2019int\u00e9r\u00eat, les sites qu\u2019il a visit\u00e9s ou les applications qu\u2019il a utilis\u00e9es, ses donn\u00e9es d\u00e9mographiques ou sa localisation, pour cr\u00e9er ou modifier un profil utilisateur pour afficher du contenu personnalis\u00e9.\n"},"6":{"id":6,"name":"S\u00e9lectionner du contenu personnalis\u00e9","description":"Du contenu personnalis\u00e9 peut vous \u00eatre pr\u00e9sent\u00e9 sur la base de votre profil utilisateur. ","descriptionLegal":"Pour s\u00e9lectionner du contenu personnalis\u00e9, les partenaires peuvent :\n* S\u00e9lectionner du contenu personnalis\u00e9 sur la base d\u2019un profil utilisateur induit des donn\u00e9es relatives \u00e0 son activit\u00e9 en ligne, ses centres d\u2019int\u00e9r\u00eat, les sites qu\u2019il a visit\u00e9s, les applications qu\u2019il a utilis\u00e9es, sa localisation ou ses donn\u00e9es socio-d\u00e9mographiques.\n"},"7":{"id":7,"name":"Mesurer la performance des publicit\u00e9s","description":"La performance et l\u2019efficacit\u00e9 des publicit\u00e9s que vous voyez ou avec lesquelles vous interagissez peuvent \u00eatre mesur\u00e9es.","descriptionLegal":"Pour mesurer la performance des publicit\u00e9s, les partenaires peuvent:\n* Mesurer si et comment des publicit\u00e9s ont \u00e9t\u00e9 pr\u00e9sent\u00e9e \u00e0 un utilisateur et comment celui-ci a interagi avec celles-ci\n* G\u00e9n\u00e9rer des rapports sur les publicit\u00e9s, notamment sur leur performance\n* G\u00e9n\u00e9rer des rapports sur les utilisateurs ayant interagi avec des publicit\u00e9s en utilisant des donn\u00e9es issues de cette interaction \n* Fournir des rapports aux \u00e9diteurs sur les publicit\u00e9s pr\u00e9sent\u00e9es/affich\u00e9es sur leurs propri\u00e9t\u00e9s num\u00e9riques \n* \u00c9valuer si une publicit\u00e9 diffus\u00e9e dans un contexte \u00e9ditorial appropri\u00e9 (conforme \u00e0 l\u2019image de la marque) sans danger pour la marque)\n* D\u00e9terminer le pourcentage du visionnage \u00e9ventuel de la publicit\u00e9 et sa dur\u00e9e \n* Combiner ces informations avec d\u2019autres informations collect\u00e9es au pr\u00e9alable, pouvant provenir de sites internet et applications\nLes partenaires ne peuvent pas: \n* Croiser des donn\u00e9es d\u2019audience, issues ou d\u00e9riv\u00e9es d\u2019un panel, avec des donn\u00e9es de mesure de performance, sans base l\u00e9gale pour titre \"Finalit\u00e9 9\". \n"},"8":{"id":8,"name":"Mesurer la performance du contenu","description":"La performance et l\u2019efficacit\u00e9 du contenu que vous voyez ou avec lequel vous interagissez peuvent \u00eatre mesur\u00e9es.","descriptionLegal":"Pour mesurer la performance du contenu, les partenaires peuvent:\n* Mesurer comment le contenu a \u00e9t\u00e9 diffus\u00e9 et comment les utilisateurs ont interagi avec, et g\u00e9n\u00e9rer des rapports.\n* G\u00e9n\u00e9rer des rapports \u00e0 l\u2019aide d\u2019informations directement mesurables ou connues, sur les utilisateurs qui ont interagi avec le contenu\nLes partenaires ne peuvent pas:\n* Mesurer si et comment des publicit\u00e9s (y compris des publicit\u00e9s natives) ont \u00e9t\u00e9 pr\u00e9sent\u00e9es \u00e0 un utilisateur et comment celui-ci a interagi avec, sans base l\u00e9gale distincte\n* Croiser des donn\u00e9es d\u2019audience, issues ou d\u00e9riv\u00e9es d\u2019un panel, avec des donn\u00e9es de mesure de performance, sans base l\u00e9gale pour titre \"Finalit\u00e9 9\u201d. "},"9":{"id":9,"name":"Exploiter des \u00e9tudes de march\u00e9 afin de g\u00e9n\u00e9rer des donn\u00e9es d\u2019audience","description":"Les \u00e9tudes de march\u00e9 peuvent servir \u00e0 en apprendre davantage sur les audiences qui visitent des sites/utilisent des applications et voient des publicit\u00e9s.","descriptionLegal":"Pour utiliser des \u00e9tudes de march\u00e9 afin de g\u00e9n\u00e9rer des donn\u00e9es d\u2019audience, les partenaires peuvent:\n* Fournir des rapports agr\u00e9g\u00e9s aux annonceurs ou \u00e0 leurs repr\u00e9sentants sur les audiences expos\u00e9es \u00e0 leurs publicit\u00e9s, en utilisant des donn\u00e9es issues d\u2019un panel ou d\u2019un autre dispositif.\n* Fournir des rapports agr\u00e9g\u00e9s aux \u00e9diteurs sur les audiences expos\u00e9es \u00e0 des contenus et/ou des publicit\u00e9s ou qui ont interagi avec des contenus et/ou les publicit\u00e9s sur leurs sites, en utilisant des donn\u00e9es issues d\u2019un panel ou d\u2019un autre dispositif. \n* Combiner des donn\u00e9es hors ligne \u00e0 celles d\u2019un utilisateur en ligne dans le cadre d\u2019\u00e9tudes de march\u00e9 pour g\u00e9n\u00e9rer des donn\u00e9es d\u2019audience si les partenaires ont d\u00e9clar\u00e9 faire correspondre et associer des sources de donn\u00e9es hors ligne (Fonctionnalit\u00e9 1)\n* Texte dans la version anglaise : Combiner ces informations avec des donn\u00e9es d\u00e9j\u00e0 collect\u00e9es que ce soit sur le web ou via des applications. \nLes partenaires ne peuvent pas : \n* Mesurer la performance et l\u2019efficacit\u00e9 des publicit\u00e9s qui ont \u00e9t\u00e9 pr\u00e9sent\u00e9es \u00e0 un utilisateur en particulier, ou avec lesquelles il a interagi, sans s\u2019appuyer sur une base l\u00e9gale sp\u00e9cifique pour la mesure de la performance publicitaire.\n* \u00c9valuer le contenu qui a \u00e9t\u00e9 pr\u00e9sent\u00e9 \u00e0 un utilisateur en particulier et la fa\u00e7on dont ce dernier a r\u00e9agi sans s\u2019appuyer sur une base l\u00e9gale sp\u00e9cifique pour la mesure de la performance des contenus.\n"},"10":{"id":10,"name":"D\u00e9velopper et am\u00e9liorer les produits","description":"Vos donn\u00e9es peuvent \u00eatre utilis\u00e9es pour am\u00e9liorer les syst\u00e8mes et logiciels existants et pour d\u00e9velopper de nouveaux produits.","descriptionLegal":"Pour d\u00e9velopper de nouveaux produits et am\u00e9liorer des produits existants, les partenaires peuvent:\n* Utiliser des informations pour am\u00e9liorer leurs produits existants en y ajoutant de nouvelles fonctionnalit\u00e9s et pour d\u00e9velopper de nouveaux produits\n* Cr\u00e9er de nouveaux mod\u00e8les et algorithmes gr\u00e2ce au machine-learning \nLes partenaires ne peuvent pas:\n* Effectuer toute autre op\u00e9ration de traitement des donn\u00e9es autoris\u00e9e par une autre finalit\u00e9 dans le cadre de cette finalit\u00e9\n"}},"specialPurposes":{"1":{"id":1,"name":"Assurer la s\u00e9curit\u00e9, pr\u00e9venir la fraude et d\u00e9boguer","description":"Vos donn\u00e9es peuvent \u00eatre utilis\u00e9es pour surveiller et pr\u00e9venir les activit\u00e9s frauduleuses, et s\u2019assurer que les syst\u00e8mes et processus fonctionnent correctement et en toute s\u00e9curit\u00e9.","descriptionLegal":"Pour garantir la s\u00e9curit\u00e9, pr\u00e9venir la fraude et d\u00e9boguer, les partenaires peuvent:\n* Veiller \u00e0 ce que les donn\u00e9es soient transmises en toute s\u00e9curit\u00e9 \n* D\u00e9tecter et pr\u00e9venir les activit\u00e9s malveillantes, frauduleuses, inappropri\u00e9es ou ill\u00e9gales.\n* Assurer un fonctionnement correct et efficace des syst\u00e8mes et des processus, y compris surveiller et am\u00e9liorer la performance des syst\u00e8mes et processus utilis\u00e9s pour des finalit\u00e9s autoris\u00e9es\nLes partenaires ne peuvent pas:\n* Effectuer, au titre de cette finalit\u00e9, toute autre op\u00e9ration de traitement des donn\u00e9es autoris\u00e9e pour une finalit\u00e9 diff\u00e9rente .\nRemarque: Les donn\u00e9es collect\u00e9es et utilis\u00e9es pour assurer la s\u00e9curit\u00e9, pr\u00e9venir la fraude et d\u00e9boguer peuvent inclure des caract\u00e9ristiques d\u2019appareil envoy\u00e9es automatiquement \u00e0 des fins d'identification, des donn\u00e9es de g\u00e9olocalisation pr\u00e9cises et des donn\u00e9es obtenues par l\u2019analyse active des caract\u00e9ristiques de l\u2019appareil \u00e0 des fins d\u2019identification sans notification distincte et/ou opt-in distinct \n"},"2":{"id":2,"name":"Diffuser techniquement les publicit\u00e9s ou le contenu","description":"Votre terminal peut recevoir et envoyer des informations qui vous permettent de voir des publicit\u00e9s et du contenu et d\u2019interagir avec eux.","descriptionLegal":"Pour fournir des informations et r\u00e9pondre aux appels techniques, les partenaires peuvent:\n* Utiliser l\u2019adresse IP d\u2019un utilisateur pour diffuser une publicit\u00e9 sur Internet\n* R\u00e9agir \u00e0 l\u2019interaction d\u2019un utilisateur avec une publicit\u00e9 en dirigeant l\u2019utilisateur vers une page d\u2019accueil\n* Utiliser l\u2019adresse IP d\u2019un utilisateur pour diffuser du contenu sur Internet\n* R\u00e9agir \u00e0 l\u2019interaction d\u2019un utilisateur avec du contenu en dirigeant l\u2019utilisateur vers une page d\u2019accueil\n* Utiliser des informations sur le type de terminal et les capacit\u00e9s du terminal pour pr\u00e9senter des publicit\u00e9s ou du contenu, par exemple, pour pr\u00e9senter une publicit\u00e9 \u00e0 la bonne taille ou une vid\u00e9o dans un format pris en charge par le terminal \nLes partenaires ne peuvent pas:\n* Effectuer, au titre de cette finalit\u00e9, toute autre op\u00e9ration de traitement des donn\u00e9es autoris\u00e9e pour une finalit\u00e9 diff\u00e9rente \n"}},"features":{"1":{"id":1,"name":"Mettre en correspondance et combiner des sources de donn\u00e9es hors ligne","description":"Les donn\u00e9es issues de sources de donn\u00e9es hors ligne peuvent \u00eatre combin\u00e9es \u00e0 votre activit\u00e9 en ligne \u00e0 l\u2019appui d\u2019une ou de plusieurs finalit\u00e9s.","descriptionLegal":"Les partenaires peuvent : \n* Combiner des donn\u00e9es obtenues hors ligne avec des donn\u00e9es collect\u00e9es en ligne \u00e0 l\u2019appui d\u2019une ou de plusieurs Finalit\u00e9s ou Finalit\u00e9s sp\u00e9ciales.\n"},"2":{"id":2,"name":"Relier diff\u00e9rents terminaux","description":"Diff\u00e9rents terminaux peuvent \u00eatre identifi\u00e9s comme vous appartenant ou appartenant \u00e0 votre foyer \u00e0 l\u2019appui d\u2019une ou de plusieurs finalit\u00e9s","descriptionLegal":"Les partnenaires peuvent :\n* D\u00e9terminer, selon une approche d\u00e9terministe, que deux terminaux ou plus appartiennent au m\u00eame utilisateur ou au m\u00eame foyer\n* D\u00e9terminer, selon une approche probabiliste, que deux terminaux ou plus appartiennent au m\u00eame utilisateur ou au m\u00eame foyer\n* Analyser activement les caract\u00e9ristiques du terminal pour l\u2019identification probabiliste si les utilisateurs ont autoris\u00e9 les partenanaires \u00e0 analyser activement les caract\u00e9ristiques du terminal pour l\u2019identification (Fonctionnalit\u00e9 sp\u00e9ciale 2)\n"},"3":{"id":3,"name":"Recevoir et utiliser des caract\u00e9ristiques d\u2019identification d\u2019appareil envoy\u00e9es automatiquement","description":"Votre appareil peut \u00eatre distingu\u00e9 d\u2019autres appareils en fonction des informations qu\u2019il envoie automatiquement, telles que l\u2019adresse IP ou le type de navigateur.","descriptionLegal":"Les partenaires peuvent :\n* Cr\u00e9er un identifiant \u00e0 l\u2019aide des donn\u00e9es collect\u00e9es automatiquement \u00e0 partir d\u2019un appareil pour des caract\u00e9ristiques sp\u00e9cifiques ; par ex., adresse IP, cha\u00eene d\u2019agent utilisateur.\n* Utiliser cet identifiant pour r\u00e9identifier un appareil.\nLes partenaires ne peuvent pas :\n* Cr\u00e9er un identifiant \u00e0 l\u2019aide des donn\u00e9es collect\u00e9es via une analyse active d\u2019un terminal pour l\u2019identification de caract\u00e9ristiques sp\u00e9cifiques (par exemple, des polices install\u00e9es ou la r\u00e9solution d\u2019\u00e9cran) sans une adh\u00e9sion distincte de l\u2019utilisateur \u00e0 l\u2019analyse active des caract\u00e9ristiques de l\u2019appareil \u00e0 des fins d\u2019identification.\n* Utiliser cet identifiant pour r\u00e9-identifier un terminal.\n"}},"specialFeatures":{"1":{"id":1,"name":"Utiliser des donn\u00e9es de g\u00e9olocalisation pr\u00e9cises","description":"Vos donn\u00e9es de g\u00e9olocalisation pr\u00e9cises peuvent \u00eatre utilis\u00e9es \u00e0 l\u2019appui d\u2019une ou de plusieurs finalit\u00e9s. Cela signifie que votre localisation peut \u00eatre pr\u00e9cise \u00e0 plusieurs m\u00e8tres pr\u00e8s.","descriptionLegal":"Les partnenaires peuvent :\n* Collecter et traiter des donn\u00e9es de g\u00e9olocalisation pr\u00e9cises \u00e0 l\u2019appui d\u2019une ou de plusieurs finalit\u00e9s.\nN.B. Une g\u00e9olocalisation pr\u00e9cise signifie qu\u2019il n\u2019y a aucune restriction \u00e0 la pr\u00e9cision de la localisation d\u2019un utilisateur ; elle peut \u00eatre pr\u00e9cise \u00e0 quelques m\u00e8tres pr\u00e8s.\n"},"2":{"id":2,"name":"Analyser activement les caract\u00e9ristiques du terminal pour l\u2019identification","description":"Votre terminal peut \u00eatre identifi\u00e9 sur la base d\u2019une analyse de la combinaison unique de caract\u00e9ristiques de votre terminal.","descriptionLegal":"Les partenaires peuvent :\n* Cr\u00e9er un identifiant \u00e0 l\u2019aide des donn\u00e9es collect\u00e9es via une analyse active d\u2019un terminal pour l\u2019identification de caract\u00e9ristiques sp\u00e9cifiques, par exemple des polices install\u00e9es ou la r\u00e9solution d\u2019\u00e9cran. \n* Utiliser cet identifiant pour r\u00e9-identifier un terminal.\n"}},"stacks":{"1":{"id":1,"purposes":[],"specialFeatures":[1,2],"name":"Donn\u00e9es de g\u00e9olocalisation pr\u00e9cises et identification par analyse du terminal","description":"Des informations de g\u00e9olocalisation pr\u00e9cises et des informations sur les caract\u00e9ristiques de l\u2019appareil peuvent \u00eatre utilis\u00e9es."},"2":{"id":2,"purposes":[2,7],"specialFeatures":[],"name":"Publicit\u00e9s standards et mesure de performance des publicit\u00e9s","description":"Des publicit\u00e9s standards peuvent \u00eatre diffus\u00e9es. La performance des publicit\u00e9s peut \u00eatre mesur\u00e9e."},"3":{"id":3,"purposes":[2,3,4],"specialFeatures":[],"name":"Publicit\u00e9s personnalis\u00e9es","description":"Les publicit\u00e9s peuvent \u00eatre personnalis\u00e9es sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser les publicit\u00e9s."},"4":{"id":4,"purposes":[2,7,9],"specialFeatures":[],"name":"Publicit\u00e9s standards et mesure de performance des publicit\u00e9s","description":"Des publicit\u00e9s standards peuvent \u00eatre diffus\u00e9es. La performance des publicit\u00e9s peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"5":{"id":5,"purposes":[2,3,7],"specialFeatures":[],"name":"Publicit\u00e9s standards, profil de publicit\u00e9s personnalis\u00e9es et mesure de performance des publicit\u00e9s","description":"Des publicit\u00e9s standards peuvent \u00eatre diffus\u00e9es. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser les publicit\u00e9s. La performance des publicit\u00e9s peut \u00eatre mesur\u00e9e."},"6":{"id":6,"purposes":[2,4,7],"specialFeatures":[],"name":"Affichage de publicit\u00e9s personnalis\u00e9es et mesure de performance des publicit\u00e9s","description":"Les publicit\u00e9s peuvent \u00eatre personnalis\u00e9es sur la base d\u2019un profil. La performance des publicit\u00e9s peut \u00eatre mesur\u00e9e."},"7":{"id":7,"purposes":[2,4,7,9],"specialFeatures":[],"name":"Affichage de publicit\u00e9s personnalis\u00e9es, mesure de performance des publicit\u00e9s, et donn\u00e9es d\u2019audience","description":"Les publicit\u00e9s peuvent \u00eatre personnalis\u00e9es sur la base d\u2019un profil. La performance des publicit\u00e9s peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"8":{"id":8,"purposes":[2,3,4,7],"specialFeatures":[],"name":"Publicit\u00e9s personnalis\u00e9es et mesure de performance des annonces","description":"Les publicit\u00e9s peuvent \u00eatre personnalis\u00e9es sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser les publicit\u00e9s. La performance des publicit\u00e9s peut \u00eatre mesur\u00e9e."},"9":{"id":9,"purposes":[2,3,4,7,9],"specialFeatures":[],"name":"Publicit\u00e9s personnalis\u00e9es, mesure de performance des publicit\u00e9s, et donn\u00e9es d\u2019audience","description":"Les publicit\u00e9s peuvent \u00eatre personnalis\u00e9es sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser les publicit\u00e9s. La performance des publicit\u00e9s peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"10":{"id":10,"purposes":[3,4],"specialFeatures":[],"name":"Profil de publicit\u00e9s personnalis\u00e9es et affichage","description":"Les publicit\u00e9s peuvent \u00eatre personnalis\u00e9es sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser les publicit\u00e9s. "},"11":{"id":11,"purposes":[5,6],"specialFeatures":[],"name":"Contenu personnalis\u00e9","description":"Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu."},"12":{"id":12,"purposes":[6,8],"specialFeatures":[],"name":"Affichage de contenu personnalis\u00e9 et mesure de performance du contenu","description":"Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. La performance du contenu peut \u00eatre mesur\u00e9e."},"13":{"id":13,"purposes":[6,8,9],"specialFeatures":[],"name":"Affichage de contenu personnalis\u00e9, mesure de performance du contenu et donn\u00e9es d\u2019audience","description":"Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. La performance du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"14":{"id":14,"purposes":[5,6,8],"specialFeatures":[],"name":"Contenu personnalis\u00e9 et mesure de performance du contenu","description":"Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu. La performance du contenu peut \u00eatre mesur\u00e9e."},"15":{"id":15,"purposes":[5,6,8,9],"specialFeatures":[],"name":"Contenu personnalis\u00e9, mesure de performance du contenu et donn\u00e9es d\u2019audience","description":"Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu. La performance du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"16":{"id":16,"purposes":[5,6,8,9,10],"specialFeatures":[],"name":"Contenu personnalis\u00e9, mesure de performance du contenu, donn\u00e9es d\u2019audience, et d\u00e9veloppement produit","description":"Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu. La performance du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu. Les donn\u00e9es peuvent \u00eatre utilis\u00e9es pour cr\u00e9er ou am\u00e9liorer l\u2019exp\u00e9rience utilisateur, des syst\u00e8mes et logiciels"},"17":{"id":17,"purposes":[7,8,9],"specialFeatures":[],"name":"Mesure de performance des annonces et du contenu et donn\u00e9es d\u2019audience","description":"La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"18":{"id":18,"purposes":[7,8],"specialFeatures":[],"name":"Mesure de performance des publicit\u00e9s et du contenu","description":"La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e."},"19":{"id":19,"purposes":[7,9],"specialFeatures":[],"name":"Mesure de performance des publicit\u00e9s et donn\u00e9es d\u2019audience","description":"La performance des publicit\u00e9s peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu"},"20":{"id":20,"purposes":[7,8,9,10],"specialFeatures":[],"name":"Mesure de performance des publicit\u00e9s et du contenu, donn\u00e9es d\u2019audience, et d\u00e9veloppement produit","description":"La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu. Les donn\u00e9es peuvent \u00eatre utilis\u00e9es pour cr\u00e9er ou am\u00e9liorer l\u2019exp\u00e9rience utilisateur, les syst\u00e8mes et les logiciels. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"21":{"id":21,"purposes":[8,9,10],"specialFeatures":[],"name":"Mesure de performance du contenu, donn\u00e9es d\u2019audience, et d\u00e9veloppement produit.","description":"La performance du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu. Les donn\u00e9es peuvent \u00eatre utilis\u00e9es pour cr\u00e9er ou am\u00e9liorer l\u2019exp\u00e9rience utilisateur, les syst\u00e8mes et les logiciels."},"22":{"id":22,"purposes":[8,10],"specialFeatures":[],"name":"Mesure de performance du contenu, et d\u00e9veloppement produit","description":"La performance du contenu peut \u00eatre mesur\u00e9e. Les donn\u00e9es peuvent \u00eatre utilis\u00e9es pour cr\u00e9er ou am\u00e9liorer l\u2019exp\u00e9rience utilisateur, les syst\u00e8mes et les logiciels."},"23":{"id":23,"purposes":[2,4,6,7,8],"specialFeatures":[],"name":"Affichage de publicit\u00e9s et de contenu personnalis\u00e9s, mesure de performance des publicit\u00e9s et du contenu","description":"Les publicit\u00e9s et le contenu peuvent \u00eatre personnalis\u00e9s sur la base d\u2019un profil. La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e."},"24":{"id":24,"purposes":[2,4,6,7,8,9],"specialFeatures":[],"name":"Affichage de publicit\u00e9s et de contenu personnalis\u00e9s, mesure de performance des publicit\u00e9s et du contenu, et donn\u00e9es d\u2019audience","description":"Les publicit\u00e9s et le contenu peuvent \u00eatre personnalis\u00e9s sur la base d\u2019un profil. La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu. Les donn\u00e9es peuvent \u00eatre utilis\u00e9es pour cr\u00e9er ou am\u00e9liorer l\u2019exp\u00e9rience utilisateur, les syst\u00e8mes et les logiciels."},"25":{"id":25,"purposes":[2,3,4,5,6,7,8],"specialFeatures":[],"name":"Publicit\u00e9s et contenu personnalis\u00e9s, mesure de performance des publicit\u00e9s et du contenu","description":"Les publicit\u00e9s et le contenu peuvent \u00eatre personnalis\u00e9s sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser les publicit\u00e9s et le contenu. La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e."},"26":{"id":26,"purposes":[2,3,4,5,6,7,8,9],"specialFeatures":[],"name":"Publicit\u00e9s et contenu personnalis\u00e9s, mesure de performance des publicit\u00e9s et du contenu, et donn\u00e9es d\u2019audience","description":"Les publicit\u00e9s et le contenu peuvent \u00eatre personnalis\u00e9s sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser les publicit\u00e9s et le contenu. La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"27":{"id":27,"purposes":[3,5],"specialFeatures":[],"name":"Publicit\u00e9s personnalis\u00e9es et profil de contenu","description":"Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour personnaliser les publicit\u00e9s et le contenu. "},"28":{"id":28,"purposes":[2,4,6],"specialFeatures":[],"name":"Affichage de publicit\u00e9s et de contenu personnalis\u00e9s","description":"Les publicit\u00e9s et le contenu peuvent \u00eatre personnalis\u00e9s sur la base d\u2019un profil. "},"29":{"id":29,"purposes":[2,7,8,9],"specialFeatures":[],"name":"Publicit\u00e9s standards, mesure de performance des publicit\u00e9s et du contenu, et donn\u00e9es d\u2019audience","description":"Des publicit\u00e9s standards peuvent \u00eatre diffus\u00e9es. La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"30":{"id":30,"purposes":[2,4,5,6,7,8,9],"specialFeatures":[],"name":"Affichage de publicit\u00e9s personnalis\u00e9es, contenu personnalis\u00e9, mesure de performance des publicit\u00e9s et du contenu, et donn\u00e9es d\u2019audience","description":"Les publicit\u00e9s et le contenu peuvent \u00eatre personnalis\u00e9s sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu. La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"31":{"id":31,"purposes":[2,4,5,6,7,8,9,10],"specialFeatures":[],"name":"Affichage de publicit\u00e9s personnalis\u00e9es, contenu personnalis\u00e9, mesure de performance des publicit\u00e9s et du contenu, donn\u00e9es d\u2019audience et d\u00e9veloppement de produit","description":"Les publicit\u00e9s et le contenu peuvent \u00eatre personnalis\u00e9s sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu. La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu. Les donn\u00e9es peuvent \u00eatre utilis\u00e9es pour cr\u00e9er ou am\u00e9liorer l\u2019exp\u00e9rience utilisateur, les syst\u00e8mes et les logiciels."},"32":{"id":32,"purposes":[2,5,6,7,8,9],"specialFeatures":[],"name":"Publicit\u00e9s standards, contenu personnalis\u00e9, mesure de performance des publicit\u00e9s et du contenu, et donn\u00e9es d\u2019audience","description":"Des publicit\u00e9s standards peuvent \u00eatre diffus\u00e9es. Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu. La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"33":{"id":33,"purposes":[2,5,6,7,8,9,10],"specialFeatures":[],"name":"Publicit\u00e9s standards, contenu personnalis\u00e9, mesure de performance des publicit\u00e9s et du contenu, donn\u00e9es d\u2019audience, et d\u00e9veloppement produit","description":"Des publicit\u00e9s standards peuvent \u00eatre diffus\u00e9es. Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu. La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu. Les donn\u00e9es peuvent \u00eatre utilis\u00e9es pour cr\u00e9er ou am\u00e9liorer l\u2019exp\u00e9rience utilisateur, les syst\u00e8mes et les logiciels."},"34":{"id":34,"purposes":[2,5,6,8,9],"specialFeatures":[],"name":"Publicit\u00e9s standards, contenu personnalis\u00e9, mesure de performance du contenu, et donn\u00e9es d\u2019audience","description":"Des publicit\u00e9s standards peuvent \u00eatre diffus\u00e9es. Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu. La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"35":{"id":35,"purposes":[2,5,6,8,9,10],"specialFeatures":[],"name":"Publicit\u00e9s standards, contenu personnalis\u00e9, mesure de performance du contenu, donn\u00e9es d\u2019audience et d\u00e9veloppement de produit ","description":"Des publicit\u00e9s standards peuvent \u00eatre diffus\u00e9es. Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu. La performance du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu. Les donn\u00e9es peuvent \u00eatre utilis\u00e9es pour cr\u00e9er ou am\u00e9liorer l\u2019exp\u00e9rience utilisateur, les syst\u00e8mes et les logiciels."},"36":{"id":36,"purposes":[2,5,6,7],"specialFeatures":[],"name":"Publicit\u00e9s standard, contenu personnalis\u00e9 et mesure de performance des publicit\u00e9s","description":"Des publicit\u00e9s standards peuvent \u00eatre diffus\u00e9es. Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu. La performance des publicit\u00e9s peut \u00eatre mesur\u00e9e."},"37":{"id":37,"purposes":[2,5,6,7,10],"specialFeatures":[],"name":"Publicit\u00e9s standards, contenu personnalis\u00e9, mesure de performance des publicit\u00e9s, et d\u00e9veloppement produit","description":"Des publicit\u00e9s standards peuvent \u00eatre diffus\u00e9es. Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu. La performance des publicit\u00e9s peut \u00eatre mesur\u00e9e. Les donn\u00e9es peuvent \u00eatre utilis\u00e9es pour cr\u00e9er ou am\u00e9liorer l\u2019exp\u00e9rience utilisateur, les syst\u00e8mes et les logiciels."}}} \ No newline at end of file