/// <summary>
        /// Uses obsolete category Hardware > Flooring (5264193646140135688). This is expected to
        /// fail with the error {@code CriterionError.INVALID_PRODUCT_BIDDING_CATEGORY}.
        /// </summary>
        private void UseObsoleteCategory()
        {
            tree.Root.RemoveAllChildren();
            ProductPartitionNode hardwareLevel1 = tree.Root.AsSubdivision()
                                                  .AddChild(ProductDimensions.CreateBiddingCategory(
                                                                ProductDimensionType.BIDDING_CATEGORY_L1, 1689639310991627077L))
                                                  .AsSubdivision();

            hardwareLevel1
            .AddChild(ProductDimensions.CreateBiddingCategory(
                          ProductDimensionType.BIDDING_CATEGORY_L2, 5264193646140135688L)).CpcBid =
                1000000L;
            hardwareLevel1
            .AddChild(
                ProductDimensions.CreateBiddingCategory(
                    ProductDimensionType.BIDDING_CATEGORY_L2)).AsExcludedUnit();
            tree.Root.AddChild(
                ProductDimensions.CreateBiddingCategory(
                    ProductDimensionType.BIDDING_CATEGORY_L1))
            .AsExcludedUnit();
            try
            {
                tree = ExecuteTreeOperations();
                Assert.Fail("Did not throw CriterionError.INVALID_PRODUCT_BIDDING_CATEGORY");
            }
            catch (AdWordsApiException e)
            {
                ApiError[] errors = (e.ApiException as ApiException).errors;
                Assert.That(errors != null && errors.Length == 1);
                Assert.That(errors[0] is CriterionError);
                Assert.That((errors[0] as CriterionError).reason ==
                            CriterionErrorReason.INVALID_PRODUCT_BIDDING_CATEGORY);
            }
        }
    public void TestCreateBiddingCategory() {
      ProductBiddingCategory categoryA = new ProductBiddingCategory() {
        type = ProductDimensionType.BIDDING_CATEGORY_L1,
        value = 2L
      };

      ProductBiddingCategory categoryB = ProductDimensions.CreateBiddingCategory(
          ProductDimensionType.BIDDING_CATEGORY_L1, 2L);

      Assert.True(comparer.Equals(categoryA, categoryB));

      ProductBiddingCategory categoryC = new ProductBiddingCategory() {
        type = ProductDimensionType.BIDDING_CATEGORY_L1,
      };

      ProductBiddingCategory categoryD = ProductDimensions.CreateBiddingCategory(
          ProductDimensionType.BIDDING_CATEGORY_L1);

      Assert.True(comparer.Equals(categoryC, categoryD));
    }
        /// <summary>
        /// Runs the code example.
        /// </summary>
        /// <param name="user">The AdWords user.</param>
        /// <param name="adGroupId">The ad group to which product partition is
        /// added.</param>
        public void Run(AdWordsUser user, long adGroupId)
        {
            using (AdGroupCriterionService adGroupCriterionService =
                       (AdGroupCriterionService)user.GetService(
                           AdWordsService.v201802.AdGroupCriterionService)) {
                // Build a new ProductPartitionTree using the ad group's current set of criteria.
                ProductPartitionTree partitionTree =
                    ProductPartitionTree.DownloadAdGroupTree(user, adGroupId);

                Console.WriteLine("Original tree: {0}", partitionTree);

                // Clear out any existing criteria.
                ProductPartitionNode rootNode = partitionTree.Root.RemoveAllChildren();

                // Make the root node a subdivision.
                rootNode = rootNode.AsSubdivision();

                // Add a unit node for condition = NEW.
                ProductPartitionNode newConditionNode = rootNode.AddChild(
                    ProductDimensions.CreateCanonicalCondition(ProductCanonicalConditionCondition.NEW));
                newConditionNode.AsBiddableUnit().CpcBid = 200000;

                ProductPartitionNode usedConditionNode = rootNode.AddChild(
                    ProductDimensions.CreateCanonicalCondition(ProductCanonicalConditionCondition.USED));
                usedConditionNode.AsBiddableUnit().CpcBid = 100000;

                // Add a subdivision node for condition = null (everything else).
                ProductPartitionNode otherConditionNode =
                    rootNode.AddChild(ProductDimensions.CreateCanonicalCondition()).AsSubdivision();

                // Add a unit node under condition = null for brand = "CoolBrand".
                ProductPartitionNode coolBrandNode = otherConditionNode.AddChild(
                    ProductDimensions.CreateBrand("CoolBrand"));
                coolBrandNode.AsBiddableUnit().CpcBid = 900000L;

                // Add a unit node under condition = null for brand = "CheapBrand".
                ProductPartitionNode cheapBrandNode = otherConditionNode.AddChild(
                    ProductDimensions.CreateBrand("CheapBrand"));
                cheapBrandNode.AsBiddableUnit().CpcBid = 10000L;

                // Add a subdivision node under condition = null for brand = null (everything else).
                ProductPartitionNode otherBrandNode = otherConditionNode.AddChild(
                    ProductDimensions.CreateBrand(null)).AsSubdivision();

                // Add unit nodes under condition = null/brand = null.
                // The value for each bidding category is a fixed ID for a specific
                // category. You can retrieve IDs for categories from the ConstantDataService.
                // See the 'GetProductCategoryTaxonomy' example for more details.

                // Add a unit node under condition = null/brand = null for product type
                // level 1 = 'Luggage & Bags'.
                ProductPartitionNode luggageAndBagNode = otherBrandNode.AddChild(
                    ProductDimensions.CreateBiddingCategory(ProductDimensionType.BIDDING_CATEGORY_L1,
                                                            -5914235892932915235L));
                luggageAndBagNode.AsBiddableUnit().CpcBid = 750000L;

                // Add a unit node under condition = null/brand = null for product type
                // level 1 = null (everything else).
                ProductPartitionNode everythingElseNode = otherBrandNode.AddChild(
                    ProductDimensions.CreateBiddingCategory(ProductDimensionType.BIDDING_CATEGORY_L1));
                everythingElseNode.AsBiddableUnit().CpcBid = 110000L;

                try {
                    // Make the mutate request, using the operations returned by the ProductPartitionTree.
                    AdGroupCriterionOperation[] mutateOperations = partitionTree.GetMutateOperations();

                    if (mutateOperations.Length == 0)
                    {
                        Console.WriteLine("Skipping the mutate call because the original tree and the " +
                                          "current tree are logically identical.");
                    }
                    else
                    {
                        adGroupCriterionService.mutate(mutateOperations);
                    }

                    // The request was successful, so create a new ProductPartitionTree based on the updated
                    // state of the ad group.
                    partitionTree = ProductPartitionTree.DownloadAdGroupTree(user, adGroupId);

                    Console.WriteLine("Final tree: {0}", partitionTree);
                } catch (Exception e) {
                    throw new System.ApplicationException("Failed to set shopping product partition.", e);
                }
            }
        }