示例#1
0
    public void DeserializeNativePmWithBackButtonUiElementPasses()
    {
        Dictionary <string, string> popupBgColors = null;
        string json = @"
{
   ""id"": ""Root"",
   ""type"": ""NativeOtt"",
   ""name"": ""Native OTT"",
   ""children"": [
      {
         ""id"": ""HomeView"",
         ""type"": ""NativeView"",
         ""name"": ""Home View"",
         ""settings"": {
            ""style"": {
               ""backgroundColor"": ""#e5e8ef""
            }
         },
         ""children"": [
            {
               ""id"": ""BackButton"",
               ""type"": ""NativeButton"",
               ""name"": ""Back button"",
               ""settings"": {
                  ""text"": ""Back"",
                  ""startFocus"": false,
                  ""style"": {
                     ""backgroundColor"": ""#ffffff"",
                     ""font"": {
                        ""fontSize"": 16,
                        ""fontWeight"": ""400"",
                        ""color"": ""#000000"",
                        ""fontFamily"": ""arial, helvetica, sans-serif""
                     }
                  }               
               }
            }
        ]
      }
    ]
}";
        Dictionary <string, List <CmpUiElementModel> > elements = NativeUiJsonDeserializer.DeserializeNativePm(json, ref popupBgColors);

        Assert.IsNotEmpty(elements);
        Assert.AreEqual(elements.Count, 1);
        Assert.AreEqual(elements["HomeView"].Count, 1);
        var el = elements["HomeView"][0] as CmpBackButtonModel;

        Assert.IsNotNull(el);
        Assert.AreEqual(el.id, "BackButton");
        Assert.AreEqual(el.type, "NativeButton");
        Assert.AreEqual(el.name, "Back button");
        Assert.AreEqual(el.Text, "Back");
        Assert.AreEqual(el.StartFocus !, false);
        Assert.AreEqual(el.BackgroundColor, "#ffffff");
        Assert.AreEqual(el.Font.Color, "#000000");
        Assert.AreEqual(el.Font.fontWeight, "400");
        Assert.AreEqual(el.Font.fontFamily, "arial, helvetica, sans-serif");
        Assert.AreEqual(el.Font.fontSize, 16);
    }
示例#2
0
    public void DeserializeShortCategoriesWithNullCollectionPasses()
    {
        List <CmpShortCategoryModel> shortCategories = null;

        NativeUiJsonDeserializer.DeserializeShortCategories(ONE_SHORT_CATEGORY_COLLECTION_JSON, ref shortCategories);
        Assert.NotNull(shortCategories);
    }
示例#3
0
    private static void OnPrivacyManagerViewsSuccessCallback(string json)
    {
        switch (CmpCampaignPopupQueue.CurrentCampaignToShow())
        {
        case 0:
            NativeUiJsonDeserializer.DeserializeExtraCall(json: json,
                                                          categoryModels: ref gdprCategories,
                                                          specialPurposeModels: ref gdprSpecialPurposes,
                                                          featureModels: ref gdprFeatures,
                                                          specialFeatureModels: ref gdprSpecialFeatures,
                                                          vendorModels: ref gdprVendors);
            isGdprPmInitialized = true;
            break;

        case 2:
            NativeUiJsonDeserializer.DeserializeExtraCall(json: json,
                                                          categoryModels: ref ccpaCategories,
                                                          specialPurposeModels: ref ccpaSpecialPurposes,
                                                          featureModels: ref ccpaFeatures,
                                                          specialFeatureModels: ref ccpaSpecialFeatures,
                                                          vendorModels: ref ccpaVendors);
            isCcpaPmInitialized = true;
            break;
        }
        SaveContext.UpdateUserConsentUIState();
    }
示例#4
0
    private static void OnMessageSuccessCallback(string json)
    {
        var message = NativeUiJsonDeserializer.DeserializeMessageGdprGetResponse(json);

        if (message.message?.categories != null && message.message?.categories.Count > 0)
        {
            shortCategories?.Clear();
            shortCategories = message.message?.categories;
        }
        if (message.ui != null && message.ui.Count > 0)
        {
            switch (CmpCampaignPopupQueue.CurrentCampaignToShow())
            {
            case 0:
                gdprElements?.Clear();
                gdprElements = message.ui;
                break;

            case 2:
                ccpaElements?.Clear();
                ccpaElements = message.ui;
                break;
            }
        }
        if (message.popupBgColors != null && message.popupBgColors.Count > 0)
        {
            popupBgColors?.Clear();
            popupBgColors = message.popupBgColors;
        }
        SaveContext.UpdateUserConsentUIState();
        isInitialized         = true;
        IsPmReadyForResurface = true;
    }
示例#5
0
    public void DeserializeShortCategoriesPassesWithEmptyCollection()
    {
        List <CmpShortCategoryModel> shortCategories = null;

        NativeUiJsonDeserializer.DeserializeShortCategories(ONE_ODD_SHORT_CATEGORY_COLLECTION_JSON_2, ref shortCategories);
        Assert.NotNull(shortCategories);
        Assert.AreEqual(shortCategories.Count, 0);
    }
示例#6
0
    public void DeserializeShortCategoriesFailsWithInvalidOperationException()
    {
        List <CmpShortCategoryModel> shortCategories = null;

        Assert.Throws <InvalidOperationException>(
            delegate
        {
            NativeUiJsonDeserializer.DeserializeShortCategories(ONE_ODD_SHORT_CATEGORY_COLLECTION_JSON_3, ref shortCategories);
        });
    }
示例#7
0
    public void DeserializeShortCategoriesPassesWithNullElements()
    {
        List <CmpShortCategoryModel> shortCategories = null;

        NativeUiJsonDeserializer.DeserializeShortCategories(ONE_ODD_SHORT_CATEGORY_COLLECTION_JSON, ref shortCategories);
        Assert.NotNull(shortCategories);
        Assert.AreEqual(shortCategories.Count, 1);
        Assert.IsNull(shortCategories[0]._id);
        Assert.IsNull(shortCategories[0].type);
        Assert.IsNull(shortCategories[0].name);
        Assert.IsNull(shortCategories[0].description);
    }
示例#8
0
    public void DeserializeNativePmNoChildrenPropertyFails()
    {
        Dictionary <string, string> popupBgColors = null;
        string json = @"{
           ""id"": ""Root"",
           ""type"": ""NativeOtt"",
           ""name"": ""Native OTT""
        }";

        Assert.Catch <KeyNotFoundException>(delegate
        {
            Dictionary <string, List <CmpUiElementModel> > elements = NativeUiJsonDeserializer.DeserializeNativePm(json, ref popupBgColors);
        });
    }
示例#9
0
    public void DeserializeNativePmWithNullChildrenFails()
    {
        Dictionary <string, string> popupBgColors = null;
        string json = @"{
           ""id"": ""Root"",
           ""type"": ""NativeOtt"",
           ""name"": ""Native OTT"",
           ""children"": null
        }";

        Assert.Catch <InvalidOperationException>(delegate
        {
            Dictionary <string, List <CmpUiElementModel> > elements = NativeUiJsonDeserializer.DeserializeNativePm(json, ref popupBgColors);
        });
    }
示例#10
0
    public void DeserializeNativePmWithNativeImageUiElementPasses()
    {
        Dictionary <string, string> popupBgColors = null;
        string json = @"
{
   ""id"": ""Root"",
   ""type"": ""NativeOtt"",
   ""name"": ""Native OTT"",
   ""children"": [
      {
         ""id"": ""HomeView"",
         ""type"": ""NativeView"",
         ""name"": ""Home View"",
         ""settings"": {
            ""style"": {
               ""backgroundColor"": ""#e5e8ef""
            }
         },
         ""children"": [
            {
               ""id"": ""LogoImage"",
               ""type"": ""NativeImage"",
               ""name"": ""Logo"",
               ""settings"": {
                  ""src"": ""https://i.pinimg.com/originals/5a/ae/50/5aae503e4f037a5a4375944d8861fb6a.png"",
                  ""style"": {
                     ""width"": 170
                  }
               }
            }
        ]
      }
    ]
}";
        Dictionary <string, List <CmpUiElementModel> > elements = NativeUiJsonDeserializer.DeserializeNativePm(json, ref popupBgColors);

        Assert.IsNotEmpty(elements);
        Assert.AreEqual(elements.Count, 1);
        Assert.AreEqual(elements["HomeView"].Count, 1);
        var el = elements["HomeView"][0] as CmpNativeImageModel;

        Assert.IsNotNull(el);
        Assert.AreEqual(el.id, "LogoImage");
        Assert.AreEqual(el.type, "NativeImage");
        Assert.AreEqual(el.name, "Logo");
        Assert.AreEqual(el.LogoImageLink, "https://i.pinimg.com/originals/5a/ae/50/5aae503e4f037a5a4375944d8861fb6a.png");
    }
示例#11
0
    public void DeserializeNativePmWithNullUiElementPasses()
    {
        Dictionary <string, string> popupBgColors = null;
        string json = @"
{
   ""id"": ""Root"",
   ""type"": ""NativeOtt"",
   ""name"": ""Native OTT"",
   ""children"": [
      {
         ""id"": ""HomeView"",
         ""type"": ""NativeView"",
         ""name"": ""Home View"",
         ""settings"": {
            ""style"": {
               ""backgroundColor"": ""#e5e8ef""
            }
         },
         ""children"": [
            null,
            {
               ""id"": ""Header"",
               ""type"": ""NativeText"",
               ""name"": ""Header"",
               ""settings"": {
                  ""text"": ""Privacy"",
                  ""style"": {
                     ""font"": {
                        ""fontSize"": 28,
                        ""fontWeight"": ""400"",
                        ""color"": ""#000000"",
                        ""fontFamily"": ""arial, helvetica, sans-serif""
                     }
                  }
               }
            }
        ]
      }
    ]
}";
        Dictionary <string, List <CmpUiElementModel> > elements = NativeUiJsonDeserializer.DeserializeNativePm(json, ref popupBgColors);

        Assert.IsNotEmpty(elements);
        Assert.AreEqual(elements.Count, 1);
        Assert.AreEqual(elements["HomeView"].Count, 1);
        Assert.IsNotNull(elements["HomeView"][0]);
    }
示例#12
0
    public void DeserializeNativePmWithNoViewIdPasses()
    {
        Dictionary <string, string> popupBgColors = null;
        string json = @"
{
   ""id"": ""Root"",
   ""type"": ""NativeOtt"",
   ""name"": ""Native OTT"",
   ""children"": [
      {
         ""id"": null,
         ""type"": ""NativeView"",
         ""name"": ""Home View"",
         ""settings"": {
            ""style"": {
               ""backgroundColor"": ""#e5e8ef""
            }
         },
         ""children"": [
            {
               ""id"": ""Header"",
               ""type"": ""NativeText"",
               ""name"": ""Header"",
               ""settings"": {
                  ""text"": ""Privacy"",
                  ""style"": {
                     ""font"": {
                        ""fontSize"": 28,
                        ""fontWeight"": ""400"",
                        ""color"": ""#000000"",
                        ""fontFamily"": ""arial, helvetica, sans-serif""
                     }
                  }
               }
            }
        ]
      }
    ]
}";

        LogAssert.Expect(LogType.Error, ">>>DAFUQ >:C");
        Dictionary <string, List <CmpUiElementModel> > elements = NativeUiJsonDeserializer.DeserializeNativePm(json, ref popupBgColors);

        Assert.IsEmpty(elements);
        Assert.IsEmpty(popupBgColors);
    }
示例#13
0
    public void DeserializeShortCategoriesWithNotNullCollectionPasses()
    {
        List <CmpShortCategoryModel> shortCategories = new List <CmpShortCategoryModel> {
            new CmpShortCategoryModel()
        };

        NativeUiJsonDeserializer.DeserializeShortCategories(ONE_SHORT_CATEGORY_COLLECTION_JSON, ref shortCategories);
        Assert.NotNull(shortCategories);
        Assert.AreEqual(shortCategories.Count, 2);
        var sublist      = shortCategories.GetRange(1, 1);
        var sublistJson  = JsonSerializer.Serialize(sublist);
        var deserialized = JsonSerializer.Deserialize <List <CmpShortCategoryModel> >(sublistJson);

        Assert.AreEqual(deserialized[0]._id, sublist[0]._id);
        Assert.AreEqual(deserialized[0].name, sublist[0].name);
        Assert.AreEqual(deserialized[0].type, sublist[0].type);
        Assert.AreEqual(deserialized[0].description, sublist[0].description);
    }
示例#14
0
    public void DeserializeNativePmWithSliderUiElementPasses()
    {
        Dictionary <string, string> popupBgColors = null;
        string json = @"
{
   ""id"": ""Root"",
   ""type"": ""NativeOtt"",
   ""name"": ""Native OTT"",
   ""children"": [
      {
         ""id"": ""HomeView"",
         ""type"": ""NativeView"",
         ""name"": ""Home View"",
         ""settings"": {
            ""style"": {
               ""backgroundColor"": ""#e5e8ef""
            }
         },
         ""children"": [
            {
               ""id"": ""CategoriesSlider"",
               ""type"": ""Slider"",
               ""name"": ""Categories Slider"",
               ""settings"": {
                  ""leftText"": ""CONSENT"",
                  ""rightText"": ""LEGITIMATE INTEREST"",
                  ""style"": {
                     ""backgroundColor"": ""#d8d9dd"",
                     ""activeBackgroundColor"": ""#777a7e"",
                     ""font"": {
                        ""fontSize"": 14,
                        ""fontWeight"": ""400"",
                        ""color"": ""#000000"",
                        ""fontFamily"": ""arial, helvetica, sans-serif""
                     },
                     ""activeFont"": {
                        ""fontSize"": 14,
                        ""fontWeight"": ""400"",
                        ""color"": ""#ffffff"",
                        ""fontFamily"": ""arial, helvetica, sans-serif""
                     }
                  }
               }
            }
        ]
      }
    ]
}";
        Dictionary <string, List <CmpUiElementModel> > elements = NativeUiJsonDeserializer.DeserializeNativePm(json, ref popupBgColors);

        Assert.IsNotEmpty(elements);
        Assert.AreEqual(elements.Count, 1);
        Assert.AreEqual(elements["HomeView"].Count, 1);
        var el = elements["HomeView"][0] as CmpSliderModel;

        Assert.IsNotNull(el);
        Assert.AreEqual(el.id, "CategoriesSlider");
        Assert.AreEqual(el.type, "Slider");
        Assert.AreEqual(el.name, "Categories Slider");
        Assert.AreEqual(el.LeftText, "CONSENT");
        Assert.AreEqual(el.RightText, "LEGITIMATE INTEREST");
        Assert.AreEqual(el.BackgroundColor, "#d8d9dd");
        Assert.AreEqual(el.ActiveBackgroundColor, "#777a7e");
        Assert.AreEqual(el.DefaultFont.Color, "#000000");
        Assert.AreEqual(el.DefaultFont.fontWeight, "400");
        Assert.AreEqual(el.DefaultFont.fontFamily, "arial, helvetica, sans-serif");
        Assert.AreEqual(el.DefaultFont.fontSize, 14);
        Assert.AreEqual(el.ActiveFont.Color, "#ffffff");
        Assert.AreEqual(el.ActiveFont.fontWeight, "400");
        Assert.AreEqual(el.ActiveFont.fontFamily, "arial, helvetica, sans-serif");
        Assert.AreEqual(el.ActiveFont.fontSize, 14);
    }
示例#15
0
    public void DeserializeNativePmWithLongButtonUiElementPasses()
    {
        Dictionary <string, string> popupBgColors = null;
        string json = @"
{
   ""id"": ""Root"",
   ""type"": ""NativeOtt"",
   ""name"": ""Native OTT"",
   ""children"": [
      {
         ""id"": ""HomeView"",
         ""type"": ""NativeView"",
         ""name"": ""Home View"",
         ""settings"": {
            ""style"": {
               ""backgroundColor"": ""#e5e8ef""
            }
         },
         ""children"": [
            {
               ""id"": ""VendorButton"",
               ""type"": ""LongButton"",
               ""name"": ""Vendors Buttons"",
               ""settings"": {
                  ""onText"": ""On"",
                  ""offText"": ""Off"",
                  ""customText"": ""Custom"",
                  ""style"": {
                     ""font"": {
                        ""fontSize"": 14,
                        ""fontWeight"": ""400"",
                        ""fontFamily"": ""arial, helvetica, sans-serif"",
                        ""color"": ""#060606""
                     },
                     ""onFocusBackgroundColor"": ""#ffffff"",
                     ""onUnfocusBackgroundColor"": ""#f1f2f6""
                  }
               }
            }
        ]
      }
    ]
}";
        Dictionary <string, List <CmpUiElementModel> > elements = NativeUiJsonDeserializer.DeserializeNativePm(json, ref popupBgColors);

        Assert.IsNotEmpty(elements);
        Assert.AreEqual(elements.Count, 1);
        Assert.AreEqual(elements["HomeView"].Count, 1);
        var el = elements["HomeView"][0] as CmpLongButtonModel;

        Assert.IsNotNull(el);
        Assert.AreEqual(el.id, "VendorButton");
        Assert.AreEqual(el.type, "LongButton");
        Assert.AreEqual(el.name, "Vendors Buttons");
        Assert.AreEqual(el.OnText, "On");
        Assert.AreEqual(el.OffText, "Off");
        Assert.AreEqual(el.CustomText, "Custom");
        Assert.AreEqual(el.OnFocusColorCode, "#ffffff");
        Assert.AreEqual(el.OnUnfocusColorCode, "#f1f2f6");
        Assert.AreEqual(el.Font.Color, "#060606");
        Assert.AreEqual(el.Font.fontWeight, "400");
        Assert.AreEqual(el.Font.fontFamily, "arial, helvetica, sans-serif");
        Assert.AreEqual(el.Font.fontSize, 14);
    }
示例#16
0
    private static void OnGetMessagesSuccessCallback(string json)
    {
        GetMessageResponse messages = NativeUiJsonDeserializer.DeserializeGetMessages(json);

        SaveContext.SaveCampaigns(messages.campaigns);
        SaveContext.SaveLocalState(messages.localState);
        SaveContext.SavePropertyId(messages.propertyId);
        var gdprCamp = messages.GetGdprCampaign();
        var ccpaCamp = messages.GetCcpaCampaign();

        if (gdprCamp != null)
        {
            if (gdprCamp?.message == null || gdprCamp.ui == null || gdprCamp.ui.Count == 0)
            {
                if (gdprCamp.userConsent == null)
                {
                    UnityEngine.Debug.LogError("UserConsent is NULL");
                }
                else
                {
                    gdprUserConsent = new PostConsentUserConsent()
                    {
                        TCData = gdprCamp.userConsent.TCData,
                        grants = gdprCamp.userConsent.grants,
                        // specialFeatures = gdprCamp.userConsent.,
                        // legIntCategories = gdprCamp.userConsent.,
                        // acceptedVendors = gdprCamp.userConsent.,
                        // acceptedCategories = gdprCamp.userConsent.,
                        euconsent      = gdprCamp.userConsent.euconsent,
                        addtlConsent   = gdprCamp.userConsent.addtlConsent,
                        dateCreated    = gdprCamp.userConsent.dateCreated,
                        consentedToAll = gdprCamp.userConsent.consentedToAll.GetValueOrDefault(false)
                    };
                    SaveContext.SaveGdprUserConsent(gdprUserConsent);
                    CmpCampaignPopupQueue.DequeueCampaignId();
                    isGdprConsented = true;
                }
            }
            else
            {
                GdprMessage gdpr = gdprCamp?.message;
                shortCategories = gdpr?.categories;
                popupBgColors   = gdprCamp?.popupBgColors;
                gdprElements    = gdprCamp?.ui;
            }
        }
        if (ccpaCamp != null)
        {
            if (ccpaCamp.userConsent != null && (!ccpaCamp.userConsent.newUser || ccpaCamp.userConsent.rejectedAll || ccpaCamp.userConsent.status.Equals("consentedAll")))
            {
                ccpaUserConsent = new PostConsentUserConsent()
                {
                    uspstring          = ccpaCamp.userConsent.uspstring,
                    status             = ccpaCamp.userConsent.status,
                    rejectedVendors    = ccpaCamp.userConsent.rejectedVendors.ToArray(),
                    rejectedCategories = ccpaCamp.userConsent.rejectedCategories.ToArray(),
                    signedLspa         = ccpaCamp.userConsent.signedLspa,
                    rejectedAll        = ccpaCamp.userConsent.rejectedAll,
                };
                SaveContext.SaveCcpaUserConsent(ccpaUserConsent);
                CmpCampaignPopupQueue.DequeueCampaignId();
                isCcpaConsented = true;
            }
            else if (ccpaCamp?.message != null || ccpaCamp.ui != null || ccpaCamp.ui.Count != 0)
            {
                BaseMessage ccpa = ccpaCamp?.message;
                popupBgColors = ccpaCamp.popupBgColors;
                ccpaElements  = ccpaCamp.ui;
                // shortCategories ??
            }
            else if (ccpaCamp.userConsent == null)
            {
                UnityEngine.Debug.LogError("UserConsent is NULL");
            }
        }
        isInitialized = true;
        if (!CmpCampaignPopupQueue.IsCampaignAvailable)
        {
            CmpPopupDestroyer.DestroyAllHelperGO();
        }
    }
示例#17
0
    public void DeserializeExtraCallPasses()
    {
        List <CmpCategoryModel>       categoryModels       = null;
        List <CmpSpecialPurposeModel> specialPurposeModels = null;
        List <CmpFeatureModel>        featureModels        = null;
        List <CmpSpecialFeatureModel> specialFeatureModels = null;
        List <CmpVendorModel>         vendorModels         = null;
        string json = @"
{
   ""categories"":[
      {
         ""_id"":""sahdfbasdfhasouf"",
         ""type"":""IAB_PURPOSE"",
         ""name"":""Store and/or access information on a device"",
         ""iabId"":1,
         ""description"":""Vendors can:\n* Store and access information on the device such as cookies and device identifiers presented to a user."",
         ""friendlyDescription"":""Cookies, device identifiers, or other information can be stored or accessed on your device for the purposes presented to you."",
         ""disclosureOnly"":false,
         ""requiringConsentVendors"":[
            {
               ""vendorId"":""sahdfbasdfhasouf"",
               ""vendorType"":""IAB"",
               ""name"":""LoopMe Limited"",
               ""policyUrl"":""https://loopme.com/privacy-policy/""
            }
         ],
         ""legIntVendors"":[
            {
               ""vendorId"":""sahdfbasdfhasouf"",
               ""vendorType"":""CUSTOM"",
               ""name"":""Google Charts"",
               ""policyUrl"":""https://developers.google.com/chart/interactive/docs/security_privacy"",
               ""cookies"":[ ]
            }
         ],
         ""disclosureOnlyVendors"":[ ],
         ""doNotAllowVendors"":{ }
      }
   ],
   ""specialPurposes"":[
      {
         ""_id"":""sahdfbasdfhasouf"",
         ""iabId"":1,
         ""type"":""IAB"",
         ""name"":""Ensure security, prevent fraud, and debug"",
         ""description"":""To ensure security, prevent fraud and debug vendors can:\n* Ensure data are securely transmitted\n* Detect and prevent malicious, fraudulent, invalid, or illegal activity.\n* Ensure correct and efficient operation of systems and processes, including to monitor and enhance the performance of systems and processes engaged in permitted purposes\nVendors cannot:\n* Conduct any other data processing operation allowed under a different purpose under this purpose.\nNote: Data collected and used to ensure security, prevent fraud, and debug may include automatically-sent device characteristics for identification, precise geolocation data, and data obtained by actively scanning device characteristics for identification without separate disclosure and/or opt-in."",
         ""vendors"":[
            {
               ""name"":""LoopMe Limited"",
               ""policyUrl"":""https://loopme.com/privacy-policy/""
            }
         ]
      }
   ],
   ""features"":[
      {
         ""_id"":""sahdfbasdfhasouf"",
         ""iabId"":1,
         ""name"":""Match and combine offline data sources"",
         ""description"":""Vendors can:\n* Combine data obtained offline with data collected online in support of one or more Purposes or Special Purposes."",
         ""vendors"":[
            {
               ""name"":""LoopMe Limited"",
               ""policyUrl"":""https://loopme.com/privacy-policy/""
            }
         ]
      }
   ],
   ""specialFeatures"":[
      {
         ""_id"":""sahdfbasdfhasouf"",
         ""iabId"":1,
         ""name"":""Use precise geolocation data"",
         ""description"":""Vendors can:\n* Collect and process precise geolocation data in support of one or more purposes.\nN.B. Precise geolocation means that there are no restrictions on the precision of a user’s location; this can be accurate to within several meters."",
         ""vendors"":[
            {
               ""name"":""LoopMe Limited"",
               ""vendorId"":""sahdfbasdfhasouf"",
               ""policyUrl"":""https://loopme.com/privacy-policy/""
            }
         ]
      }
   ],
   ""vendors"":[
      {
         ""vendorId"":""sahdfbasdfhasouf"",
         ""iabId"":109,
         ""vendorType"":""IAB"",
         ""name"":""LoopMe Limited"",
         ""policyUrl"":""https://loopme.com/privacy-policy/"",
         ""legIntCategories"":[
            {
               ""type"":""IAB_PURPOSE"",
               ""iabId"":10,
               ""name"":""Develop and improve products""
            }
         ],
         ""consentCategories"":[
            {
               ""type"":""IAB_PURPOSE"",
               ""iabId"":1,
               ""name"":""Store and/or access information on a device""
            }
         ],
         ""disclosureOnlyCategories"":[ ],
         ""iabSpecialPurposes"":[
            ""Ensure security, prevent fraud, and debug"",
            ""Technically deliver ads or content""
         ],
         ""iabFeatures"":[
            ""Match and combine offline data sources"",
            ""Link different devices""
         ],
         ""iabSpecialFeatures"":[
            ""Use precise geolocation data""
         ],
         ""cookieHeader"":""LoopMe Limited stores cookies with a maximum duration of about 365 Day(s) (31536000 Second(s)). This vendor also uses other methods like \""local storage\"" to store and access information on your device.""
      }
   ]
}
";

        NativeUiJsonDeserializer.DeserializeExtraCall(json,
                                                      ref categoryModels,
                                                      ref specialPurposeModels,
                                                      ref featureModels,
                                                      ref specialFeatureModels,
                                                      ref vendorModels);
        Assert.NotNull(categoryModels);
        Assert.NotNull(specialPurposeModels);
        Assert.NotNull(featureModels);
        Assert.NotNull(specialFeatureModels);
        Assert.NotNull(vendorModels);
        Assert.AreEqual(categoryModels.Count, 1);
        Assert.AreEqual(specialPurposeModels.Count, 1);
        Assert.AreEqual(featureModels.Count, 1);
        Assert.AreEqual(specialFeatureModels.Count, 1);
        Assert.AreEqual(vendorModels.Count, 1);
        var cat = categoryModels[0];

        Assert.AreEqual(cat._id, "sahdfbasdfhasouf");
        Assert.AreEqual(cat.type, "IAB_PURPOSE");
        Assert.AreEqual(cat.name, "Store and/or access information on a device");
        Assert.AreEqual(cat.iabId, 1);
        Assert.AreEqual(cat.description, "Vendors can:\n* Store and access information on the device such as cookies and device identifiers presented to a user.");
        Assert.AreEqual(cat.friendlyDescription, "Cookies, device identifiers, or other information can be stored or accessed on your device for the purposes presented to you.");
        Assert.AreEqual(cat.disclosureOnly, false);
        Assert.AreEqual(cat.requiringConsentVendors.Count, 1);
        Assert.AreEqual(cat.requiringConsentVendors[0].vendorId, "sahdfbasdfhasouf");
        Assert.AreEqual(cat.requiringConsentVendors[0].vendorType, "IAB");
        Assert.AreEqual(cat.requiringConsentVendors[0].name, "LoopMe Limited");
        Assert.AreEqual(cat.requiringConsentVendors[0].policyUrl, "https://loopme.com/privacy-policy/");
        Assert.AreEqual(cat.legIntVendors.Count, 1);
        Assert.AreEqual(cat.legIntVendors[0].vendorId, "sahdfbasdfhasouf");
        Assert.AreEqual(cat.legIntVendors[0].vendorType, "CUSTOM");
        Assert.AreEqual(cat.legIntVendors[0].name, "Google Charts");
        Assert.AreEqual(cat.legIntVendors[0].policyUrl, "https://developers.google.com/chart/interactive/docs/security_privacy");
        var specPurp = specialPurposeModels[0];

        Assert.AreEqual(specPurp._id, "sahdfbasdfhasouf");
        Assert.AreEqual(specPurp.iabId, 1);
        Assert.AreEqual(specPurp.type, "IAB");
        Assert.AreEqual(specPurp.name, "Ensure security, prevent fraud, and debug");
        Assert.AreEqual(specPurp.description, "To ensure security, prevent fraud and debug vendors can:\n* Ensure data are securely transmitted\n* Detect and prevent malicious, fraudulent, invalid, or illegal activity.\n* Ensure correct and efficient operation of systems and processes, including to monitor and enhance the performance of systems and processes engaged in permitted purposes\nVendors cannot:\n* Conduct any other data processing operation allowed under a different purpose under this purpose.\nNote: Data collected and used to ensure security, prevent fraud, and debug may include automatically-sent device characteristics for identification, precise geolocation data, and data obtained by actively scanning device characteristics for identification without separate disclosure and/or opt-in.");
        Assert.AreEqual(specPurp.vendors.Count, 1);
        Assert.AreEqual(specPurp.vendors[0].name, "LoopMe Limited");
        Assert.AreEqual(specPurp.vendors[0].policyUrl, "https://loopme.com/privacy-policy/");
        var feat = featureModels[0];

        Assert.AreEqual(feat._id, "sahdfbasdfhasouf");
        Assert.AreEqual(feat.iabId, 1);
        Assert.AreEqual(feat.name, "Match and combine offline data sources");
        Assert.AreEqual(feat.description, "Vendors can:\n* Combine data obtained offline with data collected online in support of one or more Purposes or Special Purposes.");
        Assert.AreEqual(feat.vendors.Count, 1);
        Assert.AreEqual(feat.vendors[0].name, "LoopMe Limited");
        Assert.AreEqual(feat.vendors[0].policyUrl, "https://loopme.com/privacy-policy/");
        var specFeat = specialFeatureModels[0];

        Assert.AreEqual(specFeat._id, "sahdfbasdfhasouf");
        Assert.AreEqual(specFeat.iabId, 1);
        Assert.AreEqual(specFeat.name, "Use precise geolocation data");
        Assert.AreEqual(specFeat.description, "Vendors can:\n* Collect and process precise geolocation data in support of one or more purposes.\nN.B. Precise geolocation means that there are no restrictions on the precision of a user’s location; this can be accurate to within several meters.");
        Assert.AreEqual(specFeat.vendors.Count, 1);
        Assert.AreEqual(specFeat.vendors[0].name, "LoopMe Limited");
        Assert.AreEqual(specFeat.vendors[0].vendorId, "sahdfbasdfhasouf");
        Assert.AreEqual(specFeat.vendors[0].policyUrl, "https://loopme.com/privacy-policy/");
        var vendr = vendorModels[0];

        Assert.AreEqual(vendr.vendorId, "sahdfbasdfhasouf");
        Assert.AreEqual(vendr.iabId, 109);
        Assert.AreEqual(vendr.vendorType, "IAB");
        Assert.AreEqual(vendr.name, "LoopMe Limited");
        Assert.AreEqual(vendr.policyUrl, "https://loopme.com/privacy-policy/");
        Assert.AreEqual(vendr.legIntCategories.Count, 1);
        Assert.AreEqual(vendr.legIntCategories[0].type, "IAB_PURPOSE");
        Assert.AreEqual(vendr.legIntCategories[0].iabId, 10);
        Assert.AreEqual(vendr.legIntCategories[0].name, "Develop and improve products");
        Assert.AreEqual(vendr.consentCategories[0].type, "IAB_PURPOSE");
        Assert.AreEqual(vendr.consentCategories[0].iabId, 1);
        Assert.AreEqual(vendr.consentCategories[0].name, "Store and/or access information on a device");
        Assert.AreEqual(vendr.iabSpecialPurposes[0], "Ensure security, prevent fraud, and debug");
        Assert.AreEqual(vendr.iabSpecialPurposes[1], "Technically deliver ads or content");
        Assert.AreEqual(vendr.iabSpecialPurposes.Count, 2);
        Assert.AreEqual(vendr.iabFeatures[0], "Match and combine offline data sources");
        Assert.AreEqual(vendr.iabFeatures[1], "Link different devices");
        Assert.AreEqual(vendr.iabFeatures.Count, 2);
        Assert.AreEqual(vendr.iabSpecialFeatures.Count, 1);
        Assert.AreEqual(vendr.iabSpecialFeatures[0], "Use precise geolocation data");
        Assert.AreEqual(vendr.cookieHeader, "LoopMe Limited stores cookies with a maximum duration of about 365 Day(s) (31536000 Second(s)). This vendor also uses other methods like \"local storage\" to store and access information on your device.");
    }